From 0bf822f17b54731cb6bffa66e7660842381b2ae7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 11 Feb 2016 16:48:54 -0800 Subject: [PATCH 001/292] update and add another entity script --- .../CellScience/Scripts/moveRandomly.js | 138 ++------------- .../Scripts/zoomAndMoveRandomly.js | 159 ++++++++++++++++++ .../CellScience/backgroundMusicAC.js | 8 +- .../CellScience/importCellScience.js | 4 +- 4 files changed, 181 insertions(+), 128 deletions(-) create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js index a975f74733..8c3a6c0852 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js @@ -8,124 +8,32 @@ var self = this; - this.preload = function(entityId) { - //print('preload move randomly') + this.preload=function(entityId){ this.isConnected = false; this.entityId = entityId; - this.updateInterval = 100; - this.posFrame = 0; - this.rotFrame = 0; - this.posInterval = 100; - this.rotInterval = 100; this.minVelocity = 1; this.maxVelocity = 5; this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; - - this.initialize(entityId); - this.initTimeout = null; - - - var userData = { - ownershipKey: { - owner: MyAvatar.sessionUUID - }, - grabbableKey: { - grabbable: false - } - }; - - Entities.editEntity(entityId, { - userData: JSON.stringify(userData) - }) + Script.setTimeout(self.move,self.getTotalWait()) } - this.initialize = function(entityId) { - //print('move randomly should initialize' + entityId) - var properties = Entities.getEntityProperties(entityId); - if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { - self.initTimeout = Script.setTimeout(function() { - //print('no user data yet, try again in one second') - self.initialize(entityId); - }, 1000) - } else { - //print('userdata before parse attempt' + properties.userData) - self.userData = null; - try { - self.userData = JSON.parse(properties.userData); - } catch (err) { - //print('error parsing json'); - //print('properties are:' + properties.userData); - return; - } - Script.update.connect(self.update); - this.isConnected = true; - } - } - - this.update = function(deltaTime) { - // print('jbp in update') - var data = Entities.getEntityProperties(self.entityId, 'userData').userData; - var userData; - try { - userData = JSON.parse(data) - } catch (e) { - //print('error parsing json' + data) - return; - }; - - // print('userdata is' + data) - //if the entity doesnt have an owner set yet - if (userData.hasOwnProperty('ownershipKey') !== true) { - //print('no movement owner yet') - return; - } - - //print('owner is:::' + userData.ownershipKey.owner) - //get all the avatars to see if the owner is around + this.getTotalWait = function() { var avatars = AvatarList.getAvatarIdentifiers(); - var ownerIsAround = false; + var avatarCount = avatars.length; + var random = Math.random() * 2000; + var totalWait = random * (avatarCount * 2); - //if the current owner is not me... - if (userData.ownershipKey.owner !== MyAvatar.sessionUUID) { + return totalWait + } - //look to see if the current owner is around anymore - for (var i = 0; i < avatars.length; i++) { - if (avatars[i] === userData.ownershipKey.owner) { - ownerIsAround = true - //the owner is around - return; - }; - } - //if the owner is not around, then take ownership - if (ownerIsAround === false) { - //print('taking ownership') + this.move = function() { + print('jbp im the owner so move it') + + - var userData = { - ownershipKey: { - owner: MyAvatar.sessionUUID - }, - grabbableKey: { - grabbable: false - } - }; - Entities.editEntity(self.entityId, { - userData: JSON.stringify(data) - }) - } - } - //but if the current owner IS me, then move it - else { - //print('jbp im the owner so move it') - self.posFrame++; - self.rotFrame++; - - if (self.posFrame > self.posInterval) { - - self.posInterval = 100 * Math.random() + 300; - self.posFrame = 0; var magnitudeV = self.maxVelocity; var directionV = { @@ -137,16 +45,9 @@ //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); Entities.editEntity(self.entityId, { velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)) - }); - } - - if (self.rotFrame > self.rotInterval) { - - self.rotInterval = 100 * Math.random() + 250; - self.rotFrame = 0; - + var magnitudeAV = self.maxAngularVelocity; var directionAV = { @@ -160,20 +61,13 @@ }); - } - - } + + Script.setTimeout(self.move,self.getTotalWait()) } - this.unload = function() { - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - if (this.isConnected === true) { - Script.update.disconnect(this.update); - } + this.unload = function() { } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js new file mode 100644 index 0000000000..f0f77b12e0 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -0,0 +1,159 @@ +// Copyright 2016 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + var teleport; + var portalDestination; + var animationURL; + var self = this; + + this.entered = true; + + this.preload = function(entityID) { + this.entityId = entityID; + this.initialize(entityID); + this.initTimeout = null; + this.minVelocity = 1; + this.maxVelocity = 5; + this.minAngularVelocity = 0.01; + this.maxAngularVelocity = 0.03; + Script.setTimeout(self.move, self.getTotalWait()) + } + + this.initialize = function(entityID) { + // print(' should initialize') + var properties = Entities.getEntityProperties(entityID); + if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { + self.initTimeout = Script.setTimeout(function() { + // print(' no user data yet, try again in one second') + self.initialize(entityID); + }, 1000) + } else { + // print(' has userData') + self.portalDestination = properties.userData; + animationURL = properties.modelURL; + self.soundOptions = { + stereo: true, + loop: false, + localOnly: false, + position: properties.position, + volume: 0.5 + }; + + self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); + // print(" portal destination is " + self.portalDestination); + } + } + + this.enterEntity = function(entityID) { + //print('ENTERED A BOUNDARY ENTITY, SHOULD ZOOM', entityID) + var data = JSON.parse(Entities.getEntityProperties(this.entityId).userData); + //print('DATA IS::' + data) + if (data != null) { + print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); + + MyAvatar.position = data.location; + + // if (data.hasOwnProperty('entryPoint') && data.hasOwnProperty('target')) { + // this.lookAtTarget(data.entryPoint, data.target); + // } + // else{ + + // } + } + + } + + this.lookAtTarget = function(entryPoint, target) { + //print('SHOULD LOOK AT TARGET') + var direction = Vec3.normalize(Vec3.subtract(entryPoint, target)); + var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, { + x: 1, + y: 0, + z: 0 + }); + var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, { + x: 0, + y: 1, + z: 0 + }); + + MyAvatar.goToLocation(entryPoint, true, yaw); + + MyAvatar.headYaw = 0; + + } + + this.leaveEntity = function(entityID) { + Entities.editEntity(entityID, { + animationURL: animationURL, + animationSettings: '{ "frameIndex": 1, "running": false }' + }); + this.entered = false; + if (this.initTimeout !== null) { + Script.clearTimeout(this.initTimeout); + } + //playSound(); + } + + this.unload = function() { + if (this.initTimeout !== null) { + Script.clearTimeout(this.initTimeout); + } + } + + this.hoverEnterEntity = function(entityID) { + Entities.editEntity(entityID, { + animationURL: animationURL, + animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }' + }); + } + + this.getTotalWait = function() { + var avatars = AvatarList.getAvatarIdentifiers(); + var avatarCount = avatars.length; + var random = Math.random() * 2000; + var totalWait = random * (avatarCount * 2); + + return totalWait + } + + + this.move = function() { + print('jbp im the owner so move it') + + var magnitudeV = self.maxVelocity; + var directionV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + + //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); + Entities.editEntity(self.entityId, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)) + }); + + + + var magnitudeAV = self.maxAngularVelocity; + + var directionAV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + Entities.editEntity(self.entityId, { + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + + }); + + Script.setTimeout(self.move, self.getTotalWait()) + } + +}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js b/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js index 0ee5b3bf32..1b4c06caaa 100644 --- a/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js +++ b/unpublishedScripts/DomainContent/CellScience/backgroundMusicAC.js @@ -7,7 +7,7 @@ var soundMap = [{ y: 15850, z: 15850 }, - volume: 0.1, + volume: 0.03, loop: true } }, { @@ -19,7 +19,7 @@ var soundMap = [{ y: 15950, z: 15950 }, - volume: 0.1, + volume: 0.03, loop: true } }, { @@ -31,7 +31,7 @@ var soundMap = [{ y: 15650, z: 15650 }, - volume: 0.1, + volume: 0.03, loop: true } }, { @@ -43,7 +43,7 @@ var soundMap = [{ y: 15750, z: 15750 }, - volume: 0.1, + volume: 0.03, loop: true } } diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index ca0eb21f21..7d9a49294f 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1035; +var version = 1039; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -120,7 +120,7 @@ var scenes = [{ location: locations.cellLayout[1], baseURL: baseLocation }), - script: "zoom.js?" + version, + script: "zoomAndMoveRandomly.js?" + version, visible: true }], boundary: { From f346ac7023c4ea9f4819bc13677867ac9b9add91 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 12 Feb 2016 13:58:02 -0800 Subject: [PATCH 002/292] logging --- examples/gridTest.js | 5 +++-- .../CellScience/Scripts/moveRandomly.js | 8 ++------ .../CellScience/Scripts/navigationButton.js | 6 +++--- .../CellScience/Scripts/showIdentification.js | 3 ++- .../DomainContent/CellScience/Scripts/zoom.js | 1 + .../Scripts/zoomAndMoveRandomly.js | 1 - .../CellScience/importCellScience.js | 20 +++++++++++-------- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/examples/gridTest.js b/examples/gridTest.js index 0d6040470f..5bbd3246ae 100644 --- a/examples/gridTest.js +++ b/examples/gridTest.js @@ -17,8 +17,8 @@ var SIZE = 10.0; var SEPARATION = 20.0; var ROWS_X = 30; var ROWS_Z = 30; -var TYPE = "Sphere"; // Right now this can be "Box" or "Model" or "Sphere" -var MODEL_URL = "https://hifi-public.s3.amazonaws.com/models/props/LowPolyIsland/CypressTreeGroup.fbx"; +var TYPE = "Model"; // Right now this can be "Box" or "Model" or "Sphere" +var MODEL_URL = "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Instances/vesicle.fbx"; var MODEL_DIMENSION = { x: 33, y: 16, z: 49 }; var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast. var SCRIPT_INTERVAL = 100; @@ -38,6 +38,7 @@ Script.setInterval(function () { var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); for (var i = 0; i < numToCreate; i++) { var position = { x: SIZE + (x * SEPARATION), y: SIZE, z: SIZE + (z * SEPARATION) }; + print('position:'+JSON.stringify(position)) if (TYPE == "Model") { Entities.addEntity({ type: TYPE, diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js index 8c3a6c0852..2cced94672 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js @@ -9,6 +9,7 @@ var self = this; this.preload=function(entityId){ + print('JBP MOVE RANDOMLY PRELOAD') this.isConnected = false; this.entityId = entityId; this.minVelocity = 1; @@ -22,7 +23,7 @@ this.getTotalWait = function() { var avatars = AvatarList.getAvatarIdentifiers(); var avatarCount = avatars.length; - var random = Math.random() * 2000; + var random = Math.random() * 5000; var totalWait = random * (avatarCount * 2); return totalWait @@ -30,11 +31,6 @@ this.move = function() { - print('jbp im the owner so move it') - - - - var magnitudeV = self.maxVelocity; var directionV = { x: Math.random() - 0.5, diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js index 4136f1f81b..16fb31189a 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js @@ -17,6 +17,7 @@ var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; this.preload = function(entityId) { + print('JBP NAV PRELOAD') this.entityId = entityId; this.initialize(entityId); this.initTimeout = null; @@ -58,14 +59,13 @@ self.buttonImageURL = baseURL + "GUI/GUI_" + self.userData.name + ".png?" + version; print('JBP BUTTON IMAGE URL:' + self.buttonImageURL) if (self.button === undefined) { - // print('NAV NO BUTTON ADDING ONE!!') + print('JBP NO BUTTON ADDING ONE!!') self.button = true; self.addButton(); } else { - // print('NAV SELF ALREADY HAS A BUTTON!!') + print('JBP SELF ALREADY HAS A BUTTON!!') } - } } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index d8b32ab176..b7aad5e652 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -10,8 +10,9 @@ var self = this; var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; - var version = 2; + var version = 3; this.preload = function(entityId) { + print('JBP SHOW IDENTIFICATION PRELOAD') this.soundPlaying = null; this.entityId = entityId; self.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index da41ec64ba..d075966524 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -14,6 +14,7 @@ this.entered = true; this.preload = function(entityID) { + print('JBP Zoom PRELOAD') this.entityId = entityID; this.initialize(entityID); this.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index f0f77b12e0..e4ee59cb6b 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -124,7 +124,6 @@ this.move = function() { - print('jbp im the owner so move it') var magnitudeV = self.maxVelocity; var directionV = { diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 7d9a49294f..bf112f5bad 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1039; +var version = 1041; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -645,8 +645,7 @@ function createLayoutLights() { } function CreateNavigationButton(scene, number) { - // print('NAV NAVIGATION CREATING NAV!!' +scene.name + " " + number) - + print('JBP NAVIGATION CREATING NAV!!' +scene.name + " " + number) Entities.addEntity({ type: "Box", @@ -657,11 +656,11 @@ function CreateNavigationButton(scene, number) { blue: 0 }, dimensions: { - x: 16000, - y: 16000, - z: 16000 + x: 14000, + y: 14000, + z: 14000 }, - visible: false, + visible: true, userData: JSON.stringify({ name: scene.name, entryPoint: scene.entryPoint, @@ -9045,4 +9044,9 @@ createLayoutLights(); Script.scriptEnding.connect(function() { Entities.addingEntity.disconnect(makeUngrabbable); -}); \ No newline at end of file +}); + +Script.setTimeout(function(){ + print('JBP stopping cell science import'); + Script.stop(); +},30000) \ No newline at end of file From e828a7e6e2b2fd0dfae93bfa202108b01698ce87 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 12 Feb 2016 19:38:40 -0800 Subject: [PATCH 003/292] quiet prints --- .../CellScience/Scripts/moveRandomly.js | 1 - .../CellScience/Scripts/navigationButton.js | 22 +++++++++---------- .../CellScience/Scripts/showIdentification.js | 1 - .../DomainContent/CellScience/Scripts/zoom.js | 1 - .../CellScience/importCellScience.js | 14 +++++------- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js index 2cced94672..cc822ddf8a 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js @@ -9,7 +9,6 @@ var self = this; this.preload=function(entityId){ - print('JBP MOVE RANDOMLY PRELOAD') this.isConnected = false; this.entityId = entityId; this.minVelocity = 1; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js index 16fb31189a..c1187bc6d5 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/navigationButton.js @@ -7,7 +7,7 @@ (function() { - var version = 11; + var version = 12; var added = false; this.frame = 0; var utilsScript = Script.resolvePath('utils.js'); @@ -17,29 +17,27 @@ var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; this.preload = function(entityId) { - print('JBP NAV PRELOAD') this.entityId = entityId; this.initialize(entityId); this.initTimeout = null; } this.initialize = function(entityId) { - print('JBP nav button should initialize' + entityId) var properties = Entities.getEntityProperties(entityId); if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { self.initTimeout = Script.setTimeout(function() { - print('JBP no user data yet, try again in one second') + // print(' no user data yet, try again in one second') self.initialize(entityId); }, 1000) } else { - print('JBP userdata before parse attempt' + properties.userData) + // print('userdata before parse attempt' + properties.userData) self.userData = null; try { self.userData = JSON.parse(properties.userData); } catch (err) { - print('JBP error parsing json'); - print('JBP properties are:' + properties.userData); + // print(' error parsing json'); + // print(' properties are:' + properties.userData); return; } @@ -47,9 +45,9 @@ var mySavedSettings = Settings.getValue(entityId); if (mySavedSettings.buttons !== undefined) { - print('JBP preload buttons' + mySavedSettings.buttons) + // print(' preload buttons' + mySavedSettings.buttons) mySavedSettings.buttons.forEach(function(b) { - print('JBP deleting button' + b) + // print(' deleting button' + b) Overlays.deleteOverlay(b); }) Settings.setValue(entityId, '') @@ -57,14 +55,14 @@ self.buttonImageURL = baseURL + "GUI/GUI_" + self.userData.name + ".png?" + version; - print('JBP BUTTON IMAGE URL:' + self.buttonImageURL) + // print(' BUTTON IMAGE URL:' + self.buttonImageURL) if (self.button === undefined) { - print('JBP NO BUTTON ADDING ONE!!') + // print(' NO BUTTON ADDING ONE!!') self.button = true; self.addButton(); } else { - print('JBP SELF ALREADY HAS A BUTTON!!') + //print(' SELF ALREADY HAS A BUTTON!!') } } } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js index b7aad5e652..3f6067693c 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showIdentification.js @@ -12,7 +12,6 @@ var version = 3; this.preload = function(entityId) { - print('JBP SHOW IDENTIFICATION PRELOAD') this.soundPlaying = null; this.entityId = entityId; self.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index d075966524..da41ec64ba 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -14,7 +14,6 @@ this.entered = true; this.preload = function(entityID) { - print('JBP Zoom PRELOAD') this.entityId = entityID; this.initialize(entityID); this.initTimeout = null; diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index bf112f5bad..db50635f93 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1041; +var version = 1043; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -609,12 +609,10 @@ function ImportScene(scene) { clearAllNav(); function clearAllNav() { - // print('NAV CLEARING ALL NAV'); var result = Entities.findEntities(MyAvatar.position, 25000); result.forEach(function(r) { var properties = Entities.getEntityProperties(r, "name"); if (properties.name.indexOf('navigation button') > -1) { - // print('NAV DELETING NAV BUTTON AT START:: '+r) Entities.deleteEntity(r); } }) @@ -645,8 +643,6 @@ function createLayoutLights() { } function CreateNavigationButton(scene, number) { - print('JBP NAVIGATION CREATING NAV!!' +scene.name + " " + number) - Entities.addEntity({ type: "Box", name: scene.name + " navigation button", @@ -656,11 +652,11 @@ function CreateNavigationButton(scene, number) { blue: 0 }, dimensions: { - x: 14000, - y: 14000, - z: 14000 + x: 16000, + y: 16000, + z: 16000 }, - visible: true, + visible: false, userData: JSON.stringify({ name: scene.name, entryPoint: scene.entryPoint, From 0ad7bacf02f359929c81e56afe72bb212c2fcb85 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 15 Feb 2016 21:50:10 -0800 Subject: [PATCH 004/292] Changing diffuse to albedo and breaking everything... --- interface/src/ModelPackager.cpp | 6 +-- libraries/fbx/src/FBXReader.h | 2 +- libraries/fbx/src/FBXReader_Material.cpp | 4 +- libraries/fbx/src/OBJReader.cpp | 4 +- .../src/model-networking/ModelCache.cpp | 36 +++++++++--------- .../src/model-networking/ModelCache.h | 4 +- libraries/model/src/model/Material.cpp | 6 +-- libraries/model/src/model/Material.h | 36 +++++++++--------- libraries/model/src/model/Material.slh | 38 ++----------------- libraries/model/src/model/TextureMap.h | 2 +- .../render-utils/src/DebugDeferredBuffer.cpp | 14 +++---- .../render-utils/src/DebugDeferredBuffer.h | 2 +- .../src/DeferredLightingEffect.cpp | 6 +-- libraries/render-utils/src/GeometryCache.cpp | 4 +- .../render-utils/src/MeshPartPayload.cpp | 18 ++++----- libraries/render-utils/src/Model.cpp | 2 +- .../render-utils/src/RenderPipelines.cpp | 6 +-- libraries/render-utils/src/model.slf | 2 +- libraries/render-utils/src/model_emissive.slf | 2 +- libraries/render-utils/src/model_lightmap.slf | 2 +- .../src/model_lightmap_normal_map.slf | 2 +- .../model_lightmap_normal_specular_map.slf | 2 +- .../src/model_lightmap_specular_map.slf | 2 +- .../render-utils/src/model_normal_map.slf | 2 +- .../src/model_normal_specular_map.slf | 2 +- .../render-utils/src/model_specular_map.slf | 12 +++--- .../render-utils/src/model_translucent.slf | 8 ++-- .../src/model_translucent_emissive.slf | 8 ++-- .../src/skin_model_normal_map.slv | 2 +- libraries/render/src/render/ShapePipeline.cpp | 4 +- libraries/render/src/render/ShapePipeline.h | 4 +- 31 files changed, 106 insertions(+), 138 deletions(-) diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 64ab76c64c..fa87a5f657 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -342,9 +342,9 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename void ModelPackager::listTextures() { _textures.clear(); foreach (const FBXMaterial mat, _geometry->materials) { - if (!mat.diffuseTexture.filename.isEmpty() && mat.diffuseTexture.content.isEmpty() && - !_textures.contains(mat.diffuseTexture.filename)) { - _textures << mat.diffuseTexture.filename; + if (!mat.albedoTexture.filename.isEmpty() && mat.albedoTexture.content.isEmpty() && + !_textures.contains(mat.albedoTexture.filename)) { + _textures << mat.albedoTexture.filename; } if (!mat.normalTexture.filename.isEmpty() && mat.normalTexture.content.isEmpty() && !_textures.contains(mat.normalTexture.filename)) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 51cb5baf9f..6dc8a31bc7 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -151,7 +151,7 @@ public: QString materialID; model::MaterialPointer _material; - FBXTexture diffuseTexture; + FBXTexture albedoTexture; FBXTexture opacityTexture; FBXTexture normalTexture; FBXTexture specularTexture; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index e947a0356e..b82d4c0877 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -79,7 +79,7 @@ void FBXReader::consolidateFBXMaterials() { } } - material.diffuseTexture = diffuseTexture; + material.albedoTexture = diffuseTexture; detectDifferentUVs = (diffuseTexture.texcoordSet != 0) || (!diffuseTexture.transform.isIdentity()); } @@ -140,7 +140,7 @@ void FBXReader::consolidateFBXMaterials() { auto diffuse = material.diffuseColor; // FIXME: Do not use the Diffuse Factor yet as some FBX models have it set to 0 // diffuse *= material.diffuseFactor; - material._material->setDiffuse(diffuse); + material._material->setAlbedo(diffuse); float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z)); // FIXME: Do not use the Specular Factor yet as some FBX models have it set to 0 diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 11164afbbb..3286e5e974 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -555,11 +555,11 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, model::MaterialPointer modelMaterial = fbxMaterial._material; if (!objMaterial.diffuseTextureFilename.isEmpty()) { - fbxMaterial.diffuseTexture.filename = objMaterial.diffuseTextureFilename; + fbxMaterial.albedoTexture.filename = objMaterial.diffuseTextureFilename; } modelMaterial->setEmissive(fbxMaterial.emissiveColor); - modelMaterial->setDiffuse(fbxMaterial.diffuseColor); + modelMaterial->setAlbedo(fbxMaterial.diffuseColor); modelMaterial->setMetallic(glm::length(fbxMaterial.specularColor)); modelMaterial->setGloss(fbxMaterial.shininess); diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2f8e04890c..6551ca5a60 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -136,7 +136,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { if (!_isLoadedWithTextures) { for (auto&& material : _materials) { - if ((material->diffuseTexture && !material->diffuseTexture->isLoaded()) || + if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || (material->normalTexture && !material->normalTexture->isLoaded()) || (material->specularTexture && !material->specularTexture->isLoaded()) || (material->emissiveTexture && !material->emissiveTexture->isLoaded())) { @@ -154,15 +154,15 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u for (auto&& material : _materials) { auto networkMaterial = material->_material; auto oldTextureMaps = networkMaterial->getTextureMaps(); - if (material->diffuseTextureName == name) { - material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE); + if (material->albedoTextureName == name) { + material->albedoTexture = textureCache->getTexture(url, DEFAULT_TEXTURE); - auto diffuseMap = model::TextureMapPointer(new model::TextureMap()); - diffuseMap->setTextureSource(material->diffuseTexture->_textureSource); - diffuseMap->setTextureTransform( - oldTextureMaps[model::MaterialKey::DIFFUSE_MAP]->getTextureTransform()); + auto albedoMap = model::TextureMapPointer(new model::TextureMap()); + albedoMap->setTextureSource(material->albedoTexture->_textureSource); + albedoMap->setTextureTransform( + oldTextureMaps[model::MaterialKey::ALBEDO_MAP]->getTextureTransform()); - networkMaterial->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); + networkMaterial->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); } else if (material->normalTextureName == name) { material->normalTexture = textureCache->getTexture(url); @@ -200,9 +200,9 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u QStringList NetworkGeometry::getTextureNames() const { QStringList result; for (auto&& material : _materials) { - if (!material->diffuseTextureName.isEmpty() && material->diffuseTexture) { - QString textureURL = material->diffuseTexture->getURL().toString(); - result << material->diffuseTextureName + ":\"" + textureURL + "\""; + if (!material->albedoTextureName.isEmpty() && material->albedoTexture) { + QString textureURL = material->albedoTexture->getURL().toString(); + result << material->albedoTextureName + ":\"" + textureURL + "\""; } if (!material->normalTextureName.isEmpty() && material->normalTexture) { @@ -310,15 +310,15 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const networkMaterial->_material = material._material; - if (!material.diffuseTexture.filename.isEmpty()) { - networkMaterial->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content); - networkMaterial->diffuseTextureName = material.diffuseTexture.name; + if (!material.albedoTexture.filename.isEmpty()) { + networkMaterial->albedoTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.albedoTexture.filename)), DEFAULT_TEXTURE, material.albedoTexture.content); + networkMaterial->albedoTextureName = material.albedoTexture.name; - auto diffuseMap = model::TextureMapPointer(new model::TextureMap()); - diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource); - diffuseMap->setTextureTransform(material.diffuseTexture.transform); + auto albedoMap = model::TextureMapPointer(new model::TextureMap()); + albedoMap->setTextureSource(networkMaterial->albedoTexture->_textureSource); + albedoMap->setTextureTransform(material.albedoTexture.transform); - material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); + material._material->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); } if (!material.normalTexture.filename.isEmpty()) { networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index b2d81c5900..2cb67e7e87 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -174,8 +174,8 @@ public: class NetworkMaterial { public: model::MaterialPointer _material; - QString diffuseTextureName; - QSharedPointer diffuseTexture; + QString albedoTextureName; + QSharedPointer albedoTexture; QString normalTextureName; QSharedPointer normalTexture; QString specularTextureName; diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 1d0f6ee5d9..95f540e762 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -44,9 +44,9 @@ Material& Material::operator= (const Material& material) { Material::~Material() { } -void Material::setDiffuse(const Color& diffuse, bool isSRGB) { - _key.setDiffuse(glm::any(glm::greaterThan(diffuse, Color(0.0f)))); - _schemaBuffer.edit()._diffuse = (isSRGB ? ColorUtils::toLinearVec3(diffuse) : diffuse); +void Material::setAlbedo(const Color& albedo, bool isSRGB) { + _key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f)))); + _schemaBuffer.edit()._albedo = (isSRGB ? ColorUtils::toLinearVec3(albedo) : albedo); } void Material::setMetallic(float metallic) { diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index cb5a285dba..d2c7a04683 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -28,13 +28,13 @@ class MaterialKey { public: enum FlagBit { EMISSIVE_VAL_BIT = 0, - DIFFUSE_VAL_BIT, + ALBEDO_VAL_BIT, METALLIC_VAL_BIT, GLOSS_VAL_BIT, TRANSPARENT_VAL_BIT, EMISSIVE_MAP_BIT, - DIFFUSE_MAP_BIT, + ALBEDO_MAP_BIT, METALLIC_MAP_BIT, GLOSS_MAP_BIT, TRANSPARENT_MAP_BIT, @@ -47,7 +47,7 @@ public: enum MapChannel { EMISSIVE_MAP = 0, - DIFFUSE_MAP, + ALBEDO_MAP, METALLIC_MAP, GLOSS_MAP, TRANSPARENT_MAP, @@ -71,13 +71,13 @@ public: MaterialKey build() const { return MaterialKey(_flags); } Builder& withEmissive() { _flags.set(EMISSIVE_VAL_BIT); return (*this); } - Builder& withDiffuse() { _flags.set(DIFFUSE_VAL_BIT); return (*this); } + Builder& withAlbedo() { _flags.set(ALBEDO_VAL_BIT); return (*this); } Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); } Builder& withGloss() { _flags.set(GLOSS_VAL_BIT); return (*this); } Builder& withTransparent() { _flags.set(TRANSPARENT_VAL_BIT); return (*this); } Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); } - Builder& withDiffuseMap() { _flags.set(DIFFUSE_MAP_BIT); return (*this); } + Builder& withAlbedoMap() { _flags.set(ALBEDO_MAP_BIT); return (*this); } Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); } Builder& withGlossMap() { _flags.set(GLOSS_MAP_BIT); return (*this); } Builder& withTransparentMap() { _flags.set(TRANSPARENT_MAP_BIT); return (*this); } @@ -86,7 +86,7 @@ public: Builder& withLightmapMap() { _flags.set(LIGHTMAP_MAP_BIT); return (*this); } // Convenient standard keys that we will keep on using all over the place - static MaterialKey opaqueDiffuse() { return Builder().withDiffuse().build(); } + static MaterialKey opaqueAlbedo() { return Builder().withAlbedo().build(); } }; void setEmissive(bool value) { _flags.set(EMISSIVE_VAL_BIT, value); } @@ -95,11 +95,11 @@ public: void setEmissiveMap(bool value) { _flags.set(EMISSIVE_MAP_BIT, value); } bool isEmissiveMap() const { return _flags[EMISSIVE_MAP_BIT]; } - void setDiffuse(bool value) { _flags.set(DIFFUSE_VAL_BIT, value); } - bool isDiffuse() const { return _flags[DIFFUSE_VAL_BIT]; } + void setAlbedo(bool value) { _flags.set(ALBEDO_VAL_BIT, value); } + bool isAlbedo() const { return _flags[ALBEDO_VAL_BIT]; } - void setDiffuseMap(bool value) { _flags.set(DIFFUSE_MAP_BIT, value); } - bool isDiffuseMap() const { return _flags[DIFFUSE_MAP_BIT]; } + void setAlbedoMap(bool value) { _flags.set(ALBEDO_MAP_BIT, value); } + bool isAlbedoMap() const { return _flags[ALBEDO_MAP_BIT]; } void setMetallic(bool value) { _flags.set(METALLIC_VAL_BIT, value); } bool isMetallic() const { return _flags[METALLIC_VAL_BIT]; } @@ -154,11 +154,11 @@ public: Builder& withoutEmissiveMap() { _value.reset(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); } Builder& withEmissiveMap() { _value.set(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); } - Builder& withoutDiffuse() { _value.reset(MaterialKey::DIFFUSE_VAL_BIT); _mask.set(MaterialKey::DIFFUSE_VAL_BIT); return (*this); } - Builder& withDiffuse() { _value.set(MaterialKey::DIFFUSE_VAL_BIT); _mask.set(MaterialKey::DIFFUSE_VAL_BIT); return (*this); } + Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } + Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } - Builder& withoutDiffuseMap() { _value.reset(MaterialKey::DIFFUSE_MAP_BIT); _mask.set(MaterialKey::DIFFUSE_MAP_BIT); return (*this); } - Builder& withDiffuseMap() { _value.set(MaterialKey::DIFFUSE_MAP_BIT); _mask.set(MaterialKey::DIFFUSE_MAP_BIT); return (*this); } + Builder& withoutAlbedoMap() { _value.reset(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } + Builder& withAlbedoMap() { _value.set(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } Builder& withoutMetallic() { _value.reset(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT); return (*this); } Builder& withMetallic() { _value.set(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT); return (*this); } @@ -185,7 +185,7 @@ public: Builder& withLightmapMap() { _value.set(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); } // Convenient standard keys that we will keep on using all over the place - static MaterialFilter opaqueDiffuse() { return Builder().withDiffuse().withoutTransparent().build(); } + static MaterialFilter opaqueAlbedo() { return Builder().withAlbedo().withoutTransparent().build(); } }; // Item Filter operator testing if a key pass the filter @@ -223,8 +223,8 @@ public: void setEmissive(const Color& emissive, bool isSRGB = true); Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._emissive) : _schemaBuffer.get()._emissive); } - void setDiffuse(const Color& diffuse, bool isSRGB = true); - Color getDiffuse(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._diffuse) : _schemaBuffer.get()._diffuse); } + void setAlbedo(const Color& albedo, bool isSRGB = true); + Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._albedo) : _schemaBuffer.get()._albedo); } void setMetallic(float metallic); float getMetallic() const { return _schemaBuffer.get()._metallic.x; } @@ -239,7 +239,7 @@ public: class Schema { public: - glm::vec3 _diffuse{ 0.5f }; + glm::vec3 _albedo{ 0.5f }; float _opacity{1.f}; glm::vec3 _metallic{ 0.03f }; float _gloss{0.1f}; diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index f48bdfa8f1..1f9a290fe7 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -12,7 +12,7 @@ <@def MODEL_MATERIAL_SLH@> struct Material { - vec4 _diffuse; + vec4 _albedoOpacity; vec4 _specular; vec4 _emissive; vec4 _spare; @@ -26,40 +26,8 @@ Material getMaterial() { return _mat; } - 0.04045 - // constants: - // T = 0.04045 - // A = 1 / 1.055 = 0.94786729857 - // B = 0.055 * A = 0.05213270142 - // C = 1 / 12.92 = 0.0773993808 - // G = 2.4 - const float T = 0.04045; - const float A = 0.947867; - const float B = 0.052132; - const float C = 0.077399; - const float G = 2.4; - - if (cs > T) { - return pow((cs * A + B), G); - } else { - return cs * C; - } -} - -vec3 SRGBToLinear(vec3 srgb) { - return vec3(componentSRGBToLinear(srgb.x),componentSRGBToLinear(srgb.y),componentSRGBToLinear(srgb.z)); -} -vec3 getMaterialDiffuse(Material m) { return (gl_FragCoord.x < 800 ? SRGBToLinear(m._diffuse.rgb) : m._diffuse.rgb); } -*/!> - -float getMaterialOpacity(Material m) { return m._diffuse.a; } -vec3 getMaterialDiffuse(Material m) { return m._diffuse.rgb; } +float getMaterialOpacity(Material m) { return m._albedoOpacity.a; } +vec3 getMaterialAlbedo(Material m) { return m._albedoOpacity.rgb; } vec3 getMaterialSpecular(Material m) { return m._specular.rgb; } float getMaterialShininess(Material m) { return m._specular.a; } diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index 6bc5b8228c..4b625356e9 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -27,7 +27,7 @@ typedef glm::vec3 Color; class TextureUsage { public: gpu::Texture::Type _type{ gpu::Texture::TEX_2D }; - Material::MapFlags _materialUsage{ MaterialKey::DIFFUSE_MAP }; + Material::MapFlags _materialUsage{ MaterialKey::ALBEDO_MAP }; int _environmentUsage = 0; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 06d8709dc5..0be3ce422d 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -39,7 +39,7 @@ void DebugDeferredBufferConfig::setMode(int newMode) { } enum Slot { - Diffuse = 0, + Albedo = 0, Normal, Specular, Depth, @@ -52,9 +52,9 @@ enum Slot { -static const std::string DEFAULT_DIFFUSE_SHADER { +static const std::string DEFAULT_ALBEDO_SHADER { "vec4 getFragmentColor() {" - " return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" + " return vec4(pow(texture(albedoMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; @@ -144,8 +144,8 @@ DebugDeferredBuffer::DebugDeferredBuffer() { std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string customFile) { switch (mode) { - case DiffuseMode: - return DEFAULT_DIFFUSE_SHADER; + case AlbedoMode: + return DEFAULT_ALBEDO_SHADER; case SpecularMode: return DEFAULT_SPECULAR_SHADER; case RoughnessMode: @@ -206,7 +206,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str const auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding("diffuseMap", Diffuse)); + slotBindings.insert(gpu::Shader::Binding("albedoMap", Albedo)); slotBindings.insert(gpu::Shader::Binding("normalMap", Normal)); slotBindings.insert(gpu::Shader::Binding("specularMap", Specular)); slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); @@ -262,7 +262,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setPipeline(getPipeline(_mode, first)); - batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture()); + batch.setResourceTexture(Albedo, framebufferCache->getDeferredColorTexture()); batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture()); batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index b31985d6a3..221de9a68e 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -47,7 +47,7 @@ protected: enum Mode : uint8_t { // Use Mode suffix to avoid collisions - DiffuseMode = 0, + AlbedoMode = 0, SpecularMode, RoughnessMode, NormalMode, diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index d0387cd3d4..d66c1ba2a3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -525,7 +525,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), DEFERRED_BUFFER_COLOR_UNIT)); + slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), DEFERRED_BUFFER_COLOR_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), DEFERRED_BUFFER_NORMAL_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), DEFERRED_BUFFER_EMISSIVE_UNIT)); slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), DEFERRED_BUFFER_DEPTH_UNIT)); @@ -584,10 +584,10 @@ void DeferredLightingEffect::setAmbientLightMode(int preset) { } } -void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity) { +void DeferredLightingEffect::setGlobalLight(const glm::vec3& direction, const glm::vec3& color, float intensity, float ambientIntensity) { auto light = _allocatedLights.front(); light->setDirection(direction); - light->setColor(diffuse); + light->setColor(color); light->setIntensity(intensity); light->setAmbientIntensity(ambientIntensity); } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index ed6b8f2f5b..34a02b51d2 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -504,7 +504,7 @@ GeometryCache::GeometryCache() : std::make_shared(getSimplePipeline(), nullptr, [](const render::ShapePipeline&, gpu::Batch& batch) { // Set the defaults needed for a simple program - batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP, + batch.setResourceTexture(render::ShapePipeline::Slot::ALBEDO_MAP, DependencyManager::get()->getWhiteTexture()); batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, DependencyManager::get()->getNormalFittingTexture()); @@ -1848,7 +1848,7 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool cul // If not textured, set a default diffuse map if (!textured) { - batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP, + batch.setResourceTexture(render::ShapePipeline::Slot::ALBEDO_MAP, DependencyManager::get()->getWhiteTexture()); } // Set a default normal map diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index c0003219a0..31f17c3bc2 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -145,20 +145,20 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto textureMaps = _drawMaterial->getTextureMaps(); glm::mat4 texcoordTransform[2]; - // Diffuse - if (materialKey.isDiffuseMap()) { - auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP]; - if (diffuseMap && diffuseMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView()); + // Albedo + if (materialKey.isAlbedoMap()) { + auto albedoMap = textureMaps[model::MaterialKey::ALBEDO_MAP]; + if (albedoMap && albedoMap->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, albedoMap->getTextureView()); - if (!diffuseMap->getTextureTransform().isIdentity()) { - diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]); + if (!albedoMap->getTextureTransform().isIdentity()) { + albedoMap->getTextureTransform().getMatrix(texcoordTransform[0]); } } else { - batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, textureCache->getGrayTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, textureCache->getWhiteTexture()); } // Normal map diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 91c9ec623d..2ef5b5e792 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1197,7 +1197,7 @@ void Model::segregateMeshGroups() { if (showingCollisionHull) { if (!_collisionHullMaterial) { _collisionHullMaterial = std::make_shared(); - _collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f)); + _collisionHullMaterial->setAlbedo(glm::vec3(1.0f, 0.5f, 0.0f)); _collisionHullMaterial->setMetallic(0.02f); _collisionHullMaterial->setGloss(1.0f); } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index fce9ce1c28..fbaa7df1b1 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -66,7 +66,7 @@ void initStencilPipeline(gpu::PipelinePointer& pipeline) { gpu::BufferView getDefaultMaterialBuffer() { model::Material::Schema schema; - schema._diffuse = vec3(1.0f); + schema._albedo = vec3(1.0f); schema._opacity = 1.0f; schema._metallic = vec3(0.1f); schema._gloss = 10.0f; @@ -74,8 +74,8 @@ gpu::BufferView getDefaultMaterialBuffer() { } void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { - // Set a default diffuse map - batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP, + // Set a default albedo map + batch.setResourceTexture(render::ShapePipeline::Slot::ALBEDO_MAP, DependencyManager::get()->getWhiteTexture()); // Set a default normal map batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index f455030f6f..353c772327 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -33,7 +33,7 @@ void main(void) { packDeferredFragment( normalize(_normal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_emissive.slf b/libraries/render-utils/src/model_emissive.slf index 25239691cd..9705897399 100644 --- a/libraries/render-utils/src/model_emissive.slf +++ b/libraries/render-utils/src/model_emissive.slf @@ -26,7 +26,7 @@ void main(void) { vec4 texel = texture(diffuseMap, _texCoord0); Material mat = getMaterial(); - vec3 fragColor = getMaterialDiffuse(mat) * texel.rgb * _color; + vec3 fragColor = getMaterialAlbedo(mat) * texel.rgb * _color; packDeferredFragmentLightmap( normalize(_normal), diff --git a/libraries/render-utils/src/model_lightmap.slf b/libraries/render-utils/src/model_lightmap.slf index ab92d2bf4c..7cfeb5da32 100755 --- a/libraries/render-utils/src/model_lightmap.slf +++ b/libraries/render-utils/src/model_lightmap.slf @@ -38,7 +38,7 @@ void main(void) { packDeferredFragmentLightmap( normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slf b/libraries/render-utils/src/model_lightmap_normal_map.slf index 78c802be51..165ef4bf04 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map.slf @@ -51,7 +51,7 @@ void main(void) { packDeferredFragmentLightmap( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index 1b7416baa5..591cc45a40 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -55,7 +55,7 @@ void main(void) { packDeferredFragmentLightmap( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, specular, // no use of getMaterialSpecular(mat) getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index efdfcd6be9..97c1713e96 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -43,7 +43,7 @@ void main(void) { packDeferredFragmentLightmap( normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, specular, // no use of getMaterialSpecular(mat) getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 5479cec8eb..5749a437c8 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -44,7 +44,7 @@ void main(void) { packDeferredFragment( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index 2ebcdaae44..7f27747791 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -49,7 +49,7 @@ void main(void) { packDeferredFragment( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + getMaterialAlbedo(mat) * diffuse.rgb * _color, specular, //getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index e7f639194d..7e6e8f6f57 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the specular texture uniform sampler2D specularMap; @@ -29,16 +29,16 @@ in vec3 _color; void main(void) { - // set the diffuse, normal, specular data - vec4 diffuse = texture(diffuseMap, _texCoord0); + // set the albedo, normal, specular data + vec4 albedo = texture(albedoMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; Material mat = getMaterial(); packDeferredFragment( normalize(_normal), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialDiffuse(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, specular, //getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index c6f745ed0f..1ce0d22bc5 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -40,7 +40,7 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 d return vec4(color, opacity); } -uniform sampler2D diffuseMap; +uniform sampler2D albedoMap; in vec2 _texCoord0; in vec4 _position; @@ -51,15 +51,15 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(diffuseMap, _texCoord0); + vec4 albedo = texture(albedoMap, _texCoord0); Material mat = getMaterial(); vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - vec3 fragDiffuse = getMaterialDiffuse(mat) * diffuse.rgb * _color; + vec3 fragDiffuse = getMaterialAlbedo(mat) * albedo.rgb * _color; vec3 fragSpecular = getMaterialSpecular(mat); float fragGloss = getMaterialShininess(mat) / 128; - float fragOpacity = getMaterialOpacity(mat) * diffuse.a * _alpha; + float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; _fragColor = evalGlobalColor(1.0, fragPosition, diff --git a/libraries/render-utils/src/model_translucent_emissive.slf b/libraries/render-utils/src/model_translucent_emissive.slf index a2c7186f6f..82faf7cf45 100644 --- a/libraries/render-utils/src/model_translucent_emissive.slf +++ b/libraries/render-utils/src/model_translucent_emissive.slf @@ -14,7 +14,7 @@ <@include model/Material.slh@> -uniform sampler2D diffuseMap; +uniform sampler2D albedoMap; in vec2 _texCoord0; in vec3 _color; @@ -23,11 +23,11 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(diffuseMap, _texCoord0); + vec4 albedo = texture(albedoMap, _texCoord0); Material mat = getMaterial(); - vec3 fragColor = getMaterialDiffuse(mat) * diffuse.rgb * _color; - float fragOpacity = getMaterialOpacity(mat) * diffuse.a * _alpha; + vec3 fragColor = getMaterialAlbedo(mat) * albedo.rgb * _color; + float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; _fragColor = vec4(fragColor, fragOpacity); } diff --git a/libraries/render-utils/src/skin_model_normal_map.slv b/libraries/render-utils/src/skin_model_normal_map.slv index cec93a024e..003b35b79b 100755 --- a/libraries/render-utils/src/skin_model_normal_map.slv +++ b/libraries/render-utils/src/skin_model_normal_map.slv @@ -34,7 +34,7 @@ void main(void) { skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz); - // pass along the diffuse color + // pass along the color _color = colorToLinearRGB(inColor.rgb); // and the texture coordinates diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index b77c9c3451..1103507bf5 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -53,7 +53,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); - slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Slot::DIFFUSE_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::ALBEDO_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::SPECULAR_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::LIGHTMAP_MAP)); @@ -66,7 +66,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); locations->emissiveParams = program->getUniforms().findLocation("emissiveParams"); locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); - locations->diffuseTextureUnit = program->getTextures().findLocation("diffuseMap"); + locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap"); locations->normalTextureUnit = program->getTextures().findLocation("normalMap"); locations->specularTextureUnit = program->getTextures().findLocation("specularMap"); locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 4fd1dc22c5..4b6247aa54 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -195,7 +195,7 @@ public: public: static const int SKINNING_GPU = 2; static const int MATERIAL_GPU = 3; - static const int DIFFUSE_MAP = 0; + static const int ALBEDO_MAP = 0; static const int NORMAL_MAP = 1; static const int SPECULAR_MAP = 2; static const int LIGHTMAP_MAP = 3; @@ -206,7 +206,7 @@ public: class Locations { public: int texcoordMatrices; - int diffuseTextureUnit; + int albedoTextureUnit; int normalTextureUnit; int specularTextureUnit; int emissiveTextureUnit; From 71863a1550e20341a39308a03f2053a3e8a5aed4 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 16 Feb 2016 09:33:24 -0800 Subject: [PATCH 005/292] Fixing the material names --- .../entities-renderer/src/paintStroke.slf | 2 +- .../src/untextured_particle.slv | 2 +- libraries/render-utils/src/DeferredBuffer.slh | 6 ++--- .../render-utils/src/DeferredBufferWrite.slh | 12 +++++----- .../render-utils/src/DeferredGlobalLight.slh | 22 +++++++++---------- .../render-utils/src/DeferredLightingEffect.h | 2 +- libraries/render-utils/src/GeometryCache.cpp | 2 +- libraries/render-utils/src/animdebugdraw.slv | 2 +- libraries/render-utils/src/model.slf | 10 ++++----- libraries/render-utils/src/model_emissive.slf | 4 ++-- libraries/render-utils/src/model_lightmap.slf | 10 ++++----- libraries/render-utils/src/model_lightmap.slv | 2 +- .../src/model_lightmap_normal_map.slf | 10 ++++----- .../src/model_lightmap_normal_map.slv | 2 +- .../model_lightmap_normal_specular_map.slf | 12 +++++----- .../src/model_lightmap_specular_map.slf | 12 +++++----- .../render-utils/src/model_normal_map.slf | 10 ++++----- .../render-utils/src/model_normal_map.slv | 2 +- .../src/model_normal_specular_map.slf | 12 +++++----- .../render-utils/src/model_translucent.slf | 10 ++++----- libraries/render-utils/src/overlay3D.slf | 14 ++++++------ .../render-utils/src/overlay3D_emissive.slf | 6 ++--- .../src/overlay3D_translucent.slf | 14 ++++++------ .../src/overlay3D_translucent_emissive.slf | 4 ++-- libraries/render-utils/src/skin_model.slv | 2 +- 25 files changed, 93 insertions(+), 93 deletions(-) diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index fc659d5928..9b7193bbfc 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -15,7 +15,7 @@ <@include DeferredBufferWrite.slh@> -// the diffuse texture +// the albedo texture uniform sampler2D originalTexture; // the interpolated normal diff --git a/libraries/entities-renderer/src/untextured_particle.slv b/libraries/entities-renderer/src/untextured_particle.slv index ab0ea15219..85f9d438bf 100644 --- a/libraries/entities-renderer/src/untextured_particle.slv +++ b/libraries/entities-renderer/src/untextured_particle.slv @@ -16,7 +16,7 @@ out vec4 _color; void main(void) { - // pass along the diffuse color + // pass along the color _color = colorToLinearRGBA(inColor); TransformCamera cam = getTransformCamera(); diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 3f9aef6dd1..40c4349ae2 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -12,8 +12,8 @@ <@def DEFERRED_BUFFER_SLH@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the normal texture uniform sampler2D normalMap; @@ -83,7 +83,7 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec DeferredFragment frag; frag.depthVal = texture(depthMap, texcoord).r; frag.normalVal = texture(normalMap, texcoord); - frag.diffuseVal = texture(diffuseMap, texcoord); + frag.diffuseVal = texture(albedoMap, texcoord); frag.specularVal = texture(specularMap, texcoord); frag.obscurance = texture(obscuranceMap, texcoord).x; diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 1045c4afc7..5cf40fad2d 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -43,32 +43,32 @@ float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { const vec3 DEFAULT_SPECULAR = vec3(0.1); const float DEFAULT_SHININESS = 10; -void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { +void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, vec3 specular, float shininess) { if (alpha != 1.0) { discard; } - _fragColor0 = vec4(diffuse.rgb, 1.0); // Opaque + _fragColor0 = vec4(albedo.rgb, 1.0); // Opaque _fragColor1 = vec4(bestFitNormal(normal), 1.0); _fragColor2 = vec4(specular, shininess / 128.0); } -void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) { +void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, vec3 specular, float shininess, vec3 emissive) { if (alpha != 1.0) { discard; } - _fragColor0 = vec4(diffuse.rgb, 0.5); + _fragColor0 = vec4(albedo.rgb, 0.5); _fragColor1 = vec4(bestFitNormal(normal), 0.5); _fragColor2 = vec4(emissive, shininess / 128.0); } -void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { +void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3 specular, float shininess) { if (alpha <= 0.0) { discard; } - _fragColor0 = vec4(diffuse.rgb, alpha); + _fragColor0 = vec4(albedo.rgb, alpha); // _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); // _fragColor2 = vec4(specular, shininess / 128.0); } diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 75fe187e46..30c52fb3b6 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -70,7 +70,7 @@ uniform SphericalHarmonics ambientSphere; <@include model/Light.slh@> <@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss) { // Need the light now Light light = getLight(); @@ -79,11 +79,11 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec3 color = diffuse.rgb * getLightColor(light) * obscurance * getLightAmbientIntensity(light); + vec3 color = albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); + color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); return color; } @@ -93,7 +93,7 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc <$declareSphericalHarmonics()$> -vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss) { // Need the light now Light light = getLight(); @@ -102,11 +102,11 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa vec3 fragEyeDir = normalize(fragEyeVector.xyz); vec3 ambientNormal = fragNormal.xyz; - vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, ambientNormal).xyz * obscurance * getLightAmbientIntensity(light); + vec3 color = albedo * evalSphericalLight(ambientSphere, ambientNormal).xyz * obscurance * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); + color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); return color; } @@ -117,7 +117,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa <$declareSkyboxMap()$> <$declareSphericalHarmonics()$> -vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss) { // Need the light now Light light = getLight(); @@ -125,18 +125,18 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec3 color = diffuse.rgb * evalSphericalLight(ambientSphere, fragNormal).xyz * obscurance * getLightAmbientIntensity(light); + vec3 color = albedo * evalSphericalLight(ambientSphere, fragNormal).xyz * obscurance * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); + color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); return color; } <@endfunc@> <@func declareEvalLightmappedColor()@> -vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 diffuse, vec3 lightmap) { +vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) { Light light = getLight(); @@ -156,7 +156,7 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur // ambient is a tiny percentage of the lightmap and only when in the shadow vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); - return obscurance * diffuse * (ambientLight + diffuseLight); + return obscurance * albedo * (ambientLight + diffuseLight); } <@endfunc@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 6ef5794d95..9eef530bbc 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -50,7 +50,7 @@ public: // update global lighting void setAmbientLightMode(int preset); - void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity); + void setGlobalLight(const glm::vec3& direction, const glm::vec3& color, float intensity, float ambientIntensity); void setGlobalSkybox(const model::SkyboxPointer& skybox); const LightStage& getLightStage() { return _lightStage; } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 34a02b51d2..991397df8b 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1846,7 +1846,7 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emissive, bool depthBiased) { batch.setPipeline(getSimplePipeline(textured, culled, emissive, depthBiased)); - // If not textured, set a default diffuse map + // If not textured, set a default albedo map if (!textured) { batch.setResourceTexture(render::ShapePipeline::Slot::ALBEDO_MAP, DependencyManager::get()->getWhiteTexture()); diff --git a/libraries/render-utils/src/animdebugdraw.slv b/libraries/render-utils/src/animdebugdraw.slv index 3cb356c055..ffa44b6cee 100644 --- a/libraries/render-utils/src/animdebugdraw.slv +++ b/libraries/render-utils/src/animdebugdraw.slv @@ -16,7 +16,7 @@ out vec4 _color; void main(void) { - // pass along the diffuse color + // pass along the color _color = colorToLinearRGBA(inColor.rgba); TransformCamera cam = getTransformCamera(); diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index 353c772327..d00ef917fb 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -16,7 +16,7 @@ <@include model/Material.slh@> // the diffuse texture -uniform sampler2D diffuseMap; +uniform sampler2D albedoMap; in vec4 _position; in vec3 _normal; @@ -25,15 +25,15 @@ in vec2 _texCoord0; void main(void) { - // Fetch diffuse map - vec4 diffuse = texture(diffuseMap, _texCoord0); + // Fetch albedo map + vec4 albedo = texture(albedoMap, _texCoord0); Material mat = getMaterial(); packDeferredFragment( normalize(_normal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_emissive.slf b/libraries/render-utils/src/model_emissive.slf index 9705897399..ba0abc44c2 100644 --- a/libraries/render-utils/src/model_emissive.slf +++ b/libraries/render-utils/src/model_emissive.slf @@ -15,7 +15,7 @@ <@include DeferredBufferWrite.slh@> <@include model/Material.slh@> -uniform sampler2D diffuseMap; +uniform sampler2D albedoMap; in vec2 _texCoord0; in vec3 _normal; @@ -23,7 +23,7 @@ in vec3 _color; in float _alpha; void main(void) { - vec4 texel = texture(diffuseMap, _texCoord0); + vec4 texel = texture(albedoMap, _texCoord0); Material mat = getMaterial(); vec3 fragColor = getMaterialAlbedo(mat) * texel.rgb * _color; diff --git a/libraries/render-utils/src/model_lightmap.slf b/libraries/render-utils/src/model_lightmap.slf index 7cfeb5da32..ff91cc402d 100755 --- a/libraries/render-utils/src/model_lightmap.slf +++ b/libraries/render-utils/src/model_lightmap.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the emissive map texture and parameters uniform sampler2D emissiveMap; @@ -30,15 +30,15 @@ in vec3 _normal; in vec3 _color; void main(void) { - vec4 diffuse = texture(diffuseMap, _texCoord0); + vec4 albedo = texture(albedoMap, _texCoord0); vec4 emissive = texture(emissiveMap, _texCoord1); Material mat = getMaterial(); packDeferredFragmentLightmap( normalize(_normal), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap.slv b/libraries/render-utils/src/model_lightmap.slv index eacc91245c..8696b70373 100755 --- a/libraries/render-utils/src/model_lightmap.slv +++ b/libraries/render-utils/src/model_lightmap.slv @@ -28,7 +28,7 @@ out vec3 _normal; out vec3 _color; void main(void) { - // pass along the diffuse color in linear space + // pass along the color in linear space _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slf b/libraries/render-utils/src/model_lightmap_normal_map.slf index 165ef4bf04..fa6cc60e1f 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the normal map texture uniform sampler2D normalMap; @@ -43,15 +43,15 @@ void main(void) { normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); // set the diffuse, normal, specular data - vec4 diffuse = texture(diffuseMap, _texCoord0); + vec4 albedo = texture(albedoMap, _texCoord0); vec4 emissive = texture(emissiveMap, _texCoord1); Material mat = getMaterial(); packDeferredFragmentLightmap( normalize(viewNormal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slv b/libraries/render-utils/src/model_lightmap_normal_map.slv index 6046a67e10..eb8f80656d 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slv +++ b/libraries/render-utils/src/model_lightmap_normal_map.slv @@ -29,7 +29,7 @@ out vec3 _tangent; out vec3 _color; void main(void) { - // pass along the diffuse color in linear space + // pass along the color in linear space _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index 591cc45a40..a9e6325320 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the emissive map texture and parameters uniform sampler2D emissiveMap; @@ -45,8 +45,8 @@ void main(void) { vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - // set the diffuse, normal, specular data - vec4 diffuse = texture(diffuseMap, _texCoord0); + // set the albedo, normal, specular data + vec4 albedo = texture(albedoMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; vec4 emissive = texture(emissiveMap, _texCoord1); @@ -54,8 +54,8 @@ void main(void) { packDeferredFragmentLightmap( normalize(viewNormal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, specular, // no use of getMaterialSpecular(mat) getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index 97c1713e96..531e07c411 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the emissive map texture and parameters uniform sampler2D emissiveMap; @@ -33,8 +33,8 @@ in vec3 _normal; in vec3 _color; void main(void) { - // set the diffuse, normal, specular data - vec4 diffuse = texture(diffuseMap, _texCoord0); + // set the albedo, normal, specular data + vec4 albedo = texture(albedoMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; vec4 emissive = texture(emissiveMap, _texCoord1); @@ -42,8 +42,8 @@ void main(void) { packDeferredFragmentLightmap( normalize(_normal), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, specular, // no use of getMaterialSpecular(mat) getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 5749a437c8..aff8049d1d 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the normal map texture uniform sampler2D normalMap; @@ -37,14 +37,14 @@ void main(void) { vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - vec4 diffuse = texture(diffuseMap, _texCoord0.st); + vec4 albedo = texture(albedoMap, _texCoord0.st); Material mat = getMaterial(); packDeferredFragment( normalize(viewNormal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_normal_map.slv b/libraries/render-utils/src/model_normal_map.slv index 5ed4e37278..f7711cd326 100755 --- a/libraries/render-utils/src/model_normal_map.slv +++ b/libraries/render-utils/src/model_normal_map.slv @@ -28,7 +28,7 @@ out vec3 _tangent; out vec3 _color; void main(void) { - // pass along the diffuse color + // pass along the color _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index 7f27747791..703648c5ed 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -16,8 +16,8 @@ <@include model/Material.slh@> -// the diffuse texture -uniform sampler2D diffuseMap; +// the albedo texture +uniform sampler2D albedoMap; // the normal map texture uniform sampler2D normalMap; @@ -40,16 +40,16 @@ void main(void) { vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - // set the diffuse, normal, specular data - vec4 diffuse = texture(diffuseMap, _texCoord0); + // set the albedo, normal, specular data + vec4 albedo = texture(albedoMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; Material mat = getMaterial(); packDeferredFragment( normalize(viewNormal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), diffuse.a), - getMaterialAlbedo(mat) * diffuse.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), + getMaterialAlbedo(mat) * albedo.rgb * _color, specular, //getMaterialSpecular(mat), getMaterialShininess(mat)); } diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 1ce0d22bc5..d90662a574 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -20,7 +20,7 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss, float opacity) { // Need the light now Light light = getLight(); @@ -31,11 +31,11 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 d vec3 fragEyeDir; <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> - vec3 color = opacity * diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); + vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(albedo * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); return vec4(color, opacity); } @@ -56,7 +56,7 @@ void main(void) { Material mat = getMaterial(); vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - vec3 fragDiffuse = getMaterialAlbedo(mat) * albedo.rgb * _color; + vec3 fragAlbedo = getMaterialAlbedo(mat) * albedo.rgb * _color; vec3 fragSpecular = getMaterialSpecular(mat); float fragGloss = getMaterialShininess(mat) / 128; float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; @@ -64,7 +64,7 @@ void main(void) { _fragColor = evalGlobalColor(1.0, fragPosition, fragNormal, - fragDiffuse, + fragAlbedo, fragSpecular, fragGloss, fragOpacity); diff --git a/libraries/render-utils/src/overlay3D.slf b/libraries/render-utils/src/overlay3D.slf index 66a48e95f4..8de7a23898 100644 --- a/libraries/render-utils/src/overlay3D.slf +++ b/libraries/render-utils/src/overlay3D.slf @@ -17,7 +17,7 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss, float opacity) { // Need the light now Light light = getLight(); @@ -28,11 +28,11 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 d vec3 fragEyeDir; <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> - vec3 color = opacity * diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); + vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(albedo * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); return vec4(color, opacity); } @@ -48,14 +48,14 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(originalTexture, _texCoord0); + vec4 albedo = texture(originalTexture, _texCoord0); vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - vec3 fragDiffuse = diffuse.rgb * _color; + vec3 fragAlbedo = albedo.rgb * _color; vec3 fragSpecular = vec3(0.1); float fragGloss = 10.0 / 128.0; - float fragOpacity = diffuse.a; + float fragOpacity = albedo.a; if (fragOpacity <= 0.1) { discard; @@ -64,7 +64,7 @@ void main(void) { vec4 color = evalGlobalColor(1.0, fragPosition, fragNormal, - fragDiffuse, + fragAlbedo, fragSpecular, fragGloss, fragOpacity); diff --git a/libraries/render-utils/src/overlay3D_emissive.slf b/libraries/render-utils/src/overlay3D_emissive.slf index ad689baf91..727eb0f317 100644 --- a/libraries/render-utils/src/overlay3D_emissive.slf +++ b/libraries/render-utils/src/overlay3D_emissive.slf @@ -20,12 +20,12 @@ in vec3 _color; out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(originalTexture, _texCoord0); + vec4 albedo = texture(originalTexture, _texCoord0); - if (diffuse.a <= 0.1) { + if (albedo.a <= 0.1) { discard; } - vec4 color = vec4(diffuse.rgb * _color, diffuse.a); + vec4 color = vec4(albedo.rgb * _color, albedo.a); // Apply standard tone mapping _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index dcc15ba25b..8e6dbb9eff 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -18,7 +18,7 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss, float opacity) { // Need the light now Light light = getLight(); @@ -29,11 +29,11 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 d vec3 fragEyeDir; <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> - vec3 color = opacity * diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); + vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(albedo * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); return vec4(color, opacity); } @@ -49,19 +49,19 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(originalTexture, _texCoord0); + vec4 albedo = texture(originalTexture, _texCoord0); vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - vec3 fragDiffuse = diffuse.rgb * _color; + vec3 fragAlbedo = albedo.rgb * _color; vec3 fragSpecular = vec3(0.1); float fragGloss = 10.0 / 128.0; - float fragOpacity = diffuse.a * _alpha; + float fragOpacity = albedo.a * _alpha; vec4 color = evalGlobalColor(1.0, fragPosition, fragNormal, - fragDiffuse, + fragAlbedo, fragSpecular, fragGloss, fragOpacity); diff --git a/libraries/render-utils/src/overlay3D_translucent_emissive.slf b/libraries/render-utils/src/overlay3D_translucent_emissive.slf index bcfec7d588..61935f3c67 100644 --- a/libraries/render-utils/src/overlay3D_translucent_emissive.slf +++ b/libraries/render-utils/src/overlay3D_translucent_emissive.slf @@ -21,7 +21,7 @@ in float _alpha; out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(originalTexture, _texCoord0); + vec4 albedo = texture(originalTexture, _texCoord0); - _fragColor = vec4(diffuse.rgb * _color, diffuse.a * _alpha); + _fragColor = vec4(albedo.rgb * _color, albedo.a * _alpha); } diff --git a/libraries/render-utils/src/skin_model.slv b/libraries/render-utils/src/skin_model.slv index 8ab475e1fd..199b97ba53 100755 --- a/libraries/render-utils/src/skin_model.slv +++ b/libraries/render-utils/src/skin_model.slv @@ -32,7 +32,7 @@ void main(void) { skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal); - // pass along the diffuse color + // pass along the color _color = colorToLinearRGB(inColor.rgb); // and the texture coordinates From b03f639e2cbb64327ddd777593b8548ca8c9e5a0 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 16 Feb 2016 17:20:23 -0800 Subject: [PATCH 006/292] Renaming and rearranging the material fields to support PBR fbx materials --- libraries/fbx/src/FBXReader.cpp | 33 ++++++++++++-- libraries/fbx/src/FBXReader.h | 12 ++++- libraries/fbx/src/FBXReader_Material.cpp | 44 +++++++++++++++---- libraries/fbx/src/OBJReader.cpp | 2 +- libraries/model/src/model/Material.cpp | 11 +++-- libraries/model/src/model/Material.h | 11 +++-- .../render-utils/src/MeshPartPayload.cpp | 4 +- libraries/render-utils/src/Model.cpp | 2 +- .../render-utils/src/RenderPipelines.cpp | 2 +- .../render-utils/src/simple_textured.slf | 2 +- .../src/simple_textured_emisive.slf | 2 +- 11 files changed, 99 insertions(+), 26 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 1be3bbb5f6..daaa2d94be 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -865,6 +865,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } } else if (object.name == "Material") { FBXMaterial material; + if (object.properties.at(1).toByteArray().contains("StingrayPBS1")) { + material.isPBSMaterial = true; + } foreach (const FBXNode& subobject, object.children) { bool properties = false; QByteArray propertyName; @@ -879,7 +882,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS propertyName = "P"; index = 4; } - if (properties) { + if (properties && !material.isPBSMaterial) { foreach (const FBXNode& property, subobject.children) { if (property.name == propertyName) { if (property.properties.at(0) == "DiffuseColor") { @@ -914,6 +917,22 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS #endif } } + } else if (properties && material.isPBSMaterial) { + std::vector unknowns; + foreach(const FBXNode& property, subobject.children) { + if (property.name == propertyName) { + if (property.properties.at(0) == "Maya|base_color") { + material.diffuseColor = getVec3(property.properties, index); + } else if (property.properties.at(0) == "Maya|metallic") { + material.metallic = property.properties.at(index).value(); + } else if (property.properties.at(0) == "Maya|roughness") { + material.roughness = property.properties.at(index).value(); + } else { + const QString propname = property.properties.at(0).toString(); + unknowns.push_back(propname.toStdString()); + } + } + } } #if defined(DEBUG_FBXREADER) else { @@ -1032,7 +1051,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS QByteArray type = connection.properties.at(3).toByteArray().toLower(); if (type.contains("diffuse")) { diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - + } else if (type.contains("tex_color_map")) { + qDebug() << "insert color map for diffuse!"; + diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("transparentcolor")) { // it should be TransparentColor... // THis is how Maya assign a texture that affect diffuse color AND transparency ? diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); @@ -1042,7 +1063,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("specular") || type.contains("reflection")) { specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - + } else if (type.contains("metallic")) { + metallicTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type == "lcl rotation") { localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type == "lcl translation") { @@ -1056,8 +1078,11 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS zComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("shininess")) { + shininessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + counter++; + } else if (type.contains("roughness")) { + roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); counter++; - } else if (_loadLightmaps && type.contains("emissive")) { emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 6dc8a31bc7..755a1e70f2 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -111,7 +111,8 @@ public: QString texcoordSetName; bool isBumpmap{ false }; - + bool isGlossmap{ true }; + bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } }; @@ -148,6 +149,9 @@ public: float shininess = 23.0f; float opacity = 1.0f; + float metallic{ 0.0f }; + float roughness{ 1.0f }; + QString materialID; model::MaterialPointer _material; @@ -156,7 +160,10 @@ public: FBXTexture normalTexture; FBXTexture specularTexture; FBXTexture emissiveTexture; + FBXTexture metallicTexture; + FBXTexture roughnessTexture; + bool isPBSMaterial{ false }; bool needTangentSpace() const; }; @@ -402,6 +409,9 @@ public: QHash specularTextures; QHash emissiveTextures; QHash ambientTextures; + QHash metallicTextures; + QHash roughnessTextures; + QHash shininessTextures; QHash _fbxMaterials; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index b82d4c0877..64ee958330 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -100,17 +100,38 @@ void FBXReader::consolidateFBXMaterials() { material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } - - + FBXTexture specularTexture; QString specularTextureID = specularTextures.value(material.materialID); if (!specularTextureID.isNull()) { specularTexture = getTexture(specularTextureID); detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity()); - material.specularTexture = specularTexture; } + FBXTexture metallicTexture; + QString metallicTextureID = metallicTextures.value(material.materialID); + if (!metallicTextureID.isNull()) { + metallicTexture = getTexture(metallicTextureID); + detectDifferentUVs |= (metallicTexture.texcoordSet != 0) || (!metallicTexture.transform.isIdentity()); + material.metallicTexture = metallicTexture; + } + + FBXTexture roughnessTexture; + QString roughnessTextureID = roughnessTextures.value(material.materialID); + QString shininessTextureID = shininessTextures.value(material.materialID); + if (!roughnessTextureID.isNull()) { + roughnessTexture = getTexture(roughnessTextureID); + roughnessTexture.isGlossmap = false; + material.roughnessTexture = roughnessTexture; + detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity()); + } else if (!shininessTextureID.isNull()) { + roughnessTexture = getTexture(roughnessTextureID); + roughnessTexture.isGlossmap = true; + material.roughnessTexture = roughnessTexture; + detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity()); + } + FBXTexture emissiveTexture; glm::vec2 emissiveParams(0.f, 1.f); emissiveParams.x = _lightmapOffset; @@ -142,11 +163,18 @@ void FBXReader::consolidateFBXMaterials() { // diffuse *= material.diffuseFactor; material._material->setAlbedo(diffuse); - float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z)); - // FIXME: Do not use the Specular Factor yet as some FBX models have it set to 0 - // metallic *= material.specularFactor; - material._material->setMetallic(metallic); - material._material->setGloss(material.shininess); + if (material.isPBSMaterial) { + material._material->setRoughness(material.roughness); + material._material->setMetallic(material.metallic); + } else { + material._material->setRoughness(model::Material::shininessToRoughness(material.shininess)); + + float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z)); + // FIXME: Do not use the Specular Factor yet as some FBX models have it set to 0 + // metallic *= material.specularFactor; + material._material->setMetallic(metallic); + + } if (material.opacity <= 0.0f) { material._material->setOpacity(1.0f); diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 3286e5e974..0e56753164 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -561,7 +561,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, modelMaterial->setEmissive(fbxMaterial.emissiveColor); modelMaterial->setAlbedo(fbxMaterial.diffuseColor); modelMaterial->setMetallic(glm::length(fbxMaterial.specularColor)); - modelMaterial->setGloss(fbxMaterial.shininess); + modelMaterial->setRoughness(model::Material::shininessToRoughness(fbxMaterial.shininess)); if (fbxMaterial.opacity <= 0.0f) { modelMaterial->setOpacity(1.0f); diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 95f540e762..206b95e8a1 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -58,12 +58,17 @@ void Material::setEmissive(const Color& emissive, bool isSRGB) { _key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f)))); _schemaBuffer.edit()._emissive = (isSRGB ? ColorUtils::toLinearVec3(emissive) : emissive); } - +/* void Material::setGloss(float gloss) { - _key.setGloss((gloss > 0.0f)); - _schemaBuffer.edit()._gloss = gloss; + setRoughness(1.0 - gloss); +}*/ +void Material::setRoughness(float roughness) { + roughness = std::min(1.0f, std::max(roughness, 0.0f)); + _key.setGloss((roughness < 1.0f)); + _schemaBuffer.edit()._roughness = roughness; } + void Material::setOpacity(float opacity) { _key.setTransparent((opacity < 1.0f)); _schemaBuffer.edit()._opacity = opacity; diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index d2c7a04683..a5281bb117 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -229,8 +229,10 @@ public: void setMetallic(float metallic); float getMetallic() const { return _schemaBuffer.get()._metallic.x; } - void setGloss(float gloss); - float getGloss() const { return _schemaBuffer.get()._gloss; } + // void setGloss(float gloss); + void setRoughness(float gloss); + float getGloss() const { return 1.0f - getRoughness(); } + float getRoughness() const { return _schemaBuffer.get()._roughness; } void setOpacity(float opacity); float getOpacity() const { return _schemaBuffer.get()._opacity; } @@ -242,7 +244,7 @@ public: glm::vec3 _albedo{ 0.5f }; float _opacity{1.f}; glm::vec3 _metallic{ 0.03f }; - float _gloss{0.1f}; + float _roughness{ 0.9f }; glm::vec3 _emissive{ 0.0f }; float _spare0{0.0f}; glm::vec4 _spareVec4{0.0f}; // for alignment beauty, Material size == Mat4x4 @@ -256,6 +258,9 @@ public: void setTextureMap(MapChannel channel, const TextureMapPointer& textureMap); const TextureMaps& getTextureMaps() const { return _textureMaps; } + // conversion from previous properties to PBR equivalent + static float shininessToRoughness(float shininess) { return 1.0f - shininess / 128.0f; } + protected: MaterialKey _key; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 31f17c3bc2..a78d384dd1 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -167,7 +167,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (normalMap && normalMap->isDefined()) { batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, normalMap->getTextureView()); - // texcoord are assumed to be the same has diffuse + // texcoord are assumed to be the same has albedo } else { batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture()); } @@ -181,7 +181,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (specularMap && specularMap->isDefined()) { batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); - // texcoord are assumed to be the same has diffuse + // texcoord are assumed to be the same has albedo } else { batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 2ef5b5e792..e1646437d1 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1199,7 +1199,7 @@ void Model::segregateMeshGroups() { _collisionHullMaterial = std::make_shared(); _collisionHullMaterial->setAlbedo(glm::vec3(1.0f, 0.5f, 0.0f)); _collisionHullMaterial->setMetallic(0.02f); - _collisionHullMaterial->setGloss(1.0f); + _collisionHullMaterial->setRoughness(0.5f); } _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); } else { diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index fbaa7df1b1..1011d4081c 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -69,7 +69,7 @@ gpu::BufferView getDefaultMaterialBuffer() { schema._albedo = vec3(1.0f); schema._opacity = 1.0f; schema._metallic = vec3(0.1f); - schema._gloss = 10.0f; + schema._roughness = 0.9f; return gpu::BufferView(std::make_shared(sizeof(model::Material::Schema), (const gpu::Byte*) &schema)); } diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index 727c029bbe..6c99343a28 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -15,7 +15,7 @@ <@include DeferredBufferWrite.slh@> <@include model/Material.slh@> -// the diffuse texture +// the albedo texture uniform sampler2D originalTexture; // the interpolated normal diff --git a/libraries/render-utils/src/simple_textured_emisive.slf b/libraries/render-utils/src/simple_textured_emisive.slf index 1dd3d667a6..2119af17fb 100644 --- a/libraries/render-utils/src/simple_textured_emisive.slf +++ b/libraries/render-utils/src/simple_textured_emisive.slf @@ -14,7 +14,7 @@ <@include DeferredBufferWrite.slh@> -// the diffuse texture +// the albedo texture uniform sampler2D originalTexture; // the interpolated normal From 2ed7f997e3d493aad6fc3e1d1da096859ccfb0b8 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 17 Feb 2016 10:44:15 -0800 Subject: [PATCH 007/292] A few changes in the material call back --- libraries/fbx/src/FBXReader.cpp | 2 ++ libraries/model/src/model/Material.slh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index daaa2d94be..f4225e6e73 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -867,6 +867,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS FBXMaterial material; if (object.properties.at(1).toByteArray().contains("StingrayPBS1")) { material.isPBSMaterial = true; + } else if (object.properties.at(1).toByteArray().contains("StingrayPBS2")) { + material.isPBSMaterial = true; } foreach (const FBXNode& subobject, object.children) { bool properties = false; diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index 1f9a290fe7..a190a1c552 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -29,6 +29,6 @@ Material getMaterial() { float getMaterialOpacity(Material m) { return m._albedoOpacity.a; } vec3 getMaterialAlbedo(Material m) { return m._albedoOpacity.rgb; } vec3 getMaterialSpecular(Material m) { return m._specular.rgb; } -float getMaterialShininess(Material m) { return m._specular.a; } +float getMaterialShininess(Material m) { return (1 - m._specular.a); } <@endif@> From bfc619497e735861ccd9ae4f956a51df2cb6becd Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 13:33:19 -0800 Subject: [PATCH 008/292] spawning model --- .../whiteboardV2/whiteboardSpawner.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/homeContent/whiteboardV2/whiteboardSpawner.js diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js new file mode 100644 index 0000000000..76992062dc --- /dev/null +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -0,0 +1,32 @@ +// +// whiteboardSpawner.js +// examples/homeContent/whiteboardV2 +// +// Created by Eric Levina on 2/17/16 +// Copyright 2016 High Fidelity, Inc. +// +// Run this script to spawn a whiteboard and associated acoutrements that one can paint on usignmarkers +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + +var orientation = Camera.getOrientation(); +orientation = Quat.safeEulerAngles(orientation); +orientation.x = 0; +orientation = Quat.fromVec3Degrees(orientation); +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); + +var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; +var whiteboard = Entities.addEntity({ + type: "Model", + modelURL: WHITEBOARD_MODEL_URL, + position: center +}); + + +function cleanup() { + Entities.deleteEntity(whiteboard); +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file From bb2fd0072c1533881780ec7c2cf3688e7b1ef882 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 13:41:58 -0800 Subject: [PATCH 009/292] collision hull --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 76992062dc..7cdbef5a7a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -17,11 +17,16 @@ orientation.x = 0; orientation = Quat.fromVec3Degrees(orientation); var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); + var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; +var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; var whiteboard = Entities.addEntity({ type: "Model", modelURL: WHITEBOARD_MODEL_URL, - position: center + position: center, + shapeType: 'compound', + compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, + dimensions: { x: 0.4636, y: 2.7034, z: 1.8653} }); From 9e8d123b1664a6a189859eaeef9c31fe957f2451 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 13:58:04 -0800 Subject: [PATCH 010/292] spawning marker and whiteboard correctly --- .../whiteboardV2/whiteboardSpawner.js | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 7cdbef5a7a..c101d3df9a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -14,24 +14,41 @@ var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); orientation.x = 0; +var whiteboardRotation = Quat.fromVec3Degrees({x: orientation.x, y: orientation.y - 90, z: orientation.z}); orientation = Quat.fromVec3Degrees(orientation); -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); +var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; var whiteboard = Entities.addEntity({ type: "Model", modelURL: WHITEBOARD_MODEL_URL, - position: center, + position: whiteboardPosition, + rotation: whiteboardRotation, shapeType: 'compound', compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, dimensions: { x: 0.4636, y: 2.7034, z: 1.8653} }); +var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); +var MARKER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/marker-blue.fbx"; +var marker = Entities.addEntity({ + type: "Model", + modelURL: MARKER_MODEL_URL, + shapeType: "box", + dynamic: true, + gravity: {x: 0, y: -1, z: 0}, + rotation: whiteboardRotation, + velocity: {x: 0, y: -0.1, z: 0}, + position: markerPosition, + dimensions: {x: 0.0270, y: 0.0272, z: 0.1641} +}); + function cleanup() { Entities.deleteEntity(whiteboard); + Entities.deleteEntity(marker); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 073661b78de92f751e3160a3d03e0caa6aa7a46c Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 14:25:21 -0800 Subject: [PATCH 011/292] markers in right spot --- .../whiteboardV2/whiteboardSpawner.js | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index c101d3df9a..a8796f56fb 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -14,7 +14,11 @@ var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); orientation.x = 0; -var whiteboardRotation = Quat.fromVec3Degrees({x: orientation.x, y: orientation.y - 90, z: orientation.z}); +var whiteboardRotation = Quat.fromVec3Degrees({ + x: orientation.x, + y: orientation.y - 90, + z: orientation.z +}); orientation = Quat.fromVec3Degrees(orientation); @@ -28,7 +32,11 @@ var whiteboard = Entities.addEntity({ rotation: whiteboardRotation, shapeType: 'compound', compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, - dimensions: { x: 0.4636, y: 2.7034, z: 1.8653} + dimensions: { + x: 0.4636, + y: 2.7034, + z: 1.8653 + } }); var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); @@ -38,11 +46,49 @@ var marker = Entities.addEntity({ modelURL: MARKER_MODEL_URL, shapeType: "box", dynamic: true, - gravity: {x: 0, y: -1, z: 0}, + gravity: { + x: 0, + y: -1, + z: 0 + }, rotation: whiteboardRotation, - velocity: {x: 0, y: -0.1, z: 0}, + velocity: { + x: 0, + y: -0.1, + z: 0 + }, position: markerPosition, - dimensions: {x: 0.0270, y: 0.0272, z: 0.1641} + dimensions: { + x: 0.0270, + y: 0.0272, + z: 0.1641 + }, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + "x": 0.03257002681493759, + "y": 0.15036098659038544, + "z": 0.051217660307884216 + }, { + "x": -0.5274277329444885, + "y": -0.23446641862392426, + "z": -0.05400913953781128, + "w": 0.8148180246353149 + }], + LeftHand: [{ + "x": -0.031699854880571365, + "y": 0.15150733292102814, + "z": 0.041107177734375 + }, { + "x": 0.649201512336731, + "y": 0.1007731482386589, + "z": 0.3215889632701874, + "w": -0.6818817853927612 + }] + } + } + }) }); From df84a166e483439d842ded12065b4e690c7eda43 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 15:08:42 -0800 Subject: [PATCH 012/292] spawning marker tips- parenting to markers --- .../homeContent/whiteboardV2/whiteboardSpawner.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a8796f56fb..4a1a89c250 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -51,7 +51,7 @@ var marker = Entities.addEntity({ y: -1, z: 0 }, - rotation: whiteboardRotation, + // rotation: whiteboardRotation, velocity: { x: 0, y: -0.1, @@ -91,10 +91,20 @@ var marker = Entities.addEntity({ }) }); +var markerTip = Entities.addEntity({ + type: "Box", + dimensions: {x: 0.05, y: 0.05, z: 0.05}, + position: Vec3.sum(markerPosition, {x: 0.0, y: 0.001, z: 0.1}), + parentID: marker, + color: {red: 200, green: 10, blue: 200}, + collisionless: true +}) + function cleanup() { Entities.deleteEntity(whiteboard); Entities.deleteEntity(marker); + Entities.deleteEntity(markerTip); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From d7edc8c2ba789aee877d835c5492e07690cf4463 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 17 Feb 2016 16:06:30 -0800 Subject: [PATCH 013/292] Adding more fields ready for the PBR stingray materials --- libraries/fbx/src/FBXReader.cpp | 57 ++++++++++++++++++++++++--------- libraries/fbx/src/FBXReader.h | 25 +++++++++++---- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index f4225e6e73..a95a66f7e1 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -923,12 +923,34 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS std::vector unknowns; foreach(const FBXNode& property, subobject.children) { if (property.name == propertyName) { - if (property.properties.at(0) == "Maya|base_color") { + if (property.properties.at(0) == "Maya|use_normal_map") { + material.useNormalMap = (bool)property.properties.at(index).value(); + + } else if (property.properties.at(0) == "Maya|base_color") { material.diffuseColor = getVec3(property.properties, index); - } else if (property.properties.at(0) == "Maya|metallic") { - material.metallic = property.properties.at(index).value(); + } else if (property.properties.at(0) == "Maya|use_color_map") { + material.useAlbedoMap = (bool) property.properties.at(index).value(); + } else if (property.properties.at(0) == "Maya|roughness") { material.roughness = property.properties.at(index).value(); + } else if (property.properties.at(0) == "Maya|use_roughness_map") { + material.useRoughnessMap = (bool)property.properties.at(index).value(); + + } else if (property.properties.at(0) == "Maya|metallic") { + material.metallic = property.properties.at(index).value(); + } else if (property.properties.at(0) == "Maya|use_metallic_map") { + material.useMetallicMap = (bool)property.properties.at(index).value(); + + } else if (property.properties.at(0) == "Maya|emissive") { + material.emissiveColor = getVec3(property.properties, index); + } else if (property.properties.at(0) == "Maya|emissive_intensity") { + material.emissiveIntensity = property.properties.at(index).value(); + } else if (property.properties.at(0) == "Maya|use_emissive_map") { + material.useEmissiveMap = (bool)property.properties.at(index).value(); + + } else if (property.properties.at(0) == "Maya|use_ao_map") { + material.useOcclusionMap = (bool)property.properties.at(index).value(); + } else { const QString propname = property.properties.at(0).toString(); unknowns.push_back(propname.toStdString()); @@ -1054,7 +1076,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS if (type.contains("diffuse")) { diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("tex_color_map")) { - qDebug() << "insert color map for diffuse!"; diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("transparentcolor")) { // it should be TransparentColor... // THis is how Maya assign a texture that affect diffuse color AND transparency ? @@ -1063,10 +1084,25 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("normal")) { normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type.contains("tex_normal_map")) { + normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("specular") || type.contains("reflection")) { specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - } else if (type.contains("metallic")) { + } else if (type.contains("tex_metallic_map")) { metallicTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type.contains("shininess")) { + shininessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type.contains("tex_roughness_map")) { + roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (_loadLightmaps && type.contains("emissive")) { + emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type.contains("tex_emissive_map")) { + roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (_loadLightmaps && type.contains("ambient")) { + ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (_loadLightmaps && type.contains("tex_ao_map")) { + occlusionTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type == "lcl rotation") { localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type == "lcl translation") { @@ -1079,17 +1115,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } else if (type == "d|z") { zComponents.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - } else if (type.contains("shininess")) { - shininessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - counter++; - } else if (type.contains("roughness")) { - roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - counter++; - } else if (_loadLightmaps && type.contains("emissive")) { - emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - - } else if (_loadLightmaps && type.contains("ambient")) { - ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else { QString typenam = type.data(); counter++; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 755a1e70f2..680cbe2fd4 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -151,17 +151,29 @@ public: float metallic{ 0.0f }; float roughness{ 1.0f }; + float emissiveIntensity{ 1.0f }; + + bool useNormalMap{ false }; + bool useAlbedoMap{ false }; + bool useOpacityMap{ false }; + bool useRoughnessMap{ false }; + bool useSpecularMap{ false }; + bool useMetallicMap{ false }; + bool useEmissiveMap{ false }; + bool useOcclusionMap{ false }; QString materialID; model::MaterialPointer _material; + FBXTexture normalTexture; FBXTexture albedoTexture; FBXTexture opacityTexture; - FBXTexture normalTexture; - FBXTexture specularTexture; - FBXTexture emissiveTexture; - FBXTexture metallicTexture; FBXTexture roughnessTexture; + FBXTexture specularTexture; + FBXTexture metallicTexture; + FBXTexture emissiveTexture; + FBXTexture occlusionTexture; + bool isPBSMaterial{ false }; bool needTangentSpace() const; @@ -407,11 +419,12 @@ public: QHash bumpTextures; QHash normalTextures; QHash specularTextures; - QHash emissiveTextures; - QHash ambientTextures; QHash metallicTextures; QHash roughnessTextures; QHash shininessTextures; + QHash emissiveTextures; + QHash ambientTextures; + QHash occlusionTextures; QHash _fbxMaterials; From 7f23ee04be9995f11b55731c48103ddcada0315b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 17:16:43 -0800 Subject: [PATCH 014/292] basic marker entity script --- .../whiteboardV2/markerEntityScript.js | 35 +++++++++++++++++++ .../whiteboardV2/whiteboardSpawner.js | 12 ++----- 2 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 examples/homeContent/whiteboardV2/markerEntityScript.js diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js new file mode 100644 index 0000000000..43a7ec1788 --- /dev/null +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -0,0 +1,35 @@ +// +// markerTipEntityScript.js +// examples/homeContent/markerTipEntityScript +// +// Created by Eric Levin on 2/17/15. +// Copyright 2016 High Fidelity, Inc. +// + +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + + +(function() { + Script.include("../../libraries/utils.js"); + + MarkerTip = function() { + _this = this; + }; + + MarkerTip.prototype = { + + continueNearGrab: function() { + print("EBL Conintue ") + }, + + preload: function(entityID) { + this.entityID = entityID; + + } + }; + + // entity scripts always need to return a newly constructed object of our type + return new MarkerTip(); +}); diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 4a1a89c250..a699bcafa2 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -41,6 +41,7 @@ var whiteboard = Entities.addEntity({ var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); var MARKER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/marker-blue.fbx"; +var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: MARKER_MODEL_URL, @@ -51,7 +52,6 @@ var marker = Entities.addEntity({ y: -1, z: 0 }, - // rotation: whiteboardRotation, velocity: { x: 0, y: -0.1, @@ -63,6 +63,7 @@ var marker = Entities.addEntity({ y: 0.0272, z: 0.1641 }, + script: MARKER_SCRIPT_URL, userData: JSON.stringify({ wearable: { joints: { @@ -91,20 +92,11 @@ var marker = Entities.addEntity({ }) }); -var markerTip = Entities.addEntity({ - type: "Box", - dimensions: {x: 0.05, y: 0.05, z: 0.05}, - position: Vec3.sum(markerPosition, {x: 0.0, y: 0.001, z: 0.1}), - parentID: marker, - color: {red: 200, green: 10, blue: 200}, - collisionless: true -}) function cleanup() { Entities.deleteEntity(whiteboard); Entities.deleteEntity(marker); - Entities.deleteEntity(markerTip); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 728e8c763d43033f4d788821fc8fe57cc959173a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 17 Feb 2016 17:30:01 -0800 Subject: [PATCH 015/292] ray cast --- .../whiteboardV2/markerEntityScript.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 43a7ec1788..ef6f6b005d 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -21,12 +21,25 @@ MarkerTip.prototype = { continueNearGrab: function() { - print("EBL Conintue ") + + // cast a ray from marker and see if it hits anything + + var props = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); + + var pickRay = { + origin: props.position, + direction: Quat.getFront(props.rotation) + } + + var intersection = Entities.findRayIntersection(pickRay, true); + + if (intersection.intersects) { + print("INTERSECTION!") + } }, preload: function(entityID) { this.entityID = entityID; - } }; From 214723f1bfdf86cf1821265742e53d016be628a0 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 18 Feb 2016 14:27:47 -0800 Subject: [PATCH 016/292] baton for moving vesicles" " --- .../CellScience/Scripts/colorRandomly.js | 104 +++++ .../CellScience/Scripts/moveRandomly.js | 71 ---- .../CellScience/Scripts/moveRandomly2.js | 95 +++++ .../CellScience/Scripts/virtualBaton.js | 381 ++++++++++++++++++ .../Scripts/zoomAndMoveRandomly.js | 48 ++- .../CellScience/importCellScience.js | 10 +- 6 files changed, 618 insertions(+), 91 deletions(-) create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js create mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js new file mode 100644 index 0000000000..cf4ee810e7 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js @@ -0,0 +1,104 @@ +// Copyright 2016 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +(function() { + + Script.include(Script.resolvePath('virtualBaton.js')); + + var self = this; + + var baton; + var iOwn = false; + var currentInterval; + var _entityId; + + function startUpdate() { + iOwn = true; + print('i am the owner ' + _entityId) + } + + function stopUpdateAndReclaim() { + print('i released the object ' + _entityId) + iOwn = false; + baton.claim(startUpdate, stopUpdateAndReclaim); + } + + this.preload = function(entityId) { + this.isConnected = false; + this.entityId = entityId; + _entityId = entityId; + this.minVelocity = 1; + this.maxVelocity = 5; + this.minAngularVelocity = 0.01; + this.maxAngularVelocity = 0.03; + baton = virtualBaton({ + batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + }); + stopUpdateAndReclaim(); + currentInterval = Script.setInterval(self.move, self.getTotalWait()) + } + + + this.getTotalWait = function() { + return (Math.random() * 5000) * 2; + // var avatars = AvatarList.getAvatarIdentifiers(); + // var avatarCount = avatars.length; + // var random = Math.random() * 5000; + // var totalWait = random * (avatarCount * 2); + // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) + // return totalWait + } + + + this.move = function() { + if (!iOwn) { + return; + } + + var properties = Entities.getEntityProperties(self.entityId); + var color = properties.color; + + var newColor; + var red = { + red: 255, + green: 0, + blue: 0 + } + var green = { + red: 0, + green: 255, + blue: 0 + } + var blue = { + red: 0, + green: 0, + blue: 255 + } + if (color.red > 0) { + newColor = green; + } + if (color.green > 0) { + newColor = blue; + } + if (color.blue > 0) { + newColor = red + } + Entities.editEntity(self.entityId, { + color: newColor + }); + + + } + + + this.unload = function() { + baton.release(function() {}); + Script.clearTimeout(currentInterval); + } + + + +}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js deleted file mode 100644 index cc822ddf8a..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly.js +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 High Fidelity, Inc. -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -(function() { - - var self = this; - - this.preload=function(entityId){ - this.isConnected = false; - this.entityId = entityId; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - Script.setTimeout(self.move,self.getTotalWait()) - } - - - this.getTotalWait = function() { - var avatars = AvatarList.getAvatarIdentifiers(); - var avatarCount = avatars.length; - var random = Math.random() * 5000; - var totalWait = random * (avatarCount * 2); - - return totalWait - } - - - this.move = function() { - var magnitudeV = self.maxVelocity; - var directionV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - - //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); - Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)) - }); - - - var magnitudeAV = self.maxAngularVelocity; - - var directionAV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); - Entities.editEntity(self.entityId, { - angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) - - }); - - - - Script.setTimeout(self.move,self.getTotalWait()) - } - - - this.unload = function() { - - } - - - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js new file mode 100644 index 0000000000..f720ca91cc --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js @@ -0,0 +1,95 @@ +// Copyright 2016 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +(function() { + + Script.include('virtualBaton.js'); + + var self = this; + + var baton; + var iOwn = false; + var currentInterval; + var _entityId; + + function startUpdate() { + iOwn = true; + print('i am the owner ' + _entityId) + } + + function stopUpdateAndReclaim() { + print('i released the object ' + _entityId) + iOwn = false; + baton.claim(startUpdate, stopUpdateAndReclaim); + } + + this.preload = function(entityId) { + this.isConnected = false; + this.entityId = entityId; + _entityId = entityId; + this.minVelocity = 1; + this.maxVelocity = 5; + this.minAngularVelocity = 0.01; + this.maxAngularVelocity = 0.03; + baton = virtualBaton({ + batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + }); + stopUpdateAndReclaim(); + currentInterval = Script.setInterval(self.move, self.getTotalWait()) + } + + + this.getTotalWait = function() { + return (Math.random() * 5000) * 2; + // var avatars = AvatarList.getAvatarIdentifiers(); + // var avatarCount = avatars.length; + // var random = Math.random() * 5000; + // var totalWait = random * (avatarCount * 2); + // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) + // return totalWait + } + + + this.move = function() { + if (!iOwn) { + return; + } + + var magnitudeV = self.maxVelocity; + var directionV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + + //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); + + var magnitudeAV = self.maxAngularVelocity; + + var directionAV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + Entities.editEntity(self.entityId, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + + }); + + + } + + + this.unload = function() { + baton.release(function() {}); + Script.clearInterval(currentInterval); + } + + + +}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js new file mode 100644 index 0000000000..63f96a5c1e --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js @@ -0,0 +1,381 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true */ +/*global Messages, Script, MyAvatar, AvatarList, Entities, print */ + +// Created by Howard Stearns +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Allows cooperating scripts to pass a "virtual baton" between them, +// which is useful when part of a script should only be executed by +// the one participant that is holding this particular baton. +// +// A virtual baton is simply any string agreed upon by the scripts +// that use it. Only one script at a time can hold the baton, and it +// holds it until that script releases it, or the other scripts +// determine that the holding script is not responding. The script +// automatically determines who among claimants has the baton, if anyone, +// and holds an "election" if necessary. +// +// See entityScript/tribble.js as an example, and the functions +// virtualBaton(), claim(), release(). +// + +// Answers a new virtualBaton for the given parameters, of which 'key' +// is required. +function virtualBatonf(options) { + // Answer averages (number +/- variability). Avoids having everyone act in lockstep. + function randomize(number, variability) { + var allowedDeviation = number * variability; // one side of the deviation range + var allowedDeviationRange = allowedDeviation * 2; // total range for +/- deviation + var randomDeviation = Math.random() * allowedDeviationRange; + var result = number - allowedDeviation + randomDeviation; + return result; + } + // Allow testing outside in a harness outside of High Fidelity. + // See sourceCodeSandbox/tests/mocha/test/testVirtualBaton.js + var globals = options.globals || {}, + messages = globals.Messages || Messages, + myAvatar = globals.MyAvatar || MyAvatar, + avatarList = globals.AvatarList || AvatarList, + entities = globals.Entities || Entities, + timers = globals.Script || Script, + log = globals.print || print; + + var batonName = options.batonName, // The identify of the baton. + // instanceId is the identify of this particular copy of the script among all copies using the same batonName + // in the domain. For example, if you wanted only one entity among multiple entity scripts to hold the baton, + // you could specify virtualBaton({batonName: 'someBatonName', instanceId: MyAvatar.sessionUUID + entityID}). + instanceId = options.instanceId || myAvatar.sessionUUID, + // virtualBaton() returns the exports object with properties. You can pass in an object to be side-effected. + exports = options.exports || {}, + // Handy to set false if we believe the optimizations are wrong, or to use both values in a test harness. + useOptimizations = (options.useOptimizations === undefined) ? true : options.useOptimizations, + electionTimeout = options.electionTimeout || randomize(500, 0.2), // ms. If no winner in this time, hold a new election. + recheckInterval = options.recheckInterval || randomize(500, 0.2), // ms. Check that winners remain connected. + // If you supply your own instanceId, you might also supply a connectionTest that answers + // truthy iff the given id is still valid and connected, and is run at recheckInterval. You + // can use exports.validId (see below), and the default answers truthy if id is valid or a + // concatenation of two valid ids. (This handles the most common cases of instanceId being + // either (the default) MyAvatar.sessionUUID, an entityID, or the concatenation (in either + // order) of both.) + connectionTest = options.connectionTest || function connectionTest(id) { + var idLength = 38; + if (id.length === idLength) { + return exports.validId(id); + } + return (id.length === 2 * idLength) && exports.validId(id.slice(0, idLength)) && exports.validId(id.slice(idLength)); + }; + + if (!batonName) { + throw new Error("A virtualBaton must specify a batonName."); + } + // Truthy if id exists as either a connected avatar or valid entity. + exports.validId = function validId(id) { + var avatar = avatarList.getAvatar(id); + if (avatar && (avatar.sessionUUID === id)) { + return true; + } + var properties = entities.getEntityProperties(id, ['type']); + return properties && properties.type; + }; + + // Various logging, controllable through options. + function debug() { // Display the arguments not just [Object object]. + log.apply(null, [].map.call(arguments, JSON.stringify)); + } + function debugFlow() { + if (options.debugFlow) { + debug.apply(null, arguments); + } + } + function debugSend(destination, operation, data) { + if (options.debugSend) { + debug('baton:', batonName, instanceId, 's=>', destination, operation, data); + } + } + function debugReceive(senderID, operation, data) { // senderID is client sessionUUID -- not necessarily instanceID! + if (options.debugReceive) { + debug('baton:', batonName, senderID, '=>r', instanceId, operation, data); + } + } + + // Messages: Just synactic sugar for hooking things up to Messages system. + // We create separate subchannel strings for each operation within our general channelKey, instead of using + // a switch in the receiver. + var channelKey = "io.highfidelity.virtualBaton:" + batonName, + subchannelHandlers = {}, // Message channel string => {receiver, op} + subchannelKeys = {}; // operation => Message channel string + function subchannelKey(operation) { + return channelKey + ':' + operation; + } + function receive(operation, handler) { // Record a handler for an operation on our channelKey + var subKey = subchannelKey(operation); + subchannelHandlers[subKey] = {receiver: handler, op: operation}; + subchannelKeys[operation] = subKey; + messages.subscribe(subKey); + } + function sendHelper(subchannel, data) { + var message = JSON.stringify(data); + messages.sendMessage(subchannel, message); + } + function send1(operation, destination, data) { // Send data for an operation to just one destination on our channelKey. + debugSend(destination, operation, data); + sendHelper(subchannelKey(operation) + destination, data); + } + function send(operation, data) { // Send data for an operation on our channelKey. + debugSend('-', operation, data); + sendHelper(subchannelKeys[operation], data); + } + function messageHandler(channel, messageString, senderID) { + var handler = subchannelHandlers[channel]; + if (!handler) { + return; + } + var data = JSON.parse(messageString); + debugReceive(senderID, handler.op, data); + handler.receiver(data); + } + messages.messageReceived.connect(messageHandler); + + var nPromises = 0, nAccepted = 0, electionWatchdog; + + // It would be great if we had a way to know how many subscribers our channel has. Failing that... + var nNack = 0, previousNSubscribers = 0, lastGathering = 0, thisTimeout = electionTimeout; + function nSubscribers() { // Answer the number of subscribers. + // To find nQuorum, we need to know how many scripts are being run using this batonName, which isn't + // the same as the number of clients! + // + // If we overestimate by too much, we may fail to reach consensus, which triggers a new + // election proposal, so we take the number of acceptors to be the max(nPromises, nAccepted) + // + nNack reported in the previous round. + // + // If we understimate by too much, there can be different pockets on the Internet that each + // believe they have agreement on different holders of the baton, which is precisely what + // the virtualBaton is supposed to avoid. Therefore we need to allow 'nack' to gather stragglers. + + var now = Date.now(), elapsed = now - lastGathering; + if (elapsed >= thisTimeout) { + previousNSubscribers = Math.max(nPromises, nAccepted) + nNack; + lastGathering = now; + } // ...otherwise we use the previous value unchanged. + + // On startup, we do one proposal that we cannot possibly close, so that we'll + // lock things up for the full electionTimeout to gather responses. + if (!previousNSubscribers) { + var LARGE_INTEGER = Number.MAX_SAFE_INTEGER || (-1 >>> 1); // QT doesn't define the ECMA constant. Max int will do for our purposes. + previousNSubscribers = LARGE_INTEGER; + } + return previousNSubscribers; + } + + // MAIN ALGORITHM + // + // Internally, this uses the Paxos algorith to hold elections. + // Alternatively, we could have the message server pick and maintain a winner, but it would + // still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages. + // Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer + // (such as the server). + function betterNumber(number, best) { + return (number.number || 0) > best.number; + } + // Paxos Proposer behavior + var proposalNumber = 0, + nQuorum = 0, + bestPromise = {number: 0}, + claimCallback, + releaseCallback; + function propose() { // Make a new proposal, so that we learn/update the proposalNumber and winner. + // Even though we send back a 'nack' if the proposal is obsolete, with network errors + // there's no way to know for certain that we've failed. The electionWatchdog will try a new + // proposal if we have not been accepted by a quorum after election Timeout. + if (electionWatchdog) { + // If we had a means of determining nSubscribers other than by counting, we could just + // timers.clearTimeout(electionWatchdog) and not return. + return; + } + thisTimeout = randomize(electionTimeout, 0.5); // Note use in nSubcribers. + electionWatchdog = timers.setTimeout(function () { + electionWatchdog = null; + propose(); + }, thisTimeout); + var nAcceptors = nSubscribers(); + nQuorum = Math.floor(nAcceptors / 2) + 1; + + proposalNumber = Math.max(proposalNumber, bestPromise.number) + 1; + debugFlow('baton:', batonName, instanceId, 'propose', proposalNumber, + 'claim:', !!claimCallback, 'nAcceptors:', nAcceptors, nPromises, nAccepted, nNack); + nPromises = nAccepted = nNack = 0; + send('prepare!', {number: proposalNumber, proposerId: instanceId}); + } + // We create a distinguished promise subchannel for our id, because promises need only be sent to the proposer. + receive('promise' + instanceId, function (data) { + if (betterNumber(data, bestPromise)) { + bestPromise = data; + } + if ((data.proposalNumber === proposalNumber) && (++nPromises >= nQuorum)) { // Note check for not being a previous round + var answer = {number: data.proposalNumber, proposerId: data.proposerId, winner: bestPromise.winner}; // Not data.number. + if (!answer.winner || (answer.winner === instanceId)) { // We get to pick. + answer.winner = claimCallback ? instanceId : null; + } + send('accept!', answer); + } + }); + receive('nack' + instanceId, function (data) { // An acceptor reports more recent data... + if (data.proposalNumber === proposalNumber) { + nNack++; // For updating nQuorum. + // IWBNI if we started our next proposal right now/here, but we need a decent nNack count. + // Lets save that optimization for another day... + } + }); + // Paxos Acceptor behavior + var bestProposal = {number: 0}, accepted = {}; + function acceptedId() { + return accepted && accepted.winner; + } + receive('prepare!', function (data) { + var response = {proposalNumber: data.number, proposerId: data.proposerId}; + if (betterNumber(data, bestProposal)) { + bestProposal = data; + if (accepted.winner && connectionTest(accepted.winner)) { + response.number = accepted.number; + response.winner = accepted.winner; + } + send1('promise', data.proposerId, response); + } else { + send1('nack', data.proposerId, response); + } + }); + receive('accept!', function (data) { + if (!betterNumber(bestProposal, data)) { + bestProposal = accepted = data; // Update both with current data. Might have missed the proposal earlier. + if (useOptimizations) { + // The Paxos literature describes every acceptor sending 'accepted' to + // every proposer and learner. In our case, these are the same nodes that received + // the 'accept!' message, so we can send to just the originating proposer and invoke + // our own accepted handler directly. + // Note that this optimization cannot be used with Byzantine Paxos (which needs another + // multi-broadcast to detect lying and collusion). + debugSend('/', 'accepted', data); + debugReceive(instanceId, 'accepted', data); // direct on next line, which doesn't get logging. + subchannelHandlers[subchannelKey('accepted') + instanceId].receiver(data); + if (data.proposerId !== instanceId) { // i.e., we didn't already do it directly on the line above. + send1('accepted', data.proposerId, data); + } + } else { + send('accepted', data); + } + } else { + send1('nack', data.proposerId, {proposalNumber: data.number}); + } + }); + // Paxos Learner behavior. + function localRelease() { + var callback = releaseCallback; + debugFlow('baton:', batonName, 'localRelease', 'callback:', !!releaseCallback); + if (!releaseCallback) { + return; + } // Already released, but we might still receive a stale message. That's ok. + releaseCallback = undefined; + callback(batonName); // Pass batonName so that clients may use the same handler for different batons. + } + receive('accepted' + (useOptimizations ? instanceId : ''), function (data) { // See note in 'accept!' regarding use of instanceId here. + if (betterNumber(accepted, data)) { // Especially when !useOptimizations, we can receive other acceptances late. + return; + } + var oldAccepted = accepted; + debugFlow('baton:', batonName, instanceId, 'accepted', data.number, data.winner); + accepted = data; + // If we are proposer, make sure we get a quorum of acceptances. + if ((data.proposerId === instanceId) && (data.number === proposalNumber) && (++nAccepted >= nQuorum)) { + if (electionWatchdog) { + timers.clearTimeout(electionWatchdog); + electionWatchdog = null; + } + } + // If we are the winner -- regardless of whether we were the proposer. + if (acceptedId() === instanceId) { + if (claimCallback) { + var callback = claimCallback; + claimCallback = undefined; + callback(batonName); + } else if (!releaseCallback) { // We won, but have been released and are no longer interested. + // Propose that someone else take the job. + timers.setTimeout(propose, 0); // Asynchronous to queue message handling if some are synchronous and others not. + } + } else if (releaseCallback && (oldAccepted.winner === instanceId)) { // We've been released by someone else! + localRelease(); // This can happen if enough people thought we'd disconnected. + } + }); + + // Public Interface + // + // Registers an intent to hold the baton: + // Calls onElection(batonName) once, if you are elected by the scripts + // to be the unique holder of the baton, which may be never. + // Calls onRelease(batonName) once, if the baton held by you is released, + // whether this is by you calling release(), or by losing + // an election when you become disconnected. + // You may claim again at any time after the start of onRelease + // being called. + exports.claim = function claim(onElection, onRelease) { + debugFlow('baton:', batonName, instanceId, 'claim'); + if (claimCallback) { + log("Ignoring attempt to claim virtualBaton " + batonName + ", which is already waiting for claim."); + return; + } + if (releaseCallback) { + log("Ignoring attempt to claim virtualBaton " + batonName + ", which is somehow incorrect released, and that should not happen."); + return; + } + claimCallback = onElection; + releaseCallback = onRelease; + propose(); + return exports; // Allows chaining. e.g., var baton = virtualBaton({batonName: 'foo'}.claim(onClaim, onRelease); + }; + // Release the baton you hold, or just log that you are not holding it. + exports.release = function release(optionalReplacementOnRelease) { + debugFlow('baton:', batonName, instanceId, 'release'); + if (optionalReplacementOnRelease) { // If you want to change. + releaseCallback = optionalReplacementOnRelease; + } + if (acceptedId() !== instanceId) { + log("Ignoring attempt to release virtualBaton " + batonName + ", which is not being held."); + return; + } + localRelease(); + if (!claimCallback) { // No claim set in release callback. + propose(); + } + return exports; + }; + exports.recheckWatchdog = timers.setInterval(function recheck() { + var holder = acceptedId(); // If we're waiting and we notice the holder is gone, ... + if (holder && claimCallback && !electionWatchdog && !connectionTest(holder)) { + bestPromise.winner = null; // used if the quorum agrees that old winner is not there + propose(); // ... propose an election. + } + }, recheckInterval); + exports.unload = function unload() { // Disconnect from everything. + messages.messageReceived.disconnect(messageHandler); + timers.clearInterval(exports.recheckWatchdog); + if (electionWatchdog) { + timers.clearTimeout(electionWatchdog); + } + electionWatchdog = claimCallback = releaseCallback = null; + Object.keys(subchannelHandlers).forEach(messages.unsubscribe); + debugFlow('baton:', batonName, instanceId, 'unload'); + return exports; + }; + + // Gather nAcceptors by making two proposals with some gathering time, even without a claim. + propose(); + return exports; +} +if (typeof module !== 'undefined') { // Allow testing in nodejs. + module.exports = virtualBatonf; +} else { + virtualBaton = virtualBatonf; +} diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index e4ee59cb6b..16c83b29dd 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -9,19 +9,42 @@ var teleport; var portalDestination; var animationURL; - var self = this; this.entered = true; + Script.include('virtualBaton.js'); + + var self = this; + var baton; + var iOwn = false; + var currentInterval; + var _entityId; + + function startUpdate() { + iOwn = true; + print('i am the owner ' + _entityId) + } + + function stopUpdateAndReclaim() { + print('i released the object ' + _entityId) + iOwn = false; + baton.claim(startUpdate, stopUpdateAndReclaim); + } this.preload = function(entityID) { this.entityId = entityID; + _entityId = entityID; this.initialize(entityID); this.initTimeout = null; this.minVelocity = 1; this.maxVelocity = 5; this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; - Script.setTimeout(self.move, self.getTotalWait()) + baton = virtualBaton({ + batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + }); + stopUpdateAndReclaim(); + currentInterval = Script.setInterval(self.move, self.getTotalWait()) + } this.initialize = function(entityID) { @@ -104,6 +127,8 @@ if (this.initTimeout !== null) { Script.clearTimeout(this.initTimeout); } + baton.release(function() {}); + Script.clearInterval(currentInterval); } this.hoverEnterEntity = function(entityID) { @@ -114,16 +139,13 @@ } this.getTotalWait = function() { - var avatars = AvatarList.getAvatarIdentifiers(); - var avatarCount = avatars.length; - var random = Math.random() * 2000; - var totalWait = random * (avatarCount * 2); - - return totalWait + return (Math.random() * 5000) * 2; } - this.move = function() { + if (!iOwn) { + return; + } var magnitudeV = self.maxVelocity; var directionV = { @@ -133,11 +155,6 @@ }; //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); - Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)) - }); - - var magnitudeAV = self.maxAngularVelocity; @@ -148,11 +165,12 @@ }; //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); - Script.setTimeout(self.move, self.getTotalWait()) + } }) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index db50635f93..63f99c53a3 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1043; +var version = 1049; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -194,7 +194,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, { //golgi vesicles model: "vesicle", @@ -238,7 +238,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, { model: "vesicle", @@ -304,7 +304,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, { //outer vesicles model: "vesicle", @@ -326,7 +326,7 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly.js?" + version, + script: "moveRandomly2.js?" + version, visible: true }, // {//wigglies From 39d4fbf19dba163eda9b7bcd3e685cab55ff4e50 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 18 Feb 2016 15:23:32 -0800 Subject: [PATCH 017/292] refactoring --- .../whiteboardV2/markerEntityScript.js | 17 +++++++---- .../whiteboardV2/whiteboardSpawner.js | 30 ++----------------- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index ef6f6b005d..3ed89e82c1 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -13,7 +13,7 @@ (function() { Script.include("../../libraries/utils.js"); - + MarkerTip = function() { _this = this; }; @@ -22,22 +22,29 @@ continueNearGrab: function() { + _this.continueHolding(); + }, + + continueEquip: function() { + _this.continueHolding(); + }, + + continueHolding: function() { // cast a ray from marker and see if it hits anything var props = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); var pickRay = { - origin: props.position, + origin: props.position, direction: Quat.getFront(props.rotation) } var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { - print("INTERSECTION!") } }, - + preload: function(entityID) { this.entityID = entityID; } @@ -45,4 +52,4 @@ // entity scripts always need to return a newly constructed object of our type return new MarkerTip(); -}); +}); \ No newline at end of file diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a699bcafa2..535c817121 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -40,7 +40,7 @@ var whiteboard = Entities.addEntity({ }); var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); -var MARKER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/marker-blue.fbx"; +var MARKER_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx"; var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", @@ -63,33 +63,7 @@ var marker = Entities.addEntity({ y: 0.0272, z: 0.1641 }, - script: MARKER_SCRIPT_URL, - userData: JSON.stringify({ - wearable: { - joints: { - RightHand: [{ - "x": 0.03257002681493759, - "y": 0.15036098659038544, - "z": 0.051217660307884216 - }, { - "x": -0.5274277329444885, - "y": -0.23446641862392426, - "z": -0.05400913953781128, - "w": 0.8148180246353149 - }], - LeftHand: [{ - "x": -0.031699854880571365, - "y": 0.15150733292102814, - "z": 0.041107177734375 - }, { - "x": 0.649201512336731, - "y": 0.1007731482386589, - "z": 0.3215889632701874, - "w": -0.6818817853927612 - }] - } - } - }) + script: MARKER_SCRIPT_URL }); From 903824809c2ee76c2901016a9b71f97b8fb7b76a Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 18 Feb 2016 18:33:32 -0800 Subject: [PATCH 018/292] trying to have better support for the materials --- .../tools/render/debugFramebuffer.js | 51 +++++++++++++++++++ .../utilities/tools/render/framebuffer.qml | 40 +++++++++++++++ libraries/fbx/src/FBXReader.cpp | 12 ++--- libraries/fbx/src/FBXReader.h | 6 ++- libraries/fbx/src/FBXReader_Material.cpp | 46 +++++++++-------- .../src/model-networking/ModelCache.cpp | 46 ++++++++++++++--- .../src/model-networking/ModelCache.h | 4 ++ .../src/model-networking/TextureCache.cpp | 4 ++ .../src/model-networking/TextureCache.h | 2 +- libraries/model/src/model/TextureMap.cpp | 49 ++++++++++++++++++ libraries/model/src/model/TextureMap.h | 1 + libraries/render-utils/src/DeferredBuffer.slh | 2 +- .../render-utils/src/DeferredGlobalLight.slh | 12 ++--- .../render-utils/src/DeferredLighting.slh | 6 +-- .../render-utils/src/MeshPartPayload.cpp | 6 +-- 15 files changed, 236 insertions(+), 51 deletions(-) create mode 100644 examples/utilities/tools/render/debugFramebuffer.js create mode 100644 examples/utilities/tools/render/framebuffer.qml diff --git a/examples/utilities/tools/render/debugFramebuffer.js b/examples/utilities/tools/render/debugFramebuffer.js new file mode 100644 index 0000000000..4aad8f9488 --- /dev/null +++ b/examples/utilities/tools/render/debugFramebuffer.js @@ -0,0 +1,51 @@ +// +// debug.js +// examples/utilities/tools/render +// +// Sam Gateau created on 2/18/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var DDB = Render.RenderDeferredTask.DebugDeferredBuffer; +DDB.enabled = true; +oldConfig = DDB.toJSON(); + + +// Set up the qml ui +var qml = Script.resolvePath('framebuffer.qml'); +var window = new OverlayWindow({ + title: 'Framebuffer Debug', + source: qml, + width: 400, height: 400, +}); +window.setPosition(25, 50); +window.closed.connect(function() { Script.stop(); }); + +// Debug buffer sizing +var resizing = false; + +Controller.mousePressEvent.connect(function (e) { + if (shouldStartResizing(e.x)) { + resizing = true; + } +}); +Controller.mouseReleaseEvent.connect(function() { resizing = false; }); +Controller.mouseMoveEvent.connect(function (e) { resizing && setDebugBufferSize(e.x); }); + + +function shouldStartResizing(eventX) { + var x = Math.abs(eventX - Window.innerWidth * (1.0 + DDB.size.x) / 2.0); + var mode = DDB.mode; + return mode !== -1 && x < 20; +} + +function setDebugBufferSize(x) { + x = (2.0 * (x / Window.innerWidth) - 1.0); // scale + x = Math.min(Math.max(-1, x), 1); // clamp + DDB.size = { x: x, y: -1, z: 1, w: 1 }; +} + +Script.scriptEnding.connect(function () { DDB.fromJSON(oldConfig); }); diff --git a/examples/utilities/tools/render/framebuffer.qml b/examples/utilities/tools/render/framebuffer.qml new file mode 100644 index 0000000000..734c62ad19 --- /dev/null +++ b/examples/utilities/tools/render/framebuffer.qml @@ -0,0 +1,40 @@ +// +// main.qml +// examples/utilities/tools/render +// +// Created by Zach Pomerantz on 2/8/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Column { + spacing: 8 + Column { + id: debug + property var config: Render.getConfig("DebugDeferredBuffer") + + function setDebugMode(mode) { + debug.config.enabled = (mode != -1); + debug.config.mode = mode; + } + + Label { text: qsTr("Debug Buffer") } + ExclusiveGroup { id: bufferGroup } + Repeater { + model: [ + "Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth", + "Lighting", "Shadow", "Pyramid Depth", "Ambient Occlusion", "Custom Shader" + ] + RadioButton { + text: qsTr(modelData) + exclusiveGroup: bufferGroup + checked: index == 0 + onCheckedChanged: if (checked) debug.setDebugMode(index - 1); + } + } + } +} diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 7af67039ef..1778e06894 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -865,9 +865,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } } else if (object.name == "Material") { FBXMaterial material; - if (object.properties.at(1).toByteArray().contains("StingrayPBS1")) { - material.isPBSMaterial = true; - } else if (object.properties.at(1).toByteArray().contains("StingrayPBS2")) { + if (object.properties.at(1).toByteArray().contains("StingrayPBS")) { material.isPBSMaterial = true; } foreach (const FBXNode& subobject, object.children) { @@ -1079,7 +1077,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("transparentcolor")) { // it should be TransparentColor... // THis is how Maya assign a texture that affect diffuse color AND transparency ? - diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + transparentTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("bump")) { bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("normal")) { @@ -1094,13 +1092,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS shininessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("tex_roughness_map")) { roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - } else if (_loadLightmaps && type.contains("emissive")) { + } else if (type.contains("emissive")) { emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("tex_emissive_map")) { roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - } else if (_loadLightmaps && type.contains("ambient")) { + } else if (type.contains("ambient")) { ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - } else if (_loadLightmaps && type.contains("tex_ao_map")) { + } else if (type.contains("tex_ao_map")) { occlusionTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type == "lcl rotation") { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 680cbe2fd4..6a59ac6aef 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -135,7 +135,7 @@ public: diffuseColor(diffuseColor), specularColor(specularColor), emissiveColor(emissiveColor), - emissiveParams(emissiveParams), + lightmapParams(emissiveParams), shininess(shininess), opacity(opacity) {} @@ -145,7 +145,6 @@ public: float specularFactor = 1.0f; glm::vec3 emissiveColor{ 0.0f }; - glm::vec2 emissiveParams{ 0.0f, 1.0f }; float shininess = 23.0f; float opacity = 1.0f; @@ -173,6 +172,8 @@ public: FBXTexture metallicTexture; FBXTexture emissiveTexture; FBXTexture occlusionTexture; + FBXTexture lightmapTexture; + glm::vec2 lightmapParams{ 0.0f, 1.0f }; bool isPBSMaterial{ false }; @@ -416,6 +417,7 @@ public: QHash diffuseTextures; + QHash transparentTextures; QHash bumpTextures; QHash normalTextures; QHash specularTextures; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 64ee958330..cce2f2162a 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -80,10 +80,19 @@ void FBXReader::consolidateFBXMaterials() { } material.albedoTexture = diffuseTexture; - detectDifferentUVs = (diffuseTexture.texcoordSet != 0) || (!diffuseTexture.transform.isIdentity()); } - + + + FBXTexture transparentTexture; + QString transparentTextureID = transparentTextures.value(material.materialID); + if (!transparentTextureID.isNull()) { + transparentTexture = getTexture(transparentTextureID); + + material.opacityTexture = transparentTexture; + detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity()); + } + FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(material.materialID); QString normalTextureID = normalTextures.value(material.materialID); @@ -133,25 +142,23 @@ void FBXReader::consolidateFBXMaterials() { } FBXTexture emissiveTexture; - glm::vec2 emissiveParams(0.f, 1.f); - emissiveParams.x = _lightmapOffset; - emissiveParams.y = _lightmapLevel; - QString emissiveTextureID = emissiveTextures.value(material.materialID); - QString ambientTextureID = ambientTextures.value(material.materialID); - if (_loadLightmaps && (!emissiveTextureID.isNull() || !ambientTextureID.isNull())) { - - if (!emissiveTextureID.isNull()) { - emissiveTexture = getTexture(emissiveTextureID); - emissiveParams.y = 4.0f; - } else if (!ambientTextureID.isNull()) { - emissiveTexture = getTexture(ambientTextureID); - } - - material.emissiveParams = emissiveParams; - material.emissiveTexture = emissiveTexture; - + if (!emissiveTextureID.isNull()) { + emissiveTexture = getTexture(emissiveTextureID); detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity()); + material.emissiveTexture = emissiveTexture; + } + + glm::vec2 lightmapParams(0.f, 1.f); + lightmapParams.x = _lightmapOffset; + lightmapParams.y = _lightmapLevel; + FBXTexture ambientTexture; + QString ambientTextureID = ambientTextures.value(material.materialID); + if (_loadLightmaps && !ambientTextureID.isNull()) { + ambientTexture = getTexture(ambientTextureID); + detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity()); + material.lightmapTexture = ambientTexture; + material.lightmapParams = lightmapParams; } // Finally create the true material representation @@ -168,7 +175,6 @@ void FBXReader::consolidateFBXMaterials() { material._material->setMetallic(material.metallic); } else { material._material->setRoughness(model::Material::shininessToRoughness(material.shininess)); - float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z)); // FIXME: Do not use the Specular Factor yet as some FBX models have it set to 0 // metallic *= material.specularFactor; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 6551ca5a60..3de21e5b0e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -139,7 +139,8 @@ bool NetworkGeometry::isLoadedWithTextures() const { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || (material->normalTexture && !material->normalTexture->isLoaded()) || (material->specularTexture && !material->specularTexture->isLoaded()) || - (material->emissiveTexture && !material->emissiveTexture->isLoaded())) { + (material->emissiveTexture && !material->emissiveTexture->isLoaded()) || + (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } } @@ -180,6 +181,13 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u } else if (material->emissiveTextureName == name) { material->emissiveTexture = textureCache->getTexture(url); + auto emissiveMap = model::TextureMapPointer(new model::TextureMap()); + emissiveMap->setTextureSource(material->emissiveTexture->_textureSource); + + networkMaterial->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); + } else if (material->lightmapTextureName == name) { + material->emissiveTexture = textureCache->getTexture(url); + auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); lightmapMap->setTextureSource(material->emissiveTexture->_textureSource); lightmapMap->setTextureTransform( @@ -219,6 +227,10 @@ QStringList NetworkGeometry::getTextureNames() const { QString textureURL = material->emissiveTexture->getURL().toString(); result << material->emissiveTextureName + ":\"" + textureURL + "\""; } + if (!material->lightmapTextureName.isEmpty() && material->lightmapTexture) { + QString textureURL = material->lightmapTexture->getURL().toString(); + result << material->lightmapTextureName + ":\"" + textureURL + "\""; + } } return result; @@ -333,20 +345,38 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content); networkMaterial->specularTextureName = material.specularTexture.name; - auto glossMap = model::TextureMapPointer(new model::TextureMap()); - glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource); + auto specularMap = model::TextureMapPointer(new model::TextureMap()); + specularMap->setTextureSource(networkMaterial->specularTexture->_textureSource); - material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap); + material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, specularMap); + } + if (!material.roughnessTexture.filename.isEmpty()) { + networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), ROUGHNESS_TEXTURE, material.roughnessTexture.content); + networkMaterial->roughnessTextureName = material.roughnessTexture.name; + + auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); + roughnessMap->setTextureSource(networkMaterial->roughnessTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, roughnessMap); } if (!material.emissiveTexture.filename.isEmpty()) { - networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), LIGHTMAP_TEXTURE, material.emissiveTexture.content); + networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content); networkMaterial->emissiveTextureName = material.emissiveTexture.name; + auto emissiveMap = model::TextureMapPointer(new model::TextureMap()); + emissiveMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); + } + if (!material.lightmapTexture.filename.isEmpty()) { + networkMaterial->lightmapTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.lightmapTexture.filename)), LIGHTMAP_TEXTURE, material.lightmapTexture.content); + networkMaterial->lightmapTextureName = material.lightmapTexture.name; + auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); - lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource); - lightmapMap->setTextureTransform(material.emissiveTexture.transform); - lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y); + lightmapMap->setTextureSource(networkMaterial->lightmapTexture->_textureSource); + lightmapMap->setTextureTransform(material.lightmapTexture.transform); + lightmapMap->setLightmapOffsetScale(material.lightmapParams.x, material.lightmapParams.y); material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 2cb67e7e87..1d43424813 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -180,8 +180,12 @@ public: QSharedPointer normalTexture; QString specularTextureName; QSharedPointer specularTexture; + QString roughnessTextureName; + QSharedPointer roughnessTexture; QString emissiveTextureName; QSharedPointer emissiveTexture; + QString lightmapTextureName; + QSharedPointer lightmapTexture; }; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 8201339e93..2ec9ab4027 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -212,6 +212,10 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { return TextureLoaderFunc(model::TextureUsage::createNormalTextureFromNormalImage); break; } + case ROUGHNESS_TEXTURE: { + return TextureLoaderFunc(model::TextureUsage::createRoughnessTextureFromImage); + break; + } case CUSTOM_TEXTURE: { return _textureLoader; break; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 033b4bede6..1a0d22a8d3 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -29,7 +29,7 @@ class NetworkTexture; typedef QSharedPointer NetworkTexturePointer; -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, CUBE_TEXTURE, LIGHTMAP_TEXTURE, CUSTOM_TEXTURE }; +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, ROUGHNESS_TEXTURE, EMISSIVE_TEXTURE, CUBE_TEXTURE, LIGHTMAP_TEXTURE, CUSTOM_TEXTURE }; /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache, public Dependency { diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index cd42419f6a..17d610e87f 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -223,6 +223,55 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm return theTexture; } +gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + QImage image = srcImage; + if (!image.hasAlphaChannel()) { + if (image.format() != QImage::Format_RGB888) { + image = image.convertToFormat(QImage::Format_RGB888); + } + } else { + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); + } + } + + image = image.convertToFormat(QImage::Format_Grayscale8); + + /* gpu::Texture* theTexture = nullptr; + if ((image.width() > 0) && (image.height() > 0)) { + + // Actual alpha channel? + for (int y = 0; y < image.height(); ++y) { + QRgb* data = reinterpret_cast(image.scanLine(y)); + for (int x = 0; x < image.width(); ++x) { + data[x]auto alpha = q(data[x]); + if (alpha != 255) { + validAlpha = true; + break; + } + } + } + */ + + + gpu::Texture* theTexture = nullptr; + if ((image.width() > 0) && (image.height() > 0)) { + // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); + bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); + + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + + theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + theTexture->autoGenerateMips(-1); + + // FIXME queue for transfer to GPU and block on completion + } + + return theTexture; +} + class CubeLayout { public: int _widthRatio = 1; diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index 4b625356e9..1e7f313dc8 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -34,6 +34,7 @@ public: static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName); + static gpu::Texture* createRoughnessTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName); diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 40c4349ae2..339b85ec1a 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -105,7 +105,7 @@ DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec frag.diffuse = frag.diffuseVal.xyz; frag.specular = frag.specularVal.xyz; - frag.gloss = frag.specularVal.w; + frag.gloss = (frag.specularVal.w * 125)*(frag.specularVal.w * 125); return frag; diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 18a1aaffb6..aad06c9305 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -30,7 +30,7 @@ vec4 evalSkyboxLight(vec3 direction, float lod) { <@include model/Light.slh@> <@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss) { +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float gloss) { // Need the light now Light light = getLight(); @@ -41,7 +41,7 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc vec3 color = albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, fresnel, gloss); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); @@ -52,7 +52,7 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc <@func declareEvalAmbientSphereGlobalColor()@> -vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss) { +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float gloss) { // Need the light now Light light = getLight(); @@ -64,7 +64,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), ambientNormal).xyz * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, fresnel, gloss); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); @@ -76,7 +76,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa <$declareSkyboxMap()$> -vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss) { +vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float gloss) { // Need the light now Light light = getLight(); @@ -87,7 +87,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, fresnel, gloss); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index cf03861c2f..01403a8180 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -23,8 +23,8 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 sp // Specular Lighting depends on the half vector and the gloss vec3 halfDir = normalize(fragEyeDir + fragLightDir); - float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); - specularPower *= (gloss * 128.0 * 0.125 + 0.25); + float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss); + specularPower *= (gloss * 0.125 + 0.25); float shlickPower = (1.0 - dot(fragLightDir,halfDir)); float shlickPower2 = shlickPower * shlickPower; @@ -47,7 +47,7 @@ vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 // Specular Lighting depends on the half vector and the gloss vec3 halfDir = normalize(fragEyeDir + fragLightDir); - float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); + float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss); vec3 reflect = specularPower * specular * diffuse; return vec4(reflect, diffuse); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index a78d384dd1..f7642cf008 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -175,9 +175,9 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr); } - // TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that - if (materialKey.isGlossMap()) { - auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP]; + // Metallic map + if (materialKey.isMetallicMap()) { + auto specularMap = textureMaps[model::MaterialKey::METALLIC_MAP]; if (specularMap && specularMap->isDefined()) { batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); From e103fd364e3b95dedc0523e832e2403a3105cec8 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 19 Feb 2016 09:24:22 -0800 Subject: [PATCH 019/292] USing metallic and not gloss map --- libraries/render-utils/src/MeshPartPayload.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index f7642cf008..9c6c8522fd 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -378,7 +378,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); - bool hasSpecular = drawMaterialKey.isGlossMap(); + //bool hasSpecular = drawMaterialKey.isGlossMap(); + bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); bool isSkinned = _isSkinned; From f4ee9acb9c0ea5eca8271fc0cf9d69a913cd272a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 09:49:22 -0800 Subject: [PATCH 020/292] intersecting --- examples/homeContent/whiteboardV2/markerEntityScript.js | 5 ++++- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3ed89e82c1..4faf64b542 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -39,14 +39,17 @@ direction: Quat.getFront(props.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true); + var intersection = Entities.findRayIntersection(pickRay, true, [], [_this.entityID]); if (intersection.intersects) { + var name = Entities.getEntityProperties(intersection.entityID); + print("intersection") } }, preload: function(entityID) { this.entityID = entityID; + print("EBL PRELOAD"); } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 535c817121..68c4422364 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -27,6 +27,7 @@ var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteb var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; var whiteboard = Entities.addEntity({ type: "Model", + name: "whiteboard", modelURL: WHITEBOARD_MODEL_URL, position: whiteboardPosition, rotation: whiteboardRotation, @@ -63,6 +64,7 @@ var marker = Entities.addEntity({ y: 0.0272, z: 0.1641 }, + name: "marker", script: MARKER_SCRIPT_URL }); From 6765973a4a98d2b4b310c52cbb4c538bcabe7af7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 09:56:30 -0800 Subject: [PATCH 021/292] correct positioning on equip --- .../whiteboardV2/markerEntityScript.js | 3 +- .../whiteboardV2/whiteboardSpawner.js | 28 ++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 4faf64b542..47a308d564 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -39,11 +39,10 @@ direction: Quat.getFront(props.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true, [], [_this.entityID]); + var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { var name = Entities.getEntityProperties(intersection.entityID); - print("intersection") } }, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 68c4422364..fdecb01f21 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -65,7 +65,33 @@ var marker = Entities.addEntity({ z: 0.1641 }, name: "marker", - script: MARKER_SCRIPT_URL + script: MARKER_SCRIPT_URL, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.001109793782234192, + y: 0.13991504907608032, + z: 0.05035984516143799 + }, { + x: -0.7360993027687073, + y: -0.04330085217952728, + z: -0.10863728821277618, + w: -0.6666942238807678 + }], + LeftHand: [{ + x: 0.007193896919488907, + y: 0.15147076547145844, + z: 0.06174466013908386 + }, { + x: -0.4174973964691162, + y: 0.631147563457489, + z: -0.3890438377857208, + w: -0.52535080909729 + }] + } + } + }) }); From 8e9cd3ae2a62f2f414183f32ccbb4e6c5d10e62b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 10:38:13 -0800 Subject: [PATCH 022/292] passing whiteboard in to marker --- examples/homeContent/whiteboardV2/markerEntityScript.js | 8 ++++++++ examples/homeContent/whiteboardV2/whiteboardSpawner.js | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 47a308d564..d3a4f97fe9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -43,12 +43,20 @@ if (intersection.intersects) { var name = Entities.getEntityProperties(intersection.entityID); + + this.paint() } }, preload: function(entityID) { this.entityID = entityID; print("EBL PRELOAD"); + }, + + setWhiteboard: function(myId, data) { + _this.whiteboard = JSON.parse(data[0]); + var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); + Entities.editEntity(_this.whiteboard, {position: {x: 0, y: 1, z: 0}}); } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index fdecb01f21..b5d1c07959 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -94,6 +94,10 @@ var marker = Entities.addEntity({ }) }); +Script.setTimeout(function() { + Entities.callEntityMethod(marker, "setWhiteboard", [JSON.stringify(whiteboard)]); +}, 1000) + function cleanup() { From ddce8d5a3a8a63a95774a9404ed8edbc014029da Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 10:59:05 -0800 Subject: [PATCH 023/292] Marker basics working, now just need to tweak --- .../whiteboardV2/markerEntityScript.js | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d3a4f97fe9..e879b71144 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -16,6 +16,7 @@ MarkerTip = function() { _this = this; + _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; }; MarkerTip.prototype = { @@ -42,12 +43,48 @@ var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects) { - var name = Entities.getEntityProperties(intersection.entityID); - this.paint() + this.paint(intersection.intersection) } }, + newStroke: function(position) { + _this.strokeBasePosition = position; + _this.currentStroke = Entities.addEntity({ + type: "PolyLine", + name: "marker stroke", + dimensions: { + x: 10, + y: 10, + z: 10 + }, + position: position, + textures: _this.MARKER_TEXTURE_URL, + color: {red: 0, green: 10, blue: 200} + }); + + _this.linePoints = []; + _this.normals = []; + _this.strokeWidths = []; + }, + + paint: function(position) { + if (!_this.currentStroke) { + _this.newStroke(position); + } + + var localPoint = Vec3.subtract(position, this.strokeBasePosition); + _this.linePoints.push(localPoint); + _this.normals.push(_this._whiteboardNormal); + this.strokeWidths.push(0.02); + + Entities.editEntity(_this.currentStroke, { + linePoints: _this.linePoints, + normals: _this.normals, + strokeWidths: _this.strokeWidths + }); + }, + preload: function(entityID) { this.entityID = entityID; print("EBL PRELOAD"); @@ -56,7 +93,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - Entities.editEntity(_this.whiteboard, {position: {x: 0, y: 1, z: 0}}); + this._whiteboardNormal = Vec3.multiply(Quat.getFront(props.rotation), -1); } }; From b58026bf4bf83ab071b61558887090dcc9f32f75 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 11:04:17 -0800 Subject: [PATCH 024/292] max points --- .../homeContent/whiteboardV2/markerEntityScript.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index e879b71144..81e65cacb9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -14,6 +14,8 @@ (function() { Script.include("../../libraries/utils.js"); + var MAX_POINTS_PER_STROKE = 40; + MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; @@ -40,7 +42,7 @@ direction: Quat.getFront(props.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true); + var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); if (intersection.intersects) { @@ -83,6 +85,10 @@ normals: _this.normals, strokeWidths: _this.strokeWidths }); + + if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { + _this.currentStroke = null; + } }, preload: function(entityID) { @@ -93,7 +99,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - this._whiteboardNormal = Vec3.multiply(Quat.getFront(props.rotation), -1); + this._whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); } }; From 94bf15f3284e8a5c13fb466556474c2b3cf7c09a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 11:21:17 -0800 Subject: [PATCH 025/292] need to fix zfighting --- .../homeContent/whiteboardV2/markerEntityScript.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 81e65cacb9..73e8ce86db 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -18,7 +18,9 @@ MarkerTip = function() { _this = this; - _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/paintStroke.png"; + _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; + this.strokeForwardOffset = 0.0005; + this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; }; MarkerTip.prototype = { @@ -76,8 +78,11 @@ } var localPoint = Vec3.subtract(position, this.strokeBasePosition); + // localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); + _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + _this.linePoints.push(localPoint); - _this.normals.push(_this._whiteboardNormal); + _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(0.02); Entities.editEntity(_this.currentStroke, { @@ -99,7 +104,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - this._whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); + _this.whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); } }; From 9a8b76df476547c4b4cf51e9ee5d371a226d701a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 11:32:13 -0800 Subject: [PATCH 026/292] no more zfighting --- examples/homeContent/whiteboardV2/markerEntityScript.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 73e8ce86db..a2ab8ac285 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -21,6 +21,7 @@ _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; + this.STROKE_WIDTH = 0.003; }; MarkerTip.prototype = { @@ -78,12 +79,12 @@ } var localPoint = Vec3.subtract(position, this.strokeBasePosition); - // localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); + // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); - this.strokeWidths.push(0.02); + this.strokeWidths.push(_this.STROKE_WIDTH); Entities.editEntity(_this.currentStroke, { linePoints: _this.linePoints, @@ -104,7 +105,7 @@ setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Vec3.multiply(Quat.getRight(props.rotation), -1); + _this.whiteboardNormal = Quat.getRight(props.rotation); } }; From 0564cd8145848d0f24f85277b03f75c4bdf53976 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 12:02:34 -0800 Subject: [PATCH 027/292] returning if less than min distance --- .../whiteboardV2/markerEntityScript.js | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index a2ab8ac285..d4bd7bc272 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -21,7 +21,11 @@ _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; - this.STROKE_WIDTH = 0.003; + this.STROKE_WIDTH = 0.003 + _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.5; + _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; + _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; + _this.strokes = []; }; MarkerTip.prototype = { @@ -38,18 +42,20 @@ continueHolding: function() { // cast a ray from marker and see if it hits anything - var props = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); + var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); + var pickRay = { - origin: props.position, - direction: Quat.getFront(props.rotation) + origin: markerProps.position, + direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects) { - + if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) + } else { + _this.currentStroke = null; } }, @@ -71,6 +77,8 @@ _this.linePoints = []; _this.normals = []; _this.strokeWidths = []; + + _this.strokes.push(_this.currentStroke); }, paint: function(position) { @@ -82,6 +90,15 @@ localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + if (_this.linePoints.length > 0) { + var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length-1]); + if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) { + print("EBL not enough distance") + return; + } + } + + _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -99,13 +116,14 @@ preload: function(entityID) { this.entityID = entityID; + print("EBL PRELOAD"); }, setWhiteboard: function(myId, data) { _this.whiteboard = JSON.parse(data[0]); - var props = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Quat.getRight(props.rotation); + var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); + _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); } }; From 40176b04244dedaa5bcea1170c72c7f9e6102ce5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 14:06:55 -0800 Subject: [PATCH 028/292] no gaps --- .../homeContent/whiteboardV2/markerEntityScript.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d4bd7bc272..1bd7acf1d9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -22,7 +22,7 @@ this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; this.STROKE_WIDTH = 0.003 - _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.5; + _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.2; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; @@ -56,6 +56,7 @@ this.paint(intersection.intersection) } else { _this.currentStroke = null; + _this.oldPosition = null; } }, @@ -82,11 +83,16 @@ }, paint: function(position) { + var basePosition = position; if (!_this.currentStroke) { - _this.newStroke(position); + if (_this.oldPosition) { + basePosition = _this.oldPosition; + print("EBL USE OLD POSITION FOR NEW STROKE!") + } + _this.newStroke(basePosition); } - var localPoint = Vec3.subtract(position, this.strokeBasePosition); + var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; @@ -111,6 +117,7 @@ if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { _this.currentStroke = null; + _this.oldPosition = position; } }, From 9ae1ccee50016f4cb03590ff3f39d556f746bd01 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 14:15:55 -0800 Subject: [PATCH 029/292] passing marker color accross --- examples/homeContent/whiteboardV2/markerEntityScript.js | 8 +++++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 6 +++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 1bd7acf1d9..bc5304ea7f 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -72,7 +72,7 @@ }, position: position, textures: _this.MARKER_TEXTURE_URL, - color: {red: 0, green: 10, blue: 200} + color: _this.markerColor }); _this.linePoints = []; @@ -127,10 +127,12 @@ print("EBL PRELOAD"); }, - setWhiteboard: function(myId, data) { - _this.whiteboard = JSON.parse(data[0]); + setProperties: function(myId, data) { + var data = JSON.parse(data); + _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); + _this.markerColor = data.markerColor; } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index b5d1c07959..24b5d2a046 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -95,7 +95,11 @@ var marker = Entities.addEntity({ }); Script.setTimeout(function() { - Entities.callEntityMethod(marker, "setWhiteboard", [JSON.stringify(whiteboard)]); + var data = { + whiteboard: whiteboard, + markerColor: {red: 10, green: 10, blue: 200} + } + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) From 756b7e223d96508d03ec17ef2e59dfd5646396d0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 15:56:12 -0800 Subject: [PATCH 030/292] need to figure out why only one marker working --- .../whiteboardV2/markerEntityScript.js | 3 +- .../whiteboardV2/whiteboardSpawner.js | 173 +++++++++++------- 2 files changed, 110 insertions(+), 66 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index bc5304ea7f..66ca061c05 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -99,12 +99,10 @@ if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length-1]); if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) { - print("EBL not enough distance") return; } } - _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -131,6 +129,7 @@ var data = JSON.parse(data); _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); + print("EBL: MARKER COLOR " + JSON.stringify(data.markerColor)); _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); _this.markerColor = data.markerColor; } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 24b5d2a046..33b559838b 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -13,13 +13,19 @@ var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); -orientation.x = 0; -var whiteboardRotation = Quat.fromVec3Degrees({ - x: orientation.x, +var markerRotation = Quat.fromVec3Degrees({ + x: orientation.x + 10, y: orientation.y - 90, z: orientation.z +}) +orientation.x = 0; +var whiteboardRotation = Quat.fromVec3Degrees({ + x: 0, + y: orientation.y - 90, + z: 0 }); orientation = Quat.fromVec3Degrees(orientation); +var markers = []; var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); @@ -40,73 +46,112 @@ var whiteboard = Entities.addEntity({ } }); -var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); -var MARKER_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx"; -var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); -var marker = Entities.addEntity({ - type: "Model", - modelURL: MARKER_MODEL_URL, - shapeType: "box", - dynamic: true, - gravity: { - x: 0, - y: -1, - z: 0 - }, - velocity: { - x: 0, - y: -0.1, - z: 0 - }, - position: markerPosition, - dimensions: { - x: 0.0270, - y: 0.0272, - z: 0.1641 - }, - name: "marker", - script: MARKER_SCRIPT_URL, - userData: JSON.stringify({ - wearable: { - joints: { - RightHand: [{ - x: 0.001109793782234192, - y: 0.13991504907608032, - z: 0.05035984516143799 - }, { - x: -0.7360993027687073, - y: -0.04330085217952728, - z: -0.10863728821277618, - w: -0.6666942238807678 - }], - LeftHand: [{ - x: 0.007193896919488907, - y: 0.15147076547145844, - z: 0.06174466013908386 - }, { - x: -0.4174973964691162, - y: 0.631147563457489, - z: -0.3890438377857208, - w: -0.52535080909729 - }] - } - } - }) -}); +createMarkers(); +function createMarkers() { + var modelURLS = [ + "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx", + "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-red.fbx", + "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-black.fbx", + ]; -Script.setTimeout(function() { - var data = { - whiteboard: whiteboard, - markerColor: {red: 10, green: 10, blue: 200} - } - Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); -}, 1000) + var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); + + createMarker(modelURLS[0], markerPosition, { + red: 10, + green: 10, + blue: 200 + }); + + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); + createMarker(modelURLS[1], markerPosition, { + red: 200, + green: 10, + blue: 10 + }); + + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); + createMarker(modelURLS[2], markerPosition, { + red: 10, + green: 10, + blue: 10 + }); +} + + +function createMarker(modelURL, markerPosition, markerColor) { + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var marker = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + rotation: markerRotation, + shapeType: "box", + dynamic: true, + gravity: { + x: 0, + y: -1, + z: 0 + }, + velocity: { + x: 0, + y: -0.1, + z: 0 + }, + position: markerPosition, + dimensions: { + x: 0.0270, + y: 0.0272, + z: 0.1641 + }, + name: "marker", + script: MARKER_SCRIPT_URL, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.001109793782234192, + y: 0.13991504907608032, + z: 0.05035984516143799 + }, { + x: -0.7360993027687073, + y: -0.04330085217952728, + z: -0.10863728821277618, + w: -0.6666942238807678 + }], + LeftHand: [{ + x: 0.007193896919488907, + y: 0.15147076547145844, + z: 0.06174466013908386 + }, { + x: -0.4174973964691162, + y: 0.631147563457489, + z: -0.3890438377857208, + w: -0.52535080909729 + }] + } + } + }) + }); + + markers.push(marker); + + Script.setTimeout(function() { + var data = { + whiteboard: whiteboard, + markerColor: markerColor + } + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); + }, 1000) + + +} function cleanup() { Entities.deleteEntity(whiteboard); - Entities.deleteEntity(marker); + markers.forEach(function(marker){ + Entities.deleteEntity(marker); + }); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From 68e289b433db8836cda12d857a36de047a30bbe1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 17:32:33 -0800 Subject: [PATCH 031/292] Fixed bug where spawning one marker would destroy the other --- .../whiteboardV2/markerEntityScript.js | 15 ++++++--- .../whiteboardV2/whiteboardSpawner.js | 33 ++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 66ca061c05..d905db07dd 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -15,7 +15,7 @@ Script.include("../../libraries/utils.js"); var MAX_POINTS_PER_STROKE = 40; - +var _this; MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; @@ -49,12 +49,17 @@ origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - + print('MARKER ID'+_this.entityID) + print('MARKER POSITION'+JSON.stringify(markerProps.position)) var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - + print('WHITEBOARD AT CONTINUE:: '+_this.whiteboard); + print('DOES INTERSECT??'+intersection.intersects) + print('MARKER DISTANCE::'+Vec3.distance(intersection.intersection, markerProps.position)) + print('MAX DISTANCE::'+_this.MAX_MARKER_TO_BOARD_DISTANCE) if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) } else { + print('not painting because intersection') _this.currentStroke = null; _this.oldPosition = null; } @@ -103,6 +108,7 @@ } } + print("PAINT " + JSON.stringify(_this.markerColor)); _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -127,9 +133,10 @@ setProperties: function(myId, data) { var data = JSON.parse(data); + print("EBL SET PROPERTIES! ON " + JSON.stringify(data.markerColor)+ "id:"+ JSON.stringify(myId)); + _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - print("EBL: MARKER COLOR " + JSON.stringify(data.markerColor)); _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); _this.markerColor = data.markerColor; } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 33b559838b..c3dcd3e6d7 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -10,6 +10,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +Script.include("../../libraries/utils.js") var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); @@ -62,19 +63,23 @@ function createMarkers() { blue: 200 }); - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); - createMarker(modelURLS[1], markerPosition, { - red: 200, - green: 10, - blue: 10 - }); - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); - createMarker(modelURLS[2], markerPosition, { - red: 10, - green: 10, - blue: 10 - }); + Script.setTimeout(function() { + + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); + createMarker(modelURLS[1], markerPosition, { + red: 200, + green: 10, + blue: 10 + }); + }, 1000); + + // markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); + // createMarker(modelURLS[2], markerPosition, { + // red: 10, + // green: 10, + // blue: 10 + // }); } @@ -139,6 +144,10 @@ function createMarker(modelURL, markerPosition, markerColor) { whiteboard: whiteboard, markerColor: markerColor } + var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; + print("EBL MARKER URL " + JSON.stringify(modelURL)) + print("EBL MARKER COLOR " + JSON.stringify(markerColor)) + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) From 6fe9730897c4c62a79595d82f6fac09e3d097136 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 17:33:54 -0800 Subject: [PATCH 032/292] all three markers --- .../whiteboardV2/whiteboardSpawner.js | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index c3dcd3e6d7..a566e69f52 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -15,7 +15,7 @@ Script.include("../../libraries/utils.js") var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); var markerRotation = Quat.fromVec3Degrees({ - x: orientation.x + 10, + x: orientation.x + 10, y: orientation.y - 90, z: orientation.z }) @@ -48,6 +48,7 @@ var whiteboard = Entities.addEntity({ }); createMarkers(); + function createMarkers() { var modelURLS = [ "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-blue.fbx", @@ -64,22 +65,20 @@ function createMarkers() { }); - Script.setTimeout(function() { - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); - createMarker(modelURLS[1], markerPosition, { - red: 200, - green: 10, - blue: 10 - }); - }, 1000); + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); + createMarker(modelURLS[1], markerPosition, { + red: 200, + green: 10, + blue: 10 + }); - // markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); - // createMarker(modelURLS[2], markerPosition, { - // red: 10, - // green: 10, - // blue: 10 - // }); + markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation))); + createMarker(modelURLS[2], markerPosition, { + red: 10, + green: 10, + blue: 10 + }); } @@ -147,7 +146,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; print("EBL MARKER URL " + JSON.stringify(modelURL)) print("EBL MARKER COLOR " + JSON.stringify(markerColor)) - + Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) @@ -158,7 +157,7 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); - markers.forEach(function(marker){ + markers.forEach(function(marker) { Entities.deleteEntity(marker); }); } From ec369959088612210df8761b53d8f963ff04e0cf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 19 Feb 2016 17:36:02 -0800 Subject: [PATCH 033/292] moar whiteboard logging removal --- .../homeContent/whiteboardV2/markerEntityScript.js | 11 ----------- .../homeContent/whiteboardV2/whiteboardSpawner.js | 2 -- 2 files changed, 13 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d905db07dd..74b7746514 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -49,17 +49,10 @@ var _this; origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - print('MARKER ID'+_this.entityID) - print('MARKER POSITION'+JSON.stringify(markerProps.position)) var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - print('WHITEBOARD AT CONTINUE:: '+_this.whiteboard); - print('DOES INTERSECT??'+intersection.intersects) - print('MARKER DISTANCE::'+Vec3.distance(intersection.intersection, markerProps.position)) - print('MAX DISTANCE::'+_this.MAX_MARKER_TO_BOARD_DISTANCE) if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) } else { - print('not painting because intersection') _this.currentStroke = null; _this.oldPosition = null; } @@ -92,7 +85,6 @@ var _this; if (!_this.currentStroke) { if (_this.oldPosition) { basePosition = _this.oldPosition; - print("EBL USE OLD POSITION FOR NEW STROKE!") } _this.newStroke(basePosition); } @@ -108,7 +100,6 @@ var _this; } } - print("PAINT " + JSON.stringify(_this.markerColor)); _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); @@ -128,12 +119,10 @@ var _this; preload: function(entityID) { this.entityID = entityID; - print("EBL PRELOAD"); }, setProperties: function(myId, data) { var data = JSON.parse(data); - print("EBL SET PROPERTIES! ON " + JSON.stringify(data.markerColor)+ "id:"+ JSON.stringify(myId)); _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a566e69f52..26d373266b 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -144,8 +144,6 @@ function createMarker(modelURL, markerPosition, markerColor) { markerColor: markerColor } var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; - print("EBL MARKER URL " + JSON.stringify(modelURL)) - print("EBL MARKER COLOR " + JSON.stringify(markerColor)) Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); }, 1000) From 39a785297919ba58400ef97ba9870a3c216e77a4 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 19 Feb 2016 18:43:07 -0800 Subject: [PATCH 034/292] MOving forward with PBR rendering, cleaning up the lighting shaders and the packi/unpack deferredBuffer shaders --- .../utilities/tools/render/framebuffer.qml | 16 ++++++- libraries/entities-renderer/src/polyvox.slf | 5 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 5 +- .../src/model-networking/ModelCache.cpp | 13 +++++- libraries/model/src/model/Material.cpp | 2 +- libraries/model/src/model/Material.h | 39 ++++++++-------- .../render-utils/src/DebugDeferredBuffer.cpp | 46 ++++++++++++++++--- .../render-utils/src/DebugDeferredBuffer.h | 11 +++-- libraries/render-utils/src/DeferredBuffer.slh | 45 +++++++++++++----- .../render-utils/src/DeferredBufferWrite.slh | 17 ++++--- .../render-utils/src/DeferredGlobalLight.slh | 12 ++--- .../render-utils/src/DeferredLighting.slh | 16 ++++--- .../render-utils/src/MeshPartPayload.cpp | 16 ++++++- .../src/directional_ambient_light.slf | 3 +- .../src/directional_ambient_light_shadow.slf | 3 +- .../render-utils/src/directional_light.slf | 3 +- .../src/directional_light_shadow.slf | 3 +- .../src/directional_skybox_light.slf | 3 +- .../src/directional_skybox_light_shadow.slf | 3 +- libraries/render-utils/src/model.slf | 5 +- libraries/render-utils/src/model_emissive.slf | 3 +- libraries/render-utils/src/model_lightmap.slf | 3 +- .../src/model_lightmap_normal_map.slf | 3 +- .../model_lightmap_normal_specular_map.slf | 3 +- .../src/model_lightmap_specular_map.slf | 3 +- .../render-utils/src/model_normal_map.slf | 5 +- .../src/model_normal_specular_map.slf | 6 ++- .../render-utils/src/model_specular_map.slf | 6 ++- .../render-utils/src/model_translucent.slf | 6 ++- libraries/render-utils/src/overlay3D.slf | 10 ++-- .../src/overlay3D_translucent.slf | 10 ++-- libraries/render-utils/src/point_light.slf | 2 +- libraries/render-utils/src/sdf_text3D.slf | 20 ++++++-- libraries/render-utils/src/simple.slf | 4 +- .../render-utils/src/simple_textured.slf | 4 +- .../src/simple_textured_emisive.slf | 4 +- libraries/render-utils/src/spot_light.slf | 2 +- tests/gpu-test/src/unlit.slf | 2 +- 38 files changed, 248 insertions(+), 114 deletions(-) diff --git a/examples/utilities/tools/render/framebuffer.qml b/examples/utilities/tools/render/framebuffer.qml index 734c62ad19..20b8b384d8 100644 --- a/examples/utilities/tools/render/framebuffer.qml +++ b/examples/utilities/tools/render/framebuffer.qml @@ -26,8 +26,20 @@ Column { ExclusiveGroup { id: bufferGroup } Repeater { model: [ - "Off", "Diffuse", "Metallic", "Roughness", "Normal", "Depth", - "Lighting", "Shadow", "Pyramid Depth", "Ambient Occlusion", "Custom Shader" + "Off", + "Depth", + "Diffuse", + "Normal", + "Roughness", + "Metallic", + "Fresnel", + "Emissive", + "Lightmap", + "Lighting", + "Shadow", + "Pyramid Depth", + "Ambient Occlusion", + "Custom Shader" ] RadioButton { text: qsTr(modelData) diff --git a/libraries/entities-renderer/src/polyvox.slf b/libraries/entities-renderer/src/polyvox.slf index 2bdecbf9fe..38d9494a61 100644 --- a/libraries/entities-renderer/src/polyvox.slf +++ b/libraries/entities-renderer/src/polyvox.slf @@ -28,9 +28,6 @@ void main(void) { vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz)); worldNormal = normalize(worldNormal); - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; - float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x; float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y; float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z; @@ -44,5 +41,5 @@ void main(void) { vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x); vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0); - packDeferredFragment(_normal, 1.0, vec3(diffuse), specular, shininess); + packDeferredFragment(_normal, 1.0, vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR); } diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 35ad7dbbd8..c27c5dd97d 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -162,8 +162,6 @@ GLBackend::GLShader* compileShader(const Shader& shader) { char* temp = new char[infoLength] ; glGetShaderInfoLog(glshader, infoLength, NULL, temp); - qCWarning(gpulogging) << "GLShader::compileShader - failed to compile the gl shader object:"; - qCWarning(gpulogging) << temp; /* filestream.open("debugshader.glsl.info.txt"); @@ -173,7 +171,10 @@ GLBackend::GLShader* compileShader(const Shader& shader) { } */ + qCWarning(gpulogging) << "GLShader::compileShader - failed to compile the gl shader object:"; qCWarning(gpulogging) << srcstr; + qCWarning(gpulogging) << "GLShader::compileShader - errors:"; + qCWarning(gpulogging) << temp; delete[] temp; glDeleteShader(glshader); diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 3de21e5b0e..63cc113f5a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -177,7 +177,7 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u auto glossMap = model::TextureMapPointer(new model::TextureMap()); glossMap->setTextureSource(material->specularTexture->_textureSource); - networkMaterial->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap); + networkMaterial->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, glossMap); } else if (material->emissiveTextureName == name) { material->emissiveTexture = textureCache->getTexture(url); @@ -350,6 +350,15 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, specularMap); } + if (!material.metallicTexture.filename.isEmpty()) { + networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.metallicTexture.filename)), SPECULAR_TEXTURE, material.metallicTexture.content); + networkMaterial->specularTextureName = material.metallicTexture.name; + + auto metallicMap = model::TextureMapPointer(new model::TextureMap()); + metallicMap->setTextureSource(networkMaterial->specularTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); + } if (!material.roughnessTexture.filename.isEmpty()) { networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), ROUGHNESS_TEXTURE, material.roughnessTexture.content); networkMaterial->roughnessTextureName = material.roughnessTexture.name; @@ -357,7 +366,7 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); roughnessMap->setTextureSource(networkMaterial->roughnessTexture->_textureSource); - material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, roughnessMap); + material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); } if (!material.emissiveTexture.filename.isEmpty()) { networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content); diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 2d2bb38b62..770b110ad9 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -61,7 +61,7 @@ void Material::setAlbedo(const Color& albedo, bool isSRGB) { void Material::setRoughness(float roughness) { roughness = std::min(1.0f, std::max(roughness, 0.0f)); - _key.setGloss((roughness < 1.0f)); + _key.setGlossy((roughness < 1.0f)); _schemaBuffer.edit()._roughness = roughness; } diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 88a8e27611..df58f60eb1 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -30,13 +30,13 @@ public: EMISSIVE_VAL_BIT = 0, ALBEDO_VAL_BIT, METALLIC_VAL_BIT, - GLOSS_VAL_BIT, + GLOSSY_VAL_BIT, TRANSPARENT_VAL_BIT, EMISSIVE_MAP_BIT, ALBEDO_MAP_BIT, METALLIC_MAP_BIT, - GLOSS_MAP_BIT, + ROUGHNESS_MAP_BIT, TRANSPARENT_MAP_BIT, NORMAL_MAP_BIT, LIGHTMAP_MAP_BIT, @@ -49,7 +49,7 @@ public: EMISSIVE_MAP = 0, ALBEDO_MAP, METALLIC_MAP, - GLOSS_MAP, + ROUGHNESS_MAP, TRANSPARENT_MAP, NORMAL_MAP, LIGHTMAP_MAP, @@ -73,13 +73,13 @@ public: Builder& withEmissive() { _flags.set(EMISSIVE_VAL_BIT); return (*this); } Builder& withAlbedo() { _flags.set(ALBEDO_VAL_BIT); return (*this); } Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); } - Builder& withGloss() { _flags.set(GLOSS_VAL_BIT); return (*this); } + Builder& withGlossy() { _flags.set(GLOSSY_VAL_BIT); return (*this); } Builder& withTransparent() { _flags.set(TRANSPARENT_VAL_BIT); return (*this); } Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _flags.set(ALBEDO_MAP_BIT); return (*this); } Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); } - Builder& withGlossMap() { _flags.set(GLOSS_MAP_BIT); return (*this); } + Builder& withRoughnessMap() { _flags.set(ROUGHNESS_MAP_BIT); return (*this); } Builder& withTransparentMap() { _flags.set(TRANSPARENT_MAP_BIT); return (*this); } Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); } @@ -107,11 +107,12 @@ public: void setMetallicMap(bool value) { _flags.set(METALLIC_MAP_BIT, value); } bool isMetallicMap() const { return _flags[METALLIC_MAP_BIT]; } - void setGloss(bool value) { _flags.set(GLOSS_VAL_BIT, value); } - bool isGloss() const { return _flags[GLOSS_VAL_BIT]; } + void setGlossy(bool value) { _flags.set(GLOSSY_VAL_BIT, value); } + bool isGlossy() const { return _flags[GLOSSY_VAL_BIT]; } + bool isRough() const { return !_flags[GLOSSY_VAL_BIT]; } - void setGlossMap(bool value) { _flags.set(GLOSS_MAP_BIT, value); } - bool isGlossMap() const { return _flags[GLOSS_MAP_BIT]; } + void setRoughnessMap(bool value) { _flags.set(ROUGHNESS_MAP_BIT, value); } + bool isRoughnessMap() const { return _flags[ROUGHNESS_MAP_BIT]; } void setTransparent(bool value) { _flags.set(TRANSPARENT_VAL_BIT, value); } bool isTransparent() const { return _flags[TRANSPARENT_VAL_BIT]; } @@ -166,11 +167,11 @@ public: Builder& withoutMetallicMap() { _value.reset(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT); return (*this); } Builder& withMetallicMap() { _value.set(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT); return (*this); } - Builder& withoutGloss() { _value.reset(MaterialKey::GLOSS_VAL_BIT); _mask.set(MaterialKey::GLOSS_VAL_BIT); return (*this); } - Builder& withGloss() { _value.set(MaterialKey::GLOSS_VAL_BIT); _mask.set(MaterialKey::GLOSS_VAL_BIT); return (*this); } + Builder& withoutGlossy() { _value.reset(MaterialKey::GLOSSY_VAL_BIT); _mask.set(MaterialKey::GLOSSY_VAL_BIT); return (*this); } + Builder& withGlossy() { _value.set(MaterialKey::GLOSSY_VAL_BIT); _mask.set(MaterialKey::GLOSSY_VAL_BIT); return (*this); } - Builder& withoutGlossMap() { _value.reset(MaterialKey::GLOSS_MAP_BIT); _mask.set(MaterialKey::GLOSS_MAP_BIT); return (*this); } - Builder& withGlossMap() { _value.set(MaterialKey::GLOSS_MAP_BIT); _mask.set(MaterialKey::GLOSS_MAP_BIT); return (*this); } + Builder& withoutRoughnessMap() { _value.reset(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT); return (*this); } + Builder& withRoughnessMap() { _value.set(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT); return (*this); } Builder& withoutTransparent() { _value.reset(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); } Builder& withTransparent() { _value.set(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); } @@ -241,14 +242,14 @@ public: // Schema to access the attribute values of the material class Schema { public: - glm::vec3 _emissive{ 0.0f }; - float _opacity{ 1.f }; + glm::vec3 _emissive{ 0.0f }; // No Emissive + float _opacity{ 1.f }; // Opacity = 1 => Not Transparent - glm::vec3 _albedo{ 0.5f }; - float _roughness{ 0.9f }; + glm::vec3 _albedo{ 0.5f }; // Grey albedo => isAlbedo + float _roughness{ 1.0f }; // Roughness = 1 => Not Glossy - glm::vec3 _fresnel{ 0.03f }; - float _metallic{ 0.0f }; + glm::vec3 _fresnel{ 0.03f }; // Fresnel value for a default non metallic + float _metallic{ 0.0f }; // Not Metallic glm::vec4 _spare0{ 0.0f }; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 0be3ce422d..1126023f41 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -54,25 +54,51 @@ enum Slot { static const std::string DEFAULT_ALBEDO_SHADER { "vec4 getFragmentColor() {" - " return vec4(pow(texture(albedoMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return vec4(pow(frag.diffuse, vec3(1.0 / 2.2)), 1.0);" " }" }; -static const std::string DEFAULT_SPECULAR_SHADER { +static const std::string DEFAULT_FRESNEL_SHADER{ "vec4 getFragmentColor() {" - " return vec4(texture(specularMap, uv).xyz, 1.0);" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return vec4(pow(frag.specular, vec3(1.0 / 2.2)), 1.0);" + " }" +}; + +static const std::string DEFAULT_METALLIC_SHADER { + "vec4 getFragmentColor() {" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return vec4(vec3(frag.metallic), 1.0);" " }" }; static const std::string DEFAULT_ROUGHNESS_SHADER { "vec4 getFragmentColor() {" - " return vec4(vec3(texture(specularMap, uv).a), 1.0);" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return vec4(vec3(frag.roughness), 1.0);" " }" }; static const std::string DEFAULT_NORMAL_SHADER { "vec4 getFragmentColor() {" - " return vec4(normalize(texture(normalMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return vec4(normalize(frag.normal), 1.0);" " }" }; + +static const std::string DEFAULT_EMISSIVE_SHADER{ + "vec4 getFragmentColor() {" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return (frag.mode != LIGHT_MAPPED ? vec4(pow(frag.emissive, vec3(1.0 / 2.2)), 1.0) : vec4(vec3(0.0), 1.0));" + " }" +}; + +static const std::string DEFAULT_LIGHTMAP_SHADER{ + "vec4 getFragmentColor() {" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return (frag.mode == LIGHT_MAPPED ? vec4(frag.emissive, 1.0) : vec4(vec3(0.0), 1.0));" + " }" +}; + static const std::string DEFAULT_DEPTH_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(texture(depthMap, uv).x), 1.0);" @@ -146,14 +172,20 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust switch (mode) { case AlbedoMode: return DEFAULT_ALBEDO_SHADER; - case SpecularMode: - return DEFAULT_SPECULAR_SHADER; + case FresnelMode: + return DEFAULT_FRESNEL_SHADER; + case MetallicMode: + return DEFAULT_METALLIC_SHADER; case RoughnessMode: return DEFAULT_ROUGHNESS_SHADER; case NormalMode: return DEFAULT_NORMAL_SHADER; case DepthMode: return DEFAULT_DEPTH_SHADER; + case EmissiveMode: + return DEFAULT_EMISSIVE_SHADER; + case LightmapMode: + return DEFAULT_LIGHTMAP_SHADER; case LightingMode: return DEFAULT_LIGHTING_SHADER; case ShadowMode: diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 221de9a68e..0d72eeec8a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -47,11 +47,14 @@ protected: enum Mode : uint8_t { // Use Mode suffix to avoid collisions - AlbedoMode = 0, - SpecularMode, - RoughnessMode, + DepthMode = 0, + AlbedoMode, NormalMode, - DepthMode, + RoughnessMode, + MetallicMode, + FresnelMode, + EmissiveMode, + LightmapMode, LightingMode, ShadowMode, PyramidDepthMode, diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 339b85ec1a..49cabee727 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -64,52 +64,73 @@ vec4 evalEyePositionFromZ(DeferredTransform deferredTransform, float depthVal, v } struct DeferredFragment { - float depthVal; vec4 normalVal; vec4 diffuseVal; vec4 specularVal; vec4 position; vec3 normal; + float metallic; vec3 diffuse; float obscurance; vec3 specular; - float gloss; + float roughness; + vec3 emissive; int mode; + float depthVal; }; const int LIGHT_MAPPED = 1; -DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) { - DeferredFragment frag; - frag.depthVal = texture(depthMap, texcoord).r; - frag.normalVal = texture(normalMap, texcoord); - frag.diffuseVal = texture(albedoMap, texcoord); - frag.specularVal = texture(specularMap, texcoord); - frag.obscurance = texture(obscuranceMap, texcoord).x; - +vec4 unpackDeferredPosition(DeferredTransform deferredTransform, float depthValue, vec2 texcoord) { if (getStereoMode(deferredTransform)) { if (texcoord.x > 0.5) { texcoord.x -= 0.5; } texcoord.x *= 2.0; } - frag.position = evalEyePositionFromZ(deferredTransform, frag.depthVal, texcoord); + return evalEyePositionFromZ(deferredTransform, depthValue, texcoord); +} + +DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { + + DeferredFragment frag; + frag.depthVal = -1; + frag.normalVal = texture(normalMap, texcoord); + frag.diffuseVal = texture(albedoMap, texcoord); + frag.specularVal = texture(specularMap, texcoord); + frag.obscurance = texture(obscuranceMap, texcoord).x; // Unpack the normal from the map frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); frag.mode = 0; + frag.emissive = vec3(0.0); if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { frag.mode = LIGHT_MAPPED; + frag.emissive = frag.specularVal.xyz; } frag.diffuse = frag.diffuseVal.xyz; frag.specular = frag.specularVal.xyz; - frag.gloss = (frag.specularVal.w * 125)*(frag.specularVal.w * 125); + frag.metallic = length(frag.specularVal); + frag.roughness = frag.specularVal.w; + return frag; +} + +DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) { + + float depthValue = texture(depthMap, texcoord).r; + + DeferredFragment frag = unpackDeferredFragmentNoPosition(texcoord); + + frag.depthVal = depthValue; + frag.position = unpackDeferredPosition(deferredTransform, frag.depthVal, texcoord); return frag; } + + <@endif@> diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index a54ab4cb3a..d7244cbcad 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -40,37 +40,40 @@ float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { return mix(alpha, 1.0 - alpha, step(mapAlpha, alphaThreshold)); } -const vec3 DEFAULT_SPECULAR = vec3(0.1); +const float DEFAULT_ROUGHNESS = 0.9; const float DEFAULT_SHININESS = 10; +const float DEFAULT_METALLIC = 0; +const vec3 DEFAULT_SPECULAR = vec3(0.1); -void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float shininess) { + +void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 fresnel) { if (alpha != 1.0) { discard; } _fragColor0 = vec4(albedo.rgb, 1.0); // Opaque _fragColor1 = vec4(bestFitNormal(normal), 1.0); - _fragColor2 = vec4(fresnel, shininess); + _fragColor2 = vec4(fresnel, roughness); } -void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float shininess, vec3 emissive) { +void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 fresnel, vec3 emissive) { if (alpha != 1.0) { discard; } _fragColor0 = vec4(albedo.rgb, 0.5); _fragColor1 = vec4(bestFitNormal(normal), 0.5); - _fragColor2 = vec4(emissive, shininess); + _fragColor2 = vec4(emissive, roughness); } -void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float shininess) { +void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float roughness) { if (alpha <= 0.0) { discard; } _fragColor0 = vec4(albedo.rgb, alpha); // _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); - // _fragColor2 = vec4(fresnel, shininess); + // _fragColor2 = vec4(fresnel, roughness); } <@endif@> diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index aad06c9305..de4eb746ef 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -30,7 +30,7 @@ vec4 evalSkyboxLight(vec3 direction, float lod) { <@include model/Light.slh@> <@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float gloss) { +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness) { // Need the light now Light light = getLight(); @@ -41,7 +41,7 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc vec3 color = albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, fresnel, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); @@ -52,7 +52,7 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc <@func declareEvalAmbientSphereGlobalColor()@> -vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float gloss) { +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness) { // Need the light now Light light = getLight(); @@ -64,7 +64,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), ambientNormal).xyz * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, fresnel, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); @@ -76,7 +76,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa <$declareSkyboxMap()$> -vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float gloss) { +vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness) { // Need the light now Light light = getLight(); @@ -87,7 +87,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, fresnel, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index 01403a8180..032a273d6b 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -14,15 +14,17 @@ <@func declareEvalPBRShading()@> // Frag Shading returns the diffuse amount as W and the specular rgb as xyz -vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) { +vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 specular, float roughness) { // Diffuse Lighting float diffuseDot = dot(fragNormal, fragLightDir); float facingLight = step(0.0, diffuseDot); float diffuse = diffuseDot * facingLight; - // Specular Lighting depends on the half vector and the gloss + // Specular Lighting depends on the half vector and the roughness vec3 halfDir = normalize(fragEyeDir + fragLightDir); + float gloss = (1.0 - roughness) * 128.0; + gloss *= gloss; float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss); specularPower *= (gloss * 0.125 + 0.25); @@ -38,15 +40,17 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 sp <@func declareEvalBlinnRShading()@> -vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) { +vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float roughness) { // Diffuse Lighting float diffuseDot = dot(fragNormal, fragLightDir); float facingLight = step(0.0, diffuseDot); float diffuse = diffuseDot * facingLight; - // Specular Lighting depends on the half vector and the gloss + // Specular Lighting depends on the half vector and the roughness vec3 halfDir = normalize(fragEyeDir + fragLightDir); + float gloss = (1.0 - roughness) * 128.0; + glos *= gloss; float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss); vec3 reflect = specularPower * specular * diffuse; @@ -59,8 +63,8 @@ vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 <$declareEvalPBRShading()$> // Return xyz the specular/reflection component and w the diffuse component -vec4 evalFragShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) { - return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss); +vec4 evalFragShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 specular, float roughness) { + return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, metallic, specular, roughness); } <@endif@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 9c6c8522fd..e15603cca5 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -106,7 +106,7 @@ ShapeKey MeshPartPayload::getShapeKey() const { if (drawMaterialKey.isNormalMap()) { builder.withTangents(); } - if (drawMaterialKey.isGlossMap()) { + if (drawMaterialKey.isMetallicMap()) { builder.withSpecular(); } if (drawMaterialKey.isLightmapMap()) { @@ -175,6 +175,20 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr); } + // Roughness map + /* if (materialKey.isRoughnessMap()) { + auto roughnessMap = textureMaps[model::MaterialKey::ROUGHNESS_MAP]; + if (roughnessMap && roughnessMap->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, roughnessMap->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, textureCache->getBlackTexture()); + } + } else { + batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, nullptr); + }*/ + // Metallic map if (materialKey.isMetallicMap()) { auto specularMap = textureMaps[model::MaterialKey::METALLIC_MAP]; diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index 3d1b9db46c..57f9c7e791 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -44,8 +44,9 @@ void main(void) { frag.position.xyz, frag.normal, frag.diffuse, + frag.metallic, frag.specular, - frag.gloss); + frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } } diff --git a/libraries/render-utils/src/directional_ambient_light_shadow.slf b/libraries/render-utils/src/directional_ambient_light_shadow.slf index ffe0e21851..a4d897044b 100644 --- a/libraries/render-utils/src/directional_ambient_light_shadow.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow.slf @@ -46,8 +46,9 @@ void main(void) { frag.position.xyz, frag.normal, frag.diffuse, + frag.metallic, frag.specular, - frag.gloss); + frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } } diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index e07c57a905..eed3b94c91 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -45,8 +45,9 @@ void main(void) { frag.position.xyz, frag.normal, frag.diffuse, + frag.metallic, frag.specular, - frag.gloss); + frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } } diff --git a/libraries/render-utils/src/directional_light_shadow.slf b/libraries/render-utils/src/directional_light_shadow.slf index 4aa041b847..494046bcb3 100644 --- a/libraries/render-utils/src/directional_light_shadow.slf +++ b/libraries/render-utils/src/directional_light_shadow.slf @@ -47,8 +47,9 @@ void main(void) { frag.position.xyz, frag.normal, frag.diffuse, + frag.metallic, frag.specular, - frag.gloss); + frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } } diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index 78fdc4e234..605d1de963 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -45,8 +45,9 @@ void main(void) { frag.position.xyz, frag.normal, frag.diffuse, + frag.metallic, frag.specular, - frag.gloss); + frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index bbce15be68..75a48caacf 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -47,8 +47,9 @@ void main(void) { frag.position.xyz, frag.normal, frag.diffuse, + frag.metallic, frag.specular, - frag.gloss); + frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index 63f82a4f03..d09ae500ec 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -34,6 +34,7 @@ void main(void) { normalize(_normal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialFresnel(mat), - getMaterialShininess(mat)); + getMaterialRoughness(mat), + getMaterialMetallic(mat), + getMaterialFresnel(mat)); } diff --git a/libraries/render-utils/src/model_emissive.slf b/libraries/render-utils/src/model_emissive.slf index b1b968f259..471e613eb4 100644 --- a/libraries/render-utils/src/model_emissive.slf +++ b/libraries/render-utils/src/model_emissive.slf @@ -32,7 +32,8 @@ void main(void) { normalize(_normal), texel.a, vec3(1.0), + getMaterialRoughness(mat), + getMaterialMetallic(mat), getMaterialFresnel(mat), - getMaterialShininess(mat), fragColor); } diff --git a/libraries/render-utils/src/model_lightmap.slf b/libraries/render-utils/src/model_lightmap.slf index 9287bcf821..a896f5b915 100755 --- a/libraries/render-utils/src/model_lightmap.slf +++ b/libraries/render-utils/src/model_lightmap.slf @@ -39,7 +39,8 @@ void main(void) { normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat), + getMaterialMetallic(mat), getMaterialFresnel(mat), - getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); } diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slf b/libraries/render-utils/src/model_lightmap_normal_map.slf index 496f3883ea..6431dfb069 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map.slf @@ -52,7 +52,8 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat), + getMaterialMetallic(mat), getMaterialFresnel(mat), - getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); } diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index bce14fbe94..66aacbb7f6 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -56,7 +56,8 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat), + getMaterialMetallic(mat), specular, // no use of getMaterialFresnel(mat) - getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); } diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index e7ff753d16..84fb47f73f 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -44,7 +44,8 @@ void main(void) { normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, + getMaterialRoughness(mat), + getMaterialMetallic(mat), specular, // no use of getMaterialFresnel(mat) - getMaterialShininess(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); } diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 58b1b7378e..204cfaec3f 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -45,6 +45,7 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialFresnel(mat), - getMaterialShininess(mat)); + getMaterialRoughness(mat), + getMaterialMetallic(mat), + getMaterialFresnel(mat)); } diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index 0926ffa79a..ef39460ddd 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -50,6 +50,8 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - specular, //getMaterialFresnel(mat), - getMaterialShininess(mat)); + getMaterialRoughness(mat), + getMaterialMetallic(mat), + specular //getMaterialFresnel(mat) + ); } diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index 5ad0cada15..54d6a8a33f 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -39,6 +39,8 @@ void main(void) { normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - specular, //getMaterialFresnel(mat), - getMaterialShininess(mat)); + getMaterialRoughness(mat), + getMaterialMetallic(mat), + specular //getMaterialFresnel(mat) + ); } diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 6cd3839191..3efa523434 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -37,8 +37,9 @@ void main(void) { vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); vec3 fragAlbedo = getMaterialAlbedo(mat) * albedo.rgb * _color; + float fragMetallic = getMaterialMetallic(mat); vec3 fragFresnel = getMaterialFresnel(mat); - float fragGloss = getMaterialShininess(mat) / 128; + float fragRoughness = getMaterialRoughness(mat); float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; TransformCamera cam = getTransformCamera(); @@ -50,7 +51,8 @@ void main(void) { fragPosition, fragNormal, fragAlbedo, + fragMetallic, fragFresnel, - fragGloss), + fragRoughness), fragOpacity); } diff --git a/libraries/render-utils/src/overlay3D.slf b/libraries/render-utils/src/overlay3D.slf index 8de7a23898..38199a7a82 100644 --- a/libraries/render-utils/src/overlay3D.slf +++ b/libraries/render-utils/src/overlay3D.slf @@ -17,7 +17,7 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss, float opacity) { +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 specular, float roughness, float opacity) { // Need the light now Light light = getLight(); @@ -30,7 +30,7 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, specular, roughness); color += vec3(albedo * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); @@ -53,8 +53,9 @@ void main(void) { vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); vec3 fragAlbedo = albedo.rgb * _color; + float fragMetallic = 0.0; vec3 fragSpecular = vec3(0.1); - float fragGloss = 10.0 / 128.0; + float fragRoughness = 0.9; float fragOpacity = albedo.a; if (fragOpacity <= 0.1) { @@ -65,8 +66,9 @@ void main(void) { fragPosition, fragNormal, fragAlbedo, + fragMetallic, fragSpecular, - fragGloss, + fragRoughness, fragOpacity); // Apply standard tone mapping diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf index 8e6dbb9eff..f8c18abf20 100644 --- a/libraries/render-utils/src/overlay3D_translucent.slf +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -18,7 +18,7 @@ <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> -vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, vec3 specular, float gloss, float opacity) { +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 specular, float roughness, float opacity) { // Need the light now Light light = getLight(); @@ -31,7 +31,7 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, specular, roughness); color += vec3(albedo * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); @@ -54,16 +54,18 @@ void main(void) { vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); vec3 fragAlbedo = albedo.rgb * _color; + float fragMetallic = 0.0; vec3 fragSpecular = vec3(0.1); - float fragGloss = 10.0 / 128.0; + float fragRoughness = 0.9; float fragOpacity = albedo.a * _alpha; vec4 color = evalGlobalColor(1.0, fragPosition, fragNormal, fragAlbedo, + fragMetallic, fragSpecular, - fragGloss, + fragRoughness, fragOpacity); // Apply standard tone mapping diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index fcfb0b336e..298b3751b7 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -60,7 +60,7 @@ void main(void) { vec3 fragNormal = vec3(invViewMat * vec4(frag.normal, 0.0)); vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.specular, frag.gloss); + vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); // Eval attenuation float radialAttenuation = evalLightAttenuation(light, fragLightDistance); diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 69fec0042b..faa4d02bfa 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -10,6 +10,8 @@ // 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@> + uniform sampler2D Font; uniform bool Outline; uniform vec4 Color; @@ -17,12 +19,11 @@ uniform vec4 Color; // the interpolated normal in vec3 _normal; in vec2 _texCoord0; - +/* layout(location = 0) out vec4 _fragColor0; layout(location = 1) out vec4 _fragColor1; layout(location = 2) out vec4 _fragColor2; - -const float DEFAULT_SHININESS = 10; +*/ const float gamma = 2.2; const float smoothing = 256.0; @@ -53,7 +54,16 @@ void main() { } // final color - _fragColor0 = vec4(Color.rgb, Color.a * a); + /* _fragColor0 = vec4(Color.rgb, Color.a * a); _fragColor1 = vec4(normalize(_normal.xyz), 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5); - _fragColor2 = vec4(Color.rgb, DEFAULT_SHININESS / 128.0); + _fragColor2 = vec4(Color.rgb, 10 / 128.0); + */ + packDeferredFragmentLightmap( + normalize(_normal), + Color.a * a, + Color.rgb, + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_SPECULAR, + Color.rgb); } \ No newline at end of file diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index b24e4f92ff..4b5cdfb5ce 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -51,9 +51,9 @@ void main(void) { if (emissiveAmount > 0.0) { packDeferredFragmentLightmap( - normal, 1.0, diffuse, specular, shininess, specular); + normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, specular); } else { packDeferredFragment( - normal, 1.0, diffuse, specular, shininess); + normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular); } } diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index 6c99343a28..b2bc15dbad 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -31,5 +31,7 @@ void main(void) { normalize(_normal.xyz), texel.a, _color.rgb * texel.rgb, - DEFAULT_SPECULAR, DEFAULT_SHININESS); + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_SPECULAR); } \ No newline at end of file diff --git a/libraries/render-utils/src/simple_textured_emisive.slf b/libraries/render-utils/src/simple_textured_emisive.slf index 2119af17fb..92bdee8d02 100644 --- a/libraries/render-utils/src/simple_textured_emisive.slf +++ b/libraries/render-utils/src/simple_textured_emisive.slf @@ -29,6 +29,8 @@ void main(void) { normalize(_normal), texel.a, _color.rgb, - DEFAULT_SPECULAR, DEFAULT_SHININESS, + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_SPECULAR, texel.rgb); } \ No newline at end of file diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 8170929636..a4077c0edb 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -66,7 +66,7 @@ void main(void) { vec3 fragNormal = vec3(invViewMat * vec4(frag.normal, 0.0)); vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); vec3 fragEyeDir = normalize(fragEyeVector.xyz); - vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.specular, frag.gloss); + vec4 shading = evalFragShading(fragNormal, fragLightDir, fragEyeDir, frag.metallic, frag.specular, frag.roughness); // Eval attenuation float radialAttenuation = evalLightAttenuation(light, fragLightDistance); diff --git a/tests/gpu-test/src/unlit.slf b/tests/gpu-test/src/unlit.slf index 77d28aa7e9..d070662495 100644 --- a/tests/gpu-test/src/unlit.slf +++ b/tests/gpu-test/src/unlit.slf @@ -24,5 +24,5 @@ void main(void) { normalize(_normal.xyz), 1.0, _color.rgb, - DEFAULT_SPECULAR, DEFAULT_SHININESS); + DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR); } From c7f43386e56f7b8bc9af87622dc9df2cf2b89267 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 22 Feb 2016 09:23:16 -0800 Subject: [PATCH 035/292] Compressing the g-buffer better --- libraries/render-utils/src/DeferredBuffer.slh | 33 +++++++++++++--- .../render-utils/src/DeferredBufferWrite.slh | 11 +++--- .../render-utils/src/DeferredLighting.slh | 39 +++++++++++-------- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 49cabee727..fe9b1a2a47 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -105,16 +105,39 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { frag.mode = 0; frag.emissive = vec3(0.0); - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + if (frag.normalVal.a < 0.5) { + frag.mode = 0; + frag.roughness = 2.0 * frag.normalVal.a; + } else { frag.mode = LIGHT_MAPPED; + frag.roughness = 2.0 * frag.normalVal.a - 1.0; frag.emissive = frag.specularVal.xyz; } + + // if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { + // frag.mode = LIGHT_MAPPED; + // frag.emissive = frag.specularVal.xyz; + // } - frag.diffuse = frag.diffuseVal.xyz; - frag.specular = frag.specularVal.xyz; - frag.metallic = length(frag.specularVal); - frag.roughness = frag.specularVal.w; + frag.metallic = frag.diffuseVal.a; + if (frag.metallic > 0.5) { + frag.diffuse = vec3(0); + //frag.metallic = length(frag.specularVal); + frag.specular = frag.diffuseVal.xyz; + + } else { + frag.diffuse = frag.diffuseVal.xyz; + //frag.metallic = length(frag.specularVal); + frag.specular = vec3(0.03); + } + // frag.diffuse = frag.diffuseVal.xyz; + //frag.metallic = length(frag.specularVal); + //frag.specular = frag.specularVal.xyz; + + + //frag.roughness = frag.specularVal.w; + return frag; } diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index d7244cbcad..21d579cb3a 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -50,9 +50,9 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness if (alpha != 1.0) { discard; } - - _fragColor0 = vec4(albedo.rgb, 1.0); // Opaque - _fragColor1 = vec4(bestFitNormal(normal), 1.0); + vec3 baseColor = ((metallic < 0.5) ? albedo : fresnel); + _fragColor0 = vec4(baseColor, metallic); + _fragColor1 = vec4(bestFitNormal(normal), 0.5 * clamp(roughness, 0.0, 1.0)); _fragColor2 = vec4(fresnel, roughness); } @@ -61,8 +61,9 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float r discard; } - _fragColor0 = vec4(albedo.rgb, 0.5); - _fragColor1 = vec4(bestFitNormal(normal), 0.5); + vec3 baseColor = ((metallic < 0.5) ? albedo : fresnel); + _fragColor0 = vec4(baseColor, metallic); + _fragColor1 = vec4(bestFitNormal(normal), 0.5 + 0.5 * clamp(roughness, 0.0, 1.0)); _fragColor2 = vec4(emissive, roughness); } diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index 032a273d6b..eb821cccac 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -13,28 +13,33 @@ <@func declareEvalPBRShading()@> -// Frag Shading returns the diffuse amount as W and the specular rgb as xyz -vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 specular, float roughness) { - // Diffuse Lighting - float diffuseDot = dot(fragNormal, fragLightDir); - float facingLight = step(0.0, diffuseDot); - float diffuse = diffuseDot * facingLight; - - // Specular Lighting depends on the half vector and the roughness - vec3 halfDir = normalize(fragEyeDir + fragLightDir); +vec3 fresnelSchlick(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) { + return fresnelColor + (1.0f - fresnelColor) * pow(1.0f - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); +} + +float specularDistribution(float roughness, vec3 normal, vec3 halfDir) { float gloss = (1.0 - roughness) * 128.0; gloss *= gloss; - float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss); - specularPower *= (gloss * 0.125 + 0.25); + float power = pow(clamp(dot(halfDir, normal), 0.0, 1.0), gloss); + power *= (gloss * 0.125 + 0.25); + return power; +} - float shlickPower = (1.0 - dot(fragLightDir,halfDir)); - float shlickPower2 = shlickPower * shlickPower; - float shlickPower5 = shlickPower2 * shlickPower2 * shlickPower; - vec3 fresnel = specular * (1.0 - shlickPower5) + vec3(shlickPower5); - vec3 reflect = specularPower * fresnel * diffuse; +// Frag Shading returns the diffuse amount as W and the specular rgb as xyz +vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) { + // Diffuse Lighting + //float diffuseDot = dot(fragNormal, fragLightDir); + //float facingLight = step(0.0, diffuseDot); + float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); + + // Specular Lighting + vec3 halfDir = normalize(fragEyeDir + fragLightDir); + vec3 fresnelColor = fresnelSchlick(fresnel, fragLightDir,halfDir); + float power = specularDistribution(roughness, fragNormal, halfDir); + vec3 specular = power * fresnelColor * diffuse; - return vec4(reflect, diffuse * (1 - fresnel.x)); + return vec4(specular, diffuse * (1 - fresnelColor.x)); } <@endfunc@> From f0d8ffce6582fc63e6adf9486a10c1d511f94250 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 10:25:56 -0800 Subject: [PATCH 036/292] cleanup errors --- .../DomainContent/CellScience/Scripts/moveRandomly2.js | 10 +++------- .../CellScience/Scripts/zoomAndMoveRandomly.js | 7 +++++-- .../DomainContent/CellScience/importCellScience.js | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js index f720ca91cc..ec7b249db0 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js @@ -44,12 +44,6 @@ this.getTotalWait = function() { return (Math.random() * 5000) * 2; - // var avatars = AvatarList.getAvatarIdentifiers(); - // var avatarCount = avatars.length; - // var random = Math.random() * 5000; - // var totalWait = random * (avatarCount * 2); - // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) - // return totalWait } @@ -86,7 +80,9 @@ this.unload = function() { - baton.release(function() {}); + if (baton) { + baton.release(function() {}); + } Script.clearInterval(currentInterval); } diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index 16c83b29dd..21e585cd91 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -40,7 +40,7 @@ this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity + batonName: 'io.highfidelity.vesicles:' + entityID, // One winner for each entity }); stopUpdateAndReclaim(); currentInterval = Script.setInterval(self.move, self.getTotalWait()) @@ -127,7 +127,10 @@ if (this.initTimeout !== null) { Script.clearTimeout(this.initTimeout); } - baton.release(function() {}); + if (baton) { + baton.release(function() {}); + } + Script.clearInterval(currentInterval); } diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 63f99c53a3..900a54d9e3 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1049; +var version = 1051; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From f7b3da078b2ec28209118bbd60ccd5ba2e41cb4a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 11:36:53 -0800 Subject: [PATCH 037/292] dont move cells in space, just angular velocity --- .../CellScience/Scripts/zoomAndMoveRandomly.js | 14 +++++++------- .../DomainContent/CellScience/importCellScience.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index 21e585cd91..bf249a4644 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -150,12 +150,12 @@ return; } - var magnitudeV = self.maxVelocity; - var directionV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; + // var magnitudeV = self.maxVelocity; + // var directionV = { + // x: Math.random() - 0.5, + // y: Math.random() - 0.5, + // z: Math.random() - 0.5 + // }; //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); @@ -168,7 +168,7 @@ }; //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), + // velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 900a54d9e3..b061dc6931 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1051; +var version = 1052; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From e4bc0ce69103ccdd950793255384f9a6b3719a66 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 13:08:58 -0800 Subject: [PATCH 038/292] tests --- .../DomainContent/CellScience/Scripts/zoom.js | 12 ---------- .../Scripts/zoomAndMoveRandomly.js | 23 +++++++------------ .../CellScience/importCellScience.js | 2 +- 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js index da41ec64ba..3fc5acae2a 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoom.js @@ -52,13 +52,7 @@ print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); MyAvatar.position = data.location; - - // if (data.hasOwnProperty('entryPoint') && data.hasOwnProperty('target')) { - // this.lookAtTarget(data.entryPoint, data.target); - // } - // else{ - // } } } @@ -103,10 +97,4 @@ } } - this.hoverEnterEntity = function(entityID) { - Entities.editEntity(entityID, { - animationURL: animationURL, - animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }' - }); - } }) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index bf249a4644..703c4ead33 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -15,18 +15,19 @@ var self = this; var baton; - var iOwn = false; + + this.iOwn = false; var currentInterval; var _entityId; function startUpdate() { - iOwn = true; + self.iOwn = true; print('i am the owner ' + _entityId) } function stopUpdateAndReclaim() { print('i released the object ' + _entityId) - iOwn = false; + self.iOwn = false; baton.claim(startUpdate, stopUpdateAndReclaim); } @@ -40,7 +41,7 @@ this.minAngularVelocity = 0.01; this.maxAngularVelocity = 0.03; baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityID, // One winner for each entity + batonName: 'io.highfidelity.cells:' + entityID, // One winner for each entity }); stopUpdateAndReclaim(); currentInterval = Script.setInterval(self.move, self.getTotalWait()) @@ -146,19 +147,11 @@ } this.move = function() { - if (!iOwn) { + if (self.iOwn===false) { + print('cell is not owned by me...') return; } - // var magnitudeV = self.maxVelocity; - // var directionV = { - // x: Math.random() - 0.5, - // y: Math.random() - 0.5, - // z: Math.random() - 0.5 - // }; - - //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); - var magnitudeAV = self.maxAngularVelocity; var directionAV = { @@ -166,7 +159,7 @@ y: Math.random() - 0.5, z: Math.random() - 0.5 }; - //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { // velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index b061dc6931..4ae5e5de36 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1052; +var version = 1055; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; From 46aebabd9b2330567dc89feca3f57a1ed42a0e66 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 22 Feb 2016 17:54:45 -0800 Subject: [PATCH 039/292] switch branches --- .../Scripts/zoomAndMoveRandomly.js | 20 ++++++------------- .../CellScience/importCellScience.js | 10 +++++----- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js index 703c4ead33..dd6a48c617 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js @@ -38,8 +38,8 @@ this.initTimeout = null; this.minVelocity = 1; this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; + this.minAngularVelocity = 0.03; + this.maxAngularVelocity = 0.10; baton = virtualBaton({ batonName: 'io.highfidelity.cells:' + entityID, // One winner for each entity }); @@ -69,7 +69,7 @@ }; self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); - // print(" portal destination is " + self.portalDestination); + } } @@ -81,13 +81,6 @@ print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); MyAvatar.position = data.location; - - // if (data.hasOwnProperty('entryPoint') && data.hasOwnProperty('target')) { - // this.lookAtTarget(data.entryPoint, data.target); - // } - // else{ - - // } } } @@ -143,11 +136,11 @@ } this.getTotalWait = function() { - return (Math.random() * 5000) * 2; + return (Math.random() * 5000) * 3; } this.move = function() { - if (self.iOwn===false) { + if (self.iOwn === false) { print('cell is not owned by me...') return; } @@ -159,9 +152,8 @@ y: Math.random() - 0.5, z: Math.random() - 0.5 }; - print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(self.entityId, { - // velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 4ae5e5de36..25323495d1 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1055; +var version = 1057; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -103,16 +103,16 @@ var scenes = [{ instances: [{ model: "Cell", dimensions: { - x: 550, - y: 620, - z: 550 + x: 500, + y: 570, + z: 500 }, offset: { x: 0, y: 0, z: 0 }, - radius: 500, + radius: 450, number: 10, userData: JSON.stringify({ entryPoint: locations.cellLayout[1], From 00782b0e76a598f338447011fc1e8feadcf9d057 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 22 Feb 2016 18:19:36 -0800 Subject: [PATCH 040/292] GOing home, this is in the middle of adding the Roughness texture and potentially cleaning up the different compinations of shaders regarding the material textures --- libraries/gpu/src/gpu/Format.cpp | 2 +- libraries/gpu/src/gpu/Format.h | 2 +- libraries/gpu/src/gpu/Texture.h | 54 +++++++++++++++++++ .../src/model-networking/ModelCache.cpp | 10 +++- .../src/model-networking/ModelCache.h | 7 +++ .../src/model-networking/TextureCache.cpp | 6 +-- .../src/model-networking/TextureCache.h | 10 ++-- libraries/model/src/model/Material.cpp | 6 +++ libraries/model/src/model/Material.h | 4 +- libraries/model/src/model/Material.slh | 1 + libraries/model/src/model/TextureMap.cpp | 31 ++++++++++- libraries/render-utils/src/model.slf | 7 +-- libraries/render-utils/src/model_lightmap.slf | 5 +- .../src/model_lightmap_normal_map.slf | 13 +++-- .../model_lightmap_normal_specular_map.slf | 16 +++--- .../src/model_lightmap_specular_map.slf | 6 ++- .../render-utils/src/model_normal_map.slf | 5 +- .../src/model_normal_specular_map.slf | 4 +- .../render-utils/src/model_specular_map.slf | 4 +- 19 files changed, 155 insertions(+), 38 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.cpp b/libraries/gpu/src/gpu/Format.cpp index a66fc19458..7c603919fd 100644 --- a/libraries/gpu/src/gpu/Format.cpp +++ b/libraries/gpu/src/gpu/Format.cpp @@ -11,7 +11,7 @@ using namespace gpu; const Element Element::COLOR_RGBA_32{ VEC4, NUINT8, RGBA }; -const Element Element::COLOR_RGBA{ VEC4, FLOAT, RGBA }; +const Element Element::VEC4F_COLOR_RGBA{ VEC4, FLOAT, RGBA }; const Element Element::VEC2F_UV{ VEC2, FLOAT, UV }; const Element Element::VEC2F_XY{ VEC2, FLOAT, XY }; const Element Element::VEC3F_XYZ{ VEC3, FLOAT, XYZ }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 54d40c3e12..625ca6cec3 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -247,7 +247,7 @@ public: } static const Element COLOR_RGBA_32; - static const Element COLOR_RGBA; + static const Element VEC4F_COLOR_RGBA; static const Element VEC2F_UV; static const Element VEC2F_XY; static const Element VEC3F_XYZ; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 378f49c2f4..e05dc84c25 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -14,6 +14,7 @@ #include "Resource.h" #include //min max and more +#include #include @@ -139,6 +140,53 @@ protected: class Texture : public Resource { public: + class Usage { + public: + enum FlagBit { + COLOR = 0, // Texture is a color map + NORMAL, // Texture is a normal map + ALPHA, // Texture has an alpha channel + ALPHA_MASK, // Texture alpha channel is a Mask 0/1 + + NUM_FLAGS, + }; + typedef std::bitset Flags; + + // The key is the Flags + Flags _flags; + + Usage() : _flags(0) {} + Usage(const Flags& flags) : _flags(flags) {} + + bool operator== (const Usage& rhs) const { return _flags == rhs._flags; } + bool operator!= (const Usage& rhs) const { return _flags != rhs._flags; } + + class Builder { + friend class Usage; + Flags _flags{ 0 }; + public: + Builder() {} + + Usage build() const { return Usage(_flags); } + + Builder& withColor() { _flags.set(COLOR); return (*this); } + Builder& withNormal() { _flags.set(NORMAL); return (*this); } + Builder& withAlpha() { _flags.set(ALPHA); return (*this); } + Builder& withAlphaMask() { _flags.set(ALPHA_MASK); return (*this); } + }; + Usage(const Builder& builder) : Usage(builder._flags) {} + + bool isColor() const { return _flags[COLOR]; } + bool isNormal() const { return _flags[NORMAL]; } + + bool isAlpha() const { return _flags[ALPHA]; } + bool isAlphaMask() const { return _flags[ALPHA_MASK]; } + + + bool operator==(const Usage& usage) { return (_flags == usage._flags); } + bool operator!=(const Usage& usage) { return (_flags != usage._flags); } + }; + class Pixels { public: Pixels() {} @@ -343,6 +391,10 @@ public: bool isDefined() const { return _defined; } + // Usage is a a set of flags providing Semantic about the usage of the Texture. + void setUsage(const Usage& usage) { _usage = usage; } + Usage getUsage() const { return _usage; } + // For Cube Texture, it's possible to generate the irradiance spherical harmonics and make them availalbe with the texture bool generateIrradiance(); const SHPointer& getIrradiance(uint16 slice = 0) const { return _irradiance; } @@ -380,6 +432,8 @@ protected: Type _type = TEX_1D; + Usage _usage; + SHPointer _irradiance; bool _autoGenerateMips = false; bool _isIrradianceValid = false; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 63cc113f5a..2bb71ba855 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -316,7 +316,7 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas return networkMesh; } -static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) { +static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FBXMaterial& material, const QUrl& textureBaseUrl) { auto textureCache = DependencyManager::get(); NetworkMaterial* networkMaterial = new NetworkMaterial(); @@ -324,6 +324,9 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const if (!material.albedoTexture.filename.isEmpty()) { networkMaterial->albedoTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.albedoTexture.filename)), DEFAULT_TEXTURE, material.albedoTexture.content); + QObject::connect(networkMaterial->albedoTexture.data(), &NetworkTexture::networkTextureCreated, + geometry, &NetworkGeometry::textureLoaded); + networkMaterial->albedoTextureName = material.albedoTexture.name; auto albedoMap = model::TextureMapPointer(new model::TextureMap()); @@ -407,7 +410,7 @@ void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) { QHash fbxMatIDToMatID; foreach(const FBXMaterial& material, _geometry->materials) { fbxMatIDToMatID[material.materialID] = _materials.size(); - _materials.emplace_back(buildNetworkMaterial(material, _textureBaseUrl)); + _materials.emplace_back(buildNetworkMaterial(this, material, _textureBaseUrl)); } @@ -453,3 +456,6 @@ const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) { } } +void NetworkGeometry::textureLoaded(const QWeakPointer& networkTexture) { + numTextureLoaded++; +} diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 1d43424813..c43a1e6d79 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -105,6 +105,9 @@ signals: // Fired when something went wrong. void onFailure(NetworkGeometry& networkGeometry, Error error); +public slots: + void textureLoaded(const QWeakPointer& networkTexture); + protected slots: void mappingRequestDone(const QByteArray& data); void mappingRequestError(QNetworkReply::NetworkError error); @@ -115,6 +118,7 @@ protected slots: void modelParseSuccess(FBXGeometry* geometry); void modelParseError(int error, QString str); + protected: void attemptRequestInternal(); void requestMapping(const QUrl& url); @@ -133,6 +137,7 @@ protected: QUrl _modelUrl; QVariantHash _mapping; QUrl _textureBaseUrl; + int numTextureLoaded = 0; Resource* _resource = nullptr; std::unique_ptr _geometry; // This should go away evenutally once we can put everything we need in the model::AssetPointer @@ -173,6 +178,7 @@ public: class NetworkMaterial { public: + model::MaterialPointer _material; QString albedoTextureName; QSharedPointer albedoTexture; @@ -186,6 +192,7 @@ public: QSharedPointer emissiveTexture; QString lightmapTextureName; QSharedPointer lightmapTexture; + }; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 2ec9ab4027..c10b82d235 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -339,10 +339,6 @@ void NetworkTexture::setImage(const QImage& image, void* voidTexture, int origin finishedLoading(true); - imageLoaded(image); -} - -void NetworkTexture::imageLoaded(const QImage& image) { - // nothing by default + emit networkTextureCreated(qWeakPointerCast (_self)); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 1a0d22a8d3..2cfd225889 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -83,8 +83,6 @@ private: gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; gpu::TexturePointer _normalFittingTexture; - - QHash > _dilatableNetworkTextures; }; /// A simple object wrapper for an OpenGL texture. @@ -114,7 +112,11 @@ public: int getHeight() const { return _height; } TextureLoaderFunc getTextureLoader() const; - + +signals: + void networkTextureCreated(const QWeakPointer& self); + + protected: virtual void downloadFinished(const QByteArray& data) override; @@ -123,8 +125,6 @@ protected: // FIXME: This void* should be a gpu::Texture* but i cannot get it to work for now, moving on... Q_INVOKABLE void setImage(const QImage& image, void* texture, int originalWidth, int originalHeight); - virtual void imageLoaded(const QImage& image); - private: TextureType _type; diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 770b110ad9..522debad59 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -46,11 +46,13 @@ Material::~Material() { void Material::setEmissive(const Color& emissive, bool isSRGB) { _key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f)))); + _schemaBuffer.edit()._key = (uint32) _key._flags.to_ulong(); _schemaBuffer.edit()._emissive = (isSRGB ? ColorUtils::toLinearVec3(emissive) : emissive); } void Material::setOpacity(float opacity) { _key.setTransparent((opacity < 1.0f)); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit()._opacity = opacity; } @@ -62,6 +64,7 @@ void Material::setAlbedo(const Color& albedo, bool isSRGB) { void Material::setRoughness(float roughness) { roughness = std::min(1.0f, std::max(roughness, 0.0f)); _key.setGlossy((roughness < 1.0f)); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit()._roughness = roughness; } @@ -72,6 +75,7 @@ void Material::setFresnel(const Color& fresnel, bool isSRGB) { void Material::setMetallic(float metallic) { _key.setMetallic(metallic > 0.0f); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit()._metallic = metallic; } @@ -79,9 +83,11 @@ void Material::setMetallic(float metallic) { void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { _key.setMapChannel(channel, (true)); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _textureMaps[channel] = textureMap; } else { _key.setMapChannel(channel, (false)); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _textureMaps.erase(channel); } } diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index df58f60eb1..a6b1cd3706 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -252,7 +252,9 @@ public: float _metallic{ 0.0f }; // Not Metallic - glm::vec4 _spare0{ 0.0f }; + glm::vec3 _spare0{ 0.0f }; + + uint32_t _key{ 0 }; // a copy of the materialKey // for alignment beauty, Material size == Mat4x4 diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index 90a7784042..02bd9568dc 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -37,4 +37,5 @@ float getMaterialMetallic(Material m) { return m._fresnelMetallic.a; } float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } + <@endif@> diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 17d610e87f..b75f2d6acc 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -54,22 +54,38 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) { gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { QImage image = srcImage; bool validAlpha = false; + bool alphaAsMask = true; + const uint8 OPAQUE_ALPHA = 255; + const uint8 TRANSLUCENT_ALPHA = 0; if (image.hasAlphaChannel()) { + std::map alphaHistogram; + if (image.format() != QImage::Format_ARGB32) { image = image.convertToFormat(QImage::Format_ARGB32); } - // Actual alpha channel? + // Actual alpha channel? create the histogram for (int y = 0; y < image.height(); ++y) { const QRgb* data = reinterpret_cast(image.constScanLine(y)); for (int x = 0; x < image.width(); ++x) { auto alpha = qAlpha(data[x]); - if (alpha != 255) { + alphaHistogram[alpha] ++; + if (alpha != OPAQUE_ALPHA) { validAlpha = true; break; } } } + + // If alpha was meaningfull refine + if (validAlpha && (alphaHistogram.size() > 1)) { + auto totalNumPixels = image.height() * image.width(); + auto numOpaques = alphaHistogram[OPAQUE_ALPHA]; + auto numTranslucents = alphaHistogram[TRANSLUCENT_ALPHA]; + auto numTransparents = totalNumPixels - numOpaques - numTranslucents; + + alphaAsMask = ((numTransparents / (double)totalNumPixels) < 0.05); + } } if (!validAlpha && image.format() != QImage::Format_RGB888) { @@ -89,10 +105,21 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con } theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + + auto usage = gpu::Texture::Usage::Builder().withColor(); + if (validAlpha) { + usage.withAlpha(); + if (alphaAsMask) { + usage.withAlphaMask(); + } + } + theTexture->setUsage(usage.build()); + theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); theTexture->autoGenerateMips(-1); // FIXME queue for transfer to GPU and block on completion + } return theTexture; diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index d09ae500ec..a1a75161b9 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -15,8 +15,8 @@ <@include model/Material.slh@> -// the diffuse texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; in vec4 _position; in vec3 _normal; @@ -25,8 +25,9 @@ in vec2 _texCoord0; void main(void) { - // Fetch albedo map + // Fetch maps vec4 albedo = texture(albedoMap, _texCoord0); + float roughness = texture(roughnessMap, _texCoord0); Material mat = getMaterial(); @@ -34,7 +35,7 @@ void main(void) { normalize(_normal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), getMaterialFresnel(mat)); } diff --git a/libraries/render-utils/src/model_lightmap.slf b/libraries/render-utils/src/model_lightmap.slf index a896f5b915..a3505ba779 100755 --- a/libraries/render-utils/src/model_lightmap.slf +++ b/libraries/render-utils/src/model_lightmap.slf @@ -18,6 +18,7 @@ // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the emissive map texture and parameters uniform sampler2D emissiveMap; @@ -30,7 +31,9 @@ in vec3 _normal; in vec3 _color; void main(void) { + // Fetch maps vec4 albedo = texture(albedoMap, _texCoord0); + float roughness = texture(roughnessMap, _texCoord0); vec4 emissive = texture(emissiveMap, _texCoord1); Material mat = getMaterial(); @@ -39,7 +42,7 @@ void main(void) { normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), getMaterialFresnel(mat), (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slf b/libraries/render-utils/src/model_lightmap_normal_map.slf index 6431dfb069..223cec71fb 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map.slf @@ -18,6 +18,7 @@ // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the normal map texture uniform sampler2D normalMap; @@ -34,17 +35,19 @@ in vec3 _tangent; in vec3 _color; void main(void) { + // Fetch maps + vec4 albedo = texture(albedoMap, _texCoord0); + float roughness = texture(roughness, _texCoord0); + vec4 emissive = texture(emissiveMap, _texCoord1); + vec3 localNormal = vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5); + // compute the view normal from the various bits vec3 normalizedNormal = normalize(_normal); vec3 normalizedTangent = normalize(_tangent); vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec3 localNormal = vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5); vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - - // set the diffuse, normal, specular data - vec4 albedo = texture(albedoMap, _texCoord0); - vec4 emissive = texture(emissiveMap, _texCoord1); + Material mat = getMaterial(); diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index 66aacbb7f6..99799a4b25 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -18,6 +18,7 @@ // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the emissive map texture and parameters uniform sampler2D emissiveMap; @@ -37,18 +38,19 @@ in vec3 _tangent; in vec3 _color; void main(void) { + // Fetch maps + vec4 albedo = texture(albedoMap, _texCoord0); + float roughness = texture(roughnessMap, _texCoord0); + vec3 specular = texture(specularMap, _texCoord0).rgb; + vec4 emissive = texture(emissiveMap, _texCoord1); + vec3 localNormal = vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5); + // compute the view normal from the various bits vec3 normalizedNormal = normalize(_normal); vec3 normalizedTangent = normalize(_tangent); vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec3 localNormal = vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5); vec4 viewNormal = vec4(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - - // set the albedo, normal, specular data - vec4 albedo = texture(albedoMap, _texCoord0); - vec3 specular = texture(specularMap, _texCoord0).rgb; - vec4 emissive = texture(emissiveMap, _texCoord1); Material mat = getMaterial(); @@ -56,7 +58,7 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), specular, // no use of getMaterialFresnel(mat) (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index 84fb47f73f..590dfe5727 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -18,6 +18,7 @@ // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the emissive map texture and parameters uniform sampler2D emissiveMap; @@ -33,8 +34,9 @@ in vec3 _normal; in vec3 _color; void main(void) { - // set the albedo, normal, specular data + // Fetch maps vec4 albedo = texture(albedoMap, _texCoord0); + float roughness = texture(roughnessMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; vec4 emissive = texture(emissiveMap, _texCoord1); @@ -44,7 +46,7 @@ void main(void) { normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), specular, // no use of getMaterialFresnel(mat) (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 204cfaec3f..8adde1d850 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -15,9 +15,11 @@ <@include DeferredBufferWrite.slh@> <@include model/Material.slh@> +<@include model/MaterialTextures.slh@> // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the normal map texture uniform sampler2D normalMap; @@ -38,6 +40,7 @@ void main(void) { normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); vec4 albedo = texture(albedoMap, _texCoord0.st); + float roughness = texture(roughnessMap, _texCoord0); Material mat = getMaterial(); @@ -45,7 +48,7 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), getMaterialFresnel(mat)); } diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index ef39460ddd..95a13198c0 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -18,6 +18,7 @@ // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the normal map texture uniform sampler2D normalMap; @@ -42,6 +43,7 @@ void main(void) { // set the albedo, normal, specular data vec4 albedo = texture(albedoMap, _texCoord0); + vec4 roughness = texture(roughnessMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; Material mat = getMaterial(); @@ -50,7 +52,7 @@ void main(void) { normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), specular //getMaterialFresnel(mat) ); diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index 54d6a8a33f..5821ab8154 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -18,6 +18,7 @@ // the albedo texture uniform sampler2D albedoMap; +uniform sampler2D roughnessMap; // the specular texture uniform sampler2D specularMap; @@ -31,6 +32,7 @@ in vec3 _color; void main(void) { // set the albedo, normal, specular data vec4 albedo = texture(albedoMap, _texCoord0); + float roughness = texture(roughnessMap, _texCoord0); vec3 specular = texture(specularMap, _texCoord0).rgb; Material mat = getMaterial(); @@ -39,7 +41,7 @@ void main(void) { normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat), + getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), specular //getMaterialFresnel(mat) ); From 9cb8bd0808bc0223302eea1347380e687e391ece Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 23 Feb 2016 02:41:26 -0800 Subject: [PATCH 041/292] Adding one more feature for NULL_VAR in scribe function parameters and unifying the MAterialTexture shader code --- .../render-utils/src/MaterialTextures.slh | 88 +++++++++++++++++++ libraries/render-utils/src/model.slf | 10 +-- libraries/render-utils/src/model_lightmap.slf | 17 ++-- .../src/model_lightmap_normal_map.slf | 32 ++----- .../model_lightmap_normal_specular_map.slf | 38 +++----- .../src/model_lightmap_specular_map.slf | 24 ++--- .../render-utils/src/model_normal_map.slf | 27 ++---- .../src/model_normal_specular_map.slf | 30 ++----- .../render-utils/src/model_specular_map.slf | 18 ++-- tools/scribe/src/TextTemplate.cpp | 12 ++- tools/scribe/src/TextTemplate.h | 2 + 11 files changed, 158 insertions(+), 140 deletions(-) create mode 100644 libraries/render-utils/src/MaterialTextures.slh diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh new file mode 100644 index 0000000000..47eed14a82 --- /dev/null +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -0,0 +1,88 @@ + +<@if not MODEL_MATERIAL_TEXTURES_SLH@> +<@def MODEL_MATERIAL_TEXTURES_SLH@> + +<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic)@> + +<@if withAlbedo@> +uniform sampler2D albedoMap; +vec4 fetchAlbedoMap(vec2 uv) { + return texture(albedoMap, uv); +} +<@endif@> + + +uniform sampler2D roughnessMap; +float fetchRoughnessMap(vec2 uv) { + return texture(roughnessMap, uv).r; +} +<@endif@> +!> + +<@if withNormal@> +uniform sampler2D normalMap; +vec3 fetchNormalMap(vec2 uv) { + return texture(normalMap, uv).xyz; +} +<@endif@> + +<@if withMetallic@> +uniform sampler2D specularMap; +vec3 fetchMetallicMap(vec2 uv) { + return texture(specularMap, uv).rgb; +} +<@endif@> + +<@endfunc@> + + +<@func fetchMaterialTextures(texcoord0, albedo, roughness, normal, metallic)@> +<@if albedo@> + vec4 <$albedo$> = fetchAlbedoMap(<$texcoord0$>); +<@endif@> +<@if roughness@> +float <$roughness$> = 1.0; //fetchRoughnessMap(<$texcoord0$>); +<@endif@> +<@if normal@> + vec3 <$normal$> = fetchNormalMap(<$texcoord0$>); +<@endif@> +<@if metallic@> + vec3 <$metallic$> = fetchMetallicMap(<$texcoord0$>); +<@endif@> +<@endfunc@> + + +<@func declareMaterialLightmap()@> +uniform sampler2D emissiveMap; +uniform vec2 emissiveParams; +vec3 fetchLightmapMap(vec2 uv) { + return (vec3(emissiveParams.x) + emissiveParams.y * texture(emissiveMap, uv).rgb); +} +<@endfunc@> + +<@func fetchMaterialLightmap(texcoord1, lightmapVal)@> + vec3 <$lightmapVal$> = fetchLightmapMap(<$texcoord1$>); +<@endfunc@> + + +<@func tangentToViewSpace(fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@> +{ + vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz); + vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = normalize(<$fetchedNormal$> - vec3(0.5, 0.5, 0.5)); + <$normal$> = vec3(normalizedTangent * localNormal.x + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z); +} +<@endfunc@> + +<@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index a1a75161b9..b43694bbb7 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -15,8 +15,8 @@ <@include model/Material.slh@> -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS)$> in vec4 _position; in vec3 _normal; @@ -25,10 +25,8 @@ in vec2 _texCoord0; void main(void) { - // Fetch maps - vec4 albedo = texture(albedoMap, _texCoord0); - float roughness = texture(roughnessMap, _texCoord0); - + <$fetchMaterialTextures(_texCoord0, albedo, roughness)$> + Material mat = getMaterial(); packDeferredFragment( diff --git a/libraries/render-utils/src/model_lightmap.slf b/libraries/render-utils/src/model_lightmap.slf index a3505ba779..bfe809f472 100755 --- a/libraries/render-utils/src/model_lightmap.slf +++ b/libraries/render-utils/src/model_lightmap.slf @@ -16,13 +16,9 @@ <@include model/Material.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the emissive map texture and parameters -uniform sampler2D emissiveMap; -uniform vec2 emissiveParams; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS)$> +<$declareMaterialLightmap()$> in vec4 _position; in vec2 _texCoord0; @@ -31,10 +27,9 @@ in vec3 _normal; in vec3 _color; void main(void) { - // Fetch maps - vec4 albedo = texture(albedoMap, _texCoord0); - float roughness = texture(roughnessMap, _texCoord0); - vec4 emissive = texture(emissiveMap, _texCoord1); + + <$fetchMaterialTextures(_texCoord0, albedo, roughness)$> + <$fetchMaterialLightmap(_texCoord1, emissive)$> Material mat = getMaterial(); diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slf b/libraries/render-utils/src/model_lightmap_normal_map.slf index 223cec71fb..1d305541fa 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map.slf @@ -16,16 +16,9 @@ <@include model/Material.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the normal map texture -uniform sampler2D normalMap; - -// the emissive map texture and parameters -uniform sampler2D emissiveMap; -uniform vec2 emissiveParams; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL)$> +<$declareMaterialLightmap()$> in vec4 _position; in vec2 _texCoord0; @@ -35,22 +28,15 @@ in vec3 _tangent; in vec3 _color; void main(void) { - // Fetch maps - vec4 albedo = texture(albedoMap, _texCoord0); - float roughness = texture(roughness, _texCoord0); - vec4 emissive = texture(emissiveMap, _texCoord1); - vec3 localNormal = vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5); - - // compute the view normal from the various bits - vec3 normalizedNormal = normalize(_normal); - vec3 normalizedTangent = normalize(_tangent); - vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec4 viewNormal = vec4(normalizedTangent * localNormal.x + - normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel)$> + <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> Material mat = getMaterial(); + vec3 viewNormal; + <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> + packDeferredFragmentLightmap( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), @@ -58,5 +44,5 @@ void main(void) { getMaterialRoughness(mat), getMaterialMetallic(mat), getMaterialFresnel(mat), - (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); + lightmapVal); } diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index 99799a4b25..513670fe89 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -16,19 +16,9 @@ <@include model/Material.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the emissive map texture and parameters -uniform sampler2D emissiveMap; -uniform vec2 emissiveParams; - -// the normal map texture -uniform sampler2D normalMap; - -// the specular map texture -uniform sampler2D specularMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$> +<$declareMaterialLightmap()$> in vec4 _position; in vec2 _texCoord0; @@ -38,21 +28,13 @@ in vec3 _tangent; in vec3 _color; void main(void) { - // Fetch maps - vec4 albedo = texture(albedoMap, _texCoord0); - float roughness = texture(roughnessMap, _texCoord0); - vec3 specular = texture(specularMap, _texCoord0).rgb; - vec4 emissive = texture(emissiveMap, _texCoord1); - vec3 localNormal = vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5); - - // compute the view normal from the various bits - vec3 normalizedNormal = normalize(_normal); - vec3 normalizedTangent = normalize(_tangent); - vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec4 viewNormal = vec4(normalizedTangent * localNormal.x + - normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - + <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel, specular)$> + <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> + Material mat = getMaterial(); + + vec3 viewNormal; + <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> packDeferredFragmentLightmap( normalize(viewNormal.xyz), @@ -61,5 +43,5 @@ void main(void) { getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), specular, // no use of getMaterialFresnel(mat) - (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); + lightmapVal); } diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index 590dfe5727..48db5a40dc 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -16,16 +16,9 @@ <@include model/Material.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the emissive map texture and parameters -uniform sampler2D emissiveMap; -uniform vec2 emissiveParams; - -// the specular texture -uniform sampler2D specularMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$> +<$declareMaterialLightmap()$> in vec4 _position; in vec2 _texCoord0; @@ -34,12 +27,9 @@ in vec3 _normal; in vec3 _color; void main(void) { - // Fetch maps - vec4 albedo = texture(albedoMap, _texCoord0); - float roughness = texture(roughnessMap, _texCoord0); - vec3 specular = texture(specularMap, _texCoord0).rgb; - vec4 emissive = texture(emissiveMap, _texCoord1); - + <$fetchMaterialTextures(_texCoord0, albedo, roughness, _SCRIBE_NULL, specular)$> + <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> + Material mat = getMaterial(); packDeferredFragmentLightmap( @@ -49,5 +39,5 @@ void main(void) { getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), specular, // no use of getMaterialFresnel(mat) - (vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); + lightmapVal); } diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 8adde1d850..13cb63d322 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -15,14 +15,9 @@ <@include DeferredBufferWrite.slh@> <@include model/Material.slh@> -<@include model/MaterialTextures.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the normal map texture -uniform sampler2D normalMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL)$> in vec4 _position; in vec2 _texCoord0; @@ -31,21 +26,15 @@ in vec3 _tangent; in vec3 _color; void main(void) { - // compute the view normal from the various bits - vec3 normalizedNormal = normalize(_normal.xyz); - vec3 normalizedTangent = normalize(_tangent.xyz); - vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec3 localNormal = normalize(vec3(texture(normalMap, _texCoord0.st)) - vec3(0.5, 0.5, 0.5)); - vec4 viewNormal = vec4(normalizedTangent * localNormal.x + - normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - - vec4 albedo = texture(albedoMap, _texCoord0.st); - float roughness = texture(roughnessMap, _texCoord0); - + <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel)$> + Material mat = getMaterial(); + vec3 viewNormal; + <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> + packDeferredFragment( - normalize(viewNormal.xyz), + viewNormal, evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index 95a13198c0..c4d5b22efe 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -16,15 +16,8 @@ <@include model/Material.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the normal map texture -uniform sampler2D normalMap; - -// the specular map texture -uniform sampler2D specularMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$> in vec4 _position; in vec2 _texCoord0; @@ -33,27 +26,20 @@ in vec3 _tangent; in vec3 _color; void main(void) { - // compute the view normal from the various bits - vec3 normalizedNormal = normalize(_normal); - vec3 normalizedTangent = normalize(_tangent); - vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); - vec3 localNormal = normalize(vec3(texture(normalMap, _texCoord0)) - vec3(0.5, 0.5, 0.5)); - vec4 viewNormal = vec4(normalizedTangent * localNormal.x + - normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); - // set the albedo, normal, specular data - vec4 albedo = texture(albedoMap, _texCoord0); - vec4 roughness = texture(roughnessMap, _texCoord0); - vec3 specular = texture(specularMap, _texCoord0).rgb; - + <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel, specular)$> + Material mat = getMaterial(); + vec3 viewNormal; + <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> + packDeferredFragment( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), - specular //getMaterialFresnel(mat) + vec3(specular) //getMaterialFresnel(mat) ); } diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index 5821ab8154..99f0364520 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -16,12 +16,8 @@ <@include model/Material.slh@> -// the albedo texture -uniform sampler2D albedoMap; -uniform sampler2D roughnessMap; - -// the specular texture -uniform sampler2D specularMap; +<@include MaterialTextures.slh@> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$> in vec4 _position; in vec2 _texCoord0; @@ -30,11 +26,9 @@ in vec3 _color; void main(void) { - // set the albedo, normal, specular data - vec4 albedo = texture(albedoMap, _texCoord0); - float roughness = texture(roughnessMap, _texCoord0); - vec3 specular = texture(specularMap, _texCoord0).rgb; - + + <$fetchMaterialTextures(_texCoord0, albedo, roughness, _SCRIBE_NULL, specular)$> + Material mat = getMaterial(); packDeferredFragment( @@ -43,6 +37,6 @@ void main(void) { getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), - specular //getMaterialFresnel(mat) + vec3(specular) //getMaterialFresnel(mat) ); } diff --git a/tools/scribe/src/TextTemplate.cpp b/tools/scribe/src/TextTemplate.cpp index 3ccb0baea0..741ddb6846 100755 --- a/tools/scribe/src/TextTemplate.cpp +++ b/tools/scribe/src/TextTemplate.cpp @@ -18,6 +18,8 @@ typedef TextTemplate::Block::Pointer BlockPointer; typedef TextTemplate::Config::Pointer ConfigPointer; typedef TextTemplate::Pointer TextTemplatePointer; +const std::string TextTemplate::Tag::NULL_VAR = "_SCRIBE_NULL"; + //----------------------------------------------------------------------------- TextTemplate::Config::Config() : _includes(), @@ -370,7 +372,11 @@ bool TextTemplate::convertExpressionToFuncArguments(String& src, std::vector< St token += c; } else if (c == ',') { if (!token.empty()) { - arguments.push_back(token); + if (token == Tag::NULL_VAR) { + arguments.push_back(Tag::NULL_VAR); + } else { + arguments.push_back(token); + } nbTokens++; } token.clear(); @@ -750,7 +756,9 @@ int TextTemplate::evalBlockGeneration(std::ostream& dst, const BlockPointer& blo paramCache.push_back((*it).second); (*it).second = val; } else { - vars.insert(Vars::value_type(funcBlock->command.arguments[i], val)); + if (val != Tag::NULL_VAR) { + vars.insert(Vars::value_type(funcBlock->command.arguments[i], val)); + } paramCache.push_back(""); } } diff --git a/tools/scribe/src/TextTemplate.h b/tools/scribe/src/TextTemplate.h index a6fd04da5c..44edc23c12 100755 --- a/tools/scribe/src/TextTemplate.h +++ b/tools/scribe/src/TextTemplate.h @@ -42,6 +42,8 @@ public: static const char VAR = '$'; static const char COM = '@'; static const char REM = '!'; + + static const std::string NULL_VAR; }; class Command { From 69dc9ef68f8a6da5751a76b7809d5078a9c6df08 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 09:06:35 -0800 Subject: [PATCH 042/292] added lifetime --- examples/homeContent/whiteboardV2/markerEntityScript.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 74b7746514..155077af9c 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -70,7 +70,8 @@ var _this; }, position: position, textures: _this.MARKER_TEXTURE_URL, - color: _this.markerColor + color: _this.markerColor, + lifetime: 1000 }); _this.linePoints = []; From b5ec79fd6db48c5317759a7f355173e1873349ea Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 09:53:20 -0800 Subject: [PATCH 043/292] marker only draws when equipped and held down --- .../whiteboardV2/markerEntityScript.js | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 155077af9c..d19e09bb34 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -13,9 +13,12 @@ (function() { Script.include("../../libraries/utils.js"); - + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT, + ]; var MAX_POINTS_PER_STROKE = 40; -var _this; + var _this; MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; @@ -30,21 +33,25 @@ var _this; MarkerTip.prototype = { - continueNearGrab: function() { - - _this.continueHolding(); + startEquip: function(id, params) { + _this.equipped = true; + _this.hand = params[0] == "left" ? 0 : 1; }, - continueEquip: function() { - _this.continueHolding(); + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > 0.2) { + print("EBL PAINZT"); + _this.continueHolding(); + } else { + _this.currentStroke = null; + } }, + continueHolding: function() { // cast a ray from marker and see if it hits anything - var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); - var pickRay = { origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) @@ -87,7 +94,7 @@ var _this; if (_this.oldPosition) { basePosition = _this.oldPosition; } - _this.newStroke(basePosition); + _this.newStroke(basePosition); } var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); @@ -95,7 +102,7 @@ var _this; // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { - var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length-1]); + var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); if (distance < _this.MIN_DISTANCE_BETWEEN_POINTS) { return; } @@ -119,7 +126,7 @@ var _this; preload: function(entityID) { this.entityID = entityID; - + }, setProperties: function(myId, data) { From 81ed89531da0ce3eb52372c017f2406e7e8c0f50 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 10:11:13 -0800 Subject: [PATCH 044/292] whiteboard surface parented to whiteboard --- .../whiteboardV2/markerEntityScript.js | 23 ++++++++++++------- .../whiteboardV2/whiteboardSpawner.js | 15 +++++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d19e09bb34..ae8e19c759 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -29,6 +29,7 @@ _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; + _this.PAINTING_TRIGGER_THRESHOLD = 0.2; }; MarkerTip.prototype = { @@ -39,14 +40,17 @@ }, continueEquip: function() { this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > 0.2) { - print("EBL PAINZT"); + if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { _this.continueHolding(); } else { - _this.currentStroke = null; + _this.resetStroke(); } }, + releaseEquip: function() { + _this.resetStroke(); + }, + continueHolding: function() { // cast a ray from marker and see if it hits anything @@ -60,8 +64,7 @@ if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { this.paint(intersection.intersection) } else { - _this.currentStroke = null; - _this.oldPosition = null; + _this.resetStroke(); } }, @@ -119,11 +122,15 @@ }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { - _this.currentStroke = null; - _this.oldPosition = position; + _this.resetStroke(); } }, + resetStroke: function() { + _this.currentStroke = null; + _this.oldPosition = position; + }, + preload: function(entityID) { this.entityID = entityID; @@ -134,7 +141,7 @@ _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Quat.getRight(whiteboardProps.rotation); + _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); _this.markerColor = data.markerColor; } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 26d373266b..90476a3b3d 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -47,6 +47,18 @@ var whiteboard = Entities.addEntity({ } }); +var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, {x: 0.0, y: 0.45, z: 0.0}) +var whiteboardDrawingSurface = Entities.addEntity({ + type: "Box", + name: "whiteboardDrawingSurface", + dimensions: {x: 1.85, y: 1.8, z: 0.03}, + color: {red: 200, green: 10, blue: 200}, + position: whiteboardSurfacePosition, + rotation: orientation, + visible: false, + parentID: whiteboard +}); + createMarkers(); function createMarkers() { @@ -140,7 +152,7 @@ function createMarker(modelURL, markerPosition, markerColor) { Script.setTimeout(function() { var data = { - whiteboard: whiteboard, + whiteboard: whiteboardDrawingSurface, markerColor: markerColor } var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; @@ -155,6 +167,7 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); + Entities.deleteEntity(whiteboardDrawingSurface); markers.forEach(function(marker) { Entities.deleteEntity(marker); }); From 6682b9bd580892e492a598246cb3701f4e8436ea Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 10:36:17 -0800 Subject: [PATCH 045/292] eraser is spawing --- .../whiteboardV2/whiteboardSpawner.js | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 90476a3b3d..b408fcc126 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -47,18 +47,61 @@ var whiteboard = Entities.addEntity({ } }); -var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, {x: 0.0, y: 0.45, z: 0.0}) +var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { + x: 0.0, + y: 0.45, + z: 0.0 +}) var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", name: "whiteboardDrawingSurface", - dimensions: {x: 1.85, y: 1.8, z: 0.03}, - color: {red: 200, green: 10, blue: 200}, + dimensions: { + x: 1.85, + y: 1.8, + z: 0.03 + }, + color: { + red: 200, + green: 10, + blue: 200 + }, position: whiteboardSurfacePosition, rotation: orientation, visible: false, parentID: whiteboard }); + +var WHITEBOARD_RACK_DEPTH = 1.9; + +var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; +var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); +eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); + +var eraser = Entities.addEntity({ + type: "Model", + modelURL: ERASER_MODEL_URL, + position: eraserPosition, + shapeType: "box", + dimensions: { + x: 0.0858, + y: 0.0393, + z: 0.2083 + }, + rotation: whiteboardRotation, + dynamic: true, + gravity: { + x: 0, + y: -1, + z: 0 + }, + velocity: { + x: 0, + y: -0.1, + z: 0 + } +}); + createMarkers(); function createMarkers() { @@ -68,7 +111,7 @@ function createMarkers() { "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/marker-black.fbx", ]; - var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.9, Quat.getFront(orientation))); + var markerPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); createMarker(modelURLS[0], markerPosition, { red: 10, @@ -168,6 +211,7 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); Entities.deleteEntity(whiteboardDrawingSurface); + Entities.deleteEntity(eraser); markers.forEach(function(marker) { Entities.deleteEntity(marker); }); From 20fd79fc43f1370c8e65050d1de953d4f1679294 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 11:25:46 -0800 Subject: [PATCH 046/292] Lines markers --- examples/homeContent/whiteboardV2/markerEntityScript.js | 7 ++++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index ae8e19c759..3b734cc2ad 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -25,7 +25,7 @@ this.strokeForwardOffset = 0.0005; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; this.STROKE_WIDTH = 0.003 - _this.MAX_MARKER_TO_BOARD_DISTANCE = 0.2; + _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; @@ -122,13 +122,14 @@ }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { - _this.resetStroke(); + _this.currentStroke = null; + _this.oldPosition = position; } }, resetStroke: function() { _this.currentStroke = null; - _this.oldPosition = position; + _this.oldPosition = null; }, preload: function(entityID) { diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index b408fcc126..e714070bff 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -44,7 +44,8 @@ var whiteboard = Entities.addEntity({ x: 0.4636, y: 2.7034, z: 1.8653 - } + }, + // visible: false }); var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { @@ -58,7 +59,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ dimensions: { x: 1.85, y: 1.8, - z: 0.03 + z: 0.04 }, color: { red: 200, @@ -68,7 +69,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ position: whiteboardSurfacePosition, rotation: orientation, visible: false, - parentID: whiteboard + // parentID: whiteboard }); From 8d058c2bb380a170062060b661263d2a05483997 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 11:53:27 -0800 Subject: [PATCH 047/292] eraser working --- .../whiteboardV2/eraserEntityScript.js | 80 +++++++++++++++++++ .../whiteboardV2/markerEntityScript.js | 3 +- .../whiteboardV2/whiteboardSpawner.js | 2 + 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 examples/homeContent/whiteboardV2/eraserEntityScript.js diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js new file mode 100644 index 0000000000..5662fdafc5 --- /dev/null +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -0,0 +1,80 @@ +// +// eraserEntityScript.js +// examples/homeContent/eraserEntityScript +// +// Created by Eric Levin on 2/17/15. +// Copyright 2016 High Fidelity, Inc. +// +// This entity script provides logic for an object with attached script to erase nearby marker strokes +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + + + +(function() { + Script.include("../../libraries/utils.js"); + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT, + ]; + var _this; + Eraser = function() { + _this = this; + + _this.ERASER_TRIGGER_THRESHOLD = 0.1; + _this.STROKE_NAME = "hifi-marker-stroke"; + _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.2; + }; + + Eraser.prototype = { + + startEquip: function(id, params) { + _this.equipped = true; + _this.hand = params[0] == "left" ? 0 : 1; + // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes + var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); + // Create a map of stroke entities and their positions + _this.strokeMap = []; + strokeIDs.forEach(function(strokeID) { + var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); + if (strokeProps.name === _this.STROKE_NAME) { + _this.strokeMap.push({ + strokeID: strokeID, + strokePosition: strokeProps.position + }); + } + }); + }, + continueEquip: function() { + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { + _this.continueHolding(); + } else {} + }, + + releaseEquip: function() {}, + + + continueHolding: function() { + // search for marker strokes within certain radius of eraser + var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + _this.strokeMap.forEach(function(strokeData, index) { + if (Vec3.distance(eraserPosition, strokeData.strokePosition) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { + Entities.deleteEntity(strokeData.strokeID); + _this.strokeMap.splice(index, 1); + } + }) + + }, + + + preload: function(entityID) { + this.entityID = entityID; + + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new Eraser(); +}); \ No newline at end of file diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3b734cc2ad..da37983d74 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -30,6 +30,7 @@ _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; _this.PAINTING_TRIGGER_THRESHOLD = 0.2; + this.STROKE_NAME = "hifi-marker-stroke"; }; MarkerTip.prototype = { @@ -72,7 +73,7 @@ _this.strokeBasePosition = position; _this.currentStroke = Entities.addEntity({ type: "PolyLine", - name: "marker stroke", + name: _this.STROKE_NAME, dimensions: { x: 10, y: 10, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index e714070bff..e1ccc16c89 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -76,6 +76,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; +var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js?v1" + Math.random()); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); @@ -83,6 +84,7 @@ var eraser = Entities.addEntity({ type: "Model", modelURL: ERASER_MODEL_URL, position: eraserPosition, + script: ERASER_SCRIPT_URL, shapeType: "box", dimensions: { x: 0.0858, From a2ece772ef3491a580732518b316669464f898b0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 12:08:51 -0800 Subject: [PATCH 048/292] refactor for laser pointer --- .../whiteboardV2/markerEntityScript.js | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index da37983d74..685accfb13 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -40,12 +40,8 @@ _this.hand = params[0] == "left" ? 0 : 1; }, continueEquip: function() { - this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { - _this.continueHolding(); - } else { - _this.resetStroke(); - } + _this.continueHolding(); + }, releaseEquip: function() { @@ -62,13 +58,22 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - this.paint(intersection.intersection) + + if (intersection.intersects) { + _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + _this.paint(intersection.intersection) + } else { + _this.resetStroke(); + } } else { - _this.resetStroke(); + _this.resetStroke(); } + }, + + newStroke: function(position) { _this.strokeBasePosition = position; _this.currentStroke = Entities.addEntity({ @@ -103,7 +108,7 @@ var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - // _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); @@ -138,12 +143,25 @@ }, + unload: function() { + Overlays.deleteOverlay(_this.laserPointer); + }, + setProperties: function(myId, data) { var data = JSON.parse(data); _this.whiteboard = data.whiteboard; var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); + _this.laserPointer = Overlays.addOverlay("circle3d", { + color: { + red: 200, + green: 10, + blue: 10 + }, + solid: true, + rotation: whiteboardProps.rotation + }); _this.markerColor = data.markerColor; } }; From 5e0de4bdee04b648e8bdc84580fa57ffd9c3d5c3 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 12:16:22 -0800 Subject: [PATCH 049/292] tweaks --- .../whiteboardV2/eraserEntityScript.js | 3 +-- .../whiteboardV2/markerEntityScript.js | 16 ++++++++++------ .../whiteboardV2/whiteboardSpawner.js | 10 +++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 5662fdafc5..89ce4aded6 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -23,7 +23,7 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.1; _this.STROKE_NAME = "hifi-marker-stroke"; - _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.2; + _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.4; }; Eraser.prototype = { @@ -68,7 +68,6 @@ }, - preload: function(entityID) { this.entityID = entityID; diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 685accfb13..4bf90b6562 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -5,6 +5,7 @@ // Created by Eric Levin on 2/17/15. // Copyright 2016 High Fidelity, Inc. // +// This script provides the logic for an object to draw marker strokes on its associated whiteboard // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -39,17 +40,13 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; }, - continueEquip: function() { - _this.continueHolding(); - - }, releaseEquip: function() { _this.resetStroke(); }, - continueHolding: function() { + continueEquip: function() { // cast a ray from marker and see if it hits anything var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]); @@ -58,8 +55,11 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects) { + Overlays.editOverlay(_this.laserPointer, { + visible: true, + position: intersection.intersection + }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { _this.paint(intersection.intersection) @@ -68,6 +68,9 @@ } } else { _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { + visible: true + }) } }, @@ -160,6 +163,7 @@ blue: 10 }, solid: true, + size: 0.01, rotation: whiteboardProps.rotation }); _this.markerColor = data.markerColor; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index e1ccc16c89..05aaff3565 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -5,7 +5,8 @@ // Created by Eric Levina on 2/17/16 // Copyright 2016 High Fidelity, Inc. // -// Run this script to spawn a whiteboard and associated acoutrements that one can paint on usignmarkers +// Run this script to spawn a whiteboard, markers, and an eraser. +// To draw on the whiteboard, equip a marker and hold down trigger with marker tip pointed at whiteboard // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -45,7 +46,6 @@ var whiteboard = Entities.addEntity({ y: 2.7034, z: 1.8653 }, - // visible: false }); var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { @@ -69,14 +69,14 @@ var whiteboardDrawingSurface = Entities.addEntity({ position: whiteboardSurfacePosition, rotation: orientation, visible: false, - // parentID: whiteboard + parentID: whiteboard }); var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; -var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js?v1" + Math.random()); +var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); @@ -141,7 +141,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 6fd149f22dbc63075243af6f42ba93c4a4ccf3d2 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 23 Feb 2016 12:27:05 -0800 Subject: [PATCH 050/292] no avatar --- .../DomainContent/CellScience/motorProteinControllerAC.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js b/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js index 672ec1fd92..59577d49ba 100644 --- a/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js +++ b/unpublishedScripts/DomainContent/CellScience/motorProteinControllerAC.js @@ -18,8 +18,6 @@ if (USE_LOCAL_HOST === true) { var USE_LOCAL_HOST = false; -Agent.isAvatar = true; - EntityViewer.setPosition({ x: 3000, y: 13500, From d1d4a9d6b1f6dacbfe9fdf9789e93fcbf00d66b0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 14:48:45 -0800 Subject: [PATCH 051/292] adjusted surface position --- .../whiteboardV2/markerEntityScript.js | 17 +++++++++-------- .../whiteboardV2/whiteboardSpawner.js | 11 ++++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 4bf90b6562..618a190587 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -23,7 +23,7 @@ MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; - this.strokeForwardOffset = 0.0005; + this.strokeForwardOffset = 0.0001; this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; this.STROKE_WIDTH = 0.003 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; @@ -43,6 +43,9 @@ releaseEquip: function() { _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { + visible: false + }); }, @@ -69,14 +72,12 @@ } else { _this.resetStroke(); Overlays.editOverlay(_this.laserPointer, { - visible: true - }) + visible: false + }); } }, - - newStroke: function(position) { _this.strokeBasePosition = position; _this.currentStroke = Entities.addEntity({ @@ -158,9 +159,9 @@ _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); _this.laserPointer = Overlays.addOverlay("circle3d", { color: { - red: 200, - green: 10, - blue: 10 + red: 220, + green: 35, + blue: 53 }, solid: true, size: 0.01, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 05aaff3565..378bd9ff5c 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -13,7 +13,7 @@ Script.include("../../libraries/utils.js") -var orientation = Camera.getOrientation(); +var orientation = MyAvatar.orientation; orientation = Quat.safeEulerAngles(orientation); var markerRotation = Quat.fromVec3Degrees({ x: orientation.x + 10, @@ -52,12 +52,13 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { x: 0.0, y: 0.45, z: 0.0 -}) +}); +whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(orientation))); var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", name: "whiteboardDrawingSurface", dimensions: { - x: 1.85, + x: 1.82, y: 1.8, z: 0.04 }, @@ -75,7 +76,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ var WHITEBOARD_RACK_DEPTH = 1.9; -var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser.fbx"; +var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser-2.fbx"; var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); @@ -102,7 +103,7 @@ var eraser = Entities.addEntity({ x: 0, y: -0.1, z: 0 - } + }, }); createMarkers(); From 2c7112e9a828f81a9d36936d4027da4c025b09fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 17 Feb 2016 10:53:23 -0800 Subject: [PATCH 052/292] add initial send sequence number to SendQueue --- libraries/networking/src/udt/Connection.cpp | 6 +----- libraries/networking/src/udt/Connection.h | 6 +++--- libraries/networking/src/udt/SendQueue.cpp | 24 +++++++++++++++------ libraries/networking/src/udt/SendQueue.h | 7 +++--- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 3b5b26d05d..f733d58869 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -87,7 +87,7 @@ SendQueue& Connection::getSendQueue() { // receiver is getting the sequence numbers it expects (given that the connection must still be active) // Lasily create send queue - _sendQueue = SendQueue::create(_parentSocket, _destination, _inactiveSendQueueSequenceNumber); + _sendQueue = SendQueue::create(_parentSocket, _destination); #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Created SendQueue for connection to" << _destination; @@ -109,10 +109,6 @@ SendQueue& Connection::getSendQueue() { } void Connection::queueInactive() { - // get the current sequence number from the send queue, this is to be re-used if the send - // queue is re-activated for this connection - _inactiveSendQueueSequenceNumber = _sendQueue->getCurrentSequenceNumber(); - // tell our current send queue to go down and reset our ptr to it to null stopSendQueue(); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index b58b7ec570..bf56a468aa 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -130,7 +130,9 @@ private: bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection bool _isActive { true }; // flag used for inactivity of connection - + + SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer SendQueue on creation, identifies connection during re-connect requests + LossList _lossList; // List of all missing packets SequenceNumber _lastReceivedSequenceNumber; // The largest sequence number received from the peer SequenceNumber _lastReceivedACK; // The last ACK received @@ -140,8 +142,6 @@ private: SequenceNumber _lastSentACK; // The last sent ACK SequenceNumber _lastSentACK2; // The last sent ACK sub-sequence number in an ACK2 - SequenceNumber _inactiveSendQueueSequenceNumber { 0 }; - int _acksDuringSYN { 1 }; // The number of non-SYN ACKs sent during SYN int _lightACKsDuringSYN { 1 }; // The number of lite ACKs sent during SYN interval diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 18269d1d43..8a8105bb26 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -12,6 +12,7 @@ #include "SendQueue.h" #include +#include #include #include @@ -53,10 +54,10 @@ private: Mutex2& _mutex2; }; -std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination, SequenceNumber currentSequenceNumber) { +std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destination) { Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*"); - auto queue = std::unique_ptr(new SendQueue(socket, destination, currentSequenceNumber)); + auto queue = std::unique_ptr(new SendQueue(socket, destination)); // Setup queue private thread QThread* thread = new QThread; @@ -75,12 +76,23 @@ std::unique_ptr SendQueue::create(Socket* socket, HifiSockAddr destin return queue; } -SendQueue::SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber) : +SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : _socket(socket), - _destination(dest), - _currentSequenceNumber(currentSequenceNumber) + _destination(dest) { - + + // setup psuedo-random number generation for all instances of SendQueue + static std::random_device rd; + static std::mt19937 generator(rd()); + static std::uniform_int_distribution<> distribution(0, SequenceNumber::MAX); + + // randomize the intial sequence number + _initialSequenceNumber = SequenceNumber(distribution(generator)); + + // set our member variables from randomized initial number + _currentSequenceNumber = _initialSequenceNumber - 1; + _atomicCurrentSequenceNumber = uint32_t(_currentSequenceNumber); + _lastACKSequenceNumber = uint32_t(_initialSequenceNumber); } void SendQueue::queuePacket(std::unique_ptr packet) { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index da8f5e6c3f..29ad7c6d73 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -50,8 +50,7 @@ public: Stopped }; - static std::unique_ptr create(Socket* socket, HifiSockAddr destination, - SequenceNumber currentSequenceNumber = SequenceNumber()); + static std::unique_ptr create(Socket* socket, HifiSockAddr destination); void queuePacket(std::unique_ptr packet); void queuePacketList(std::unique_ptr packetList); @@ -84,7 +83,7 @@ private slots: void run(); private: - SendQueue(Socket* socket, HifiSockAddr dest, SequenceNumber currentSequenceNumber); + SendQueue(Socket* socket, HifiSockAddr dest); SendQueue(SendQueue& other) = delete; SendQueue(SendQueue&& other) = delete; @@ -106,6 +105,8 @@ private: Socket* _socket { nullptr }; // Socket to send packet on HifiSockAddr _destination; // Destination addr + + SequenceNumber _initialSequenceNumber; // Randomized on SendQueue creation, identifies connection during re-connect requests std::atomic _lastACKSequenceNumber { 0 }; // Last ACKed sequence number From 39d9e64ee59d7fdd30fb3c09ad009d80cfe76fde Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 16 Feb 2016 11:43:06 -0800 Subject: [PATCH 053/292] process a handshake if the connection has ever received data --- libraries/networking/src/udt/Connection.cpp | 6 +++--- libraries/networking/src/udt/Connection.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index f733d58869..0e1f3ddefb 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -411,7 +411,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in return false; } - _isReceivingData = true; + _isReceivingData = _hasReceivedData = true; // mark our last receive time as now (to push the potential expiry farther) _lastReceiveTime = p_high_resolution_clock::now(); @@ -725,7 +725,7 @@ void Connection::processNAK(std::unique_ptr controlPacket) { void Connection::processHandshake(std::unique_ptr controlPacket) { - if (!_hasReceivedHandshake || _isReceivingData) { + if (!_hasReceivedHandshake || _hasReceivedData) { // server sent us a handshake - we need to assume this means state should be reset // as long as we haven't received a handshake yet or we have and we've received some data resetReceiveState(); @@ -799,7 +799,7 @@ void Connection::resetReceiveState() { // the _nakInterval need not be reset, that will happen on loss // clear sync variables - _isReceivingData = false; + _isReceivingData = _hasReceivedData = false; _connectionStart = p_high_resolution_clock::now(); _acksDuringSYN = 1; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index bf56a468aa..2f2252a139 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -129,6 +129,7 @@ private: p_high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection + bool _hasReceivedData { false }; // flag used for reset of connection state on second handshake bool _isActive { true }; // flag used for inactivity of connection SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer SendQueue on creation, identifies connection during re-connect requests From 0b569a0fabf2e67120233c00ae08257cd6f9c421 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 16:49:03 -0800 Subject: [PATCH 054/292] only show overlay if within painting range --- .../homeContent/whiteboardV2/markerEntityScript.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 618a190587..3461e31076 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -58,13 +58,14 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); - if (intersection.intersects) { + + if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { _this.paint(intersection.intersection) } else { _this.resetStroke(); @@ -91,7 +92,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 1000 + lifetime: 200 }); _this.linePoints = []; @@ -149,6 +150,9 @@ unload: function() { Overlays.deleteOverlay(_this.laserPointer); + _this.strokes.forEach( function(stroke) { + Entities.deleteEntity(stroke); + }); }, setProperties: function(myId, data) { From 045d542f11d2ffe7766090814bc985e28fd5ebbf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 18:03:38 -0800 Subject: [PATCH 055/292] lines no longer disapear after drawing for a while --- examples/homeContent/whiteboardV2/markerEntityScript.js | 7 +++---- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3461e31076..8f22910d4f 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -92,7 +92,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 200 + lifetime: 10 }); _this.linePoints = []; @@ -111,9 +111,9 @@ _this.newStroke(basePosition); } - var localPoint = Vec3.subtract(basePosition, this.strokeBasePosition); + var localPoint = Vec3.subtract(basePosition, _this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - _this.strokeForwardOffset += _this.STROKE_FORWARD_OFFSET_INCRERMENT; + _this.strokeForwardOffset -= _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); @@ -121,7 +121,6 @@ return; } } - _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); this.strokeWidths.push(_this.STROKE_WIDTH); diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 378bd9ff5c..6d5c74e273 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -142,12 +142,13 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, rotation: markerRotation, shapeType: "box", + name: "marker", dynamic: true, gravity: { x: 0, From 2f5800a4ccc268507c4436265eea62de766d687d Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 23 Feb 2016 18:31:38 -0800 Subject: [PATCH 056/292] IMproving the shading model and the loading, added the roughness, needt to clean up --- libraries/fbx/src/FBXReader_Material.cpp | 2 +- libraries/model/src/model/Material.slh | 19 +++++++++++++ libraries/render-utils/src/DeferredBuffer.slh | 5 +++- .../render-utils/src/DeferredBufferWrite.slh | 8 ++---- .../render-utils/src/DeferredLighting.slh | 2 -- .../render-utils/src/MaterialTextures.slh | 24 ++++++++++++---- .../render-utils/src/MeshPartPayload.cpp | 28 +++++++++---------- .../model_lightmap_normal_specular_map.slf | 6 ++-- .../src/model_lightmap_specular_map.slf | 2 +- .../src/model_normal_specular_map.slf | 19 +++++++++---- .../render-utils/src/model_specular_map.slf | 10 +++++-- libraries/render/src/render/ShapePipeline.cpp | 2 ++ libraries/render/src/render/ShapePipeline.h | 3 ++ 13 files changed, 89 insertions(+), 41 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index cce2f2162a..2604d83423 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -152,6 +152,7 @@ void FBXReader::consolidateFBXMaterials() { glm::vec2 lightmapParams(0.f, 1.f); lightmapParams.x = _lightmapOffset; lightmapParams.y = _lightmapLevel; + FBXTexture ambientTexture; QString ambientTextureID = ambientTextures.value(material.materialID); if (_loadLightmaps && !ambientTextureID.isNull()) { @@ -179,7 +180,6 @@ void FBXReader::consolidateFBXMaterials() { // FIXME: Do not use the Specular Factor yet as some FBX models have it set to 0 // metallic *= material.specularFactor; material._material->setMetallic(metallic); - } if (material.opacity <= 0.0f) { diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index 02bd9568dc..ac5d750bdd 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -37,5 +37,24 @@ float getMaterialMetallic(Material m) { return m._fresnelMetallic.a; } float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } +int getMaterialKey(Material m) { return floatBitsToInt(m._spare.w); } + +const int EMISSIVE_VAL_BIT = 0x00000001; +const int ALBEDO_VAL_BIT = 0x00000002; +const int METALLIC_VAL_BIT = 0x00000004; +const int GLOSSY_VAL_BIT = 0x00000008; +const int TRANSPARENT_VAL_BIT = 0x00000010; + + +const int EMISSIVE_MAP_BIT = 0x00000020; +const int ALBEDO_MAP_BIT = 0x00000040; +const int METALLIC_MAP_BIT = 0x00000080; +const int ROUGHNESS_MAP_BIT = 0x00000100; +const int TRANSPARENT_MAP_BIT = 0x00000200; +const int NORMAL_MAP_BIT = 0x00000400; + +const int LIGHTMAP_MAP_BIT = 0x00000800; + + <@endif@> diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index fe9b1a2a47..f35fc12d1f 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -120,7 +120,9 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { // } frag.metallic = frag.diffuseVal.a; - if (frag.metallic > 0.5) { + frag.diffuse = frag.diffuseVal.xyz; + frag.specular = vec3(frag.metallic); + /* if (frag.metallic > 0.5) { frag.diffuse = vec3(0); //frag.metallic = length(frag.specularVal); frag.specular = frag.diffuseVal.xyz; @@ -130,6 +132,7 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { //frag.metallic = length(frag.specularVal); frag.specular = vec3(0.03); } + */ // frag.diffuse = frag.diffuseVal.xyz; //frag.metallic = length(frag.specularVal); //frag.specular = frag.specularVal.xyz; diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 21d579cb3a..a92ce1d26a 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -50,8 +50,8 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness if (alpha != 1.0) { discard; } - vec3 baseColor = ((metallic < 0.5) ? albedo : fresnel); - _fragColor0 = vec4(baseColor, metallic); + // vec3 baseColor = ((metallic < 0.5) ? albedo : fresnel); + _fragColor0 = vec4(albedo, metallic); _fragColor1 = vec4(bestFitNormal(normal), 0.5 * clamp(roughness, 0.0, 1.0)); _fragColor2 = vec4(fresnel, roughness); } @@ -60,9 +60,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float r if (alpha != 1.0) { discard; } - - vec3 baseColor = ((metallic < 0.5) ? albedo : fresnel); - _fragColor0 = vec4(baseColor, metallic); + _fragColor0 = vec4(albedo, metallic); _fragColor1 = vec4(bestFitNormal(normal), 0.5 + 0.5 * clamp(roughness, 0.0, 1.0)); _fragColor2 = vec4(emissive, roughness); } diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index eb821cccac..ca3989256a 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -29,8 +29,6 @@ float specularDistribution(float roughness, vec3 normal, vec3 halfDir) { // Frag Shading returns the diffuse amount as W and the specular rgb as xyz vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) { // Diffuse Lighting - //float diffuseDot = dot(fragNormal, fragLightDir); - //float facingLight = step(0.0, diffuseDot); float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0); // Specular Lighting diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 47eed14a82..ab58b7cff5 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -20,14 +20,12 @@ vec4 fetchAlbedoMap(vec2 uv) { } <@endif@> - uniform sampler2D roughnessMap; float fetchRoughnessMap(vec2 uv) { return texture(roughnessMap, uv).r; } <@endif@> -!> <@if withNormal@> uniform sampler2D normalMap; @@ -38,8 +36,8 @@ vec3 fetchNormalMap(vec2 uv) { <@if withMetallic@> uniform sampler2D specularMap; -vec3 fetchMetallicMap(vec2 uv) { - return texture(specularMap, uv).rgb; +float fetchMetallicMap(vec2 uv) { + return texture(specularMap, uv).r; } <@endif@> @@ -51,13 +49,13 @@ vec3 fetchMetallicMap(vec2 uv) { vec4 <$albedo$> = fetchAlbedoMap(<$texcoord0$>); <@endif@> <@if roughness@> -float <$roughness$> = 1.0; //fetchRoughnessMap(<$texcoord0$>); + float <$roughness$> = fetchRoughnessMap(<$texcoord0$>); <@endif@> <@if normal@> vec3 <$normal$> = fetchNormalMap(<$texcoord0$>); <@endif@> <@if metallic@> - vec3 <$metallic$> = fetchMetallicMap(<$texcoord0$>); + float <$metallic$> = fetchMetallicMap(<$texcoord0$>); <@endif@> <@endfunc@> @@ -85,4 +83,18 @@ vec3 fetchLightmapMap(vec2 uv) { } <@endfunc@> + +<@func evalMaterialRoughness(fetchedRoughness, materialRoughness, matKey, roughness)@> +{ + <$roughness$> = (((<$matKey$> & ROUGHNESS_MAP_BIT) != 0) ? <$fetchedRoughness$> : <$materialRoughness$>); +} +<@endfunc@> + +<@func evalMaterialMetallic(fetchedMetallic, materialMetallic, matKey, metallic)@> +{ + <$metallic$> = (((<$matKey$> & METALLIC_MAP_BIT) != 0) ? <$fetchedMetallic$> : <$materialMetallic$>); +} +<@endfunc@> + + <@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e15603cca5..ab2a969637 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -161,6 +161,20 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, textureCache->getWhiteTexture()); } + // Roughness map + if (materialKey.isRoughnessMap()) { + auto roughnessMap = textureMaps[model::MaterialKey::ROUGHNESS_MAP]; + if (roughnessMap && roughnessMap->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, roughnessMap->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, textureCache->getWhiteTexture()); + } + } else { + batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, textureCache->getWhiteTexture()); + } + // Normal map if (materialKey.isNormalMap()) { auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP]; @@ -175,20 +189,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr); } - // Roughness map - /* if (materialKey.isRoughnessMap()) { - auto roughnessMap = textureMaps[model::MaterialKey::ROUGHNESS_MAP]; - if (roughnessMap && roughnessMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, roughnessMap->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, textureCache->getBlackTexture()); - } - } else { - batch.setResourceTexture(ShapePipeline::Slot::ROUGHNESS_MAP, nullptr); - }*/ - // Metallic map if (materialKey.isMetallicMap()) { auto specularMap = textureMaps[model::MaterialKey::METALLIC_MAP]; diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index 513670fe89..93bb3a793e 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -28,7 +28,7 @@ in vec3 _tangent; in vec3 _color; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel, specular)$> + <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel, metalllicTex)$> <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> Material mat = getMaterial(); @@ -41,7 +41,7 @@ void main(void) { evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, - getMaterialMetallic(mat), - specular, // no use of getMaterialFresnel(mat) + getMaterialMetallic(mat) * metalllicTex, + /*specular, // no use of */ getMaterialFresnel(mat), lightmapVal); } diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index 48db5a40dc..23d3a8e2b3 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -38,6 +38,6 @@ void main(void) { getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, getMaterialMetallic(mat), - specular, // no use of getMaterialFresnel(mat) + /*specular, // no use of */getMaterialFresnel(mat), lightmapVal); } diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index c4d5b22efe..66fe0cd67e 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -27,19 +27,28 @@ in vec3 _color; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel, specular)$> + <$fetchMaterialTextures(_texCoord0, albedo, roughnessTex, normalTexel, metallicTex)$> Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + vec3 viewNormal; <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> - + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; + + packDeferredFragment( normalize(viewNormal.xyz), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat) * roughness, - getMaterialMetallic(mat), - vec3(specular) //getMaterialFresnel(mat) + roughness, + metallic, + /*vec3(specular) //*/getMaterialFresnel(mat) ); } diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index 99f0364520..cfdf023ae3 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -27,16 +27,20 @@ in vec3 _color; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness, _SCRIBE_NULL, specular)$> + <$fetchMaterialTextures(_texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$> Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + + float metallic = getMaterialMetallic(mat); + <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; packDeferredFragment( normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, - getMaterialMetallic(mat), - vec3(specular) //getMaterialFresnel(mat) + metallic, + /*vec3(specular) //*/ getMaterialFresnel(mat) ); } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 1103507bf5..68c0b94766 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -54,6 +54,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::ALBEDO_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::ROUGHNESS_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::SPECULAR_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::LIGHTMAP_MAP)); @@ -67,6 +68,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->emissiveParams = program->getUniforms().findLocation("emissiveParams"); locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap"); + locations->roughnessTextureUnit = program->getTextures().findLocation("roughnessMap"); locations->normalTextureUnit = program->getTextures().findLocation("normalMap"); locations->specularTextureUnit = program->getTextures().findLocation("specularMap"); locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 4b6247aa54..b4fb622b39 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -199,6 +199,8 @@ public: static const int NORMAL_MAP = 1; static const int SPECULAR_MAP = 2; static const int LIGHTMAP_MAP = 3; + static const int ROUGHNESS_MAP = 4; + static const int LIGHT_BUFFER = 4; static const int NORMAL_FITTING_MAP = 10; }; @@ -208,6 +210,7 @@ public: int texcoordMatrices; int albedoTextureUnit; int normalTextureUnit; + int roughnessTextureUnit; int specularTextureUnit; int emissiveTextureUnit; int emissiveParams; From 0ff820199420d4c3510dbe5b43523c6e07a53bf0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 18:45:41 -0800 Subject: [PATCH 057/292] fixed line gaps --- .../acAudioSearching/howardAcAudio.js | 248 ++++++++++++++++++ .../acAudioSearching/howardSpawner.js | 248 ++++++++++++++++++ .../whiteboardV2/markerEntityScript.js | 7 +- 3 files changed, 500 insertions(+), 3 deletions(-) create mode 100644 examples/audioExamples/acAudioSearching/howardAcAudio.js create mode 100644 examples/audioExamples/acAudioSearching/howardSpawner.js diff --git a/examples/audioExamples/acAudioSearching/howardAcAudio.js b/examples/audioExamples/acAudioSearching/howardAcAudio.js new file mode 100644 index 0000000000..f5b1302e06 --- /dev/null +++ b/examples/audioExamples/acAudioSearching/howardAcAudio.js @@ -0,0 +1,248 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ +// +// ACAudioSearchAndInject.js +// audio +// +// Created by Eric Levin and Howard Stearns 2/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. +// Inject as many as practical into the audio mixer. +// See acAudioSearchAndCompatibilityEntitySpawner.js. +// +// This implementation takes some precautions to scale well: +// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. +// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only +// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). +// This implementation tries to use all the available injectors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. +var old_sound_data_key = "soundKey"; // For backwards compatibility. +var QUERY_RADIUS = 50; // meters +var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. +var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. +var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. +// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) +var UPDATES_PER_STATS_LOG = 50; + +var DEFAULT_SOUND_DATA = { + volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. + loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. + playbackGap: 1000, // in ms + playbackGapRange: 0 // in ms +}; + +Script.include("../../libraries/utils.js"); +Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. + +function ignore() {} + +function debug() { // Display the arguments not just [Object object]. + //print.apply(null, [].map.call(arguments, JSON.stringify)); +} + +EntityViewer.setKeyholeRadius(QUERY_RADIUS); + +// ENTITY DATA CACHE +// +var entityCache = {}; // A dictionary of unexpired EntityData objects. + +function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. + // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. + var that = this; + that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data + // State Transitions: + // no data => no data | sound data | expired + // expired => stop => remove + // sound data => downloading + // downloading => downloading | waiting + // waiting => playing | waiting (if too many already playing) + // playing => update position etc | no data + that.stop = function stop() { + if (!that.sound) { + return; + } + print("stopping sound", entityIdentifier, that.url); + delete that.sound; + delete that.url; + if (!that.injector) { + return; + } + that.injector.stop(); + delete that.injector; + }; + this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { + if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE + that.stop(); // Alternatively, we could fade out and then stop... + delete entityCache[entityIdentifier]; + return; + } + var properties, soundData; // Latest data, pulled from local octree. + // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. + // Most entity updates are fast and only a very few do getEntityProperties. + + function ensureSoundData() { // We only getEntityProperities when we need to. + if (properties) { + return; + } + properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); + debug("updating", that, properties); + try { + var userData = properties.userData && JSON.parse(properties.userData); + soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. + that.lastUserDataUpdate = now; // But do update these ... + that.url = soundData && soundData.url; + that.playAfter = that.url && now; + } catch (err) { + print(err, properties.userData); + } + } + // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. + if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA + ensureSoundData(); + } + if (!that.url) { // NO DATA => NO DATA + return that.stop(); + } + if (!that.sound) { // SOUND DATA => DOWNLOADING + that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. + } + if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING + return; + } + if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING + return; + } + ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. + if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) + return that.stop(); + } + var options = { + position: properties.position, + loop: soundData.loop || DEFAULT_SOUND_DATA.loop, + volume: soundData.volume || DEFAULT_SOUND_DATA.volume + }; + if (!that.injector) { // WAITING => PLAYING | WAITING + debug("starting", that, options); + that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. + if (that.injector) { + print("started", entityIdentifier, that.url); + } else { // Don't hammer ensureSoundData or injector manager. + that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); + } + return; + } + that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC + if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. + var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; + if (gap) { // WAITING => PLAYING + gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. + // Setup next play just once, now. Changes won't be looked at while we wait. + that.playAfter = now + (that.sound.duration * 1000) + gap; + // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. + that.injector.restart(); + } else { // PLAYING => NO DATA + that.playAfter = Infinity; + } + } + }; +} + +function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { + ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. + var entitySound = entityCache[entityIdentifier]; + if (!entitySound) { + entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); + } + entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. +} +var nUpdates = UPDATES_PER_STATS_LOG, + lastStats = Date.now(); + +function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. + var now = Date.now(), + expirationCutoff = now - EXPIRATION_TIME, + userDataRecheckCutoff = now - RECHECK_TIME; + Object.keys(entityCache).forEach(function(entityIdentifier) { + entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); + }); + if (nUpdates-- <= 0) { // Report statistics. + // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: + // audio-mixer: 23% of cpu (on Mac Activity Monitor) + // this script's assignment client: 106% of cpu. (overloaded) + // entities:12003 + // sounds:2000 + // playing:40 (correct) + // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) + var stats = { + entities: 0, + sounds: 0, + playing: 0, + millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG + }; + nUpdates = UPDATES_PER_STATS_LOG; + lastStats = now; + Object.keys(entityCache).forEach(function(entityIdentifier) { + var datum = entityCache[entityIdentifier]; + stats.entities++; + if (datum.url) { + stats.sounds++; + if (datum.injector && datum.injector.isPlaying) { + stats.playing++; + } + } + }); + print(JSON.stringify(stats)); + } +} + +// Update the set of which EntityData we know about. +// + +function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. + // This does at most: + // one queryOctree request of the entity server, and + // one findEntities geometry query of our own octree, and + // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. + // The idea is that this is a nice bounded piece of work that should not be done too frequently. + // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. + var avatar = AvatarList.getAvatar(avatarIdentifier), + avatarPosition = avatar && avatar.position; + if (!avatarPosition) { // No longer here. + return; + } + var timestamp = Date.now(); + EntityViewer.setPosition(avatarPosition); + EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. + var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); + debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); + entities.forEach(function(entityIdentifier) { + internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); + }); +} + +// Slowly update the set of data we have to work with. +// +var workQueue = []; + +function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates + workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { + return function() { + updateEntiesForAvatar(avatarIdentifier); + }; + }); +} +Script.setInterval(function() { + // There might be thousands of EntityData known to us, but only a few will require any work to update. + updateAllEntityData(); // i.e., this better be pretty fast. + // Each interval, we do no more than one updateEntitiesforAvatar. + if (!workQueue.length) { + workQueue = [updateWorkQueueForAvatarsPresent]; + } + workQueue.pop()(); // There's always one +}, UPDATE_TIME); \ No newline at end of file diff --git a/examples/audioExamples/acAudioSearching/howardSpawner.js b/examples/audioExamples/acAudioSearching/howardSpawner.js new file mode 100644 index 0000000000..f5b1302e06 --- /dev/null +++ b/examples/audioExamples/acAudioSearching/howardSpawner.js @@ -0,0 +1,248 @@ +"use strict"; +/*jslint nomen: true, plusplus: true, vars: true*/ +/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ +// +// ACAudioSearchAndInject.js +// audio +// +// Created by Eric Levin and Howard Stearns 2/1/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. +// Inject as many as practical into the audio mixer. +// See acAudioSearchAndCompatibilityEntitySpawner.js. +// +// This implementation takes some precautions to scale well: +// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. +// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only +// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). +// This implementation tries to use all the available injectors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. +var old_sound_data_key = "soundKey"; // For backwards compatibility. +var QUERY_RADIUS = 50; // meters +var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. +var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. +var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. +// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) +var UPDATES_PER_STATS_LOG = 50; + +var DEFAULT_SOUND_DATA = { + volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. + loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. + playbackGap: 1000, // in ms + playbackGapRange: 0 // in ms +}; + +Script.include("../../libraries/utils.js"); +Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. + +function ignore() {} + +function debug() { // Display the arguments not just [Object object]. + //print.apply(null, [].map.call(arguments, JSON.stringify)); +} + +EntityViewer.setKeyholeRadius(QUERY_RADIUS); + +// ENTITY DATA CACHE +// +var entityCache = {}; // A dictionary of unexpired EntityData objects. + +function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. + // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. + var that = this; + that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data + // State Transitions: + // no data => no data | sound data | expired + // expired => stop => remove + // sound data => downloading + // downloading => downloading | waiting + // waiting => playing | waiting (if too many already playing) + // playing => update position etc | no data + that.stop = function stop() { + if (!that.sound) { + return; + } + print("stopping sound", entityIdentifier, that.url); + delete that.sound; + delete that.url; + if (!that.injector) { + return; + } + that.injector.stop(); + delete that.injector; + }; + this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { + if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE + that.stop(); // Alternatively, we could fade out and then stop... + delete entityCache[entityIdentifier]; + return; + } + var properties, soundData; // Latest data, pulled from local octree. + // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. + // Most entity updates are fast and only a very few do getEntityProperties. + + function ensureSoundData() { // We only getEntityProperities when we need to. + if (properties) { + return; + } + properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); + debug("updating", that, properties); + try { + var userData = properties.userData && JSON.parse(properties.userData); + soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. + that.lastUserDataUpdate = now; // But do update these ... + that.url = soundData && soundData.url; + that.playAfter = that.url && now; + } catch (err) { + print(err, properties.userData); + } + } + // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. + if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA + ensureSoundData(); + } + if (!that.url) { // NO DATA => NO DATA + return that.stop(); + } + if (!that.sound) { // SOUND DATA => DOWNLOADING + that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. + } + if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING + return; + } + if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING + return; + } + ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. + if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) + return that.stop(); + } + var options = { + position: properties.position, + loop: soundData.loop || DEFAULT_SOUND_DATA.loop, + volume: soundData.volume || DEFAULT_SOUND_DATA.volume + }; + if (!that.injector) { // WAITING => PLAYING | WAITING + debug("starting", that, options); + that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. + if (that.injector) { + print("started", entityIdentifier, that.url); + } else { // Don't hammer ensureSoundData or injector manager. + that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); + } + return; + } + that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC + if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. + var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; + if (gap) { // WAITING => PLAYING + gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. + // Setup next play just once, now. Changes won't be looked at while we wait. + that.playAfter = now + (that.sound.duration * 1000) + gap; + // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. + that.injector.restart(); + } else { // PLAYING => NO DATA + that.playAfter = Infinity; + } + } + }; +} + +function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { + ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. + var entitySound = entityCache[entityIdentifier]; + if (!entitySound) { + entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); + } + entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. +} +var nUpdates = UPDATES_PER_STATS_LOG, + lastStats = Date.now(); + +function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. + var now = Date.now(), + expirationCutoff = now - EXPIRATION_TIME, + userDataRecheckCutoff = now - RECHECK_TIME; + Object.keys(entityCache).forEach(function(entityIdentifier) { + entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); + }); + if (nUpdates-- <= 0) { // Report statistics. + // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: + // audio-mixer: 23% of cpu (on Mac Activity Monitor) + // this script's assignment client: 106% of cpu. (overloaded) + // entities:12003 + // sounds:2000 + // playing:40 (correct) + // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) + var stats = { + entities: 0, + sounds: 0, + playing: 0, + millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG + }; + nUpdates = UPDATES_PER_STATS_LOG; + lastStats = now; + Object.keys(entityCache).forEach(function(entityIdentifier) { + var datum = entityCache[entityIdentifier]; + stats.entities++; + if (datum.url) { + stats.sounds++; + if (datum.injector && datum.injector.isPlaying) { + stats.playing++; + } + } + }); + print(JSON.stringify(stats)); + } +} + +// Update the set of which EntityData we know about. +// + +function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. + // This does at most: + // one queryOctree request of the entity server, and + // one findEntities geometry query of our own octree, and + // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. + // The idea is that this is a nice bounded piece of work that should not be done too frequently. + // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. + var avatar = AvatarList.getAvatar(avatarIdentifier), + avatarPosition = avatar && avatar.position; + if (!avatarPosition) { // No longer here. + return; + } + var timestamp = Date.now(); + EntityViewer.setPosition(avatarPosition); + EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. + var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); + debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); + entities.forEach(function(entityIdentifier) { + internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); + }); +} + +// Slowly update the set of data we have to work with. +// +var workQueue = []; + +function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates + workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { + return function() { + updateEntiesForAvatar(avatarIdentifier); + }; + }); +} +Script.setInterval(function() { + // There might be thousands of EntityData known to us, but only a few will require any work to update. + updateAllEntityData(); // i.e., this better be pretty fast. + // Each interval, we do no more than one updateEntitiesforAvatar. + if (!workQueue.length) { + workQueue = [updateWorkQueueForAvatarsPresent]; + } + workQueue.pop()(); // There's always one +}, UPDATE_TIME); \ No newline at end of file diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 8f22910d4f..761ef00e33 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -57,7 +57,7 @@ origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - var intersection = Entities.findRayIntersection(pickRay, true, [_this.whiteboard]); + var intersection = Entities.findRayIntersectionBlocking(pickRay, true, [_this.whiteboard]); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { Overlays.editOverlay(_this.laserPointer, { @@ -71,7 +71,8 @@ _this.resetStroke(); } } else { - _this.resetStroke(); + _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { visible: false }); @@ -92,7 +93,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 10 + lifetime: 500 }); _this.linePoints = []; From 67ec1732b348e44539770bfddeeaa9239ab429fc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 23 Feb 2016 18:46:38 -0800 Subject: [PATCH 058/292] increased eraser range --- examples/homeContent/whiteboardV2/eraserEntityScript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 89ce4aded6..66399a9b8e 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -21,9 +21,9 @@ Eraser = function() { _this = this; - _this.ERASER_TRIGGER_THRESHOLD = 0.1; + _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; - _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.4; + _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; }; Eraser.prototype = { From 46fbf38b5d38e7e7a1a9447d1e9e805fdc477ea7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 24 Feb 2016 12:36:18 -0800 Subject: [PATCH 059/292] ac movers --- .../CellScience/Scripts/colorRandomly.js | 104 ----- .../CellScience/Scripts/moveRandomly2.js | 91 ----- .../Scripts/showButtonToPlaySound.js | 4 - .../CellScience/Scripts/virtualBaton.js | 381 ------------------ .../Scripts/zoomAndMoveRandomly.js | 164 -------- .../CellScience/importCellScience.js | 43 +- .../DomainContent/CellScience/moveCellsAC.js | 96 +++++ .../CellScience/moveVesiclesAC.js | 106 +++++ 8 files changed, 212 insertions(+), 777 deletions(-) delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js delete mode 100644 unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js create mode 100644 unpublishedScripts/DomainContent/CellScience/moveCellsAC.js create mode 100644 unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js deleted file mode 100644 index cf4ee810e7..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/colorRandomly.js +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2016 High Fidelity, Inc. -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -(function() { - - Script.include(Script.resolvePath('virtualBaton.js')); - - var self = this; - - var baton; - var iOwn = false; - var currentInterval; - var _entityId; - - function startUpdate() { - iOwn = true; - print('i am the owner ' + _entityId) - } - - function stopUpdateAndReclaim() { - print('i released the object ' + _entityId) - iOwn = false; - baton.claim(startUpdate, stopUpdateAndReclaim); - } - - this.preload = function(entityId) { - this.isConnected = false; - this.entityId = entityId; - _entityId = entityId; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity - }); - stopUpdateAndReclaim(); - currentInterval = Script.setInterval(self.move, self.getTotalWait()) - } - - - this.getTotalWait = function() { - return (Math.random() * 5000) * 2; - // var avatars = AvatarList.getAvatarIdentifiers(); - // var avatarCount = avatars.length; - // var random = Math.random() * 5000; - // var totalWait = random * (avatarCount * 2); - // print('cellscience color avatarcount, totalwait: ', avatarCount, totalWait) - // return totalWait - } - - - this.move = function() { - if (!iOwn) { - return; - } - - var properties = Entities.getEntityProperties(self.entityId); - var color = properties.color; - - var newColor; - var red = { - red: 255, - green: 0, - blue: 0 - } - var green = { - red: 0, - green: 255, - blue: 0 - } - var blue = { - red: 0, - green: 0, - blue: 255 - } - if (color.red > 0) { - newColor = green; - } - if (color.green > 0) { - newColor = blue; - } - if (color.blue > 0) { - newColor = red - } - Entities.editEntity(self.entityId, { - color: newColor - }); - - - } - - - this.unload = function() { - baton.release(function() {}); - Script.clearTimeout(currentInterval); - } - - - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js b/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js deleted file mode 100644 index ec7b249db0..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/moveRandomly2.js +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2016 High Fidelity, Inc. -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -(function() { - - Script.include('virtualBaton.js'); - - var self = this; - - var baton; - var iOwn = false; - var currentInterval; - var _entityId; - - function startUpdate() { - iOwn = true; - print('i am the owner ' + _entityId) - } - - function stopUpdateAndReclaim() { - print('i released the object ' + _entityId) - iOwn = false; - baton.claim(startUpdate, stopUpdateAndReclaim); - } - - this.preload = function(entityId) { - this.isConnected = false; - this.entityId = entityId; - _entityId = entityId; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.01; - this.maxAngularVelocity = 0.03; - baton = virtualBaton({ - batonName: 'io.highfidelity.vesicles:' + entityId, // One winner for each entity - }); - stopUpdateAndReclaim(); - currentInterval = Script.setInterval(self.move, self.getTotalWait()) - } - - - this.getTotalWait = function() { - return (Math.random() * 5000) * 2; - } - - - this.move = function() { - if (!iOwn) { - return; - } - - var magnitudeV = self.maxVelocity; - var directionV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - - //print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); - - var magnitudeAV = self.maxAngularVelocity; - - var directionAV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - //print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); - Entities.editEntity(self.entityId, { - velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), - angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) - - }); - - - } - - - this.unload = function() { - if (baton) { - baton.release(function() {}); - } - Script.clearInterval(currentInterval); - } - - - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js index 6651e435b4..8ee5e0092e 100644 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js +++ b/unpublishedScripts/DomainContent/CellScience/Scripts/showButtonToPlaySound.js @@ -36,8 +36,6 @@ return; } - - self.addButton(); self.buttonShowing = false; self.showDistance = self.userData.showDistance; @@ -51,8 +49,6 @@ }; self.sound = SoundCache.getSound(this.soundURL); - - } this.addButton = function() { diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js b/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js deleted file mode 100644 index 63f96a5c1e..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/virtualBaton.js +++ /dev/null @@ -1,381 +0,0 @@ -"use strict"; -/*jslint nomen: true, plusplus: true, vars: true */ -/*global Messages, Script, MyAvatar, AvatarList, Entities, print */ - -// Created by Howard Stearns -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -// Allows cooperating scripts to pass a "virtual baton" between them, -// which is useful when part of a script should only be executed by -// the one participant that is holding this particular baton. -// -// A virtual baton is simply any string agreed upon by the scripts -// that use it. Only one script at a time can hold the baton, and it -// holds it until that script releases it, or the other scripts -// determine that the holding script is not responding. The script -// automatically determines who among claimants has the baton, if anyone, -// and holds an "election" if necessary. -// -// See entityScript/tribble.js as an example, and the functions -// virtualBaton(), claim(), release(). -// - -// Answers a new virtualBaton for the given parameters, of which 'key' -// is required. -function virtualBatonf(options) { - // Answer averages (number +/- variability). Avoids having everyone act in lockstep. - function randomize(number, variability) { - var allowedDeviation = number * variability; // one side of the deviation range - var allowedDeviationRange = allowedDeviation * 2; // total range for +/- deviation - var randomDeviation = Math.random() * allowedDeviationRange; - var result = number - allowedDeviation + randomDeviation; - return result; - } - // Allow testing outside in a harness outside of High Fidelity. - // See sourceCodeSandbox/tests/mocha/test/testVirtualBaton.js - var globals = options.globals || {}, - messages = globals.Messages || Messages, - myAvatar = globals.MyAvatar || MyAvatar, - avatarList = globals.AvatarList || AvatarList, - entities = globals.Entities || Entities, - timers = globals.Script || Script, - log = globals.print || print; - - var batonName = options.batonName, // The identify of the baton. - // instanceId is the identify of this particular copy of the script among all copies using the same batonName - // in the domain. For example, if you wanted only one entity among multiple entity scripts to hold the baton, - // you could specify virtualBaton({batonName: 'someBatonName', instanceId: MyAvatar.sessionUUID + entityID}). - instanceId = options.instanceId || myAvatar.sessionUUID, - // virtualBaton() returns the exports object with properties. You can pass in an object to be side-effected. - exports = options.exports || {}, - // Handy to set false if we believe the optimizations are wrong, or to use both values in a test harness. - useOptimizations = (options.useOptimizations === undefined) ? true : options.useOptimizations, - electionTimeout = options.electionTimeout || randomize(500, 0.2), // ms. If no winner in this time, hold a new election. - recheckInterval = options.recheckInterval || randomize(500, 0.2), // ms. Check that winners remain connected. - // If you supply your own instanceId, you might also supply a connectionTest that answers - // truthy iff the given id is still valid and connected, and is run at recheckInterval. You - // can use exports.validId (see below), and the default answers truthy if id is valid or a - // concatenation of two valid ids. (This handles the most common cases of instanceId being - // either (the default) MyAvatar.sessionUUID, an entityID, or the concatenation (in either - // order) of both.) - connectionTest = options.connectionTest || function connectionTest(id) { - var idLength = 38; - if (id.length === idLength) { - return exports.validId(id); - } - return (id.length === 2 * idLength) && exports.validId(id.slice(0, idLength)) && exports.validId(id.slice(idLength)); - }; - - if (!batonName) { - throw new Error("A virtualBaton must specify a batonName."); - } - // Truthy if id exists as either a connected avatar or valid entity. - exports.validId = function validId(id) { - var avatar = avatarList.getAvatar(id); - if (avatar && (avatar.sessionUUID === id)) { - return true; - } - var properties = entities.getEntityProperties(id, ['type']); - return properties && properties.type; - }; - - // Various logging, controllable through options. - function debug() { // Display the arguments not just [Object object]. - log.apply(null, [].map.call(arguments, JSON.stringify)); - } - function debugFlow() { - if (options.debugFlow) { - debug.apply(null, arguments); - } - } - function debugSend(destination, operation, data) { - if (options.debugSend) { - debug('baton:', batonName, instanceId, 's=>', destination, operation, data); - } - } - function debugReceive(senderID, operation, data) { // senderID is client sessionUUID -- not necessarily instanceID! - if (options.debugReceive) { - debug('baton:', batonName, senderID, '=>r', instanceId, operation, data); - } - } - - // Messages: Just synactic sugar for hooking things up to Messages system. - // We create separate subchannel strings for each operation within our general channelKey, instead of using - // a switch in the receiver. - var channelKey = "io.highfidelity.virtualBaton:" + batonName, - subchannelHandlers = {}, // Message channel string => {receiver, op} - subchannelKeys = {}; // operation => Message channel string - function subchannelKey(operation) { - return channelKey + ':' + operation; - } - function receive(operation, handler) { // Record a handler for an operation on our channelKey - var subKey = subchannelKey(operation); - subchannelHandlers[subKey] = {receiver: handler, op: operation}; - subchannelKeys[operation] = subKey; - messages.subscribe(subKey); - } - function sendHelper(subchannel, data) { - var message = JSON.stringify(data); - messages.sendMessage(subchannel, message); - } - function send1(operation, destination, data) { // Send data for an operation to just one destination on our channelKey. - debugSend(destination, operation, data); - sendHelper(subchannelKey(operation) + destination, data); - } - function send(operation, data) { // Send data for an operation on our channelKey. - debugSend('-', operation, data); - sendHelper(subchannelKeys[operation], data); - } - function messageHandler(channel, messageString, senderID) { - var handler = subchannelHandlers[channel]; - if (!handler) { - return; - } - var data = JSON.parse(messageString); - debugReceive(senderID, handler.op, data); - handler.receiver(data); - } - messages.messageReceived.connect(messageHandler); - - var nPromises = 0, nAccepted = 0, electionWatchdog; - - // It would be great if we had a way to know how many subscribers our channel has. Failing that... - var nNack = 0, previousNSubscribers = 0, lastGathering = 0, thisTimeout = electionTimeout; - function nSubscribers() { // Answer the number of subscribers. - // To find nQuorum, we need to know how many scripts are being run using this batonName, which isn't - // the same as the number of clients! - // - // If we overestimate by too much, we may fail to reach consensus, which triggers a new - // election proposal, so we take the number of acceptors to be the max(nPromises, nAccepted) - // + nNack reported in the previous round. - // - // If we understimate by too much, there can be different pockets on the Internet that each - // believe they have agreement on different holders of the baton, which is precisely what - // the virtualBaton is supposed to avoid. Therefore we need to allow 'nack' to gather stragglers. - - var now = Date.now(), elapsed = now - lastGathering; - if (elapsed >= thisTimeout) { - previousNSubscribers = Math.max(nPromises, nAccepted) + nNack; - lastGathering = now; - } // ...otherwise we use the previous value unchanged. - - // On startup, we do one proposal that we cannot possibly close, so that we'll - // lock things up for the full electionTimeout to gather responses. - if (!previousNSubscribers) { - var LARGE_INTEGER = Number.MAX_SAFE_INTEGER || (-1 >>> 1); // QT doesn't define the ECMA constant. Max int will do for our purposes. - previousNSubscribers = LARGE_INTEGER; - } - return previousNSubscribers; - } - - // MAIN ALGORITHM - // - // Internally, this uses the Paxos algorith to hold elections. - // Alternatively, we could have the message server pick and maintain a winner, but it would - // still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages. - // Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer - // (such as the server). - function betterNumber(number, best) { - return (number.number || 0) > best.number; - } - // Paxos Proposer behavior - var proposalNumber = 0, - nQuorum = 0, - bestPromise = {number: 0}, - claimCallback, - releaseCallback; - function propose() { // Make a new proposal, so that we learn/update the proposalNumber and winner. - // Even though we send back a 'nack' if the proposal is obsolete, with network errors - // there's no way to know for certain that we've failed. The electionWatchdog will try a new - // proposal if we have not been accepted by a quorum after election Timeout. - if (electionWatchdog) { - // If we had a means of determining nSubscribers other than by counting, we could just - // timers.clearTimeout(electionWatchdog) and not return. - return; - } - thisTimeout = randomize(electionTimeout, 0.5); // Note use in nSubcribers. - electionWatchdog = timers.setTimeout(function () { - electionWatchdog = null; - propose(); - }, thisTimeout); - var nAcceptors = nSubscribers(); - nQuorum = Math.floor(nAcceptors / 2) + 1; - - proposalNumber = Math.max(proposalNumber, bestPromise.number) + 1; - debugFlow('baton:', batonName, instanceId, 'propose', proposalNumber, - 'claim:', !!claimCallback, 'nAcceptors:', nAcceptors, nPromises, nAccepted, nNack); - nPromises = nAccepted = nNack = 0; - send('prepare!', {number: proposalNumber, proposerId: instanceId}); - } - // We create a distinguished promise subchannel for our id, because promises need only be sent to the proposer. - receive('promise' + instanceId, function (data) { - if (betterNumber(data, bestPromise)) { - bestPromise = data; - } - if ((data.proposalNumber === proposalNumber) && (++nPromises >= nQuorum)) { // Note check for not being a previous round - var answer = {number: data.proposalNumber, proposerId: data.proposerId, winner: bestPromise.winner}; // Not data.number. - if (!answer.winner || (answer.winner === instanceId)) { // We get to pick. - answer.winner = claimCallback ? instanceId : null; - } - send('accept!', answer); - } - }); - receive('nack' + instanceId, function (data) { // An acceptor reports more recent data... - if (data.proposalNumber === proposalNumber) { - nNack++; // For updating nQuorum. - // IWBNI if we started our next proposal right now/here, but we need a decent nNack count. - // Lets save that optimization for another day... - } - }); - // Paxos Acceptor behavior - var bestProposal = {number: 0}, accepted = {}; - function acceptedId() { - return accepted && accepted.winner; - } - receive('prepare!', function (data) { - var response = {proposalNumber: data.number, proposerId: data.proposerId}; - if (betterNumber(data, bestProposal)) { - bestProposal = data; - if (accepted.winner && connectionTest(accepted.winner)) { - response.number = accepted.number; - response.winner = accepted.winner; - } - send1('promise', data.proposerId, response); - } else { - send1('nack', data.proposerId, response); - } - }); - receive('accept!', function (data) { - if (!betterNumber(bestProposal, data)) { - bestProposal = accepted = data; // Update both with current data. Might have missed the proposal earlier. - if (useOptimizations) { - // The Paxos literature describes every acceptor sending 'accepted' to - // every proposer and learner. In our case, these are the same nodes that received - // the 'accept!' message, so we can send to just the originating proposer and invoke - // our own accepted handler directly. - // Note that this optimization cannot be used with Byzantine Paxos (which needs another - // multi-broadcast to detect lying and collusion). - debugSend('/', 'accepted', data); - debugReceive(instanceId, 'accepted', data); // direct on next line, which doesn't get logging. - subchannelHandlers[subchannelKey('accepted') + instanceId].receiver(data); - if (data.proposerId !== instanceId) { // i.e., we didn't already do it directly on the line above. - send1('accepted', data.proposerId, data); - } - } else { - send('accepted', data); - } - } else { - send1('nack', data.proposerId, {proposalNumber: data.number}); - } - }); - // Paxos Learner behavior. - function localRelease() { - var callback = releaseCallback; - debugFlow('baton:', batonName, 'localRelease', 'callback:', !!releaseCallback); - if (!releaseCallback) { - return; - } // Already released, but we might still receive a stale message. That's ok. - releaseCallback = undefined; - callback(batonName); // Pass batonName so that clients may use the same handler for different batons. - } - receive('accepted' + (useOptimizations ? instanceId : ''), function (data) { // See note in 'accept!' regarding use of instanceId here. - if (betterNumber(accepted, data)) { // Especially when !useOptimizations, we can receive other acceptances late. - return; - } - var oldAccepted = accepted; - debugFlow('baton:', batonName, instanceId, 'accepted', data.number, data.winner); - accepted = data; - // If we are proposer, make sure we get a quorum of acceptances. - if ((data.proposerId === instanceId) && (data.number === proposalNumber) && (++nAccepted >= nQuorum)) { - if (electionWatchdog) { - timers.clearTimeout(electionWatchdog); - electionWatchdog = null; - } - } - // If we are the winner -- regardless of whether we were the proposer. - if (acceptedId() === instanceId) { - if (claimCallback) { - var callback = claimCallback; - claimCallback = undefined; - callback(batonName); - } else if (!releaseCallback) { // We won, but have been released and are no longer interested. - // Propose that someone else take the job. - timers.setTimeout(propose, 0); // Asynchronous to queue message handling if some are synchronous and others not. - } - } else if (releaseCallback && (oldAccepted.winner === instanceId)) { // We've been released by someone else! - localRelease(); // This can happen if enough people thought we'd disconnected. - } - }); - - // Public Interface - // - // Registers an intent to hold the baton: - // Calls onElection(batonName) once, if you are elected by the scripts - // to be the unique holder of the baton, which may be never. - // Calls onRelease(batonName) once, if the baton held by you is released, - // whether this is by you calling release(), or by losing - // an election when you become disconnected. - // You may claim again at any time after the start of onRelease - // being called. - exports.claim = function claim(onElection, onRelease) { - debugFlow('baton:', batonName, instanceId, 'claim'); - if (claimCallback) { - log("Ignoring attempt to claim virtualBaton " + batonName + ", which is already waiting for claim."); - return; - } - if (releaseCallback) { - log("Ignoring attempt to claim virtualBaton " + batonName + ", which is somehow incorrect released, and that should not happen."); - return; - } - claimCallback = onElection; - releaseCallback = onRelease; - propose(); - return exports; // Allows chaining. e.g., var baton = virtualBaton({batonName: 'foo'}.claim(onClaim, onRelease); - }; - // Release the baton you hold, or just log that you are not holding it. - exports.release = function release(optionalReplacementOnRelease) { - debugFlow('baton:', batonName, instanceId, 'release'); - if (optionalReplacementOnRelease) { // If you want to change. - releaseCallback = optionalReplacementOnRelease; - } - if (acceptedId() !== instanceId) { - log("Ignoring attempt to release virtualBaton " + batonName + ", which is not being held."); - return; - } - localRelease(); - if (!claimCallback) { // No claim set in release callback. - propose(); - } - return exports; - }; - exports.recheckWatchdog = timers.setInterval(function recheck() { - var holder = acceptedId(); // If we're waiting and we notice the holder is gone, ... - if (holder && claimCallback && !electionWatchdog && !connectionTest(holder)) { - bestPromise.winner = null; // used if the quorum agrees that old winner is not there - propose(); // ... propose an election. - } - }, recheckInterval); - exports.unload = function unload() { // Disconnect from everything. - messages.messageReceived.disconnect(messageHandler); - timers.clearInterval(exports.recheckWatchdog); - if (electionWatchdog) { - timers.clearTimeout(electionWatchdog); - } - electionWatchdog = claimCallback = releaseCallback = null; - Object.keys(subchannelHandlers).forEach(messages.unsubscribe); - debugFlow('baton:', batonName, instanceId, 'unload'); - return exports; - }; - - // Gather nAcceptors by making two proposals with some gathering time, even without a claim. - propose(); - return exports; -} -if (typeof module !== 'undefined') { // Allow testing in nodejs. - module.exports = virtualBatonf; -} else { - virtualBaton = virtualBatonf; -} diff --git a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js b/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js deleted file mode 100644 index dd6a48c617..0000000000 --- a/unpublishedScripts/DomainContent/CellScience/Scripts/zoomAndMoveRandomly.js +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2016 High Fidelity, Inc. -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { - var teleport; - var portalDestination; - var animationURL; - - this.entered = true; - Script.include('virtualBaton.js'); - - var self = this; - var baton; - - this.iOwn = false; - var currentInterval; - var _entityId; - - function startUpdate() { - self.iOwn = true; - print('i am the owner ' + _entityId) - } - - function stopUpdateAndReclaim() { - print('i released the object ' + _entityId) - self.iOwn = false; - baton.claim(startUpdate, stopUpdateAndReclaim); - } - - this.preload = function(entityID) { - this.entityId = entityID; - _entityId = entityID; - this.initialize(entityID); - this.initTimeout = null; - this.minVelocity = 1; - this.maxVelocity = 5; - this.minAngularVelocity = 0.03; - this.maxAngularVelocity = 0.10; - baton = virtualBaton({ - batonName: 'io.highfidelity.cells:' + entityID, // One winner for each entity - }); - stopUpdateAndReclaim(); - currentInterval = Script.setInterval(self.move, self.getTotalWait()) - - } - - this.initialize = function(entityID) { - // print(' should initialize') - var properties = Entities.getEntityProperties(entityID); - if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { - self.initTimeout = Script.setTimeout(function() { - // print(' no user data yet, try again in one second') - self.initialize(entityID); - }, 1000) - } else { - // print(' has userData') - self.portalDestination = properties.userData; - animationURL = properties.modelURL; - self.soundOptions = { - stereo: true, - loop: false, - localOnly: false, - position: properties.position, - volume: 0.5 - }; - - self.teleportSound = SoundCache.getSound("https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Audio/whoosh.wav"); - - } - } - - this.enterEntity = function(entityID) { - //print('ENTERED A BOUNDARY ENTITY, SHOULD ZOOM', entityID) - var data = JSON.parse(Entities.getEntityProperties(this.entityId).userData); - //print('DATA IS::' + data) - if (data != null) { - print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); - - MyAvatar.position = data.location; - } - - } - - this.lookAtTarget = function(entryPoint, target) { - //print('SHOULD LOOK AT TARGET') - var direction = Vec3.normalize(Vec3.subtract(entryPoint, target)); - var pitch = Quat.angleAxis(Math.asin(-direction.y) * 180.0 / Math.PI, { - x: 1, - y: 0, - z: 0 - }); - var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * 180.0 / Math.PI, { - x: 0, - y: 1, - z: 0 - }); - - MyAvatar.goToLocation(entryPoint, true, yaw); - - MyAvatar.headYaw = 0; - - } - - this.leaveEntity = function(entityID) { - Entities.editEntity(entityID, { - animationURL: animationURL, - animationSettings: '{ "frameIndex": 1, "running": false }' - }); - this.entered = false; - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - //playSound(); - } - - this.unload = function() { - if (this.initTimeout !== null) { - Script.clearTimeout(this.initTimeout); - } - if (baton) { - baton.release(function() {}); - } - - Script.clearInterval(currentInterval); - } - - this.hoverEnterEntity = function(entityID) { - Entities.editEntity(entityID, { - animationURL: animationURL, - animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }' - }); - } - - this.getTotalWait = function() { - return (Math.random() * 5000) * 3; - } - - this.move = function() { - if (self.iOwn === false) { - print('cell is not owned by me...') - return; - } - - var magnitudeAV = self.maxAngularVelocity; - - var directionAV = { - x: Math.random() - 0.5, - y: Math.random() - 0.5, - z: Math.random() - 0.5 - }; - // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); - Entities.editEntity(self.entityId, { - angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) - - }); - - - } - -}) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 25323495d1..55b09cd4a7 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -120,7 +120,7 @@ var scenes = [{ location: locations.cellLayout[1], baseURL: baseLocation }), - script: "zoomAndMoveRandomly.js?" + version, + script: "zoom.js?" + version, visible: true }], boundary: { @@ -194,7 +194,6 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true }, { //golgi vesicles model: "vesicle", @@ -238,7 +237,6 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true }, { model: "vesicle", @@ -304,7 +302,6 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true }, { //outer vesicles model: "vesicle", @@ -326,32 +323,8 @@ var scenes = [{ grabbable: false } }), - script: "moveRandomly2.js?" + version, visible: true - }, - // {//wigglies - // model:"wiggly", - // dimensions:{x:320,y:40,z:160}, - // randomSize: 10, - // offset:{x:0,y:0,z:0}, - // radius:1800, - // number:50, - // userData:"", - // script:"moveRandomly", - // visible:true - // }, - //// {//wigglies - // model:"wiggly", - // dimensions:{x:640,y:80,z:320}, - // randomSize: 10, - // offset:{x:0,y:0,z:0}, - // radius:2100, - // number:50, - // userData:"", - // script:"moveRandomly", - // visible:true - // }, - { + }, { model: "hexokinase", dimensions: { x: 3, @@ -813,7 +786,7 @@ function CreateInstances(scene) { x: 0, y: 0, z: 0 - }, idBounds, 150); + }, idBounds, 150, scene.instances[i]); } //print('SCRIPT AT CREATE ENTITY: ' + script) @@ -824,8 +797,11 @@ function CreateInstances(scene) { -function CreateIdentification(name, position, rotation, dimensions, showDistance) { +function CreateIdentification(name, position, rotation, dimensions, showDistance, parentID) { //print ("creating ID for " + name); + if (parentID === undefined) { + parentID = "{00000000-0000-0000-0000-000000000000}"; + } Entities.addEntity({ type: "Sphere", name: "ID for " + name, @@ -834,6 +810,7 @@ function CreateIdentification(name, position, rotation, dimensions, showDistance green: 0, blue: 0 }, + parentID: parentID, dimensions: dimensions, position: position, rotation: rotation, @@ -9042,7 +9019,7 @@ Script.scriptEnding.connect(function() { Entities.addingEntity.disconnect(makeUngrabbable); }); -Script.setTimeout(function(){ +Script.setTimeout(function() { print('JBP stopping cell science import'); Script.stop(); -},30000) \ No newline at end of file +}, 30000) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js new file mode 100644 index 0000000000..30e83108d6 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -0,0 +1,96 @@ +var basePosition = { + x: 3000, + y: 13500, + z: 3000 +}; + +var initialized = false; + +EntityViewer.setPosition(basePosition); +EntityViewer.setKeyholeRadius(60000); +var octreeQueryInterval = Script.setInterval(function() { + EntityViewer.queryOctree(); +}, 200); + +var THROTTLE = true; +var THROTTLE_RATE = 5000; + +var sinceLastUpdate = 0; + +print('cells script') + +function findCells() { + var results = Entities.findEntities(basePosition, 60000); + + if (results.length === 0) { + print('no entities found') + return; + } + + results.forEach(function(v) { + var name = Entities.getEntityProperties(v, 'name').name; + print('name is:: ' + name) + if (name === 'Cell') { + print('found a cell!!' + v) + Script.setTimeout(function() { + moveCell(v); + }, Math.random() * THROTTLE_RATE) + } + }); +} + + +var minAngularVelocity = 0.01; +var maxAngularVelocity = 0.03; + +function moveCell(entityId) { + print('moving a cell! ' + entityId) + + var magnitudeAV = maxAngularVelocity; + + var directionAV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + Entities.editEntity(entityId, { + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + }); + +} + +function update(deltaTime) { + + // print('deltaTime',deltaTime) + if (!initialized) { + print("checking for servers..."); + if (Entities.serversExist() && Entities.canRez()) { + print("servers exist -- makeAll..."); + Entities.setPacketsPerSecond(6000); + print("PPS:" + Entities.getPacketsPerSecond()); + initialized = true; + } + return; + } + + if (THROTTLE === true) { + sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; + if (sinceLastUpdate > THROTTLE_RATE) { + print('SHOULD FIND CELLS!!!') + sinceLastUpdate = 0; + findCells(); + } else { + // print('returning in update ' + sinceLastUpdate) + return; + } + } + +} + +function unload() { + Script.update.disconnect(update); +} + +Script.update.connect(update); +Script.scriptEnding.connect(unload); \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js new file mode 100644 index 0000000000..ce8da54eb2 --- /dev/null +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -0,0 +1,106 @@ +var basePosition = { + x: 3000, + y: 13500, + z: 3000 +}; + +var initialized = false; + +EntityViewer.setPosition(basePosition); +EntityViewer.setKeyholeRadius(60000); +var octreeQueryInterval = Script.setInterval(function() { + EntityViewer.queryOctree(); +}, 200); + +var THROTTLE = true; +var THROTTLE_RATE = 5000; + +var sinceLastUpdate = 0; + +print('vesicle script') + +function findVesicles() { + var results = Entities.findEntities(basePosition, 60000); + + if (results.length === 0) { + print('no entities found') + return; + } + + results.forEach(function(v) { + var name = Entities.getEntityProperties(v, 'name').name; + print('name is:: ' + name) + if (name === 'vesicle') { + print('found a vesicle!!' + v) + Script.setTimeout(function() { + moveVesicle(v); + }, Math.random() * THROTTLE_RATE) + } + }); +} + +var minVelocity = 1; +var maxVelocity = 5; +var minAngularVelocity = 0.01; +var maxAngularVelocity = 0.03; + +function moveVesicle(entityId) { + print('moving a vesicle! ' + entityId) + var magnitudeV = maxVelocity; + var directionV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + + print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); + + var magnitudeAV = maxAngularVelocity; + + var directionAV = { + x: Math.random() - 0.5, + y: Math.random() - 0.5, + z: Math.random() - 0.5 + }; + print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + Entities.editEntity(entityId, { + velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), + angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) + }); + +} + +function update(deltaTime) { + + // print('deltaTime',deltaTime) + if (!initialized) { + print("checking for servers..."); + if (Entities.serversExist() && Entities.canRez()) { + print("servers exist -- makeAll..."); + Entities.setPacketsPerSecond(6000); + print("PPS:" + Entities.getPacketsPerSecond()); + initialized = true; + } + return; + } + + if (THROTTLE === true) { + sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; + if (sinceLastUpdate > THROTTLE_RATE) { + print('SHOULD FIND VESICLES!!!') + sinceLastUpdate = 0; + findVesicles(); + } else { + // print('returning in update ' + sinceLastUpdate) + return; + } + } + +} + +function unload() { + Script.update.disconnect(update); +} + +Script.update.connect(update); +Script.scriptEnding.connect(unload); \ No newline at end of file From baa030b7b07a24612953807d5a116398e8354f17 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 24 Feb 2016 13:18:01 -0800 Subject: [PATCH 060/292] cleanup and submit --- .../CellScience/importCellScience.js | 2 +- .../DomainContent/CellScience/moveCellsAC.js | 21 ++++++++++++------- .../CellScience/moveVesiclesAC.js | 20 +++++++++++------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 55b09cd4a7..6a6de23f4e 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1057; +var version = 1100; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js index 30e83108d6..881f8e981c 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -1,3 +1,10 @@ +// Copyright 2016 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + var basePosition = { x: 3000, y: 13500, @@ -17,21 +24,21 @@ var THROTTLE_RATE = 5000; var sinceLastUpdate = 0; -print('cells script') +//print('cells script') function findCells() { var results = Entities.findEntities(basePosition, 60000); if (results.length === 0) { - print('no entities found') + // print('no entities found') return; } results.forEach(function(v) { var name = Entities.getEntityProperties(v, 'name').name; - print('name is:: ' + name) + // print('name is:: ' + name) if (name === 'Cell') { - print('found a cell!!' + v) + // print('found a cell!!' + v) Script.setTimeout(function() { moveCell(v); }, Math.random() * THROTTLE_RATE) @@ -44,7 +51,7 @@ var minAngularVelocity = 0.01; var maxAngularVelocity = 0.03; function moveCell(entityId) { - print('moving a cell! ' + entityId) + // print('moving a cell! ' + entityId) var magnitudeAV = maxAngularVelocity; @@ -53,7 +60,7 @@ function moveCell(entityId) { y: Math.random() - 0.5, z: Math.random() - 0.5 }; - print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(entityId, { angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); @@ -77,7 +84,7 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - print('SHOULD FIND CELLS!!!') + // print('SHOULD FIND CELLS!!!') sinceLastUpdate = 0; findCells(); } else { diff --git a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js index ce8da54eb2..3e70934cba 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -1,3 +1,10 @@ +// Copyright 2016 High Fidelity, Inc. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + var basePosition = { x: 3000, y: 13500, @@ -17,7 +24,7 @@ var THROTTLE_RATE = 5000; var sinceLastUpdate = 0; -print('vesicle script') +//print('vesicle script') function findVesicles() { var results = Entities.findEntities(basePosition, 60000); @@ -31,7 +38,7 @@ function findVesicles() { var name = Entities.getEntityProperties(v, 'name').name; print('name is:: ' + name) if (name === 'vesicle') { - print('found a vesicle!!' + v) + // print('found a vesicle!!' + v) Script.setTimeout(function() { moveVesicle(v); }, Math.random() * THROTTLE_RATE) @@ -45,7 +52,7 @@ var minAngularVelocity = 0.01; var maxAngularVelocity = 0.03; function moveVesicle(entityId) { - print('moving a vesicle! ' + entityId) + // print('moving a vesicle! ' + entityId) var magnitudeV = maxVelocity; var directionV = { x: Math.random() - 0.5, @@ -53,7 +60,7 @@ function moveVesicle(entityId) { z: Math.random() - 0.5 }; - print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); + // print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x); var magnitudeAV = maxAngularVelocity; @@ -62,7 +69,7 @@ function moveVesicle(entityId) { y: Math.random() - 0.5, z: Math.random() - 0.5 }; - print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(entityId, { velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)), angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) @@ -71,7 +78,6 @@ function moveVesicle(entityId) { } function update(deltaTime) { - // print('deltaTime',deltaTime) if (!initialized) { print("checking for servers..."); @@ -87,7 +93,7 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - print('SHOULD FIND VESICLES!!!') + // print('SHOULD FIND VESICLES!!!') sinceLastUpdate = 0; findVesicles(); } else { From a0d7ce145e90a689ebb26b527d4ec9bcac9bc403 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 24 Feb 2016 17:30:29 -0800 Subject: [PATCH 061/292] Adding support for emissive and occlusion maps, on to pr land --- .../utilities/tools/render/framebuffer.qml | 3 +- libraries/fbx/src/FBXReader_Material.cpp | 8 +++ .../src/model-networking/ModelCache.cpp | 9 ++++ .../src/model-networking/ModelCache.h | 2 + .../src/model-networking/TextureCache.h | 4 +- libraries/model/src/model/Material.cpp | 1 + libraries/model/src/model/Material.h | 9 ++++ libraries/model/src/model/Material.slh | 3 +- .../render-utils/src/DebugDeferredBuffer.cpp | 9 ++++ .../render-utils/src/DebugDeferredBuffer.h | 1 + libraries/render-utils/src/DeferredBuffer.slh | 27 +--------- .../render-utils/src/DeferredBufferWrite.slh | 10 ++-- .../render-utils/src/DeferredGlobalLight.slh | 17 ++++--- .../render-utils/src/MaterialTextures.slh | 51 ++++++++++++++++--- .../render-utils/src/MeshPartPayload.cpp | 36 ++++++++++--- .../src/directional_ambient_light.slf | 2 +- .../src/directional_ambient_light_shadow.slf | 2 +- .../render-utils/src/directional_light.slf | 2 +- .../src/directional_light_shadow.slf | 2 +- .../src/directional_skybox_light.slf | 2 +- .../src/directional_skybox_light_shadow.slf | 2 +- libraries/render-utils/src/model.slf | 25 ++++++--- libraries/render-utils/src/model_lightmap.slf | 6 +-- .../src/model_lightmap_normal_map.slf | 7 ++- .../model_lightmap_normal_specular_map.slf | 8 +-- .../src/model_lightmap_specular_map.slf | 10 ++-- .../render-utils/src/model_normal_map.slf | 27 +++++++--- .../src/model_normal_specular_map.slf | 22 ++++---- .../render-utils/src/model_specular_map.slf | 26 ++++++---- .../render-utils/src/model_translucent.slf | 4 +- libraries/render-utils/src/simple.slf | 2 +- .../render-utils/src/simple_textured.slf | 5 +- libraries/render/src/render/ShapePipeline.cpp | 6 ++- libraries/render/src/render/ShapePipeline.h | 6 ++- tests/gpu-test/src/unlit.slf | 2 +- 35 files changed, 241 insertions(+), 117 deletions(-) diff --git a/examples/utilities/tools/render/framebuffer.qml b/examples/utilities/tools/render/framebuffer.qml index 20b8b384d8..e31f986bc1 100644 --- a/examples/utilities/tools/render/framebuffer.qml +++ b/examples/utilities/tools/render/framebuffer.qml @@ -28,12 +28,13 @@ Column { model: [ "Off", "Depth", - "Diffuse", + "Albedo", "Normal", "Roughness", "Metallic", "Fresnel", "Emissive", + "Occlusion", "Lightmap", "Lighting", "Shadow", diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 2604d83423..188c50304d 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -149,6 +149,14 @@ void FBXReader::consolidateFBXMaterials() { material.emissiveTexture = emissiveTexture; } + FBXTexture occlusionTexture; + QString occlusionTextureID = occlusionTextures.value(material.materialID); + if (!occlusionTextureID.isNull()) { + occlusionTexture = getTexture(occlusionTextureID); + detectDifferentUVs |= (occlusionTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity()); + material.occlusionTexture = occlusionTexture; + } + glm::vec2 lightmapParams(0.f, 1.f); lightmapParams.x = _lightmapOffset; lightmapParams.y = _lightmapLevel; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2bb71ba855..7d59bb5028 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -363,6 +363,7 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); } if (!material.roughnessTexture.filename.isEmpty()) { + material.roughnessTexture.isGlossmap; networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), ROUGHNESS_TEXTURE, material.roughnessTexture.content); networkMaterial->roughnessTextureName = material.roughnessTexture.name; @@ -392,7 +393,15 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); } + if (!material.occlusionTexture.filename.isEmpty()) { + networkMaterial->occlusionTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.occlusionTexture.filename)), OCCLUSION_TEXTURE, material.occlusionTexture.content); + networkMaterial->occlusionTextureName = material.occlusionTexture.name; + auto occlusionMap = model::TextureMapPointer(new model::TextureMap()); + occlusionMap->setTextureSource(networkMaterial->occlusionTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::OCCLUSION_MAP, occlusionMap); + } return networkMaterial; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index c43a1e6d79..b517cc67ca 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -190,6 +190,8 @@ public: QSharedPointer roughnessTexture; QString emissiveTextureName; QSharedPointer emissiveTexture; + QString occlusionTextureName; + QSharedPointer occlusionTexture; QString lightmapTextureName; QSharedPointer lightmapTexture; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 2cfd225889..e9c232c4b6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -29,7 +29,9 @@ class NetworkTexture; typedef QSharedPointer NetworkTexturePointer; -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, ROUGHNESS_TEXTURE, EMISSIVE_TEXTURE, CUBE_TEXTURE, LIGHTMAP_TEXTURE, CUSTOM_TEXTURE }; +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, ROUGHNESS_TEXTURE, EMISSIVE_TEXTURE, + CUBE_TEXTURE, OCCLUSION_TEXTURE, LIGHTMAP_TEXTURE, CUSTOM_TEXTURE +}; /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache, public Dependency { diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 522debad59..10fa15edd5 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -58,6 +58,7 @@ void Material::setOpacity(float opacity) { void Material::setAlbedo(const Color& albedo, bool isSRGB) { _key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f)))); + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit()._albedo = (isSRGB ? ColorUtils::toLinearVec3(albedo) : albedo); } diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index a6b1cd3706..cdc3e4dc39 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -39,6 +39,7 @@ public: ROUGHNESS_MAP_BIT, TRANSPARENT_MAP_BIT, NORMAL_MAP_BIT, + OCCLUSION_MAP_BIT, LIGHTMAP_MAP_BIT, NUM_FLAGS, @@ -52,6 +53,7 @@ public: ROUGHNESS_MAP, TRANSPARENT_MAP, NORMAL_MAP, + OCCLUSION_MAP, LIGHTMAP_MAP, NUM_MAP_CHANNELS, @@ -83,6 +85,7 @@ public: Builder& withTransparentMap() { _flags.set(TRANSPARENT_MAP_BIT); return (*this); } Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); } + Builder& withOcclusionMap() { _flags.set(OCCLUSION_MAP_BIT); return (*this); } Builder& withLightmapMap() { _flags.set(LIGHTMAP_MAP_BIT); return (*this); } // Convenient standard keys that we will keep on using all over the place @@ -124,6 +127,9 @@ public: void setNormalMap(bool value) { _flags.set(NORMAL_MAP_BIT, value); } bool isNormalMap() const { return _flags[NORMAL_MAP_BIT]; } + void setOcclusionMap(bool value) { _flags.set(OCCLUSION_MAP_BIT, value); } + bool isOcclusionMap() const { return _flags[OCCLUSION_MAP_BIT]; } + void setLightmapMap(bool value) { _flags.set(LIGHTMAP_MAP_BIT, value); } bool isLightmapMap() const { return _flags[LIGHTMAP_MAP_BIT]; } @@ -182,6 +188,9 @@ public: Builder& withoutNormalMap() { _value.reset(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); } Builder& withNormalMap() { _value.set(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); } + Builder& withoutOcclusionMap() { _value.reset(MaterialKey::OCCLUSION_MAP_BIT); _mask.set(MaterialKey::OCCLUSION_MAP_BIT); return (*this); } + Builder& withOcclusionMap() { _value.set(MaterialKey::OCCLUSION_MAP_BIT); _mask.set(MaterialKey::OCCLUSION_MAP_BIT); return (*this); } + Builder& withoutLightmapMap() { _value.reset(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); } Builder& withLightmapMap() { _value.set(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); } diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index ac5d750bdd..d75f3df5e0 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -52,8 +52,9 @@ const int METALLIC_MAP_BIT = 0x00000080; const int ROUGHNESS_MAP_BIT = 0x00000100; const int TRANSPARENT_MAP_BIT = 0x00000200; const int NORMAL_MAP_BIT = 0x00000400; +const int OCCLUSION_MAP_BIT = 0x00000800; -const int LIGHTMAP_MAP_BIT = 0x00000800; +const int LIGHTMAP_MAP_BIT = 0x00001000; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 1126023f41..2360b6310f 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -85,6 +85,13 @@ static const std::string DEFAULT_NORMAL_SHADER { " }" }; +static const std::string DEFAULT_OCCLUSION_SHADER{ + "vec4 getFragmentColor() {" + " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + " return vec4(vec3(frag.obscurance), 1.0);" + " }" +}; + static const std::string DEFAULT_EMISSIVE_SHADER{ "vec4 getFragmentColor() {" " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" @@ -184,6 +191,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return DEFAULT_DEPTH_SHADER; case EmissiveMode: return DEFAULT_EMISSIVE_SHADER; + case OcclusionMode: + return DEFAULT_OCCLUSION_SHADER; case LightmapMode: return DEFAULT_LIGHTMAP_SHADER; case LightingMode: diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 0d72eeec8a..f4eacea5b6 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -54,6 +54,7 @@ protected: MetallicMode, FresnelMode, EmissiveMode, + OcclusionMode, LightmapMode, LightingMode, ShadowMode, diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index f35fc12d1f..bfed92018a 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -104,43 +104,20 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); frag.mode = 0; - frag.emissive = vec3(0.0); + frag.emissive = frag.specularVal.xyz; if (frag.normalVal.a < 0.5) { frag.mode = 0; frag.roughness = 2.0 * frag.normalVal.a; } else { frag.mode = LIGHT_MAPPED; frag.roughness = 2.0 * frag.normalVal.a - 1.0; - frag.emissive = frag.specularVal.xyz; } - - // if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - // frag.mode = LIGHT_MAPPED; - // frag.emissive = frag.specularVal.xyz; - // } frag.metallic = frag.diffuseVal.a; frag.diffuse = frag.diffuseVal.xyz; frag.specular = vec3(frag.metallic); - /* if (frag.metallic > 0.5) { - frag.diffuse = vec3(0); - //frag.metallic = length(frag.specularVal); - frag.specular = frag.diffuseVal.xyz; - - } else { - frag.diffuse = frag.diffuseVal.xyz; - //frag.metallic = length(frag.specularVal); - frag.specular = vec3(0.03); - } - */ - // frag.diffuse = frag.diffuseVal.xyz; - //frag.metallic = length(frag.specularVal); - //frag.specular = frag.specularVal.xyz; - - - //frag.roughness = frag.specularVal.w; + frag.obscurance = min(frag.specularVal.w, frag.obscurance); - return frag; } diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index a92ce1d26a..2a2c2883d3 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -44,25 +44,27 @@ const float DEFAULT_ROUGHNESS = 0.9; const float DEFAULT_SHININESS = 10; const float DEFAULT_METALLIC = 0; const vec3 DEFAULT_SPECULAR = vec3(0.1); +const vec3 DEFAULT_EMISSIVE = vec3(0.0); +const float DEFAULT_OCCLUSION = 1.0; -void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 fresnel) { +void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 emissive, float occlusion) { if (alpha != 1.0) { discard; } - // vec3 baseColor = ((metallic < 0.5) ? albedo : fresnel); _fragColor0 = vec4(albedo, metallic); _fragColor1 = vec4(bestFitNormal(normal), 0.5 * clamp(roughness, 0.0, 1.0)); - _fragColor2 = vec4(fresnel, roughness); + _fragColor2 = vec4(emissive, occlusion); } + void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 fresnel, vec3 emissive) { if (alpha != 1.0) { discard; } _fragColor0 = vec4(albedo, metallic); _fragColor1 = vec4(bestFitNormal(normal), 0.5 + 0.5 * clamp(roughness, 0.0, 1.0)); - _fragColor2 = vec4(emissive, roughness); + _fragColor2 = vec4(emissive, 1.0); } void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float roughness) { diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index de4eb746ef..a3fb1de3ec 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -30,7 +30,7 @@ vec4 evalSkyboxLight(vec3 direction, float lod) { <@include model/Light.slh@> <@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness) { +vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { // Need the light now Light light = getLight(); @@ -41,9 +41,11 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc vec3 color = albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); + + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); + color += emissive; return color; } @@ -52,7 +54,7 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc <@func declareEvalAmbientSphereGlobalColor()@> -vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness) { +vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { // Need the light now Light light = getLight(); @@ -64,10 +66,10 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), ambientNormal).xyz * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); - + color += emissive; return color; } <@endfunc@> @@ -76,7 +78,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa <$declareSkyboxMap()$> -vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 fresnel, float roughness) { +vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { // Need the light now Light light = getLight(); @@ -87,9 +89,10 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); + color += emissive; return color; } diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index ab58b7cff5..d0f2563d43 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -11,7 +11,7 @@ <@if not MODEL_MATERIAL_TEXTURES_SLH@> <@def MODEL_MATERIAL_TEXTURES_SLH@> -<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic)@> +<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion)@> <@if withAlbedo@> uniform sampler2D albedoMap; @@ -41,21 +41,40 @@ float fetchMetallicMap(vec2 uv) { } <@endif@> +<@if withEmissive@> +uniform sampler2D emissiveMap; +vec3 fetchEmissiveMap(vec2 uv) { + return texture(emissiveMap, uv).rgb; +} +<@endif@> + +<@if withOcclusion@> +uniform sampler2D occlusionMap; +float fetchOcclusionMap(vec2 uv) { + return texture(occlusionMap, uv).r; +} +<@endif@> <@endfunc@> -<@func fetchMaterialTextures(texcoord0, albedo, roughness, normal, metallic)@> +<@func fetchMaterialTextures(matKey, texcoord0, albedo, roughness, normal, metallic, emissive, occlusion)@> <@if albedo@> - vec4 <$albedo$> = fetchAlbedoMap(<$texcoord0$>); + vec4 <$albedo$> = (((<$matKey$> & ALBEDO_MAP_BIT) != 0) ? fetchAlbedoMap(<$texcoord0$>) : vec4(1.0)); <@endif@> <@if roughness@> - float <$roughness$> = fetchRoughnessMap(<$texcoord0$>); + float <$roughness$> = (((<$matKey$> & ROUGHNESS_MAP_BIT) != 0) ? fetchRoughnessMap(<$texcoord0$>) : 1.0); <@endif@> <@if normal@> - vec3 <$normal$> = fetchNormalMap(<$texcoord0$>); + vec3 <$normal$> = (((<$matKey$> & NORMAL_MAP_BIT) != 0) ? fetchNormalMap(<$texcoord0$>) : vec3(0.0, 1.0, 0.0)); <@endif@> <@if metallic@> - float <$metallic$> = fetchMetallicMap(<$texcoord0$>); + float <$metallic$> = (((<$matKey$> & METALLIC_MAP_BIT) != 0) ? fetchMetallicMap(<$texcoord0$>) : 0.0); +<@endif@> +<@if emissive@> + vec3 <$emissive$> = (((<$matKey$> & EMISSIVE_MAP_BIT) != 0) ? fetchEmissiveMap(<$texcoord0$>) : vec3(0.0)); +<@endif@> +<@if occlusion@> + float <$occlusion$> = (((<$matKey$> & OCCLUSION_MAP_BIT) != 0) ? fetchOcclusionMap(<$texcoord0$>) : 1.0); <@endif@> <@endfunc@> @@ -83,6 +102,15 @@ vec3 fetchLightmapMap(vec2 uv) { } <@endfunc@> +<@func evalMaterialAlbedo(fetchedAlbedo, materialAlbedo, matKey, albedo)@> +{ + <$albedo$>.xyz = (((<$matKey$> & ALBEDO_VAL_BIT) != 0) ? <$materialAlbedo$> : vec3(1.0)); + + if (((<$matKey$> & ALBEDO_MAP_BIT) != 0)) { + <$albedo$>.xyz *= <$fetchedAlbedo$>.xyz; + } +} +<@endfunc@> <@func evalMaterialRoughness(fetchedRoughness, materialRoughness, matKey, roughness)@> { @@ -96,5 +124,16 @@ vec3 fetchLightmapMap(vec2 uv) { } <@endfunc@> +<@func evalMaterialEmissive(fetchedEmissive, materialEmissive, matKey, emissive)@> +{ + <$emissive$> = (((<$matKey$> & EMISSIVE_MAP_BIT) != 0) ? <$fetchedEmissive$> : <$materialEmissive$>); +} +<@endfunc@> + +<@func evalMaterialOcclusion(fetchedOcclusion, matKey, occlusion)@> +{ + <$occlusion$> = <$fetchedOcclusion$>; +} +<@endfunc@> <@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index ab2a969637..8bba58eae2 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -193,22 +193,36 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isMetallicMap()) { auto specularMap = textureMaps[model::MaterialKey::METALLIC_MAP]; if (specularMap && specularMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::METALLIC_MAP, specularMap->getTextureView()); // texcoord are assumed to be the same has albedo } else { - batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slot::METALLIC_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::METALLIC_MAP, nullptr); } - // TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too + // Occlusion map + if (materialKey.isOcclusionMap()) { + auto specularMap = textureMaps[model::MaterialKey::OCCLUSION_MAP]; + if (specularMap && specularMap->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::OCCLUSION_MAP, specularMap->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::OCCLUSION_MAP, textureCache->getWhiteTexture()); + } + } else { + batch.setResourceTexture(ShapePipeline::Slot::OCCLUSION_MAP, nullptr); + } + + // Emissive / Lightmap if (materialKey.isLightmapMap()) { auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP]; if (lightmapMap && lightmapMap->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView()); + batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, lightmapMap->getTextureView()); auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale(); batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y); @@ -217,10 +231,18 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]); } } else { - batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture()); + batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, textureCache->getGrayTexture()); + } + } else if (materialKey.isEmissiveMap()) { + auto emissiveMap = textureMaps[model::MaterialKey::EMISSIVE_MAP]; + + if (emissiveMap && emissiveMap->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, emissiveMap->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, textureCache->getBlackTexture()); } } else { - batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, nullptr); + batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, nullptr); } // Texcoord transforms ? diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index 57f9c7e791..e1ec0d3ef0 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -45,7 +45,7 @@ void main(void) { frag.normal, frag.diffuse, frag.metallic, - frag.specular, + frag.emissive, frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/directional_ambient_light_shadow.slf b/libraries/render-utils/src/directional_ambient_light_shadow.slf index a4d897044b..963a10d579 100644 --- a/libraries/render-utils/src/directional_ambient_light_shadow.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow.slf @@ -47,7 +47,7 @@ void main(void) { frag.normal, frag.diffuse, frag.metallic, - frag.specular, + frag.emissive, frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index eed3b94c91..1a739f9389 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -46,7 +46,7 @@ void main(void) { frag.normal, frag.diffuse, frag.metallic, - frag.specular, + frag.emissive, frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/directional_light_shadow.slf b/libraries/render-utils/src/directional_light_shadow.slf index 494046bcb3..3b9b4d22c6 100644 --- a/libraries/render-utils/src/directional_light_shadow.slf +++ b/libraries/render-utils/src/directional_light_shadow.slf @@ -48,7 +48,7 @@ void main(void) { frag.normal, frag.diffuse, frag.metallic, - frag.specular, + frag.emissive, frag.roughness); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index 605d1de963..9e24a5f585 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -46,7 +46,7 @@ void main(void) { frag.normal, frag.diffuse, frag.metallic, - frag.specular, + frag.emissive, frag.roughness); _fragColor = vec4(color, frag.normalVal.a); diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index 75a48caacf..c3008b5509 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -48,7 +48,7 @@ void main(void) { frag.normal, frag.diffuse, frag.metallic, - frag.specular, + frag.emissive, frag.roughness); _fragColor = vec4(color, frag.normalVal.a); diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index b43694bbb7..c9ca6d9eb7 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -16,7 +16,7 @@ <@include model/Material.slh@> <@include MaterialTextures.slh@> -<$declareMaterialTextures(ALBEDO, ROUGHNESS)$> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> in vec4 _position; in vec3 _normal; @@ -25,15 +25,26 @@ in vec2 _texCoord0; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness)$> - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; packDeferredFragment( normalize(_normal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), - getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat) * roughness, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + albedo, + roughness, getMaterialMetallic(mat), - getMaterialFresnel(mat)); + emissive, + occlusionTex); } diff --git a/libraries/render-utils/src/model_lightmap.slf b/libraries/render-utils/src/model_lightmap.slf index bfe809f472..46d81d39e1 100755 --- a/libraries/render-utils/src/model_lightmap.slf +++ b/libraries/render-utils/src/model_lightmap.slf @@ -27,11 +27,11 @@ in vec3 _normal; in vec3 _color; void main(void) { - - <$fetchMaterialTextures(_texCoord0, albedo, roughness)$> + Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness)$> <$fetchMaterialLightmap(_texCoord1, emissive)$> - Material mat = getMaterial(); packDeferredFragmentLightmap( normalize(_normal), diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slf b/libraries/render-utils/src/model_lightmap_normal_map.slf index 1d305541fa..9ccc6e5352 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_map.slf @@ -28,11 +28,10 @@ in vec3 _tangent; in vec3 _color; void main(void) { - - <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel)$> - <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness, normalTexel)$> + <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> vec3 viewNormal; <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> diff --git a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf index 93bb3a793e..71909a789f 100755 --- a/libraries/render-utils/src/model_lightmap_normal_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_normal_specular_map.slf @@ -28,10 +28,10 @@ in vec3 _tangent; in vec3 _color; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel, metalllicTex)$> - <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness, normalTexel, metallicTex)$> + <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> vec3 viewNormal; <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> @@ -41,7 +41,7 @@ void main(void) { evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, - getMaterialMetallic(mat) * metalllicTex, + getMaterialMetallic(mat) * metallicTex, /*specular, // no use of */ getMaterialFresnel(mat), lightmapVal); } diff --git a/libraries/render-utils/src/model_lightmap_specular_map.slf b/libraries/render-utils/src/model_lightmap_specular_map.slf index 23d3a8e2b3..5eefefdc29 100755 --- a/libraries/render-utils/src/model_lightmap_specular_map.slf +++ b/libraries/render-utils/src/model_lightmap_specular_map.slf @@ -27,17 +27,17 @@ in vec3 _normal; in vec3 _color; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness, _SCRIBE_NULL, specular)$> - <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$> + <$fetchMaterialLightmap(_texCoord1, lightmapVal)$> packDeferredFragmentLightmap( normalize(_normal), evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), getMaterialAlbedo(mat) * albedo.rgb * _color, getMaterialRoughness(mat) * roughness, - getMaterialMetallic(mat), - /*specular, // no use of */getMaterialFresnel(mat), + getMaterialMetallic(mat) * metallicTex, + /*metallicTex, // no use of */getMaterialFresnel(mat), lightmapVal); } diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index 13cb63d322..a584427005 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -17,7 +17,7 @@ <@include model/Material.slh@> <@include MaterialTextures.slh@> -<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL)$> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$> in vec4 _position; in vec2 _texCoord0; @@ -26,18 +26,29 @@ in vec3 _tangent; in vec3 _color; void main(void) { - <$fetchMaterialTextures(_texCoord0, albedo, roughness, normalTexel)$> - Material mat = getMaterial(); + int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; vec3 viewNormal; - <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> + <$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$> packDeferredFragment( viewNormal, - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), - getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat) * roughness, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + albedo, + roughness, getMaterialMetallic(mat), - getMaterialFresnel(mat)); + emissive, + occlusionTex); } diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index 66fe0cd67e..cf461db7ef 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -17,7 +17,7 @@ <@include model/Material.slh@> <@include MaterialTextures.slh@> -<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC, EMISSIVE, OCCLUSION)$> in vec4 _position; in vec2 _texCoord0; @@ -26,18 +26,22 @@ in vec3 _tangent; in vec3 _color; void main(void) { - - <$fetchMaterialTextures(_texCoord0, albedo, roughnessTex, normalTexel, metallicTex)$> - Material mat = getMaterial(); int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex, occlusionTex)$> + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; float roughness = getMaterialRoughness(mat); <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; vec3 viewNormal; - <$tangentToViewSpace(normalTexel, _normal, _tangent, viewNormal)$> + <$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$> float metallic = getMaterialMetallic(mat); <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; @@ -45,10 +49,10 @@ void main(void) { packDeferredFragment( normalize(viewNormal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), - getMaterialAlbedo(mat) * albedo.rgb * _color, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + albedo, roughness, metallic, - /*vec3(specular) //*/getMaterialFresnel(mat) - ); + emissive, + occlusionTex); } diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index cfdf023ae3..32e5823430 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -17,7 +17,7 @@ <@include model/Material.slh@> <@include MaterialTextures.slh@> -<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$> +<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC, EMISSIVE, OCCLUSION)$> in vec4 _position; in vec2 _texCoord0; @@ -26,21 +26,29 @@ in vec3 _color; void main(void) { - - <$fetchMaterialTextures(_texCoord0, albedo, roughness, _SCRIBE_NULL, metallicTex)$> - Material mat = getMaterial(); int matKey = getMaterialKey(mat); + <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex, occlusionTex)$> + + vec3 albedo = getMaterialAlbedo(mat); + <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; + albedo *= _color; + + float roughness = getMaterialRoughness(mat); + <$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>; + + vec3 emissive = getMaterialEmissive(mat); + <$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>; float metallic = getMaterialMetallic(mat); <$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>; packDeferredFragment( normalize(_normal), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedo.a), - getMaterialAlbedo(mat) * albedo.rgb * _color, - getMaterialRoughness(mat) * roughness, + evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + albedo, + roughness, metallic, - /*vec3(specular) //*/ getMaterialFresnel(mat) - ); + emissive, + occlusionTex); } diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 3efa523434..086f9fe168 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -38,7 +38,7 @@ void main(void) { vec3 fragNormal = normalize(_normal); vec3 fragAlbedo = getMaterialAlbedo(mat) * albedo.rgb * _color; float fragMetallic = getMaterialMetallic(mat); - vec3 fragFresnel = getMaterialFresnel(mat); + vec3 fragEmissive = getMaterialEmissive(mat); float fragRoughness = getMaterialRoughness(mat); float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha; @@ -52,7 +52,7 @@ void main(void) { fragNormal, fragAlbedo, fragMetallic, - fragFresnel, + fragEmissive, fragRoughness), fragOpacity); } diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 4b5cdfb5ce..5ad9dc174f 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -54,6 +54,6 @@ void main(void) { normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, specular); } else { packDeferredFragment( - normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular); + normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), length(specular), DEFAULT_EMISSIVE, DEFAULT_OCCLUSION); } } diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index b2bc15dbad..0832b22214 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// simple.frag +// simple_textured.slf // fragment shader // // Created by Clément Brisset on 5/29/15. @@ -33,5 +33,6 @@ void main(void) { _color.rgb * texel.rgb, DEFAULT_ROUGHNESS, DEFAULT_METALLIC, - DEFAULT_SPECULAR); + DEFAULT_EMISSIVE, + DEFAULT_OCCLUSION); } \ No newline at end of file diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 68c0b94766..f20b5144d3 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -56,8 +56,9 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::ALBEDO_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::ROUGHNESS_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::SPECULAR_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::LIGHTMAP_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::METALLIC_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::EMISSIVE_LIGHTMAP_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::OCCLUSION_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::LIGHT_BUFFER)); slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING_MAP)); @@ -72,6 +73,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->normalTextureUnit = program->getTextures().findLocation("normalMap"); locations->specularTextureUnit = program->getTextures().findLocation("specularMap"); locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); + locations->occlusionTextureUnit = program->getTextures().findLocation("occlusionMap"); locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index b4fb622b39..963a3c76d4 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -197,9 +197,10 @@ public: static const int MATERIAL_GPU = 3; static const int ALBEDO_MAP = 0; static const int NORMAL_MAP = 1; - static const int SPECULAR_MAP = 2; - static const int LIGHTMAP_MAP = 3; + static const int METALLIC_MAP = 2; + static const int EMISSIVE_LIGHTMAP_MAP = 3; static const int ROUGHNESS_MAP = 4; + static const int OCCLUSION_MAP = 5; static const int LIGHT_BUFFER = 4; static const int NORMAL_FITTING_MAP = 10; @@ -213,6 +214,7 @@ public: int roughnessTextureUnit; int specularTextureUnit; int emissiveTextureUnit; + int occlusionTextureUnit; int emissiveParams; int normalFittingMapUnit; int skinClusterBufferUnit; diff --git a/tests/gpu-test/src/unlit.slf b/tests/gpu-test/src/unlit.slf index d070662495..f88fcb510b 100644 --- a/tests/gpu-test/src/unlit.slf +++ b/tests/gpu-test/src/unlit.slf @@ -24,5 +24,5 @@ void main(void) { normalize(_normal.xyz), 1.0, _color.rgb, - DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR); + DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION); } From 287bfeddda0c8c81cab2267bda680dd446c20c61 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 24 Feb 2016 18:31:08 -0800 Subject: [PATCH 062/292] Fixing the way the Obscurance is used with the ssao map --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 13 ++++++++++--- libraries/render-utils/src/DeferredLightingEffect.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 2360b6310f..c4c7d8c9c4 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -20,6 +20,7 @@ #include "GeometryCache.h" #include "FramebufferCache.h" +#include "TextureCache.h" #include "DeferredLightingEffect.h" #include "debug_deferred_buffer_vert.h" @@ -138,7 +139,7 @@ static const std::string DEFAULT_PYRAMID_DEPTH_SHADER { static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(occlusionMap, uv).x), 1.0);" + " return vec4(vec3(texture(obscuranceMap, uv).x), 1.0);" // When drawing color " return vec4(vec3(texture(occlusionMap, uv).xyz), 1.0);" // when drawing normal " return vec4(normalize(texture(occlusionMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" " }" @@ -251,10 +252,10 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str slotBindings.insert(gpu::Shader::Binding("normalMap", Normal)); slotBindings.insert(gpu::Shader::Binding("specularMap", Specular)); slotBindings.insert(gpu::Shader::Binding("depthMap", Depth)); + slotBindings.insert(gpu::Shader::Binding("obscuranceMap", AmbientOcclusion)); slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); slotBindings.insert(gpu::Shader::Binding("shadowMap", Shadow)); slotBindings.insert(gpu::Shader::Binding("pyramidMap", Pyramid)); - slotBindings.insert(gpu::Shader::Binding("occlusionMap", AmbientOcclusion)); slotBindings.insert(gpu::Shader::Binding("occlusionBlurredMap", AmbientOcclusionBlurred)); gpu::Shader::makeProgram(*program, slotBindings); @@ -288,6 +289,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { const auto geometryBuffer = DependencyManager::get(); const auto framebufferCache = DependencyManager::get(); + const auto textureCache = DependencyManager::get(); const auto& lightStage = DependencyManager::get()->getLightStage(); glm::mat4 projMat; @@ -310,7 +312,12 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer()); batch.setResourceTexture(Pyramid, framebufferCache->getDepthPyramidTexture()); - batch.setResourceTexture(AmbientOcclusion, framebufferCache->getOcclusionTexture()); + if (DependencyManager::get()->isAmbientOcclusionEnabled()) { + batch.setResourceTexture(AmbientOcclusion, framebufferCache->getOcclusionTexture()); + } else { + // need to assign the white texture if ao is off + batch.setResourceTexture(AmbientOcclusion, textureCache->getWhiteTexture()); + } batch.setResourceTexture(AmbientOcclusionBlurred, framebufferCache->getOcclusionBlurredTexture()); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 660e44ea1e..ad52cdce96 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -56,6 +56,7 @@ public: const LightStage& getLightStage() { return _lightStage; } void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; }; void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; } + bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; } private: DeferredLightingEffect() = default; From 4cc36d1df04d073e6fd5957fffe2efa6bd720833 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Feb 2016 17:13:48 +1300 Subject: [PATCH 063/292] Update QML UI test environment for Settings > General dialog --- tests/ui/qml/StubMenu.qml | 4 ---- tests/ui/qml/Stubs.qml | 14 ++++++++++++++ tests/ui/qml/main.qml | 12 ++++++++++++ tests/ui/src/main.cpp | 2 ++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/ui/qml/StubMenu.qml b/tests/ui/qml/StubMenu.qml index 63c9b5b3ea..fd0298988a 100644 --- a/tests/ui/qml/StubMenu.qml +++ b/tests/ui/qml/StubMenu.qml @@ -528,10 +528,6 @@ Menu { text: menuOption.turnWithHead; checkable: true } - MenuItem { - text: menuOption.comfortMode; - checkable: true - } MenuItem { text: menuOption.keyboardMotorControl; checkable: true diff --git a/tests/ui/qml/Stubs.qml b/tests/ui/qml/Stubs.qml index 3f60876e81..22b63d3f83 100644 --- a/tests/ui/qml/Stubs.qml +++ b/tests/ui/qml/Stubs.qml @@ -23,6 +23,20 @@ Item { function getUsername() { return "Jherico"; } } + Item { + objectName: "ApplicationCompositor" + property bool reticleOverDesktop: true + } + + Item { + objectName: "Preferences" + // List of categories obtained by logging categories as they are added in Interface in Preferences::addPreference(). + property var categories: [ + "Avatar Basics", "Snapshots", "Scripts", "Privacy", "Level of Detail Tuning", "Avatar Tuning", "Avatar Camera", + "Audio", "Octree", "HMD", "Sixense Controllers", "Graphics" + ] + } + Item { objectName: "ScriptDiscoveryService" //property var scriptsModelFilter: scriptsModel diff --git a/tests/ui/qml/main.qml b/tests/ui/qml/main.qml index 0bdfdb64b9..97f6224670 100644 --- a/tests/ui/qml/main.qml +++ b/tests/ui/qml/main.qml @@ -38,6 +38,18 @@ ApplicationWindow { property var tabs: []; property var urls: []; + Button { + // Shows the dialog with preferences sections but not each section's preference items + // because Preferences.preferencesByCategory() method is not stubbed out. + text: "Settings > General..." + property var builder: Component { + GeneralPreferencesDialog { } + } + onClicked: { + var runningScripts = builder.createObject(desktop); + } + } + Button { text: "Running Scripts" property var builder: Component { diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 19c0626164..dae7b47bba 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -85,9 +85,11 @@ int main(int argc, char *argv[]) { setChild(engine, "offscreenFlags"); setChild(engine, "Account"); + setChild(engine, "ApplicationCompositor"); setChild(engine, "Desktop"); setChild(engine, "ScriptDiscoveryService"); setChild(engine, "MenuHelper"); + setChild(engine, "Preferences"); setChild(engine, "urlHandler"); engine.rootContext()->setContextProperty("DebugQML", true); engine.rootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper()); From 023c04d2fe06b3449922646c698f80a848c15282 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Feb 2016 20:25:20 +1300 Subject: [PATCH 064/292] Add optional footer to "form editor" dialogs --- .../resources/qml/windows-uit/Window.qml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index ae73a53d65..4bb376346d 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -58,6 +58,8 @@ Fadable { // The content to place inside the window, determined by the client default property var content + property var footer: Item { } // Optional static footer at the bottom of the dialog. + function setDefaultFocus() {} // Default function; can be overridden by dialogs. property var rectifier: Timer { @@ -126,6 +128,7 @@ Fadable { property var pane: Item { property bool isScrolling: scrollView.height < scrollView.contentItem.height property int contentWidth: scrollView.width - (isScrolling ? 11 : 0) + property int scrollHeight: scrollView.height anchors.fill: parent anchors.rightMargin: isScrolling ? 11 : 0 @@ -162,6 +165,7 @@ Fadable { verticalScrollBarPolicy: Qt.ScrollBarAsNeeded anchors.fill: parent anchors.rightMargin: parent.isScrolling ? 1 : 0 + anchors.bottomMargin: footer.height > 0 ? footerPane.height : 0 style: ScrollViewStyle { @@ -203,7 +207,46 @@ Fadable { } } } + + Rectangle { + // Optional non-scrolling footer. + id: footerPane + anchors { + left: parent.left + bottom: parent.bottom + } + width: parent.contentWidth + height: footer.height + 2 * hifi.dimensions.contentSpacing.y + color: hifi.colors.baseGray + visible: footer.height > 0 + + Item { + // Horizontal rule. + anchors.fill: parent + + Rectangle { + width: parent.width + height: 1 + y: 1 // Stop displaying content just above horizontal rule/=. + color: hifi.colors.baseGrayShadow + } + + Rectangle { + width: parent.width + height: 1 + y: 2 + color: hifi.colors.baseGrayHighlight + } + } + + Item { + anchors.fill: parent + anchors.topMargin: 3 // Horizontal rule. + children: [ footer ] + } + } } + children: [ swallower, frame, pane, activator ] Component.onCompleted: { raise(); setDefaultFocus(); } From 10efbd996f51a606c1625ab272f3fe28b5abf167 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Feb 2016 20:26:36 +1300 Subject: [PATCH 065/292] Update General Settings dialog to use new window frame style --- .../qml/dialogs/PreferencesDialog.qml | 67 ++++++++++--------- .../hifi/dialogs/GeneralPreferencesDialog.qml | 10 +++ 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index 3b594153dc..fe27c5c514 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -1,10 +1,21 @@ +// +// PreferencesDialog.qml +// +// Created by Bradley Austin Davis on 24 Jan 2016 +// 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 +// + import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 import "../controls" as HifiControls -import "../windows" +import "../styles-uit" +import "../windows-uit" import "preferences" Window { @@ -17,6 +28,8 @@ Window { property var sections: [] property var showCategories: [] + HifiConstants { id: hifi } + function saveAll() { for (var i = 0; i < sections.length; ++i) { var section = sections[i]; @@ -33,10 +46,8 @@ Window { destroy(); } - Rectangle { - anchors.fill: parent - clip: true - color: "white" + Column { + width: pane.contentWidth Component { id: sectionBuilder @@ -71,37 +82,27 @@ Window { } } - Flickable { - id: flickable - clip: true - interactive: true - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: dialogButtons.top - anchors.bottomMargin: 8 - contentHeight: prefControls.height - contentWidth: parent.width - - Column { - id: prefControls - anchors.left: parent.left - anchors.right: parent.right - } + Column { + id: prefControls + width: pane.contentWidth } - Row { - id: dialogButtons - anchors { bottom: parent.bottom; right: parent.right; margins: 8 } + } - Button { - text: "Cancel"; - onClicked: root.restoreAll(); - } + footer: Row { + anchors { + right: parent.right; + rightMargin: hifi.dimensions.contentMargin.x + verticalCenter: parent.verticalCenter + } - Button { - text: "Save all changes" - onClicked: root.saveAll(); - } + Button { + text: "Cancel"; + onClicked: root.restoreAll(); + } + + Button { + text: "Save all changes" + onClicked: root.saveAll(); } } } diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index 81e4924204..9656b156b3 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -1,3 +1,13 @@ +// +// PreferencesDialog.qml +// +// Created by Bradley Austin Davis on 24 Jan 2016 +// 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 +// + import QtQuick 2.5 import Qt.labs.settings 1.0 From f04654fb5656267d2faa94f66ce523a916b616d4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Feb 2016 20:35:27 +1300 Subject: [PATCH 066/292] Style and swap order of save and cancel buttons --- .../resources/qml/dialogs/PreferencesDialog.qml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index fe27c5c514..fd2da3e7c1 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -13,7 +13,7 @@ import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import "../controls" as HifiControls +import "../controls-uit" as HifiControls import "../styles-uit" import "../windows-uit" import "preferences" @@ -94,15 +94,18 @@ Window { rightMargin: hifi.dimensions.contentMargin.x verticalCenter: parent.verticalCenter } + spacing: hifi.dimensions.contentSpacing.x - Button { - text: "Cancel"; - onClicked: root.restoreAll(); + HifiControls.Button { + text: "Save changes" + color: hifi.buttons.blue + onClicked: root.saveAll() } - Button { - text: "Save all changes" - onClicked: root.saveAll(); + HifiControls.Button { + text: "Cancel" + color: hifi.buttons.white + onClicked: root.restoreAll() } } } From 09029e4edd57bb8e87d7b00b4498b1fb6b4eef98 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Feb 2016 20:37:54 +1300 Subject: [PATCH 067/292] Change name of dialog to match menu item --- .../resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index 9656b156b3..95f55f504b 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -16,7 +16,7 @@ import "../../dialogs" PreferencesDialog { id: root objectName: "GeneralPreferencesDialog" - title: "General Preferences" + title: "General Settings" showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"] property var settings: Settings { category: root.objectName From b4edfe2390d5821d13e76aae5e9c77af8bc3324a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Feb 2016 12:06:22 -0800 Subject: [PATCH 068/292] no expiry for simulation ownership --- .../src/entities/EntityServer.cpp | 11 +- assignment-client/src/entities/EntityServer.h | 8 +- .../entities/src/SimpleEntitySimulation.cpp | 122 ++++++++++++------ .../entities/src/SimpleEntitySimulation.h | 7 +- libraries/physics/src/EntityMotionState.cpp | 23 ++-- 5 files changed, 106 insertions(+), 65 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index b6223497e6..b177d2a9a0 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -277,14 +277,17 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio // set of stats to have, but we'd probably want a different data structure if we keep it very long. // Since this version uses a single shared QMap for all senders, there could be some lock contention // on this QWriteLocker -void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { +void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& sessionID) { QWriteLocker locker(&_viewerSendingStatsLock); - _viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; + _viewerSendingStats[sessionID][dataID] = { usecTimestampNow(), dataLastEdited }; } -void EntityServer::trackViewerGone(const QUuid& viewerNode) { +void EntityServer::trackViewerGone(const QUuid& sessionID) { QWriteLocker locker(&_viewerSendingStatsLock); - _viewerSendingStats.remove(viewerNode); + _viewerSendingStats.remove(sessionID); + if (_entitySimulation) { + _entitySimulation->clearOwnership(sessionID); + } } QString EntityServer::serverSubclassStats() { diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index cd603f44d8..74057bfa5d 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -27,6 +27,8 @@ struct ViewerSendingStats { quint64 lastEdited; }; +class SimpleEntitySimulation; + class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { Q_OBJECT public: @@ -52,8 +54,8 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; virtual QString serverSubclassStats() override; - virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) override; - virtual void trackViewerGone(const QUuid& viewerNode) override; + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& sessionID) override; + virtual void trackViewerGone(const QUuid& sessionID) override; public slots: void pruneDeletedEntities(); @@ -65,7 +67,7 @@ private slots: void handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode); private: - EntitySimulation* _entitySimulation; + SimpleEntitySimulation* _entitySimulation; QTimer* _pruneDeletedEntitiesTimer = nullptr; QReadWriteLock _viewerSendingStatsLock; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index bdf27f4440..693d80b27d 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -18,51 +18,69 @@ #include "EntityItem.h" #include "EntitiesLogging.h" -const quint64 MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD = 2 * USECS_PER_SECOND; - -void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { - if (_entitiesWithSimulator.size() == 0) { - return; - } - - if (now < _nextSimulationExpiry) { - // nothing has expired yet - return; - } - - // If an Entity has a simulation owner but there has been no update for a while: clear the owner. - // If an Entity goes ownerless for too long: zero velocity and remove from _entitiesWithSimulator. - _nextSimulationExpiry = now + MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD; +const quint64 MAX_OWNERLESS_PERIOD = 2 * USECS_PER_SECOND; +void SimpleEntitySimulation::clearOwnership(const QUuid& ownerID) { QMutexLocker lock(&_mutex); - SetOfEntities::iterator itemItr = _entitiesWithSimulator.begin(); - while (itemItr != _entitiesWithSimulator.end()) { + SetOfEntities::iterator itemItr = _entitiesWithSimulationOwner.begin(); + while (itemItr != _entitiesWithSimulationOwner.end()) { EntityItemPointer entity = *itemItr; - quint64 expiry = entity->getLastChangedOnServer() + MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD; - if (expiry < now) { - if (entity->getSimulatorID().isNull()) { - // no simulators are volunteering - // zero the velocity on this entity so that it doesn't drift far away - entity->setVelocity(Vectors::ZERO); - entity->setAngularVelocity(Vectors::ZERO); - entity->setAcceleration(Vectors::ZERO); - // remove from list - itemItr = _entitiesWithSimulator.erase(itemItr); - continue; - } else { - // the simulator has stopped updating this object - // clear ownership and restart timer, giving nearby simulators time to volunteer - qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID(); - entity->clearSimulationOwnership(); + if (entity->getSimulatorID() == ownerID) { + // the simulator has abandonded this object --> remove from owned list + qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID(); + itemItr = _entitiesWithSimulationOwner.erase(itemItr); + + if (entity->getDynamic() && entity->hasLocalVelocity()) { + // it is still moving dynamically --> add to orphaned list + _entitiesThatNeedSimulationOwner.insert(entity); + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } } + + // remove ownership and dirty all the tree elements that contain the it + entity->clearSimulationOwnership(); entity->markAsChangedOnServer(); - // dirty all the tree elements that contain the entity DirtyOctreeElementOperator op(entity->getElement()); getEntityTree()->recurseTreeWithOperator(&op); - } else if (expiry < _nextSimulationExpiry) { - _nextSimulationExpiry = expiry; + } else { + ++itemItr; + } + } +} + +void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { + if (now > _nextOwnerlessExpiry) { + // search for ownerless objects that have expired + QMutexLocker lock(&_mutex); + _nextOwnerlessExpiry = -1; + SetOfEntities::iterator itemItr = _entitiesThatNeedSimulationOwner.begin(); + while (itemItr != _entitiesThatNeedSimulationOwner.end()) { + EntityItemPointer entity = *itemItr; + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < now) { + // no simulators have volunteered ownership --> remove from list + itemItr = _entitiesThatNeedSimulationOwner.erase(itemItr); + + if (entity->getSimulatorID().isNull() && entity->getDynamic() && entity->hasLocalVelocity()) { + // zero the derivatives + entity->setVelocity(Vectors::ZERO); + entity->setAngularVelocity(Vectors::ZERO); + entity->setAcceleration(Vectors::ZERO); + + // dirty all the tree elements that contain it + entity->markAsChangedOnServer(); + DirtyOctreeElementOperator op(entity->getElement()); + getEntityTree()->recurseTreeWithOperator(&op); + } + } else { + ++itemItr; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } + } } - ++itemItr; } } @@ -70,26 +88,46 @@ void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { EntitySimulation::addEntityInternal(entity); if (!entity->getSimulatorID().isNull()) { QMutexLocker lock(&_mutex); - _entitiesWithSimulator.insert(entity); + _entitiesWithSimulationOwner.insert(entity); + } else if (entity->getDynamic() && entity->hasLocalVelocity()) { + QMutexLocker lock(&_mutex); + _entitiesThatNeedSimulationOwner.insert(entity); + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } } } void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) { EntitySimulation::removeEntityInternal(entity); QMutexLocker lock(&_mutex); - _entitiesWithSimulator.remove(entity); + _entitiesWithSimulationOwner.remove(entity); + _entitiesThatNeedSimulationOwner.remove(entity); } void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { EntitySimulation::changeEntityInternal(entity); - if (!entity->getSimulatorID().isNull()) { + if (entity->getSimulatorID().isNull()) { QMutexLocker lock(&_mutex); - _entitiesWithSimulator.insert(entity); + _entitiesWithSimulationOwner.remove(entity); + if (entity->getDynamic() && entity->hasLocalVelocity()) { + _entitiesThatNeedSimulationOwner.insert(entity); + quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < _nextOwnerlessExpiry) { + _nextOwnerlessExpiry = expiry; + } + } + } else { + QMutexLocker lock(&_mutex); + _entitiesWithSimulationOwner.insert(entity); + _entitiesThatNeedSimulationOwner.remove(entity); } entity->clearDirtyFlags(); } void SimpleEntitySimulation::clearEntitiesInternal() { - _entitiesWithSimulator.clear(); + _entitiesWithSimulationOwner.clear(); + _entitiesThatNeedSimulationOwner.clear(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 53a7574bf2..d9c04fdcf9 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -21,6 +21,8 @@ public: SimpleEntitySimulation() : EntitySimulation() { } virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); } + void clearOwnership(const QUuid& ownerID); + protected: virtual void updateEntitiesInternal(const quint64& now) override; virtual void addEntityInternal(EntityItemPointer entity) override; @@ -28,8 +30,9 @@ protected: virtual void changeEntityInternal(EntityItemPointer entity) override; virtual void clearEntitiesInternal() override; - SetOfEntities _entitiesWithSimulator; - quint64 _nextSimulationExpiry { 0 }; + SetOfEntities _entitiesWithSimulationOwner; + SetOfEntities _entitiesThatNeedSimulationOwner; + quint64 _nextOwnerlessExpiry { 0 }; }; #endif // hifi_SimpleEntitySimulation_h diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8c0dab98db..6a818a1972 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -272,7 +272,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; if (_numInactiveUpdates > 0) { - const uint8_t MAX_NUM_INACTIVE_UPDATES = 3; + const uint8_t MAX_NUM_INACTIVE_UPDATES = 20; if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) { // clear local ownership (stop sending updates) and let the server clear itself _entity->clearSimulationOwnership(); @@ -282,7 +282,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // until it is removed from the outgoing updates // (which happens when we don't own the simulation and it isn't touching our simulation) const float INACTIVE_UPDATE_PERIOD = 0.5f; - return (dt > INACTIVE_UPDATE_PERIOD); + return (dt > INACTIVE_UPDATE_PERIOD * (float)_numInactiveUpdates); } if (!_body->isActive()) { @@ -404,8 +404,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q assert(_entity); assert(entityTreeIsLocked()); - bool active = _body->isActive(); - if (!active) { + if (!_body->isActive()) { // make sure all derivatives are zero glm::vec3 zero(0.0f); _entity->setVelocity(zero); @@ -495,16 +494,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now); #endif //def WANT_DEBUG - if (sessionID == _entity->getSimulatorID()) { - // we think we own the simulation - if (!active) { - // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID - // but we remember that we do still own it... and rely on the server to tell us that we don't - properties.clearSimulationOwner(); - _outgoingPriority = ZERO_SIMULATION_PRIORITY; - } - // else the ownership is not changing so we don't bother to pack it - } else { + if (_numInactiveUpdates > 0) { + // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID + // but we remember that we do still own it... and rely on the server to tell us that we don't + properties.clearSimulationOwner(); + _outgoingPriority = ZERO_SIMULATION_PRIORITY; + } else if (sessionID != _entity->getSimulatorID()) { // we don't own the simulation for this entity yet, but we're sending a bid for it properties.setSimulationOwner(sessionID, glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; From 5d931523adf0986dda1a333f6377fa2ecdd97c87 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 10:03:00 +1300 Subject: [PATCH 069/292] Style settings section headings --- .../qml/dialogs/PreferencesDialog.qml | 21 ++++-- .../qml/dialogs/preferences/Preference.qml | 10 +++ .../qml/dialogs/preferences/Section.qml | 69 ++++++++----------- 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index fd2da3e7c1..3b0c5dffc2 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -2,7 +2,7 @@ // PreferencesDialog.qml // // Created by Bradley Austin Davis on 24 Jan 2016 -// Copyright 2015 High Fidelity, Inc. +// Copyright 2016 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -10,8 +10,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs -import Qt.labs.settings 1.0 import "../controls-uit" as HifiControls import "../styles-uit" @@ -75,10 +73,20 @@ Window { } if (sections.length) { - sections[0].expanded = true; - if (sections.length === 1) { - sections[0].collapsable = false + // Default sections to expanded/collapsed as appropriate for dialog. + if (title === "Avatar Preferences") { + sections[0].expanded = true; + if (sections.length === 1) { + sections[0].collapsable = false + } + } else { + for (i = 0; i < sections.length; i++) { + sections[i].collapsable = false; + sections[i].expanded = true; + } } + sections[0].hasSeparator = false; + sections[sections.length - 1].hasSpacer = true; } } @@ -109,4 +117,3 @@ Window { } } } - diff --git a/interface/resources/qml/dialogs/preferences/Preference.qml b/interface/resources/qml/dialogs/preferences/Preference.qml index b119bcfcd1..733e2c4ebe 100644 --- a/interface/resources/qml/dialogs/preferences/Preference.qml +++ b/interface/resources/qml/dialogs/preferences/Preference.qml @@ -1,3 +1,13 @@ +// +// Preference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 import QtQuick.Controls 1.4 diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index 63aa19651a..ef182fcd23 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -1,20 +1,33 @@ +// +// Section.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 import QtQuick.Controls 1.4 import Hifi 1.0 -import "../../controls" as VrControls +import "../../controls-uit" as HiFiControls +import "../../styles-uit" import "." Preference { id: root property bool collapsable: true property bool expanded: false + property bool hasSeparator: true + property bool hasSpacer: false property string name: "Header" property real spacing: 8 - readonly property alias toggle: toggle - readonly property alias header: header default property alias preferences: contentContainer.children + HifiConstants { id: hifi } + function saveAll() { for (var i = 0; i < d.preferences.length; ++i) { var preference = d.preferences[i]; @@ -29,47 +42,23 @@ Preference { } } - clip: true - children: [ toggle, header, contentContainer ] - height: expanded ? header.height + contentContainer.height + root.spacing * 3 - : Math.max(toggle.height, header.height) + root.spacing * 2 - Behavior on height { PropertyAnimation {} } + children: [ contentContainer ] + + height: contentContainer.height + (root.hasSpacer ? 2 * hifi.dimensions.contentSpacing.y : 0) Component.onCompleted: d.buildPreferences(); - function toggleExpanded() { - root.expanded = !root.expanded; - } - - VrControls.FontAwesome { - id: toggle - width: root.collapsable ? height : 0 - anchors { left: parent.left; top: parent.top; margins: root.spacing } - visible: root.collapsable - enabled: root.collapsable - rotation: root.expanded ? 0 : -90 - text: "\uf078" - Behavior on rotation { PropertyAnimation {} } - MouseArea { anchors.fill: parent; onClicked: root.toggleExpanded() } - } - - Text { - id: header - anchors { left: toggle.right; top: parent.top; leftMargin: root.spacing * 2; margins: root.spacing } - font.bold: true - font.pointSize: 16 - color: "#0e7077" - text: root.name - MouseArea { anchors.fill: parent; onClicked: root.toggleExpanded() } - } - - Column { + HiFiControls.StaticSection { id: contentContainer - spacing: root.spacing - anchors { left: toggle.right; top: header.bottom; topMargin: root.spacing; right: parent.right; margins: root.spacing } - enabled: root.expanded - visible: root.expanded - clip: true + name: root.name + + hasSeparator: root.hasSeparator + + anchors { + left: parent.left + right: parent.right + margins: 0 + } } QtObject { From d255ad38054bddbfc3d38520d04789764038fccb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 10:17:36 +1300 Subject: [PATCH 070/292] Improve property naming --- interface/resources/qml/controls-uit/StaticSection.qml | 6 +++--- interface/resources/qml/dialogs/PreferencesDialog.qml | 4 ++-- interface/resources/qml/dialogs/preferences/Section.qml | 8 ++++---- interface/resources/qml/hifi/dialogs/RunningScripts.qml | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/controls-uit/StaticSection.qml b/interface/resources/qml/controls-uit/StaticSection.qml index a4857635f1..a6c8199f48 100644 --- a/interface/resources/qml/controls-uit/StaticSection.qml +++ b/interface/resources/qml/controls-uit/StaticSection.qml @@ -14,7 +14,7 @@ import "../styles-uit" Column { property string name: "Static Section" - property bool hasSeparator: false + property bool isFirst: false spacing: hifi.dimensions.contentSpacing.y @@ -28,7 +28,7 @@ Column { VerticalSpacer { } Item { - visible: hasSeparator + visible: !isFirst anchors.top: sectionName.top Rectangle { @@ -57,7 +57,7 @@ Column { color: hifi.colors.lightGrayText verticalAlignment: Text.AlignBottom height: { - if (hasSeparator) { + if (!isFirst) { hifi.dimensions.contentMargin.y } } diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index 3b0c5dffc2..b2a34c89a2 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -85,8 +85,8 @@ Window { sections[i].expanded = true; } } - sections[0].hasSeparator = false; - sections[sections.length - 1].hasSpacer = true; + sections[0].isFirst = true; + sections[sections.length - 1].isLast = true; } } diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index ef182fcd23..d6d5c71167 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -20,8 +20,8 @@ Preference { id: root property bool collapsable: true property bool expanded: false - property bool hasSeparator: true - property bool hasSpacer: false + property bool isFirst: false + property bool isLast: false property string name: "Header" property real spacing: 8 default property alias preferences: contentContainer.children @@ -44,7 +44,7 @@ Preference { children: [ contentContainer ] - height: contentContainer.height + (root.hasSpacer ? 2 * hifi.dimensions.contentSpacing.y : 0) + height: contentContainer.height + (root.isLast ? 2 * hifi.dimensions.contentSpacing.y : 0) Component.onCompleted: d.buildPreferences(); @@ -52,7 +52,7 @@ Preference { id: contentContainer name: root.name - hasSeparator: root.hasSeparator + isFirst: root.isFirst anchors { left: parent.left diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 55b8946805..f8a8c87595 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -89,6 +89,7 @@ Window { HifiControls.StaticSection { name: "Currently Running" + isFirst: true Row { spacing: hifi.dimensions.contentSpacing.x @@ -117,7 +118,6 @@ Window { HifiControls.StaticSection { name: "Load Scripts" - hasSeparator: true Row { spacing: hifi.dimensions.contentSpacing.x From ef85d0451a4008bf94333dee674858f220244a7e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:24:06 -0800 Subject: [PATCH 071/292] removed files that shouldn't be there --- .../acAudioSearching/howardAcAudio.js | 248 ------------------ .../acAudioSearching/howardSpawner.js | 248 ------------------ 2 files changed, 496 deletions(-) delete mode 100644 examples/audioExamples/acAudioSearching/howardAcAudio.js delete mode 100644 examples/audioExamples/acAudioSearching/howardSpawner.js diff --git a/examples/audioExamples/acAudioSearching/howardAcAudio.js b/examples/audioExamples/acAudioSearching/howardAcAudio.js deleted file mode 100644 index f5b1302e06..0000000000 --- a/examples/audioExamples/acAudioSearching/howardAcAudio.js +++ /dev/null @@ -1,248 +0,0 @@ -"use strict"; -/*jslint nomen: true, plusplus: true, vars: true*/ -/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ -// -// ACAudioSearchAndInject.js -// audio -// -// Created by Eric Levin and Howard Stearns 2/1/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. -// Inject as many as practical into the audio mixer. -// See acAudioSearchAndCompatibilityEntitySpawner.js. -// -// This implementation takes some precautions to scale well: -// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. -// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only -// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). -// This implementation tries to use all the available injectors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. -var old_sound_data_key = "soundKey"; // For backwards compatibility. -var QUERY_RADIUS = 50; // meters -var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. -var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. -var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. -// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) -var UPDATES_PER_STATS_LOG = 50; - -var DEFAULT_SOUND_DATA = { - volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. - loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. - playbackGap: 1000, // in ms - playbackGapRange: 0 // in ms -}; - -Script.include("../../libraries/utils.js"); -Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. - -function ignore() {} - -function debug() { // Display the arguments not just [Object object]. - //print.apply(null, [].map.call(arguments, JSON.stringify)); -} - -EntityViewer.setKeyholeRadius(QUERY_RADIUS); - -// ENTITY DATA CACHE -// -var entityCache = {}; // A dictionary of unexpired EntityData objects. - -function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. - // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. - var that = this; - that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data - // State Transitions: - // no data => no data | sound data | expired - // expired => stop => remove - // sound data => downloading - // downloading => downloading | waiting - // waiting => playing | waiting (if too many already playing) - // playing => update position etc | no data - that.stop = function stop() { - if (!that.sound) { - return; - } - print("stopping sound", entityIdentifier, that.url); - delete that.sound; - delete that.url; - if (!that.injector) { - return; - } - that.injector.stop(); - delete that.injector; - }; - this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { - if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE - that.stop(); // Alternatively, we could fade out and then stop... - delete entityCache[entityIdentifier]; - return; - } - var properties, soundData; // Latest data, pulled from local octree. - // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. - // Most entity updates are fast and only a very few do getEntityProperties. - - function ensureSoundData() { // We only getEntityProperities when we need to. - if (properties) { - return; - } - properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); - debug("updating", that, properties); - try { - var userData = properties.userData && JSON.parse(properties.userData); - soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. - that.lastUserDataUpdate = now; // But do update these ... - that.url = soundData && soundData.url; - that.playAfter = that.url && now; - } catch (err) { - print(err, properties.userData); - } - } - // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. - if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA - ensureSoundData(); - } - if (!that.url) { // NO DATA => NO DATA - return that.stop(); - } - if (!that.sound) { // SOUND DATA => DOWNLOADING - that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. - } - if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING - return; - } - if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING - return; - } - ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. - if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) - return that.stop(); - } - var options = { - position: properties.position, - loop: soundData.loop || DEFAULT_SOUND_DATA.loop, - volume: soundData.volume || DEFAULT_SOUND_DATA.volume - }; - if (!that.injector) { // WAITING => PLAYING | WAITING - debug("starting", that, options); - that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. - if (that.injector) { - print("started", entityIdentifier, that.url); - } else { // Don't hammer ensureSoundData or injector manager. - that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); - } - return; - } - that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC - if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. - var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; - if (gap) { // WAITING => PLAYING - gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. - // Setup next play just once, now. Changes won't be looked at while we wait. - that.playAfter = now + (that.sound.duration * 1000) + gap; - // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. - that.injector.restart(); - } else { // PLAYING => NO DATA - that.playAfter = Infinity; - } - } - }; -} - -function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { - ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. - var entitySound = entityCache[entityIdentifier]; - if (!entitySound) { - entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); - } - entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. -} -var nUpdates = UPDATES_PER_STATS_LOG, - lastStats = Date.now(); - -function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. - var now = Date.now(), - expirationCutoff = now - EXPIRATION_TIME, - userDataRecheckCutoff = now - RECHECK_TIME; - Object.keys(entityCache).forEach(function(entityIdentifier) { - entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); - }); - if (nUpdates-- <= 0) { // Report statistics. - // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: - // audio-mixer: 23% of cpu (on Mac Activity Monitor) - // this script's assignment client: 106% of cpu. (overloaded) - // entities:12003 - // sounds:2000 - // playing:40 (correct) - // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) - var stats = { - entities: 0, - sounds: 0, - playing: 0, - millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG - }; - nUpdates = UPDATES_PER_STATS_LOG; - lastStats = now; - Object.keys(entityCache).forEach(function(entityIdentifier) { - var datum = entityCache[entityIdentifier]; - stats.entities++; - if (datum.url) { - stats.sounds++; - if (datum.injector && datum.injector.isPlaying) { - stats.playing++; - } - } - }); - print(JSON.stringify(stats)); - } -} - -// Update the set of which EntityData we know about. -// - -function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. - // This does at most: - // one queryOctree request of the entity server, and - // one findEntities geometry query of our own octree, and - // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. - // The idea is that this is a nice bounded piece of work that should not be done too frequently. - // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. - var avatar = AvatarList.getAvatar(avatarIdentifier), - avatarPosition = avatar && avatar.position; - if (!avatarPosition) { // No longer here. - return; - } - var timestamp = Date.now(); - EntityViewer.setPosition(avatarPosition); - EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. - var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); - debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); - entities.forEach(function(entityIdentifier) { - internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); - }); -} - -// Slowly update the set of data we have to work with. -// -var workQueue = []; - -function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates - workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { - return function() { - updateEntiesForAvatar(avatarIdentifier); - }; - }); -} -Script.setInterval(function() { - // There might be thousands of EntityData known to us, but only a few will require any work to update. - updateAllEntityData(); // i.e., this better be pretty fast. - // Each interval, we do no more than one updateEntitiesforAvatar. - if (!workQueue.length) { - workQueue = [updateWorkQueueForAvatarsPresent]; - } - workQueue.pop()(); // There's always one -}, UPDATE_TIME); \ No newline at end of file diff --git a/examples/audioExamples/acAudioSearching/howardSpawner.js b/examples/audioExamples/acAudioSearching/howardSpawner.js deleted file mode 100644 index f5b1302e06..0000000000 --- a/examples/audioExamples/acAudioSearching/howardSpawner.js +++ /dev/null @@ -1,248 +0,0 @@ -"use strict"; -/*jslint nomen: true, plusplus: true, vars: true*/ -/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ -// -// ACAudioSearchAndInject.js -// audio -// -// Created by Eric Levin and Howard Stearns 2/1/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. -// Inject as many as practical into the audio mixer. -// See acAudioSearchAndCompatibilityEntitySpawner.js. -// -// This implementation takes some precautions to scale well: -// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. -// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only -// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). -// This implementation tries to use all the available injectors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. -var old_sound_data_key = "soundKey"; // For backwards compatibility. -var QUERY_RADIUS = 50; // meters -var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. -var EXPIRATION_TIME = 5 * 1000; // ms. Remove sounds that have been out of range for this time. -var RECHECK_TIME = 10 * 1000; // ms. Check for new userData properties this often when not currently playing. -// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) -var UPDATES_PER_STATS_LOG = 50; - -var DEFAULT_SOUND_DATA = { - volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. - loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. - playbackGap: 1000, // in ms - playbackGapRange: 0 // in ms -}; - -Script.include("../../libraries/utils.js"); -Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. - -function ignore() {} - -function debug() { // Display the arguments not just [Object object]. - //print.apply(null, [].map.call(arguments, JSON.stringify)); -} - -EntityViewer.setKeyholeRadius(QUERY_RADIUS); - -// ENTITY DATA CACHE -// -var entityCache = {}; // A dictionary of unexpired EntityData objects. - -function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. - // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. - var that = this; - that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data - // State Transitions: - // no data => no data | sound data | expired - // expired => stop => remove - // sound data => downloading - // downloading => downloading | waiting - // waiting => playing | waiting (if too many already playing) - // playing => update position etc | no data - that.stop = function stop() { - if (!that.sound) { - return; - } - print("stopping sound", entityIdentifier, that.url); - delete that.sound; - delete that.url; - if (!that.injector) { - return; - } - that.injector.stop(); - delete that.injector; - }; - this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { - if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE - that.stop(); // Alternatively, we could fade out and then stop... - delete entityCache[entityIdentifier]; - return; - } - var properties, soundData; // Latest data, pulled from local octree. - // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. - // Most entity updates are fast and only a very few do getEntityProperties. - - function ensureSoundData() { // We only getEntityProperities when we need to. - if (properties) { - return; - } - properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); - debug("updating", that, properties); - try { - var userData = properties.userData && JSON.parse(properties.userData); - soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. - that.lastUserDataUpdate = now; // But do update these ... - that.url = soundData && soundData.url; - that.playAfter = that.url && now; - } catch (err) { - print(err, properties.userData); - } - } - // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. - if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA - ensureSoundData(); - } - if (!that.url) { // NO DATA => NO DATA - return that.stop(); - } - if (!that.sound) { // SOUND DATA => DOWNLOADING - that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. - } - if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING - return; - } - if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING - return; - } - ensureSoundData(); // We'll play and will need position, so we might as well get soundData, too. - if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) - return that.stop(); - } - var options = { - position: properties.position, - loop: soundData.loop || DEFAULT_SOUND_DATA.loop, - volume: soundData.volume || DEFAULT_SOUND_DATA.volume - }; - if (!that.injector) { // WAITING => PLAYING | WAITING - debug("starting", that, options); - that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. - if (that.injector) { - print("started", entityIdentifier, that.url); - } else { // Don't hammer ensureSoundData or injector manager. - that.playAfter = now + (soundData.playbackGap || RECHECK_TIME); - } - return; - } - that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC - if (!that.injector.isPlaying) { // Subtle: a looping sound will not check playbackGap. - var gap = soundData.playbackGap || DEFAULT_SOUND_DATA; - if (gap) { // WAITING => PLAYING - gap = gap + randFloat(-Math.max(gap, soundData.playbackGapRange), soundData.playbackGapRange); // gapRange is bad name. Meant as +/- value. - // Setup next play just once, now. Changes won't be looked at while we wait. - that.playAfter = now + (that.sound.duration * 1000) + gap; - // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. - that.injector.restart(); - } else { // PLAYING => NO DATA - that.playAfter = Infinity; - } - } - }; -} - -function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { - ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. - var entitySound = entityCache[entityIdentifier]; - if (!entitySound) { - entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); - } - entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. -} -var nUpdates = UPDATES_PER_STATS_LOG, - lastStats = Date.now(); - -function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. - var now = Date.now(), - expirationCutoff = now - EXPIRATION_TIME, - userDataRecheckCutoff = now - RECHECK_TIME; - Object.keys(entityCache).forEach(function(entityIdentifier) { - entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); - }); - if (nUpdates-- <= 0) { // Report statistics. - // My figures using acAudioSearchCompatibleEntitySpawner.js with ONE user, N_SOUNDS = 2000, N_SILENT_ENTITIES_PER_SOUND = 5: - // audio-mixer: 23% of cpu (on Mac Activity Monitor) - // this script's assignment client: 106% of cpu. (overloaded) - // entities:12003 - // sounds:2000 - // playing:40 (correct) - // millisecondsPerUpdate:135 (100 requested, so behind by 35%. It would be nice to dig into why...) - var stats = { - entities: 0, - sounds: 0, - playing: 0, - millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG - }; - nUpdates = UPDATES_PER_STATS_LOG; - lastStats = now; - Object.keys(entityCache).forEach(function(entityIdentifier) { - var datum = entityCache[entityIdentifier]; - stats.entities++; - if (datum.url) { - stats.sounds++; - if (datum.injector && datum.injector.isPlaying) { - stats.playing++; - } - } - }); - print(JSON.stringify(stats)); - } -} - -// Update the set of which EntityData we know about. -// - -function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. - // This does at most: - // one queryOctree request of the entity server, and - // one findEntities geometry query of our own octree, and - // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. - // The idea is that this is a nice bounded piece of work that should not be done too frequently. - // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. - var avatar = AvatarList.getAvatar(avatarIdentifier), - avatarPosition = avatar && avatar.position; - if (!avatarPosition) { // No longer here. - return; - } - var timestamp = Date.now(); - EntityViewer.setPosition(avatarPosition); - EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. - var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); - debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); - entities.forEach(function(entityIdentifier) { - internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); - }); -} - -// Slowly update the set of data we have to work with. -// -var workQueue = []; - -function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates - workQueue = AvatarList.getAvatarIdentifiers().map(function(avatarIdentifier) { - return function() { - updateEntiesForAvatar(avatarIdentifier); - }; - }); -} -Script.setInterval(function() { - // There might be thousands of EntityData known to us, but only a few will require any work to update. - updateAllEntityData(); // i.e., this better be pretty fast. - // Each interval, we do no more than one updateEntitiesforAvatar. - if (!workQueue.length) { - workQueue = [updateWorkQueueForAvatarsPresent]; - } - workQueue.pop()(); // There's always one -}, UPDATE_TIME); \ No newline at end of file From e9ad06fca767f0d7e899b025a159e1a67d3c55a5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:25:12 -0800 Subject: [PATCH 072/292] removed query string --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 6d5c74e273..17c44eae41 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -142,7 +142,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 338427ed3e11a5556d401b6ca46c1a1b865575cc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:28:35 -0800 Subject: [PATCH 073/292] wait longer before sending message --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 17c44eae41..3d63eb4643 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -206,7 +206,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 1000) + }, 2000) } From 22a5f3dcc0aca96ee2439be2ad62590013dfe3a6 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:28:48 -0800 Subject: [PATCH 074/292] wait even longer --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 3d63eb4643..2974db8f59 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -206,7 +206,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 2000) + }, 3000) } From 4de951242cb63558d06e62ec1af83766083c8712 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 14:54:34 -0800 Subject: [PATCH 075/292] eraser positioned correctly --- .../whiteboardV2/whiteboardSpawner.js | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 2974db8f59..3fcf93e628 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -104,6 +104,32 @@ var eraser = Entities.addEntity({ y: -0.1, z: 0 }, + userData: JSON.stringify({ + wearable: { + joints: { + RightHand: [{ + x: 0.0207, + y: 0.1202, + z: 0.0493 + }, { + x: 0.1004, + y: 0.6424, + z: 0.717, + w: 0.250 + }], + LeftHand: [{ + x: -0.005, + y: 0.1101, + z: 0.053 + }, { + x: 0.7234, + y: 0.289, + z: 0.142, + w: 0.610 + }] + } + } + }) }); createMarkers(); @@ -206,7 +232,7 @@ function createMarker(modelURL, markerPosition, markerColor) { var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 3000) + }, 5000) } From ddae2d4f749a8aa1cd30bbcb75145367908dbb47 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 15:00:54 -0800 Subject: [PATCH 076/292] only erase stroke map on release and preload --- examples/homeContent/whiteboardV2/eraserEntityScript.js | 9 ++++++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 -- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 66399a9b8e..c78707e129 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -24,6 +24,7 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; + _this.strokeMap = []; }; Eraser.prototype = { @@ -35,10 +36,10 @@ var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); // Create a map of stroke entities and their positions - _this.strokeMap = []; + strokeIDs.forEach(function(strokeID) { var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); - if (strokeProps.name === _this.STROKE_NAME) { + if (strokeProps.name === _this.STROKE_NAME) { _this.strokeMap.push({ strokeID: strokeID, strokePosition: strokeProps.position @@ -53,7 +54,9 @@ } else {} }, - releaseEquip: function() {}, + releaseEquip: function() { + _this.strokeMap = []; + }, continueHolding: function() { diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 3fcf93e628..8402b241ed 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -149,8 +149,6 @@ function createMarkers() { blue: 200 }); - - markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation))); createMarker(modelURLS[1], markerPosition, { red: 200, From 24bf4f851f52fff5620b8462eaefcb2b3a8c775d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 15:23:02 -0800 Subject: [PATCH 077/292] can erase any stroke at any time --- .../whiteboardV2/eraserEntityScript.js | 42 ++++++------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index c78707e129..da67288829 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -24,7 +24,6 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; - _this.strokeMap = []; }; Eraser.prototype = { @@ -33,43 +32,28 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes + + }, + continueEquip: function() { + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); + if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { + _this.continueHolding(); + } + }, + + + continueHolding: function() { var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); // Create a map of stroke entities and their positions strokeIDs.forEach(function(strokeID) { var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); - if (strokeProps.name === _this.STROKE_NAME) { - _this.strokeMap.push({ - strokeID: strokeID, - strokePosition: strokeProps.position - }); + if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { + Entities.deleteEntity(strokeID); } }); }, - continueEquip: function() { - this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); - if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { - _this.continueHolding(); - } else {} - }, - - releaseEquip: function() { - _this.strokeMap = []; - }, - - - continueHolding: function() { - // search for marker strokes within certain radius of eraser - var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; - _this.strokeMap.forEach(function(strokeData, index) { - if (Vec3.distance(eraserPosition, strokeData.strokePosition) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { - Entities.deleteEntity(strokeData.strokeID); - _this.strokeMap.splice(index, 1); - } - }) - - }, preload: function(entityID) { this.entityID = entityID; From 8f304d95b39aeda6e2e20d6a5b1dfc0eea7caba9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 25 Feb 2016 15:26:42 -0800 Subject: [PATCH 078/292] rather than computing a velocity for entities held by others as a way to keep it active in local bullet, just call activateBody over and over --- interface/src/avatar/AvatarActionHold.cpp | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5b493c4215..03842ca5f9 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -153,32 +153,10 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu palmPosition = holdingAvatar->getLeftPalmPosition(); palmRotation = holdingAvatar->getLeftPalmRotation(); } - - // In this case we are simulating the grab of another avatar. - // Because the hand controller velocity for their palms is not transmitted over the - // network, we have to synthesize our own. - - if (_previousSet) { - // smooth linear velocity over two frames - glm::vec3 positionalDelta = palmPosition - _previousPositionalTarget; - linearVelocity = (positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep); - glm::quat deltaRotation = palmRotation * glm::inverse(_previousRotationalTarget); - float rotationAngle = glm::angle(deltaRotation); - if (rotationAngle > EPSILON) { - angularVelocity = glm::normalize(glm::axis(deltaRotation)); - angularVelocity *= (rotationAngle / deltaTimeStep); - } - - _previousPositionalDelta = positionalDelta; - _previousDeltaTimeStep = deltaTimeStep; - } } rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; - - // update linearVelocity based on offset via _relativePosition; - linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); return holdingAvatar; @@ -278,6 +256,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { }); forceBodyNonStatic(); + activateBody(true); } bool AvatarActionHold::updateArguments(QVariantMap arguments) { From 74452bc89009753af163f6fefb2322cdb6baf45f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 25 Feb 2016 15:34:50 -0800 Subject: [PATCH 079/292] put back some code that shouldn't have been removed --- interface/src/avatar/AvatarActionHold.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 03842ca5f9..b62cae1d58 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -157,6 +157,9 @@ std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::qu rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; + + // update linearVelocity based on offset via _relativePosition; + linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); return holdingAvatar; From 668894b3e06714be35da275127858f1505a7bfd0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 16:05:03 -0800 Subject: [PATCH 080/292] should work multiuser now --- .../whiteboardV2/markerEntityScript.js | 58 ++++++++++--------- .../whiteboardV2/whiteboardSpawner.js | 16 +---- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 761ef00e33..80ba1cea7e 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -23,22 +23,34 @@ MarkerTip = function() { _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; - this.strokeForwardOffset = 0.0001; - this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; - this.STROKE_WIDTH = 0.003 + _this.strokeForwardOffset = 0.0001; + _this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; + _this.STROKE_WIDTH = 0.003 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; _this.strokes = []; _this.PAINTING_TRIGGER_THRESHOLD = 0.2; - this.STROKE_NAME = "hifi-marker-stroke"; + _this.STROKE_NAME = "hifi-marker-stroke"; + _this.WHITEBOARD_SURFACE_NAME = "hifi-whiteboardDrawingSurface"; }; MarkerTip.prototype = { startEquip: function(id, params) { + _this.whiteboards = []; _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; + _this.markerColor = getEntityUserData(_this.entityID).markerColor; + // search for whiteboards + var markerPosition = Entities.getEntityProperties(_this.entityID, "position").position; + var entities = Entities.findEntities(markerPosition, 10); + entities.forEach(function(entity) { + var entityName = Entities.getEntityProperties(entity, "name").name; + if (entityName === _this.WHITEBOARD_SURFACE_NAME) { + _this.whiteboards.push(entity); + } + }); }, releaseEquip: function() { @@ -57,12 +69,14 @@ origin: markerProps.position, direction: Quat.getFront(markerProps.rotation) } - var intersection = Entities.findRayIntersectionBlocking(pickRay, true, [_this.whiteboard]); - + var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); + _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + print("EBL HIT") Overlays.editOverlay(_this.laserPointer, { visible: true, - position: intersection.intersection + position: intersection.intersection, + rotation: intersection.properties.rotation }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { @@ -71,8 +85,8 @@ _this.resetStroke(); } } else { - _this.resetStroke(); - + _this.resetStroke(); + Overlays.editOverlay(_this.laserPointer, { visible: false }); @@ -145,22 +159,6 @@ preload: function(entityID) { this.entityID = entityID; - - }, - - unload: function() { - Overlays.deleteOverlay(_this.laserPointer); - _this.strokes.forEach( function(stroke) { - Entities.deleteEntity(stroke); - }); - }, - - setProperties: function(myId, data) { - var data = JSON.parse(data); - - _this.whiteboard = data.whiteboard; - var whiteboardProps = Entities.getEntityProperties(_this.whiteboard, ["rotation"]); - _this.whiteboardNormal = Quat.getFront(whiteboardProps.rotation); _this.laserPointer = Overlays.addOverlay("circle3d", { color: { red: 220, @@ -169,9 +167,15 @@ }, solid: true, size: 0.01, - rotation: whiteboardProps.rotation }); - _this.markerColor = data.markerColor; + + }, + + unload: function() { + Overlays.deleteOverlay(_this.laserPointer); + _this.strokes.forEach(function(stroke) { + Entities.deleteEntity(stroke); + }); } }; diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 8402b241ed..08cd2b5a5f 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -56,7 +56,7 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(orientation))); var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", - name: "whiteboardDrawingSurface", + name: "hifi-whiteboardDrawingSurface", dimensions: { x: 1.82, y: 1.8, @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, @@ -193,6 +193,7 @@ function createMarker(modelURL, markerPosition, markerColor) { name: "marker", script: MARKER_SCRIPT_URL, userData: JSON.stringify({ + markerColor: markerColor, wearable: { joints: { RightHand: [{ @@ -222,17 +223,6 @@ function createMarker(modelURL, markerPosition, markerColor) { markers.push(marker); - Script.setTimeout(function() { - var data = { - whiteboard: whiteboardDrawingSurface, - markerColor: markerColor - } - var modelURL = Entities.getEntityProperties(marker, "modelURL").modelURL; - - Entities.callEntityMethod(marker, "setProperties", [JSON.stringify(data)]); - }, 5000) - - } From a79d334beda04001f48626fc4058b4a98ba131d2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 16:12:34 -0800 Subject: [PATCH 081/292] no query string --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 08cd2b5a5f..a5cc219240 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 0602bf7f1af7c3176874538da11d1afc4372d1cf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 16:20:35 -0800 Subject: [PATCH 082/292] logging --- examples/homeContent/whiteboardV2/markerEntityScript.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 80ba1cea7e..a9b8173097 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -48,9 +48,12 @@ entities.forEach(function(entity) { var entityName = Entities.getEntityProperties(entity, "name").name; if (entityName === _this.WHITEBOARD_SURFACE_NAME) { + _this.whiteboards.push(entity); } }); + + print("intersectable entities " + JSON.stringify(_this.whiteboards)) }, releaseEquip: function() { @@ -72,7 +75,6 @@ var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - print("EBL HIT") Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, From a25702535b09412c57f642735bbb794e222ea6ac Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 14:01:57 +1300 Subject: [PATCH 083/292] Style snapshots section --- .../resources/qml/controls-uit/TextField.qml | 10 +++-- .../preferences/BrowsablePreference.qml | 38 ++++++++++--------- .../qml/hifi/dialogs/RunningScripts.qml | 3 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index fa1f7c97ad..3f7395efcf 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -19,12 +19,16 @@ TextField { property int colorScheme: hifi.colorSchemes.light property string label: "" + property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0) + + placeholderText: textField.placeholderText FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } font.family: firaSansSemiBold.name font.pixelSize: hifi.fontSizes.textFieldInput height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered. - placeholderText: textField.label // Instead of separate label (see below). + + y: textFieldLabel.visible ? textFieldLabel.height : 0 style: TextFieldStyle { textColor: textField.colorScheme == hifi.colorSchemes.light @@ -44,9 +48,8 @@ TextField { padding.right: hifi.dimensions.textPadding } - /* - // Separate label instead of placeholderText. RalewaySemibold { + id: textFieldLabel text: textField.label size: hifi.fontSizes.inputLabel color: hifi.colors.lightGrayText @@ -55,5 +58,4 @@ TextField { anchors.bottomMargin: 4 visible: label != "" } - */ } diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml index 790d1d82ea..9a4ae2fbf9 100644 --- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml @@ -1,16 +1,24 @@ +// +// BrowsablePreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "../../dialogs" +import "../../controls-uit" Preference { id: root - property alias buttonText: button.text property alias text: dataTextField.text property alias placeholderText: dataTextField.placeholderText - property real spacing: 8 - height: labelText.height + Math.max(dataTextField.height, button.height) + spacing + property real spacing: 0 + height: Math.max(dataTextField.controlHeight, button.height) + spacing Component.onCompleted: { dataTextField.text = preference.value; @@ -21,24 +29,19 @@ Preference { preference.save(); } - Text { - id: labelText - color: enabled ? "black" : "gray" - text: root.label - } - TextField { id: dataTextField - placeholderText: root.placeholderText - text: preference.value - style: TextFieldStyle { renderType: Text.QtRendering } + anchors { - top: labelText.bottom left: parent.left right: button.left - topMargin: root.spacing - rightMargin: root.spacing + rightMargin: hifi.dimensions.contentSpacing.x + bottomMargin: spacing } + + label: root.label + placeholderText: root.placeholderText + colorScheme: hifi.colorSchemes.dark } Component { @@ -57,6 +60,5 @@ Preference { dataTextField.text = fileDialogHelper.urlToPath(fileUrl); }); } - } } diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index f8a8c87595..a174f4c4a7 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -167,8 +167,7 @@ Window { anchors.right: parent.right focus: true colorScheme: hifi.colorSchemes.dark - //placeholderText: "filter" - label: "Filter" + placeholderText: "filter" onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i") Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i") } From 513bc5d4efef82b83d66295320343c2800e9c972 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 14:10:37 +1300 Subject: [PATCH 084/292] Style scripts section --- interface/resources/qml/controls-uit/Button.qml | 2 +- .../qml/dialogs/preferences/ButtonPreference.qml | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index 9c7aee722b..5daec8eb36 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -18,7 +18,7 @@ Original.Button { id: button property int color: 0 width: 120 - height: 30 + height: 28 style: ButtonStyle { diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index b0c2846117..078a60df28 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -1,5 +1,16 @@ +// +// BrowsablePreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original + +import "../../controls-uit" Preference { id: root @@ -9,8 +20,9 @@ Preference { function save() { } - Original.Button { + Button { id: button onClicked: preference.trigger() + width: 180 } } From 4d2a65926ca81c68b810d53e650265d8186a8802 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 18:06:13 -0800 Subject: [PATCH 085/292] test --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index a5cc219240..ff2c593ea1 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 0ce4385554d4461db0d6b91af79fd64a798dc89a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 25 Feb 2016 18:22:54 -0800 Subject: [PATCH 086/292] no offset increment --- examples/homeContent/whiteboardV2/markerEntityScript.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index a9b8173097..82ea1a2b69 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,6 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_FORWARD_OFFSET_INCRERMENT = 0.00001; _this.STROKE_WIDTH = 0.003 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; @@ -130,7 +129,6 @@ var localPoint = Vec3.subtract(basePosition, _this.strokeBasePosition); localPoint = Vec3.sum(localPoint, Vec3.multiply(_this.whiteboardNormal, _this.strokeForwardOffset)); - _this.strokeForwardOffset -= _this.STROKE_FORWARD_OFFSET_INCRERMENT; if (_this.linePoints.length > 0) { var distance = Vec3.distance(localPoint, _this.linePoints[_this.linePoints.length - 1]); From b620427ae8d6fbc308e90e05b13b25c7fbcf7069 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 15:54:50 +1300 Subject: [PATCH 087/292] Fix text field label color --- interface/resources/qml/controls-uit/TextField.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index 3f7395efcf..aad07730ae 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -18,6 +18,7 @@ TextField { id: textField property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property string label: "" property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0) @@ -31,11 +32,11 @@ TextField { y: textFieldLabel.visible ? textFieldLabel.height : 0 style: TextFieldStyle { - textColor: textField.colorScheme == hifi.colorSchemes.light + textColor: isLightColorScheme ? (textField.focus ? hifi.colors.black : hifi.colors.lightGray) : (textField.focus ? hifi.colors.white : hifi.colors.lightGrayText) background: Rectangle { - color: textField.colorScheme == hifi.colorSchemes.light + color: isLightColorScheme ? (textField.focus ? hifi.colors.white : hifi.colors.lightGray) : (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow) border.color: hifi.colors.primaryHighlight @@ -52,7 +53,7 @@ TextField { id: textFieldLabel text: textField.label size: hifi.fontSizes.inputLabel - color: hifi.colors.lightGrayText + color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText anchors.left: parent.left anchors.bottom: parent.top anchors.bottomMargin: 4 From 3dc9d01aab11b66344262485ec0c7adde2c9a89a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 15:56:19 +1300 Subject: [PATCH 088/292] Style checkbox control --- .../resources/qml/controls-uit/CheckBox.qml | 70 +++++++++++++++++++ .../dialogs/preferences/ButtonPreference.qml | 2 +- .../preferences/CheckBoxPreference.qml | 15 +++- .../qml/styles-uit/HifiConstants.qml | 6 ++ 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 interface/resources/qml/controls-uit/CheckBox.qml diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml new file mode 100644 index 0000000000..a909f916cf --- /dev/null +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -0,0 +1,70 @@ +// +// CheckBox.qml +// +// Created by David Rowe on 26 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" + +Original.CheckBox { + id: checkBox + HifiConstants { id: hifi } + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + + readonly property int boxSize: 14 + readonly property int boxRadius: 3 + readonly property int checkSize: 10 + readonly property int checkRadius: 2 + + style: CheckBoxStyle { + indicator: Rectangle { + id: box + width: boxSize + height: boxSize + radius: boxRadius + gradient: Gradient { + GradientStop { + position: 0.2 + color: pressed || hovered + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart) + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) + } + GradientStop { + position: 1.0 + color: pressed || hovered + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish) + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) + } + } + + Rectangle { + id: check + width: checkSize + height: checkSize + radius: checkRadius + anchors.centerIn: parent + color: hifi.colors.checkboxChecked + border.width: 1 + border.color: hifi.colors.checkboxCheckedBorder + visible: checked && !pressed || !checked && pressed + } + } + + label: RalewaySemibold { + text: control.text + size: hifi.fontSizes.inputLabel + color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText + x: checkBox.boxSize / 2 + } + } +} diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index 078a60df28..c7b5583bf3 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -1,5 +1,5 @@ // -// BrowsablePreference.qml +// ButtonPreference.qml // // Created by Bradley Austin Davis on 18 Jan 2016 // Copyright 2016 High Fidelity, Inc. diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index f28f3ab90b..5e6ce3db3c 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -1,6 +1,16 @@ +// +// CheckBoxPreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 -import "../../controls" + +import "../../controls-uit" Preference { id: root @@ -20,5 +30,6 @@ Preference { id: checkBox anchors.fill: parent text: root.label + colorScheme: hifi.colorSchemes.dark } } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 77e74163c3..d0766663e8 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -61,6 +61,12 @@ Item { readonly property color tableRowDarkEven: "#a6181818" readonly property color tableScrollHandle: "#707070" readonly property color tableScrollBackground: "#323232" + readonly property color checkboxLightStart: "#ffffff" + readonly property color checkboxLightFinish: "#afafaf" + readonly property color checkboxDarkStart: "#7d7d7d" + readonly property color checkboxDarkFinish: "#6b6a6b" + readonly property color checkboxChecked: primaryHighlight + readonly property color checkboxCheckedBorder: "#36cdff" } Item { From 3cac94ed355915e9179a028c2d1f6e6dd70842d3 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Feb 2016 17:32:25 +1300 Subject: [PATCH 089/292] Refactor label style --- .../resources/qml/controls-uit/CheckBox.qml | 5 ++--- .../resources/qml/controls-uit/Label.qml | 20 +++++++++++++++++++ .../resources/qml/controls-uit/TextField.qml | 6 +++--- 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 interface/resources/qml/controls-uit/Label.qml diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index a909f916cf..255151e4e0 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -60,10 +60,9 @@ Original.CheckBox { } } - label: RalewaySemibold { + label: Label { text: control.text - size: hifi.fontSizes.inputLabel - color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText + colorScheme: checkBox.colorScheme x: checkBox.boxSize / 2 } } diff --git a/interface/resources/qml/controls-uit/Label.qml b/interface/resources/qml/controls-uit/Label.qml new file mode 100644 index 0000000000..f4015edd62 --- /dev/null +++ b/interface/resources/qml/controls-uit/Label.qml @@ -0,0 +1,20 @@ +// +// Label.qml +// +// Created by David Rowe on 26 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 + +import "../styles-uit" + +RalewaySemibold { + property int colorScheme: hifi.colorSchemes.light + + size: hifi.fontSizes.inputLabel + color: colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGray : hifi.colors.lightGrayText +} diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index aad07730ae..1d2d6a2298 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -13,6 +13,7 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import "../styles-uit" +import "../controls-uit" as HifiControls TextField { id: textField @@ -49,11 +50,10 @@ TextField { padding.right: hifi.dimensions.textPadding } - RalewaySemibold { + HifiControls.Label { id: textFieldLabel text: textField.label - size: hifi.fontSizes.inputLabel - color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText + colorScheme: textField.colorScheme anchors.left: parent.left anchors.bottom: parent.top anchors.bottomMargin: 4 From d64b9bb6d95713311fe2b4245336185964728268 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 26 Feb 2016 09:18:40 -0800 Subject: [PATCH 090/292] Drafting the support for gloss map --- .../src/model-networking/ModelCache.cpp | 4 ++- .../src/model-networking/TextureCache.cpp | 4 +++ .../src/model-networking/TextureCache.h | 14 +++++++-- libraries/model/src/model/TextureMap.cpp | 30 +++++++++++++++++++ libraries/model/src/model/TextureMap.h | 1 + 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 7dea008e1d..d944b0c686 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -364,7 +364,9 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB } if (!material.roughnessTexture.filename.isEmpty()) { // FIXME: COnvert from gloss to roughness if material.roughnessTexture.isGlossmap; - networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), ROUGHNESS_TEXTURE, material.roughnessTexture.content); + networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), + (material.roughnessTexture.isGlossmap ? GLOSS_TEXTURE : ROUGHNESS_TEXTURE), + material.roughnessTexture.content); networkMaterial->roughnessTextureName = material.roughnessTexture.name; auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 1b8c73bb80..d49ff91abf 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -216,6 +216,10 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { return TextureLoaderFunc(model::TextureUsage::createRoughnessTextureFromImage); break; } + case GLOSS_TEXTURE: { + return TextureLoaderFunc(model::TextureUsage::createRoughnessTextureFromGlossImage); + break; + } case SPECULAR_TEXTURE: { return TextureLoaderFunc(model::TextureUsage::createMetallicTextureFromImage); break; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index e9c232c4b6..ded90e7780 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -29,8 +29,18 @@ class NetworkTexture; typedef QSharedPointer NetworkTexturePointer; -enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, ROUGHNESS_TEXTURE, EMISSIVE_TEXTURE, - CUBE_TEXTURE, OCCLUSION_TEXTURE, LIGHTMAP_TEXTURE, CUSTOM_TEXTURE +enum TextureType { + DEFAULT_TEXTURE, + NORMAL_TEXTURE, + BUMP_TEXTURE, + SPECULAR_TEXTURE, + ROUGHNESS_TEXTURE, + GLOSS_TEXTURE, + EMISSIVE_TEXTURE, + CUBE_TEXTURE, + OCCLUSION_TEXTURE, + LIGHTMAP_TEXTURE, + CUSTOM_TEXTURE }; /// Stores cached textures, including render-to-texture targets. diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index b2504c4085..41be048440 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -280,6 +280,36 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma return theTexture; } +gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& srcImage, const std::string& srcImageName) { + QImage image = srcImage; + if (!image.hasAlphaChannel()) { + if (image.format() != QImage::Format_RGB888) { + image = image.convertToFormat(QImage::Format_RGB888); + } + } else { + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); + } + } + + image = image.convertToFormat(QImage::Format_Grayscale8); + + gpu::Texture* theTexture = nullptr; + if ((image.width() > 0) && (image.height() > 0)) { + + gpu::Element formatGPU = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); + + theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + theTexture->autoGenerateMips(-1); + + // FIXME queue for transfer to GPU and block on completion + } + + return theTexture; +} + gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { QImage image = srcImage; if (!image.hasAlphaChannel()) { diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index 886bc9d3b3..228adb25e6 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -35,6 +35,7 @@ public: static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createRoughnessTextureFromImage(const QImage& image, const std::string& srcImageName); + static gpu::Texture* createRoughnessTextureFromGlossImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createMetallicTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName); static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName); From 6c9cf386a698422ac4f03c777981a0e702ffebac Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Feb 2016 10:14:09 -0800 Subject: [PATCH 091/292] when trigger is squeezed, check for things stuck to hand and unhook them --- examples/controllers/handControllerGrab.js | 13 +++++++++ .../entities/src/EntityScriptingInterface.cpp | 27 +++++++++++++++++++ .../entities/src/EntityScriptingInterface.h | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 04e93334cb..9eac023ac4 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -801,6 +801,8 @@ function MyController(hand) { this.isInitialGrab = false; this.doubleParentGrab = false; + this.checkForStrayChildren(); + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { this.setState(STATE_RELEASE); return; @@ -1751,6 +1753,17 @@ function MyController(hand) { return data; }; + this.checkForStrayChildren = function() { + // sometimes things can get parented to a hand and this script is unaware. Search for such entities and + // unhook them. + var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, handJointIndex); + children.forEach(function(childID) { + print("disconnecting stray child of hand: " + childID); + Entities.editEntity(childID, {parentID: NULL_UUID}); + }); + } + this.deactivateEntity = function(entityID, noVelocity) { var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); if (data && data["refCount"]) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d7a47136b5..4857fb8529 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -12,6 +12,7 @@ #include "EntityItemID.h" #include +#include #include "EntitiesLogging.h" #include "EntityActionFactoryInterface.h" @@ -1063,6 +1064,32 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) { return result; } +QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) { + QVector result; + if (!_entityTree) { + return result; + } + _entityTree->withReadLock([&] { + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + return; + } + bool success; + SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success); + if (!success) { + return; + } + SpatiallyNestablePointer parent = parentWP.lock(); + if (!parent) { + return; + } + parent->forEachChild([&](SpatiallyNestablePointer child) { + result.push_back(child->getID()); + }); + }); + return result; +} + float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) { return std::abs(mass * (newVelocity - oldVelocity)); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fef000cc3d..79d8f0a0b0 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -168,7 +168,7 @@ public slots: Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); - + Q_INVOKABLE QVector getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex); signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); From 25a2d1eb93e28f35190b5e89cb2e02353def2b64 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 10:14:27 -0800 Subject: [PATCH 092/292] fixed rotation --- .../whiteboardV2/markerEntityScript.js | 2 +- .../whiteboardV2/whiteboardSpawner.js | 56 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 82ea1a2b69..e6f7e3cf81 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -72,8 +72,8 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); - _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { + _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index ff2c593ea1..6689672095 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -23,7 +23,7 @@ var markerRotation = Quat.fromVec3Degrees({ orientation.x = 0; var whiteboardRotation = Quat.fromVec3Degrees({ x: 0, - y: orientation.y - 90, + y: orientation.y, z: 0 }); orientation = Quat.fromVec3Degrees(orientation); @@ -31,8 +31,8 @@ var markers = []; var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); -var WHITEBOARD_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard-3.fbx"; -var WHITEBOARD_COLLISION_HULL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Whiteboard.obj"; +var WHITEBOARD_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Whiteboard-3+(1).fbx"; +var WHITEBOARD_COLLISION_HULL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/whiteboardCollisionHull.obj"; var whiteboard = Entities.addEntity({ type: "Model", name: "whiteboard", @@ -42,9 +42,9 @@ var whiteboard = Entities.addEntity({ shapeType: 'compound', compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL, dimensions: { - x: 0.4636, - y: 2.7034, - z: 1.8653 + x: 1.86, + y: 2.7, + z: 0.4636 }, }); @@ -68,7 +68,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ blue: 200 }, position: whiteboardSurfacePosition, - rotation: orientation, + rotation: whiteboardRotation, visible: false, parentID: whiteboard }); @@ -108,9 +108,9 @@ var eraser = Entities.addEntity({ wearable: { joints: { RightHand: [{ - x: 0.0207, - y: 0.1202, - z: 0.0493 + x: 0.020, + y: 0.120, + z: 0.049 }, { x: 0.1004, y: 0.6424, @@ -122,7 +122,7 @@ var eraser = Entities.addEntity({ y: 0.1101, z: 0.053 }, { - x: 0.7234, + x: 0.723, y: 0.289, z: 0.142, w: 0.610 @@ -186,9 +186,9 @@ function createMarker(modelURL, markerPosition, markerColor) { }, position: markerPosition, dimensions: { - x: 0.0270, - y: 0.0272, - z: 0.1641 + x: 0.027, + y: 0.027, + z: 0.164 }, name: "marker", script: MARKER_SCRIPT_URL, @@ -197,24 +197,24 @@ function createMarker(modelURL, markerPosition, markerColor) { wearable: { joints: { RightHand: [{ - x: 0.001109793782234192, - y: 0.13991504907608032, - z: 0.05035984516143799 + x: 0.001, + y: 0.139, + z: 0.050 }, { - x: -0.7360993027687073, - y: -0.04330085217952728, - z: -0.10863728821277618, - w: -0.6666942238807678 + x: -0.73, + y: -0.043, + z: -0.108, + w: -0.666 }], LeftHand: [{ - x: 0.007193896919488907, - y: 0.15147076547145844, - z: 0.06174466013908386 + x: 0.007, + y: 0.151, + z: 0.061 }, { - x: -0.4174973964691162, - y: 0.631147563457489, - z: -0.3890438377857208, - w: -0.52535080909729 + x: -0.417, + y: 0.631, + z: -0.389, + w: -0.525 }] } } From b0cb4b719994a2e825c7b56f0bf515544e8ef61f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 26 Feb 2016 10:26:02 -0800 Subject: [PATCH 093/292] disable boundaries --- .../CellScience/importCellScience.js | 513 +++++++++--------- 1 file changed, 248 insertions(+), 265 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/importCellScience.js b/unpublishedScripts/DomainContent/CellScience/importCellScience.js index 6a6de23f4e..876df8adb1 100644 --- a/unpublishedScripts/DomainContent/CellScience/importCellScience.js +++ b/unpublishedScripts/DomainContent/CellScience/importCellScience.js @@ -5,7 +5,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var version = 1100; +var version = 1112; var cellLayout; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; @@ -112,7 +112,7 @@ var scenes = [{ y: 0, z: 0 }, - radius: 450, + radius: 500, number: 10, userData: JSON.stringify({ entryPoint: locations.cellLayout[1], @@ -151,267 +151,253 @@ var scenes = [{ skybox: "cosmos_skybox_blurred" }, instances: [{ - model: "translation", - dimensions: { - x: 10, - y: 16, - z: 10 + model: "translation", + dimensions: { + x: 10, + y: 16, + z: 10 + }, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 300, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - offset: { - x: 0, - y: 0, - z: 0 + target: locations.ribosome[1], + location: locations.ribosome[0], + baseURL: baseLocation + }), + script: "zoom.js?" + version, + visible: true + }, { + model: "vesicle", + dimensions: { + x: 60, + y: 60, + z: 60 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1000, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { //golgi vesicles + model: "vesicle", + dimensions: { + x: 10, + y: 10, + z: 10 + }, + randomSize: 10, + offset: { + x: -319, + y: 66, + z: 976 + }, + radius: 140, + number: 10, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + script: "", + visible: true + }, { //golgi vesicles + model: "vesicle", + dimensions: { + x: 15, + y: 15, + z: 15 + }, + randomSize: 10, + offset: { + x: -319, + y: 66, + z: 976 + }, + radius: 115, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { + model: "vesicle", + dimensions: { + x: 50, + y: 50, + z: 50 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 600, + number: 15, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + script: "", + visible: true + }, { //outer vesicles + model: "vesicle", + dimensions: { + x: 60, + y: 60, + z: 60 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1600, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + script: "", + visible: true + }, { //outer vesicles + model: "vesicle", + dimensions: { + x: 40, + y: 40, + z: 40 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1400, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { //outer vesicles + model: "vesicle", + dimensions: { + x: 80, + y: 80, + z: 80 + }, + randomSize: 10, + offset: { + x: 0, + y: 0, + z: 0 + }, + radius: 1800, + number: 22, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }), + visible: true + }, { + model: "hexokinase", + dimensions: { + x: 3, + y: 4, + z: 3 + }, + randomSize: 10, + offset: { + x: 236, + y: 8, + z: 771 + }, + radius: 80, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - radius: 300, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.ribosome[1], - location: locations.ribosome[0], - baseURL: baseLocation - }), - script: "zoom.js?" + version, - visible: true - }, { - model: "vesicle", - dimensions: { - x: 60, - y: 60, - z: 60 + target: locations.hexokinase[1], + location: locations.hexokinase[0], + baseURL: baseLocation + }), + script: "zoom.js?" + version, + visible: true + }, { + model: "pfructo_kinase", + dimensions: { + x: 3, + y: 4, + z: 3 + }, + randomSize: 10, + offset: { + x: 236, + y: 8, + z: 771 + }, + radius: 60, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 + target: locations.hexokinase[1], + location: locations.hexokinase[0], + }), + script: "zoom.js?" + version, + visible: true + }, { + model: "glucose_isomerase", + dimensions: { + x: 3, + y: 4, + z: 3 + }, + randomSize: 10, + offset: { + x: 236, + y: 8, + z: 771 + }, + radius: 70, + number: 7, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false }, - radius: 1000, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - visible: true - }, { //golgi vesicles - model: "vesicle", - dimensions: { - x: 10, - y: 10, - z: 10 - }, - randomSize: 10, - offset: { - x: -319, - y: 66, - z: 976 - }, - radius: 140, - number: 10, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "", - visible: true - }, { //golgi vesicles - model: "vesicle", - dimensions: { - x: 15, - y: 15, - z: 15 - }, - randomSize: 10, - offset: { - x: -319, - y: 66, - z: 976 - }, - radius: 115, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - visible: true - }, { - model: "vesicle", - dimensions: { - x: 50, - y: 50, - z: 50 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 600, - number: 15, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "", - visible: true - }, { //outer vesicles - model: "vesicle", - dimensions: { - x: 60, - y: 60, - z: 60 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1600, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - script: "", - visible: true - }, { //outer vesicles - model: "vesicle", - dimensions: { - x: 40, - y: 40, - z: 40 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1400, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - visible: true - }, { //outer vesicles - model: "vesicle", - dimensions: { - x: 80, - y: 80, - z: 80 - }, - randomSize: 10, - offset: { - x: 0, - y: 0, - z: 0 - }, - radius: 1800, - number: 22, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }), - visible: true - }, { - model: "hexokinase", - dimensions: { - x: 3, - y: 4, - z: 3 - }, - randomSize: 10, - offset: { - x: 236, - y: 8, - z: 771 - }, - radius: 80, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.hexokinase[1], - location: locations.hexokinase[0], - baseURL: baseLocation - }), - script: "zoom.js?" + version, - visible: true - }, { - model: "pfructo_kinase", - dimensions: { - x: 3, - y: 4, - z: 3 - }, - randomSize: 10, - offset: { - x: 236, - y: 8, - z: 771 - }, - radius: 60, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.hexokinase[1], - location: locations.hexokinase[0], - }), - script: "zoom.js?" + version, - visible: true - }, { - model: "glucose_isomerase", - dimensions: { - x: 3, - y: 4, - z: 3 - }, - randomSize: 10, - offset: { - x: 236, - y: 8, - z: 771 - }, - radius: 70, - number: 7, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - }, - target: locations.hexokinase[1], - location: locations.hexokinase[0], - }), - script: "zoom.js?" + version, - visible: true - } - // { - // model:"NPC", - // dimensions:{x:20,y:20,z:20}, - // randomSize: 10, - // offset:{x:208.593693,y:6.113100222,z:153.3202277}, - // radius:520, - // number:25, - // userData: "", - // script:"", - // visible:true - // } - - - ], + target: locations.hexokinase[1], + location: locations.hexokinase[0], + }), + script: "zoom.js?" + version, + visible: true + }], boundary: { radius: locations.cellLayout[2], center: locations.cellLayout[0], @@ -573,7 +559,7 @@ function ImportScene(scene) { CreateZone(scene); CreateInstances(scene); - CreateBoundary(scene); + // CreateBoundary(scene); // print("done " + scene.name); @@ -797,11 +783,9 @@ function CreateInstances(scene) { -function CreateIdentification(name, position, rotation, dimensions, showDistance, parentID) { +function CreateIdentification(name, position, rotation, dimensions, showDistance) { //print ("creating ID for " + name); - if (parentID === undefined) { - parentID = "{00000000-0000-0000-0000-000000000000}"; - } + Entities.addEntity({ type: "Sphere", name: "ID for " + name, @@ -810,7 +794,6 @@ function CreateIdentification(name, position, rotation, dimensions, showDistance green: 0, blue: 0 }, - parentID: parentID, dimensions: dimensions, position: position, rotation: rotation, From 5594f1e4e586fbc3967c1ce13526915cfcc457cd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Feb 2016 10:27:34 -0800 Subject: [PATCH 094/292] if equipped entity vanishes, reset grab state --- examples/controllers/handControllerGrab.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9eac023ac4..45d27cbbb9 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1446,6 +1446,13 @@ function MyController(hand) { this.heartBeat(this.grabbedEntity); var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]); + if (!props.position) { + // server may have reset, taking our equipped entity with it. move back to "off" stte + this.setState(STATE_RELEASE); + this.callEntityMethodOnGrabbed("releaseGrab"); + return; + } + if (props.parentID == MyAvatar.sessionUUID && Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) { // for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip. From 83713898cc54ba47eaac53c8cc4f13c4ed166d83 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 26 Feb 2016 10:34:27 -0800 Subject: [PATCH 095/292] maze should delete stray balls --- unpublishedScripts/DomainContent/Home/tiltMaze/maze.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js b/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js index 557861ba30..f155c28b41 100644 --- a/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js +++ b/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js @@ -96,6 +96,9 @@ if (this.ballLocked === true) { return; } + if(this.ball!==null){ + Entities.deleteEntity(this.ball); + } var properties = { name: 'Hifi Tilt Maze Ball', From 6c6ea3f0a76ce9bdc433216f3e3bcb6ad5d678e0 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 26 Feb 2016 10:42:45 -0800 Subject: [PATCH 096/292] code cleanup --- .../DomainContent/CellScience/moveCellsAC.js | 14 +++++++------- .../DomainContent/CellScience/moveVesiclesAC.js | 10 +++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js index 881f8e981c..cf35e081e0 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveCellsAC.js @@ -30,18 +30,18 @@ function findCells() { var results = Entities.findEntities(basePosition, 60000); if (results.length === 0) { - // print('no entities found') + // print('no entities found') return; } results.forEach(function(v) { var name = Entities.getEntityProperties(v, 'name').name; - // print('name is:: ' + name) + // print('name is:: ' + name) if (name === 'Cell') { - // print('found a cell!!' + v) + // print('found a cell!!' + v) Script.setTimeout(function() { moveCell(v); - }, Math.random() * THROTTLE_RATE) + }, Math.random() * THROTTLE_RATE); } }); } @@ -51,7 +51,7 @@ var minAngularVelocity = 0.01; var maxAngularVelocity = 0.03; function moveCell(entityId) { - // print('moving a cell! ' + entityId) + // print('moving a cell! ' + entityId) var magnitudeAV = maxAngularVelocity; @@ -60,7 +60,7 @@ function moveCell(entityId) { y: Math.random() - 0.5, z: Math.random() - 0.5 }; - // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); + // print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x); Entities.editEntity(entityId, { angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV)) }); @@ -84,7 +84,7 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - // print('SHOULD FIND CELLS!!!') + // print('SHOULD FIND CELLS!!!') sinceLastUpdate = 0; findCells(); } else { diff --git a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js index 3e70934cba..922f0d94cf 100644 --- a/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js +++ b/unpublishedScripts/DomainContent/CellScience/moveVesiclesAC.js @@ -30,18 +30,17 @@ function findVesicles() { var results = Entities.findEntities(basePosition, 60000); if (results.length === 0) { - print('no entities found') + // print('no entities found'); return; } results.forEach(function(v) { var name = Entities.getEntityProperties(v, 'name').name; - print('name is:: ' + name) if (name === 'vesicle') { - // print('found a vesicle!!' + v) + //print('found a vesicle!!' + v) Script.setTimeout(function() { moveVesicle(v); - }, Math.random() * THROTTLE_RATE) + }, Math.random() * THROTTLE_RATE); } }); } @@ -78,7 +77,6 @@ function moveVesicle(entityId) { } function update(deltaTime) { - // print('deltaTime',deltaTime) if (!initialized) { print("checking for servers..."); if (Entities.serversExist() && Entities.canRez()) { @@ -93,11 +91,9 @@ function update(deltaTime) { if (THROTTLE === true) { sinceLastUpdate = sinceLastUpdate + deltaTime * 1000; if (sinceLastUpdate > THROTTLE_RATE) { - // print('SHOULD FIND VESICLES!!!') sinceLastUpdate = 0; findVesicles(); } else { - // print('returning in update ' + sinceLastUpdate) return; } } From c81f3256ddc2d9376dd134bc531af38ca09a7c68 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 10:58:22 -0800 Subject: [PATCH 097/292] rotation --- .../whiteboardV2/eraserEntityScript.js | 26 +++++++++++++++---- .../whiteboardV2/markerEntityScript.js | 2 +- .../whiteboardV2/whiteboardSpawner.js | 10 +++---- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index da67288829..86e80659bf 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -32,9 +32,11 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes - + Overlays.editOverlay(_this.searchSphere, {visible: true}); }, continueEquip: function() { + _this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + Overlays.editOverlay(_this.searchSphere, {position: _this.eraserPosition}); this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { _this.continueHolding(); @@ -43,22 +45,36 @@ continueHolding: function() { - var eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; - var strokeIDs = Entities.findEntities(eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); + var strokeIDs = Entities.findEntities(_this.eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS); // Create a map of stroke entities and their positions strokeIDs.forEach(function(strokeID) { var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]); - if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { + if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(_this.eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) { Entities.deleteEntity(strokeID); } }); }, + releaseEquip: function() { + Overlays.editOverlay(_this.searchSphere, {visible: false}); + }, + preload: function(entityID) { - this.entityID = entityID; + _this.entityID = entityID; + _this.searchSphere = Overlays.addOverlay('sphere', { + size: _this.ERASER_TO_STROKE_SEARCH_RADIUS, + color: {red: 200, green: 10, blue: 10}, + alpha: 0.2, + solid: true, + visible: false + }) }, + + unload: function() { + Overlays.deleteOverlay(_this.searchSphere); + } }; // entity scripts always need to return a newly constructed object of our type diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index e6f7e3cf81..e379fac016 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -73,7 +73,7 @@ } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); + _this.whiteboardNormal = Quat.getRight(intersection.properties.rotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 6689672095..8826c8387a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -31,7 +31,7 @@ var markers = []; var whiteboardPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation))); -var WHITEBOARD_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Whiteboard-3+(1).fbx"; +var WHITEBOARD_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Whiteboard-4.fbx"; var WHITEBOARD_COLLISION_HULL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/whiteboardCollisionHull.obj"; var whiteboard = Entities.addEntity({ type: "Model", @@ -69,7 +69,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ }, position: whiteboardSurfacePosition, rotation: whiteboardRotation, - visible: false, + // visible: false, parentID: whiteboard }); @@ -78,8 +78,8 @@ var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser-2.fbx"; var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); -var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(orientation))); -eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getFront(whiteboardRotation))); +var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(whiteboardRotation))); +eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getRight(whiteboardRotation))); var eraser = Entities.addEntity({ type: "Model", @@ -92,7 +92,7 @@ var eraser = Entities.addEntity({ y: 0.0393, z: 0.2083 }, - rotation: whiteboardRotation, + rotation: markerRotation, dynamic: true, gravity: { x: 0, From a0203cf9d58426dfd5a47123ed175cca9a887013 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 26 Feb 2016 11:13:10 -0800 Subject: [PATCH 098/292] Update BasePacket to 0-initialize data --- libraries/networking/src/udt/BasePacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/BasePacket.cpp b/libraries/networking/src/udt/BasePacket.cpp index 54342d9cba..000573d241 100644 --- a/libraries/networking/src/udt/BasePacket.cpp +++ b/libraries/networking/src/udt/BasePacket.cpp @@ -58,7 +58,7 @@ BasePacket::BasePacket(qint64 size) { Q_ASSERT(size >= 0 || size < maxPayload); _packetSize = size; - _packet.reset(new char[_packetSize]); + _packet.reset(new char[_packetSize]()); _payloadCapacity = _packetSize; _payloadSize = 0; _payloadStart = _packet.get(); From a7bb47fbccbd764847ec4fb12a70ce1d2fe6cf02 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 26 Feb 2016 11:20:31 -0800 Subject: [PATCH 099/292] Fix initialization of variables for SendQueue and Connection --- libraries/networking/src/udt/Connection.cpp | 7 +++++++ libraries/networking/src/udt/SendQueue.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 0e1f3ddefb..1ab8441ba3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -88,6 +88,7 @@ SendQueue& Connection::getSendQueue() { // Lasily create send queue _sendQueue = SendQueue::create(_parentSocket, _destination); + _lastReceivedACK = _sendQueue->getCurrentSequenceNumber(); #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Created SendQueue for connection to" << _destination; @@ -410,6 +411,12 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in // refuse to process any packets until we've received the handshake return false; } + + if (!_hasReceivedData) { + _initialReceiveSequenceNumber = sequenceNumber; + _lastReceivedSequenceNumber = sequenceNumber - 1; + _lastSentACK = sequenceNumber - 1; + } _isReceivingData = _hasReceivedData = true; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 8a8105bb26..77b0c53da7 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -92,7 +92,7 @@ SendQueue::SendQueue(Socket* socket, HifiSockAddr dest) : // set our member variables from randomized initial number _currentSequenceNumber = _initialSequenceNumber - 1; _atomicCurrentSequenceNumber = uint32_t(_currentSequenceNumber); - _lastACKSequenceNumber = uint32_t(_initialSequenceNumber); + _lastACKSequenceNumber = uint32_t(_currentSequenceNumber) - 1; } void SendQueue::queuePacket(std::unique_ptr packet) { From 1542b9da12841408836026160d2e18592d88bcf3 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 11:33:59 -0800 Subject: [PATCH 100/292] rotation works right now --- examples/homeContent/whiteboardV2/markerEntityScript.js | 6 +++--- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index e379fac016..fc4cbba1bd 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,7 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH = 0.003 + _this.STROKE_WIDTH = 0.03 _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -73,11 +73,11 @@ } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - _this.whiteboardNormal = Quat.getRight(intersection.properties.rotation); + _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, - rotation: intersection.properties.rotation + // rotation: intersection.properties.rotation }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index 8826c8387a..da9aad4c33 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -69,7 +69,7 @@ var whiteboardDrawingSurface = Entities.addEntity({ }, position: whiteboardSurfacePosition, rotation: whiteboardRotation, - // visible: false, + visible: false, parentID: whiteboard }); @@ -166,7 +166,7 @@ function createMarkers() { function createMarker(modelURL, markerPosition, markerColor) { - var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js"); + var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js?v1" + Math.random()); var marker = Entities.addEntity({ type: "Model", modelURL: modelURL, From 6e0ddb39189bf588d42ab4e27f1a1cc55b52cac2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 11:48:15 -0800 Subject: [PATCH 101/292] really fixed rotation --- examples/homeContent/whiteboardV2/markerEntityScript.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index fc4cbba1bd..064add57be 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,7 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH = 0.03 + _this.STROKE_WIDTH = 0.03; _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -72,12 +72,14 @@ direction: Quat.getFront(markerProps.rotation) } var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); + if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - _this.whiteboardNormal = Quat.getFront(intersection.properties.rotation); + var whiteboardRotation = Entities.getEntityProperties(intersection.entityID, "rotation").rotation; + _this.whiteboardNormal = Quat.getFront(whiteboardRotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, - // rotation: intersection.properties.rotation + rotation: whiteboardRotation }) _this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) { From 6d9c5856041ffd26eb1f06bbe03a463fb6fecb47 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 26 Feb 2016 12:01:59 -0800 Subject: [PATCH 102/292] add fade between depths in depth reticle --- examples/depthReticle.js | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index a60e61d07c..a8afb80df2 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -12,17 +12,24 @@ var APPARENT_2D_OVERLAY_DEPTH = 1.0; var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant -var lastDepthCheckTime = 0; +var lastDepthCheckTime = Date.now(); +var desiredDepth = APPARENT_2D_OVERLAY_DEPTH; +var wasDepth = Reticle.depth; // depth at the time we changed our desired depth +var desiredDepthLastSet = lastDepthCheckTime; // time we changed our desired depth +var TIME_BETWEEN_DEPTH_CHECKS = 100; +var TIME_TO_FADE_DEPTH = 50; Script.update.connect(function(deltaTime) { - var TIME_BETWEEN_DEPTH_CHECKS = 100; - var timeSinceLastDepthCheck = Date.now() - lastDepthCheckTime; + var now = Date.now(); + var timeSinceLastDepthCheck = now - lastDepthCheckTime; if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) { + var newDesiredDepth = desiredDepth; + lastDepthCheckTime = now; var reticlePosition = Reticle.position; // first check the 2D Overlays if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) { - Reticle.setDepth(APPARENT_2D_OVERLAY_DEPTH); + newDesiredDepth = APPARENT_2D_OVERLAY_DEPTH; } else { var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y); @@ -37,11 +44,39 @@ Script.update.connect(function(deltaTime) { // If either the overlays or entities intersect, then set the reticle depth to // the distance of intersection if (result.intersects) { - Reticle.setDepth(result.distance); + newDesiredDepth = result.distance; } else { // if nothing intersects... set the depth to some sufficiently large depth - Reticle.setDepth(APPARENT_MAXIMUM_DEPTH); + newDesiredDepth = APPARENT_MAXIMUM_DEPTH; } } + + // If the desired depth has changed, reset our fade start time + if (desiredDepth != newDesiredDepth) { + desiredDepthLastSet = now; + desiredDepth = newDesiredDepth; + wasDepth = Reticle.depth; + } + } + + // move the reticle toward the desired depth + if (desiredDepth != Reticle.depth) { + + // determine the time between now, and when we set our determined our desiredDepth + var elapsed = now - desiredDepthLastSet; + var distanceToFade = desiredDepth - wasDepth; + var percentElapsed = Math.min(1, elapsed / TIME_TO_FADE_DEPTH); + + // special case to handle no fade settings + if (TIME_TO_FADE_DEPTH == 0) { + percentElapsed = 1; + } + var depthDelta = distanceToFade * percentElapsed; + + var newDepth = wasDepth + depthDelta; + if (percentElapsed == 1) { + newDepth = desiredDepth; + } + Reticle.setDepth(newDepth); } }); From df3e26edd59fe8d3e93a610579e821054f5bb252 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 12:05:30 -0800 Subject: [PATCH 103/292] calligraphy --- .../whiteboardV2/markerEntityScript.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 064add57be..3943143185 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,7 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH = 0.03; + _this.STROKE_WIDTH_RANGE = {min: 0.002, max: 0.01}; _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -115,8 +115,6 @@ _this.linePoints = []; _this.normals = []; - _this.strokeWidths = []; - _this.strokes.push(_this.currentStroke); }, @@ -140,12 +138,20 @@ } _this.linePoints.push(localPoint); _this.normals.push(_this.whiteboardNormal); - this.strokeWidths.push(_this.STROKE_WIDTH); + + var strokeWidths = []; + for (var i = 0; i < _this.linePoints.length; i++) { + // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide + var pointsFromCenter = Math.abs(_this.linePoints.length/2 - i); + print("EBL POINTS CENTER " + pointsFromCenter) + var pointWidth = map(pointsFromCenter, 0, this.linePoints.length/2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); + strokeWidths.push(pointWidth); + } Entities.editEntity(_this.currentStroke, { linePoints: _this.linePoints, normals: _this.normals, - strokeWidths: _this.strokeWidths + strokeWidths: strokeWidths }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { From 540114971392a7d0f8df11e00ae31c3044e9f261 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 26 Feb 2016 12:10:13 -0800 Subject: [PATCH 104/292] Cleaning the tlist of textures in the NetworkTexture and in FBXMaterial --- libraries/fbx/src/FBXReader.h | 21 +-- libraries/fbx/src/FBXReader_Material.cpp | 15 ++- libraries/gpu/src/gpu/GLBackendTexture.cpp | 2 +- .../src/model-networking/ModelCache.cpp | 120 ++++++++++++------ .../src/model-networking/ModelCache.h | 8 +- .../src/model-networking/TextureCache.h | 1 + libraries/model/src/model/TextureMap.cpp | 3 + 7 files changed, 106 insertions(+), 64 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 5371d5a41d..3fefd837f3 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -111,7 +111,6 @@ public: QString texcoordSetName; bool isBumpmap{ false }; - bool isGlossmap{ true }; bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } }; @@ -151,21 +150,13 @@ public: float roughness{ 1.0f }; float emissiveIntensity{ 1.0f }; - bool useNormalMap{ false }; - bool useAlbedoMap{ false }; - bool useOpacityMap{ false }; - bool useRoughnessMap{ false }; - bool useSpecularMap{ false }; - bool useMetallicMap{ false }; - bool useEmissiveMap{ false }; - bool useOcclusionMap{ false }; - QString materialID; model::MaterialPointer _material; FBXTexture normalTexture; FBXTexture albedoTexture; FBXTexture opacityTexture; + FBXTexture glossTexture; FBXTexture roughnessTexture; FBXTexture specularTexture; FBXTexture metallicTexture; @@ -176,6 +167,16 @@ public: bool isPBSMaterial{ false }; + // THe use XXXMap are not really used to drive which map are going or not, debug only + bool useNormalMap{ false }; + bool useAlbedoMap{ false }; + bool useOpacityMap{ false }; + bool useRoughnessMap{ false }; + bool useSpecularMap{ false }; + bool useMetallicMap{ false }; + bool useEmissiveMap{ false }; + bool useOcclusionMap{ false }; + bool needTangentSpace() const; }; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index cc6452c620..d87eac405f 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -128,19 +128,20 @@ void FBXReader::consolidateFBXMaterials() { FBXTexture roughnessTexture; QString roughnessTextureID = roughnessTextures.value(material.materialID); - QString shininessTextureID = shininessTextures.value(material.materialID); if (!roughnessTextureID.isNull()) { roughnessTexture = getTexture(roughnessTextureID); - roughnessTexture.isGlossmap = false; - material.roughnessTexture = roughnessTexture; - detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity()); - } else if (!shininessTextureID.isNull()) { - roughnessTexture = getTexture(roughnessTextureID); - roughnessTexture.isGlossmap = true; material.roughnessTexture = roughnessTexture; detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity()); } + FBXTexture shininessTexture; + QString shininessTextureID = shininessTextures.value(material.materialID); + if (!shininessTextureID.isNull()) { + shininessTexture = getTexture(shininessTextureID); + material.glossTexture = shininessTexture; + detectDifferentUVs |= (shininessTexture.texcoordSet != 0) || (!shininessTexture.transform.isIdentity()); + } + FBXTexture emissiveTexture; QString emissiveTextureID = emissiveTextures.value(material.materialID); if (!emissiveTextureID.isNull()) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 8efb4736c1..efcafc9d60 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -199,7 +199,7 @@ public: } case gpu::NUINT8: { if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { - texel.internalFormat = GL_SLUMINANCE8; + texel.internalFormat = GL_SLUMINANCE; } else { texel.internalFormat = GL_R8; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index d944b0c686..f795472137 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -138,7 +138,9 @@ bool NetworkGeometry::isLoadedWithTextures() const { for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || (material->normalTexture && !material->normalTexture->isLoaded()) || - (material->specularTexture && !material->specularTexture->isLoaded()) || + (material->roughnessTexture && !material->roughnessTexture->isLoaded()) || + (material->metallicTexture && !material->metallicTexture->isLoaded()) || + (material->occlusionTexture && !material->occlusionTexture->isLoaded()) || (material->emissiveTexture && !material->emissiveTexture->isLoaded()) || (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; @@ -171,22 +173,31 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u normalMap->setTextureSource(material->normalTexture->_textureSource); networkMaterial->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); - } else if (material->specularTextureName == name) { - material->specularTexture = textureCache->getTexture(url); + } else if (material->roughnessTextureName == name) { + // FIXME: If passing a gloss map instead of a roughmap how to say that ? looking for gloss in the name ? + material->roughnessTexture = textureCache->getTexture(url, ROUGHNESS_TEXTURE); + + auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); + roughnessMap->setTextureSource(material->roughnessTexture->_textureSource); + + networkMaterial->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); + } else if (material->metallicTextureName == name) { + // FIXME: If passing a specular map instead of a metallic how to say that ? looking for wtf in the name ? + material->metallicTexture = textureCache->getTexture(url, METALLIC_TEXTURE); auto glossMap = model::TextureMapPointer(new model::TextureMap()); - glossMap->setTextureSource(material->specularTexture->_textureSource); + glossMap->setTextureSource(material->metallicTexture->_textureSource); - networkMaterial->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, glossMap); + networkMaterial->setTextureMap(model::MaterialKey::METALLIC_MAP, glossMap); } else if (material->emissiveTextureName == name) { - material->emissiveTexture = textureCache->getTexture(url); + material->emissiveTexture = textureCache->getTexture(url, EMISSIVE_TEXTURE); auto emissiveMap = model::TextureMapPointer(new model::TextureMap()); emissiveMap->setTextureSource(material->emissiveTexture->_textureSource); networkMaterial->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); } else if (material->lightmapTextureName == name) { - material->emissiveTexture = textureCache->getTexture(url); + material->emissiveTexture = textureCache->getTexture(url, LIGHTMAP_TEXTURE); auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); lightmapMap->setTextureSource(material->emissiveTexture->_textureSource); @@ -208,6 +219,11 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u QStringList NetworkGeometry::getTextureNames() const { QStringList result; for (auto&& material : _materials) { + if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) { + QString textureURL = material->emissiveTexture->getURL().toString(); + result << material->emissiveTextureName + ":\"" + textureURL + "\""; + } + if (!material->albedoTextureName.isEmpty() && material->albedoTexture) { QString textureURL = material->albedoTexture->getURL().toString(); result << material->albedoTextureName + ":\"" + textureURL + "\""; @@ -218,15 +234,21 @@ QStringList NetworkGeometry::getTextureNames() const { result << material->normalTextureName + ":\"" + textureURL + "\""; } - if (!material->specularTextureName.isEmpty() && material->specularTexture) { - QString textureURL = material->specularTexture->getURL().toString(); - result << material->specularTextureName + ":\"" + textureURL + "\""; + if (!material->roughnessTextureName.isEmpty() && material->roughnessTexture) { + QString textureURL = material->roughnessTexture->getURL().toString(); + result << material->roughnessTextureName + ":\"" + textureURL + "\""; } - if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) { - QString textureURL = material->emissiveTexture->getURL().toString(); - result << material->emissiveTextureName + ":\"" + textureURL + "\""; + if (!material->metallicTextureName.isEmpty() && material->metallicTexture) { + QString textureURL = material->metallicTexture->getURL().toString(); + result << material->metallicTextureName + ":\"" + textureURL + "\""; } + + if (!material->occlusionTextureName.isEmpty() && material->occlusionTexture) { + QString textureURL = material->occlusionTexture->getURL().toString(); + result << material->occlusionTextureName + ":\"" + textureURL + "\""; + } + if (!material->lightmapTextureName.isEmpty() && material->lightmapTexture) { QString textureURL = material->lightmapTexture->getURL().toString(); result << material->lightmapTextureName + ":\"" + textureURL + "\""; @@ -335,6 +357,7 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); } + if (!material.normalTexture.filename.isEmpty()) { networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content); networkMaterial->normalTextureName = material.normalTexture.name; @@ -344,29 +367,18 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); } - if (!material.specularTexture.filename.isEmpty()) { - networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content); - networkMaterial->specularTextureName = material.specularTexture.name; - auto specularMap = model::TextureMapPointer(new model::TextureMap()); - specularMap->setTextureSource(networkMaterial->specularTexture->_textureSource); - - material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, specularMap); - } - if (!material.metallicTexture.filename.isEmpty()) { - networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.metallicTexture.filename)), SPECULAR_TEXTURE, material.metallicTexture.content); - networkMaterial->specularTextureName = material.metallicTexture.name; - - auto metallicMap = model::TextureMapPointer(new model::TextureMap()); - metallicMap->setTextureSource(networkMaterial->specularTexture->_textureSource); - - material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); - } + // Roughness first or gloss maybe if (!material.roughnessTexture.filename.isEmpty()) { - // FIXME: COnvert from gloss to roughness if material.roughnessTexture.isGlossmap; - networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), - (material.roughnessTexture.isGlossmap ? GLOSS_TEXTURE : ROUGHNESS_TEXTURE), - material.roughnessTexture.content); + networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.roughnessTexture.filename)), ROUGHNESS_TEXTURE, material.roughnessTexture.content); + networkMaterial->roughnessTextureName = material.roughnessTexture.name; + + auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); + roughnessMap->setTextureSource(networkMaterial->roughnessTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); + } else if (!material.glossTexture.filename.isEmpty()) { + networkMaterial->roughnessTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.glossTexture.filename)), GLOSS_TEXTURE, material.glossTexture.content); networkMaterial->roughnessTextureName = material.roughnessTexture.name; auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); @@ -374,6 +386,37 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); } + + // Metallic first or specular maybe + + if (!material.metallicTexture.filename.isEmpty()) { + networkMaterial->metallicTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.metallicTexture.filename)), METALLIC_TEXTURE, material.metallicTexture.content); + networkMaterial->metallicTextureName = material.metallicTexture.name; + + auto metallicMap = model::TextureMapPointer(new model::TextureMap()); + metallicMap->setTextureSource(networkMaterial->metallicTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); + } else if (!material.specularTexture.filename.isEmpty()) { + networkMaterial->metallicTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content); + networkMaterial->metallicTextureName = material.specularTexture.name; + + auto metallicMap = model::TextureMapPointer(new model::TextureMap()); + metallicMap->setTextureSource(networkMaterial->metallicTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); + } + + if (!material.occlusionTexture.filename.isEmpty()) { + networkMaterial->occlusionTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.occlusionTexture.filename)), OCCLUSION_TEXTURE, material.occlusionTexture.content); + networkMaterial->occlusionTextureName = material.occlusionTexture.name; + + auto occlusionMap = model::TextureMapPointer(new model::TextureMap()); + occlusionMap->setTextureSource(networkMaterial->occlusionTexture->_textureSource); + + material._material->setTextureMap(model::MaterialKey::OCCLUSION_MAP, occlusionMap); + } + if (!material.emissiveTexture.filename.isEmpty()) { networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content); networkMaterial->emissiveTextureName = material.emissiveTexture.name; @@ -383,6 +426,7 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); } + if (!material.lightmapTexture.filename.isEmpty()) { networkMaterial->lightmapTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.lightmapTexture.filename)), LIGHTMAP_TEXTURE, material.lightmapTexture.content); networkMaterial->lightmapTextureName = material.lightmapTexture.name; @@ -395,15 +439,7 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); } - if (!material.occlusionTexture.filename.isEmpty()) { - networkMaterial->occlusionTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.occlusionTexture.filename)), OCCLUSION_TEXTURE, material.occlusionTexture.content); - networkMaterial->occlusionTextureName = material.occlusionTexture.name; - auto occlusionMap = model::TextureMapPointer(new model::TextureMap()); - occlusionMap->setTextureSource(networkMaterial->occlusionTexture->_textureSource); - - material._material->setTextureMap(model::MaterialKey::OCCLUSION_MAP, occlusionMap); - } return networkMaterial; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index b517cc67ca..60f185f691 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -180,16 +180,16 @@ class NetworkMaterial { public: model::MaterialPointer _material; + QString emissiveTextureName; + QSharedPointer emissiveTexture; QString albedoTextureName; QSharedPointer albedoTexture; QString normalTextureName; QSharedPointer normalTexture; - QString specularTextureName; - QSharedPointer specularTexture; QString roughnessTextureName; QSharedPointer roughnessTexture; - QString emissiveTextureName; - QSharedPointer emissiveTexture; + QString metallicTextureName; + QSharedPointer metallicTexture; QString occlusionTextureName; QSharedPointer occlusionTexture; QString lightmapTextureName; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index ded90e7780..af82d2a1ad 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -34,6 +34,7 @@ enum TextureType { NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, + METALLIC_TEXTURE = SPECULAR_TEXTURE, // for now spec and metallic texture are the same, converted to grey ROUGHNESS_TEXTURE, GLOSS_TEXTURE, EMISSIVE_TEXTURE, diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 41be048440..c775443425 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -291,6 +291,9 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s image = image.convertToFormat(QImage::Format_ARGB32); } } + + // Gloss turned into Rough + image.invertPixels(QImage::InvertRgba); image = image.convertToFormat(QImage::Format_Grayscale8); From ed9f279a6386823300279526e701a0f3b742bf02 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 12:12:27 -0800 Subject: [PATCH 105/292] moved whiteboard Surface up --- examples/homeContent/whiteboardV2/whiteboardSpawner.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index da9aad4c33..f89789ab8b 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -53,14 +53,15 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { y: 0.45, z: 0.0 }); -whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(orientation))); +whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(whiteboardRotation))); +whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getFront(whiteboardRotation))); var whiteboardDrawingSurface = Entities.addEntity({ type: "Box", name: "hifi-whiteboardDrawingSurface", dimensions: { x: 1.82, y: 1.8, - z: 0.04 + z: 0.01 }, color: { red: 200, From e83c1f71a6059b1100fd94c63c145b0b762c4ebf Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 12:17:46 -0800 Subject: [PATCH 106/292] front and back --- .../whiteboardV2/whiteboardSpawner.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index f89789ab8b..f4f18a164d 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -54,8 +54,9 @@ var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, { z: 0.0 }); whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(whiteboardRotation))); -whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getFront(whiteboardRotation))); -var whiteboardDrawingSurface = Entities.addEntity({ +var moveForwardDistance = 0.02; +whiteboardFrontSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-moveForwardDistance, Quat.getFront(whiteboardRotation))); +var whiteboardSurfaceSettings = { type: "Box", name: "hifi-whiteboardDrawingSurface", dimensions: { @@ -68,11 +69,18 @@ var whiteboardDrawingSurface = Entities.addEntity({ green: 10, blue: 200 }, - position: whiteboardSurfacePosition, + position: whiteboardFrontSurfacePosition, rotation: whiteboardRotation, visible: false, parentID: whiteboard -}); +} +var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); + + +whiteboardBackSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(moveForwardDistance, Quat.getFront(whiteboardRotation))); +whiteboardSurfaceSettings.position = whiteboardBackSurfacePosition; + +var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); var WHITEBOARD_RACK_DEPTH = 1.9; @@ -230,7 +238,8 @@ function createMarker(modelURL, markerPosition, markerColor) { function cleanup() { Entities.deleteEntity(whiteboard); - Entities.deleteEntity(whiteboardDrawingSurface); + Entities.deleteEntity(whiteboardFrontDrawingSurface); + Entities.deleteEntity(whiteboardBackDrawingSurface); Entities.deleteEntity(eraser); markers.forEach(function(marker) { Entities.deleteEntity(marker); From bf0bcbe2ecc037e74552d33550856bc985992255 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 10:48:53 +1300 Subject: [PATCH 107/292] Style spinbox control --- .../resources/qml/controls-uit/SpinBox.qml | 80 +++++++++++++++++++ .../dialogs/preferences/SpinBoxPreference.qml | 20 ++++- .../qml/styles-uit/HifiConstants.qml | 4 + 3 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 interface/resources/qml/controls-uit/SpinBox.qml diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml new file mode 100644 index 0000000000..f04cd54d16 --- /dev/null +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -0,0 +1,80 @@ +// +// SpinBox.qml +// +// Created by David Rowe on 26 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" +import "../controls-uit" as HifiControls + +SpinBox { + id: spinBox + //HifiConstants { id: hifi } // DJRTODO: Not needed? + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property string label: "" + property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height : 0) + + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pixelSize: hifi.fontSizes.textFieldInput + height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. + + y: spinBoxLabel.visible ? spinBoxLabel.height : 0 + + style: SpinBoxStyle { + background: Rectangle { + color: isLightColorScheme + ? (spinBox.focus ? hifi.colors.white : hifi.colors.lightGray) + : (spinBox.focus ? hifi.colors.black : hifi.colors.baseGrayShadow) + border.color: hifi.colors.primaryHighlight + border.width: spinBox.focus ? 1 : 0 + } + + textColor: isLightColorScheme + ? (spinBox.focus ? hifi.colors.black : hifi.colors.lightGray) + : (spinBox.focus ? hifi.colors.white : hifi.colors.lightGrayText) + selectedTextColor: hifi.colors.black + selectionColor: hifi.colors.primaryHighlight + + horizontalAlignment: Qt.AlignLeft + padding.left: hifi.dimensions.textPadding + padding.right: hifi.dimensions.spinnerSize + + incrementControl: HiFiGlyphs { + id: incrementButton + text: hifi.glyphs.forward // Adapt forward triangle to be upward triangle + rotation: -90 + y: 2 + size: hifi.dimensions.spinnerSize + color: styleData.upPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray + } + + decrementControl: HiFiGlyphs { + text: hifi.glyphs.backward // Adapt backward triangle to be downward triangle + rotation: -90 + y: -2 + size: hifi.dimensions.spinnerSize + color: styleData.downPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray + } + } + + HifiControls.Label { + id: spinBoxLabel + text: spinBox.label + colorScheme: spinBox.colorScheme + anchors.left: parent.left + anchors.bottom: parent.top + anchors.bottomMargin: 4 + visible: label != "" + } +} diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index 513ae25974..671ded55aa 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -1,10 +1,21 @@ +// +// SpinBoxPreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 + +import "../../controls-uit" Preference { id: root property alias spinner: spinner - height: spinner.height + height: spinner.controlHeight Component.onCompleted: { spinner.value = preference.value; @@ -15,9 +26,9 @@ Preference { preference.save(); } - Text { + Label { text: root.label - color: root.enabled ? "black" : "gray" + colorScheme: hifi.colorSchemes.dark anchors.verticalCenter: spinner.verticalCenter } @@ -28,5 +39,6 @@ Preference { maximumValue: preference.max width: 100 anchors { right: parent.right } + colorScheme: hifi.colorSchemes.dark } } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index d0766663e8..26899686f1 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -48,6 +48,7 @@ Item { // Other colors readonly property color white: "#ffffff" + readonly property color gray: "#808080" readonly property color black: "#000000" // Semitransparent readonly property color white50: "#80ffffff" @@ -83,6 +84,7 @@ Item { readonly property vector2d contentMargin: Qt.vector2d(12, 24) readonly property vector2d contentSpacing: Qt.vector2d(8, 12) readonly property real textPadding: 8 + readonly property real spinnerSize: 20 readonly property real tablePadding: 12 readonly property real tableRowHeight: largeScreen ? 26 : 23 readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30) @@ -110,11 +112,13 @@ Item { Item { id: glyphs + readonly property string backward: "E" readonly property string close: "w" readonly property string closeInverted: "x" readonly property string closeSmall: "C" readonly property string disclosureCollapse: "Z" readonly property string disclosureExpand: "B" + readonly property string forward: "D" readonly property string pin: "y" readonly property string pinInverted: "z" readonly property string reloadSmall: "a" From fdffd8b6e070434ec32851697f0d897c08f9ec74 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 25 Feb 2016 14:13:57 -0800 Subject: [PATCH 108/292] Track skybox mipmap levels in DeferredTransform --- .../render-utils/src/DeferredLightingEffect.cpp | 14 +++++++++++--- .../render-utils/src/DeferredLightingEffect.h | 6 +++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e2b5721bd9..736b34d779 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -94,7 +94,7 @@ void DeferredLightingEffect::init() { lp->setColor(glm::vec3(1.0f)); lp->setIntensity(1.0f); lp->setType(model::Light::SUN); - lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); + lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE); } void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& color, @@ -321,7 +321,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo if (_skyboxTexture) { program = _directionalSkyboxLightShadow; locations = _directionalSkyboxLightShadowLocations; - } else if (_ambientLightMode > -1) { + } else { program = _directionalAmbientSphereLightShadow; locations = _directionalAmbientSphereLightShadowLocations; } @@ -329,7 +329,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo if (_skyboxTexture) { program = _directionalSkyboxLight; locations = _directionalSkyboxLightLocations; - } else if (_ambientLightMode > -1) { + } else { program = _directionalAmbientSphereLight; locations = _directionalAmbientSphereLightLocations; } @@ -562,6 +562,14 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light, const gpu::TexturePointer& skyboxTexture) { _allocatedLights.front() = light; _skyboxTexture = skyboxTexture; + + // Update the available mipmap levels + if (_skyboxTexture) { + float dim = glm::max(_skyboxTexture->getHeight(), _skyboxTexture->getWidth(), _skyboxTexture->getDepth()); + auto skyboxMipmapLevels = 1 + glm::floor(glm::log2(dim)); + _deferredTransformBuffer[0].edit().skyboxMipmapLevels = skyboxMipmapLevels; + _deferredTransformBuffer[1].edit().skyboxMipmapLevels = skyboxMipmapLevels; + } } model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 7fc6d99a95..49a3825fca 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -96,7 +96,6 @@ private: std::vector _pointLights; std::vector _spotLights; - int _ambientLightMode = 0; gpu::TexturePointer _skyboxTexture; // Class describing the uniform buffer with all the parameters common to the deferred shaders @@ -104,8 +103,9 @@ private: public: glm::mat4 projection; glm::mat4 viewInverse; - float stereoSide{ 0.f }; - float spareA, spareB, spareC; + float stereoSide { 0.f }; + float skyboxMipmapLevels { 1.0f }; + float spareA, spareB; DeferredTransform() {} }; From e8f349ec31551ea85d167d9d7e4497143e6371d4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 11:02:39 +1300 Subject: [PATCH 109/292] Fix up capitalization of labels and use of colons --- .../qml/dialogs/preferences/SpinBoxPreference.qml | 2 +- interface/src/ui/PreferencesDialog.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index 671ded55aa..71b2f1f655 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -27,7 +27,7 @@ Preference { } Label { - text: root.label + text: root.label + ":" colorScheme: hifi.colorSchemes.dark anchors.verticalCenter: spinner.verticalCenter } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 78c2405ade..581f9b11a0 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -65,7 +65,7 @@ void setupPreferences() { { auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); }; auto setter = [](const QString& value) { Snapshot::snapshotsLocation.set(value); }; - auto preference = new BrowsePreference("Snapshots", "Place my Snapshots here:", getter, setter); + auto preference = new BrowsePreference("Snapshots", "Put my Snapshots here", getter, setter); preferences->addPreference(preference); } @@ -73,7 +73,7 @@ void setupPreferences() { { auto getter = []()->QString { return DependencyManager::get()->getScriptsLocation(); }; auto setter = [](const QString& value) { DependencyManager::get()->setScriptsLocation(value); }; - preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory:", getter, setter)); + preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory", getter, setter)); } preferences->addPreference(new ButtonPreference("Scripts", "Load Default Scripts", [] { @@ -83,7 +83,7 @@ void setupPreferences() { { auto getter = []()->bool {return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); }; auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); }; - preferences->addPreference(new CheckPreference("Privacy", "Send Data", getter, setter)); + preferences->addPreference(new CheckPreference("Privacy", "Send data", getter, setter)); } static const QString LOD_TUNING("Level of Detail Tuning"); @@ -299,7 +299,7 @@ void setupPreferences() { { auto getter = []()->float { return qApp->getApplicationCompositor().getHmdUIAngularSize(); }; auto setter = [](float value) { qApp->getApplicationCompositor().setHmdUIAngularSize(value); }; - auto preference = new SpinnerPreference("HMD", "User Interface Horizontal Angular Size (degrees)", getter, setter); + auto preference = new SpinnerPreference("HMD", "UI horizontal angular size (degrees)", getter, setter); preference->setMin(30); preference->setMax(160); preference->setStep(1); @@ -310,7 +310,7 @@ void setupPreferences() { { auto getter = []()->float { return controller::InputDevice::getReticleMoveSpeed(); }; auto setter = [](float value) { controller::InputDevice::setReticleMoveSpeed(value); }; - auto preference = new SpinnerPreference("Sixense Controllers", "Reticle Movement Speed", getter, setter); + auto preference = new SpinnerPreference("Sixense Controllers", "Reticle movement speed", getter, setter); preference->setMin(0); preference->setMax(100); preference->setStep(1); From b62bd682ed1c617433c6e11d52f8d63fd8dc99fe Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 11:03:57 +1300 Subject: [PATCH 110/292] Tidying --- interface/resources/qml/controls-uit/SpinBox.qml | 1 - interface/resources/qml/dialogs/PreferencesDialog.qml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index f04cd54d16..eacdd05857 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -17,7 +17,6 @@ import "../controls-uit" as HifiControls SpinBox { id: spinBox - //HifiConstants { id: hifi } // DJRTODO: Not needed? property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index b2a34c89a2..2e69db10aa 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -25,6 +25,7 @@ Window { height: 577 property var sections: [] property var showCategories: [] + minSize: Qt.vector2d(400, 500) HifiConstants { id: hifi } From c0c5084149f9724a6dbab7e587e28d99e03bee4a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Feb 2016 14:05:02 -0800 Subject: [PATCH 111/292] handle parenting loops --- libraries/shared/src/SpatiallyNestable.cpp | 31 ++++++++++++++-------- libraries/shared/src/SpatiallyNestable.h | 6 ++--- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 557b25d9b2..1a897021f1 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -15,6 +15,7 @@ #include "SpatiallyNestable.h" const float defaultAACubeSize = 1.0f; +const int maxParentingChain = 30; SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : _nestableType(nestableType), @@ -56,14 +57,14 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { }); } -Transform SpatiallyNestable::getParentTransform(bool& success) const { +Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const { Transform result; SpatiallyNestablePointer parent = getParentPointer(success); if (!success) { return result; } if (parent) { - Transform parentTransform = parent->getTransform(_parentJointIndex, success); + Transform parentTransform = parent->getTransform(_parentJointIndex, success, depth + 1); result = parentTransform.setScale(1.0f); // TODO: scaling } return result; @@ -393,11 +394,11 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) { glm::vec3 SpatiallyNestable::getVelocity(bool& success) const { glm::vec3 result; - glm::vec3 parentVelocity = getParentVelocity(success); + Transform parentTransform = getParentTransform(success); if (!success) { return result; } - Transform parentTransform = getParentTransform(success); + glm::vec3 parentVelocity = getParentVelocity(success); if (!success) { return result; } @@ -448,11 +449,11 @@ glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const { glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const { glm::vec3 result; - glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); + Transform parentTransform = getParentTransform(success); if (!success) { return result; } - Transform parentTransform = getParentTransform(success); + glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); if (!success) { return result; } @@ -499,22 +500,30 @@ glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const { return result; } -const Transform SpatiallyNestable::getTransform(bool& success) const { - // return a world-space transform for this object's location - Transform parentTransform = getParentTransform(success); +const Transform SpatiallyNestable::getTransform(bool& success, int depth) const { Transform result; + // return a world-space transform for this object's location + Transform parentTransform = getParentTransform(success, depth); _transformLock.withReadLock([&] { Transform::mult(result, parentTransform, _transform); }); return result; } -const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) const { +const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, int depth) const { // this returns the world-space transform for this object. It finds its parent's transform (which may // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform jointInWorldFrame; - Transform worldTransform = getTransform(success); + if (depth > maxParentingChain) { + success = false; + // someone created a loop. break it... + qDebug() << "Parenting loop detected."; + getThisPointer()->setParentID(QUuid()); + return jointInWorldFrame; + } + + Transform worldTransform = getTransform(success, depth); worldTransform.setScale(1.0f); // TODO -- scale; if (!success) { return jointInWorldFrame; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 2a8976b38f..ee6cccc7a8 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -52,10 +52,10 @@ public: static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); // world frame - virtual const Transform getTransform(bool& success) const; + virtual const Transform getTransform(bool& success, int depth = 0) const; virtual void setTransform(const Transform& transform, bool& success); - virtual Transform getParentTransform(bool& success) const; + virtual Transform getParentTransform(bool& success, int depth = 0) const; virtual glm::vec3 getPosition(bool& success) const; virtual glm::vec3 getPosition() const; @@ -92,7 +92,7 @@ public: virtual void setScale(const glm::vec3& scale); // get world-frame values for a specific joint - virtual const Transform getTransform(int jointIndex, bool& success) const; + virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const; virtual glm::vec3 getPosition(int jointIndex, bool& success) const; virtual glm::vec3 getScale(int jointIndex) const; From 1fbcaea4b4d6b77ab65d5031952400aa9f50fafb Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 25 Feb 2016 14:16:06 -0800 Subject: [PATCH 112/292] Fix evalSkyboxGlobalColor --- libraries/render-utils/src/DeferredBuffer.slh | 9 +- .../render-utils/src/DeferredGlobalLight.slh | 107 +++++++----------- .../src/directional_skybox_light.slf | 3 +- .../src/directional_skybox_light_shadow.slf | 3 +- 4 files changed, 49 insertions(+), 73 deletions(-) diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index bfed92018a..699926a87c 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -34,8 +34,9 @@ uniform sampler2D lightingMap; struct DeferredTransform { mat4 projection; mat4 viewInverse; - - vec4 stereoSide_spareABC; + float stereoSide; + float skyboxMipmapLevels; + vec2 _spareAB; }; layout(std140) uniform deferredTransformBuffer { @@ -46,10 +47,10 @@ DeferredTransform getDeferredTransform() { } bool getStereoMode(DeferredTransform deferredTransform) { - return (deferredTransform.stereoSide_spareABC.x != 0.0); + return (deferredTransform.stereoSide != 0.0); } float getStereoSide(DeferredTransform deferredTransform) { - return (deferredTransform.stereoSide_spareABC.x); + return (deferredTransform.stereoSide); } vec4 evalEyePositionFromZ(DeferredTransform deferredTransform, float depthVal, vec2 texcoord) { diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index a3fb1de3ec..3764b19f7c 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -11,88 +11,61 @@ <@if not DEFERRED_GLOBAL_LIGHT_SLH@> <@def DEFERRED_GLOBAL_LIGHT_SLH@> +<@include model/Light.slh@> <@include DeferredLighting.slh@> <@func declareSkyboxMap()@> - +// declareSkyboxMap uniform samplerCube skyboxMap; vec4 evalSkyboxLight(vec3 direction, float lod) { - // FIXME - //vec4 skytexel = textureLod(skyboxMap, direction, lod * textureQueryLevels(skyboxMap)); - vec4 skytexel = texture(skyboxMap, direction); - return skytexel; + // textureQueryLevels is not available until #430, so we require explicit lod + // float mipmapLevel = lod * textureQueryLevels(skyboxMap); + return textureLod(skyboxMap, direction, lod); } - <@endfunc@> -// Everything about light -<@include model/Light.slh@> +<@func prepareGlobalLight()@> + // prepareGlobalLight + + // Transform directions to worldspace + vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); + vec3 fragEyeVector = vec3(invViewMat * vec4(-position, 0.0)); + vec3 fragEyeDir = normalize(fragEyeVector); + + // Get light + Light light = getLight(); + + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); + color = vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); + color += emissive; +<@endfunc@> <@func declareEvalAmbientGlobalColor()@> vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { - - // Need the light now - Light light = getLight(); - - vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); - vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); - vec3 fragEyeDir = normalize(fragEyeVector.xyz); - - vec3 color = albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); - - - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); - - color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); - color += emissive; - + <$prepareGlobalLight()$> + color += albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(light); return color; } <@endfunc@> <@func declareEvalAmbientSphereGlobalColor()@> - - vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { - // Need the light now - Light light = getLight(); - - vec3 fragNormal = normalize(vec3(invViewMat * vec4(normal, 0.0))); - vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); - vec3 fragEyeDir = normalize(fragEyeVector.xyz); - - vec3 ambientNormal = fragNormal.xyz; - - vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), ambientNormal).xyz * obscurance * getLightAmbientIntensity(light); - - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); - - color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); - color += emissive; + <$prepareGlobalLight()$> + color += albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); return color; } <@endfunc@> <@func declareEvalSkyboxGlobalColor()@> - <$declareSkyboxMap()$> - vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { - // Need the light now - Light light = getLight(); - - vec3 fragNormal = normalize(vec3(invViewMat * vec4(normal, 0.0))); - vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); - vec3 fragEyeDir = normalize(fragEyeVector.xyz); - + <$prepareGlobalLight()$> - vec3 color = albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); - - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); - - color += vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); - color += emissive; + vec3 direction = -reflect(fragEyeDir, fragNormal); + float lod = min(1.0 + floor((1.0 - gloss) * levels), levels); + vec4 skyboxLight = evalSkyboxLight(direction, lod); + color += albedo * skyboxLight.rgb * skyboxLight.a * obscurance * getLightAmbientIntensity(light); return color; } @@ -100,26 +73,26 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu <@func declareEvalLightmappedColor()@> vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 albedo, vec3 lightmap) { - +vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 normal, vec3 diffuse, vec3 lightmap) { Light light = getLight(); - vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); - float diffuseDot = dot(fragNormal, -getLightDirection(light)); - - // need to catch normals perpendicular to the projection plane hence the magic number for the threshold - // it should be just 0, but we have innacurracy so we need to overshoot + // Catch normals perpendicular to the projection plane, hence the magic number for the threshold + // It should be just 0, but we have inaccuracy so we overshoot const float PERPENDICULAR_THRESHOLD = -0.005; + vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); // transform to worldspace + float diffuseDot = dot(fragNormal, -getLightDirection(light)); float facingLight = step(PERPENDICULAR_THRESHOLD, diffuseDot); - //float facingLight = step(PERPENDICULAR_THRESHOLD, diffuseDot); - // evaluate the shadow test but only relevant for light facing fragments + + // Reevaluate the shadow attenuation for light facing fragments float lightAttenuation = (1 - facingLight) + facingLight * shadowAttenuation; - // diffuse light is the lightmap dimmed by shadow + + // Diffuse light is the lightmap dimmed by shadow vec3 diffuseLight = lightAttenuation * lightmap; - // ambient is a tiny percentage of the lightmap and only when in the shadow + // Ambient light is the lightmap when in shadow vec3 ambientLight = (1 - lightAttenuation) * lightmap * getLightAmbientIntensity(light); - return obscurance * albedo * (ambientLight + diffuseLight); + return obscurance * albedo * (diffuseLight + ambientLight); } <@endfunc@> diff --git a/libraries/render-utils/src/directional_skybox_light.slf b/libraries/render-utils/src/directional_skybox_light.slf index 9e24a5f585..5ec6cc5da3 100755 --- a/libraries/render-utils/src/directional_skybox_light.slf +++ b/libraries/render-utils/src/directional_skybox_light.slf @@ -47,7 +47,8 @@ void main(void) { frag.diffuse, frag.metallic, frag.emissive, - frag.roughness); + frag.roughness, + deferredTransform.skyboxMipmapLevels); _fragColor = vec4(color, frag.normalVal.a); } diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index c3008b5509..b3f273b39e 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -49,7 +49,8 @@ void main(void) { frag.diffuse, frag.metallic, frag.emissive, - frag.roughness); + frag.roughness, + deferredTransform.skyboxMipmapLevels); _fragColor = vec4(color, frag.normalVal.a); } From 839303168e51a3579aaa831341f8ae72b59a7aef Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 11:20:31 +1300 Subject: [PATCH 113/292] Fix missed capital --- interface/src/ui/PreferencesDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 581f9b11a0..badf780f06 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -65,7 +65,7 @@ void setupPreferences() { { auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); }; auto setter = [](const QString& value) { Snapshot::snapshotsLocation.set(value); }; - auto preference = new BrowsePreference("Snapshots", "Put my Snapshots here", getter, setter); + auto preference = new BrowsePreference("Snapshots", "Put my snapshots here", getter, setter); preferences->addPreference(preference); } From 9a01c933221c5a65499e75442668adc08c804474 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 26 Feb 2016 14:28:27 -0800 Subject: [PATCH 114/292] Avatar: fix for rendering avatar attachments --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 83351d5188..0bd134bef5 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -400,7 +400,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { frustum = qApp->getDisplayViewFrustum(); } - if (frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) { + if (!frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) { endRender(); return; } From 48f03ba476e69a8f4b8a73d0ba3f6e25731ace8b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 14:29:43 -0800 Subject: [PATCH 115/292] markers resetting --- .../whiteboardV2/markerEntityScript.js | 26 ++++++++++++++++--- .../whiteboardV2/whiteboardSpawner.js | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 3943143185..de5d615dec 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -24,7 +24,10 @@ _this = this; _this.MARKER_TEXTURE_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/textures/markerStroke.png"; _this.strokeForwardOffset = 0.0001; - _this.STROKE_WIDTH_RANGE = {min: 0.002, max: 0.01}; + _this.STROKE_WIDTH_RANGE = { + min: 0.002, + max: 0.01 + }; _this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4; _this.MIN_DISTANCE_BETWEEN_POINTS = 0.002; _this.MAX_DISTANCE_BETWEEN_POINTS = 0.1; @@ -32,6 +35,7 @@ _this.PAINTING_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.WHITEBOARD_SURFACE_NAME = "hifi-whiteboardDrawingSurface"; + _this.MARKER_RESET_WAIT_TIME = 3000; }; MarkerTip.prototype = { @@ -60,6 +64,20 @@ Overlays.editOverlay(_this.laserPointer, { visible: false }); + + // Once user releases marker, wait a bit then put marker back to its original position and rotation + Script.setTimeout(function() { + var userData = getEntityUserData(_this.entityID); + Entities.editEntity(_this.entityID, { + position: userData.originalPosition, + rotation: userData.originalRotation, + velocity: { + x: 0, + y: -0.01, + z: 0 + } + }); + }, _this.MARKER_RESET_WAIT_TIME); }, @@ -75,7 +93,7 @@ if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { var whiteboardRotation = Entities.getEntityProperties(intersection.entityID, "rotation").rotation; - _this.whiteboardNormal = Quat.getFront(whiteboardRotation); + _this.whiteboardNormal = Quat.getFront(whiteboardRotation); Overlays.editOverlay(_this.laserPointer, { visible: true, position: intersection.intersection, @@ -142,9 +160,9 @@ var strokeWidths = []; for (var i = 0; i < _this.linePoints.length; i++) { // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide - var pointsFromCenter = Math.abs(_this.linePoints.length/2 - i); + var pointsFromCenter = Math.abs(_this.linePoints.length / 2 - i); print("EBL POINTS CENTER " + pointsFromCenter) - var pointWidth = map(pointsFromCenter, 0, this.linePoints.length/2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); + var pointWidth = map(pointsFromCenter, 0, this.linePoints.length / 2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); strokeWidths.push(pointWidth); } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index f4f18a164d..eb0886229a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -202,6 +202,8 @@ function createMarker(modelURL, markerPosition, markerColor) { name: "marker", script: MARKER_SCRIPT_URL, userData: JSON.stringify({ + originalPosition: markerPosition, + originalRotation: markerRotation, markerColor: markerColor, wearable: { joints: { From 01ef5aabcb0b2f685db9e3a151158437bdc24c86 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 26 Feb 2016 14:38:35 -0800 Subject: [PATCH 116/292] OpenVR: More reliable detection of left and right hands --- plugins/openvr/src/ViveControllerManager.cpp | 110 +++++++++---------- plugins/openvr/src/ViveControllerManager.h | 15 +-- 2 files changed, 61 insertions(+), 64 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 071d5fd631..749c9ea2e4 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -60,10 +60,10 @@ void ViveControllerManager::activate() { [this] (bool clicked) { this->setRenderControllers(clicked); }, true, true); - if (!_hmd) { - _hmd = acquireOpenVrSystem(); + if (!_system) { + _system = acquireOpenVrSystem(); } - Q_ASSERT(_hmd); + Q_ASSERT(_system); // OpenVR provides 3d mesh representations of the controllers // Disabled controller rendering code @@ -71,7 +71,7 @@ void ViveControllerManager::activate() { auto renderModels = vr::VRRenderModels(); vr::RenderModel_t model; - if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { + if (!_system->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); } else { model::Mesh* mesh = new model::Mesh(); @@ -118,7 +118,7 @@ void ViveControllerManager::activate() { } */ - // unregister with UserInputMapper + // register with UserInputMapper auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); _registeredWithInputMapper = true; @@ -130,9 +130,9 @@ void ViveControllerManager::deactivate() { _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenu(MENU_PATH); - if (_hmd) { + if (_system) { releaseOpenVrSystem(); - _hmd = nullptr; + _system = nullptr; } _inputDevice->_poseStateMap.clear(); @@ -226,56 +226,56 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { _poseStateMap.clear(); - _buttonPressedMap.clear(); PerformanceTimer perfTimer("ViveControllerManager::update"); + auto leftHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand); + auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); + + if (!jointsCaptured) { + handleHandController(leftHandDeviceIndex, inputCalibrationData, true); + handleHandController(rightHandDeviceIndex, inputCalibrationData, false); + } + int numTrackedControllers = 0; - - for (vr::TrackedDeviceIndex_t device = vr::k_unTrackedDeviceIndex_Hmd + 1; - device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) { - - if (!_hmd->IsTrackedDeviceConnected(device)) { - continue; - } - - if (_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) { - continue; - } - - if (!_trackedDevicePose[device].bPoseIsValid) { - continue; - } - + if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) { numTrackedControllers++; - bool left = numTrackedControllers == 2; + } + if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) { + numTrackedControllers++; + } + _trackedControllers = numTrackedControllers; +} - if (!jointsCaptured) { - const mat4& mat = _trackedDevicePoseMat4[device]; - const vec3 linearVelocity = _trackedDeviceLinearVelocities[device]; - const vec3 angularVelocity = _trackedDeviceAngularVelocities[device]; - handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, numTrackedControllers - 1); - } +void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) { + + if (_system->IsTrackedDeviceConnected(deviceIndex) && + _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller && + _trackedDevicePose[deviceIndex].bPoseIsValid) { + + // process pose + const mat4& mat = _trackedDevicePoseMat4[deviceIndex]; + const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex]; + const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex]; + handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand); - // handle inputs vr::VRControllerState_t controllerState = vr::VRControllerState_t(); - if (_hmd->GetControllerState(device, &controllerState)) { - //qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: "); - //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; - //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; + if (_system->GetControllerState(deviceIndex, &controllerState)) { + + // process each button for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); bool pressed = 0 != (controllerState.ulButtonPressed & mask); - handleButtonEvent(i, pressed, left); + handleButtonEvent(i, pressed, isLeftHand); } + + // process each axis for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } } } - - _trackedControllers = numTrackedControllers; } void ViveControllerManager::InputDevice::focusOutEvent() { @@ -284,42 +284,38 @@ void ViveControllerManager::InputDevice::focusOutEvent() { }; // These functions do translation from the Steam IDs to the standard controller IDs -void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) { +void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand) { //FIX ME? It enters here every frame: probably we want to enter only if an event occurs axis += vr::k_EButton_Axis0; using namespace controller; if (axis == vr::k_EButton_SteamVR_Touchpad) { - _axisStateMap[left ? LX : RX] = x; - _axisStateMap[left ? LY : RY] = y; + _axisStateMap[isLeftHand ? LX : RX] = x; + _axisStateMap[isLeftHand ? LY : RY] = y; } else if (axis == vr::k_EButton_SteamVR_Trigger) { - _axisStateMap[left ? LT : RT] = x; + _axisStateMap[isLeftHand ? LT : RT] = x; } } // These functions do translation from the Steam IDs to the standard controller IDs -void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) { +void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand) { if (!pressed) { return; } if (button == vr::k_EButton_ApplicationMenu) { - _buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); } else if (button == vr::k_EButton_Grip) { - // Tony says these are harder to reach, so make them the meta buttons - _buttonPressedMap.insert(left ? controller::LB : controller::RB); + _buttonPressedMap.insert(isLeftHand ? controller::LB : controller::RB); } else if (button == vr::k_EButton_SteamVR_Trigger) { - _buttonPressedMap.insert(left ? controller::LT : controller::RT); + _buttonPressedMap.insert(isLeftHand ? controller::LT : controller::RT); } else if (button == vr::k_EButton_SteamVR_Touchpad) { - _buttonPressedMap.insert(left ? controller::LS : controller::RS); - } else if (button == vr::k_EButton_System) { - //FIX ME: not able to ovrewrite the behaviour of this button - _buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? controller::LS : controller::RS); } } void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, - const vec3& angularVelocity, bool left) { + const vec3& angularVelocity, bool isLeftHand) { // When the sensor-to-world rotation is identity the coordinate axes look like this: // // user @@ -384,8 +380,8 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - auto translationOffset = (left ? leftTranslationOffset : rightTranslationOffset); - auto rotationOffset = (left ? leftRotationOffset : rightRotationOffset); + auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset); + auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset); glm::vec3 position = extractTranslation(mat); glm::quat rotation = glm::normalize(glm::quat_cast(mat)); @@ -399,7 +395,7 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input // handle change in velocity due to translationOffset avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat)); avatarPose.angularVelocity = angularVelocity; - _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); + _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); } controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const { diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 51339cd465..2240a528a9 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -50,7 +50,7 @@ public: private: class InputDevice : public controller::InputDevice { public: - InputDevice(vr::IVRSystem*& hmd) : controller::InputDevice("Vive"), _hmd(hmd) {} + InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {} private: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; @@ -58,13 +58,14 @@ private: virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; - void handleButtonEvent(uint32_t button, bool pressed, bool left); - void handleAxisEvent(uint32_t axis, float x, float y, bool left); + void handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); + void handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand); + void handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand); void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, - const vec3& linearVelocity, const vec3& angularVelocity, bool left); + const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); int _trackedControllers { 0 }; - vr::IVRSystem*& _hmd; + vr::IVRSystem*& _system; friend class ViveControllerManager; }; @@ -81,8 +82,8 @@ private: int _rightHandRenderID { 0 }; bool _renderControllers { false }; - vr::IVRSystem* _hmd { nullptr }; - std::shared_ptr _inputDevice { std::make_shared(_hmd) }; + vr::IVRSystem* _system { nullptr }; + std::shared_ptr _inputDevice { std::make_shared(_system) }; static const QString NAME; From d0752143dcaa16a2903b90e4da1339074b410259 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 14:49:48 -0800 Subject: [PATCH 117/292] markers and eraser reset to original positions after being dropped --- .../whiteboardV2/eraserEntityScript.js | 37 ++++++++++++++++--- .../whiteboardV2/markerEntityScript.js | 7 ++-- .../whiteboardV2/whiteboardSpawner.js | 9 +++-- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/examples/homeContent/whiteboardV2/eraserEntityScript.js b/examples/homeContent/whiteboardV2/eraserEntityScript.js index 86e80659bf..9306c7a5ab 100644 --- a/examples/homeContent/whiteboardV2/eraserEntityScript.js +++ b/examples/homeContent/whiteboardV2/eraserEntityScript.js @@ -24,6 +24,7 @@ _this.ERASER_TRIGGER_THRESHOLD = 0.2; _this.STROKE_NAME = "hifi-marker-stroke"; _this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7; + _this.ERASER_RESET_WAIT_TIME = 3000; }; Eraser.prototype = { @@ -32,11 +33,15 @@ _this.equipped = true; _this.hand = params[0] == "left" ? 0 : 1; // We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes - Overlays.editOverlay(_this.searchSphere, {visible: true}); + Overlays.editOverlay(_this.searchSphere, { + visible: true + }); }, continueEquip: function() { - _this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; - Overlays.editOverlay(_this.searchSphere, {position: _this.eraserPosition}); + _this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position; + Overlays.editOverlay(_this.searchSphere, { + position: _this.eraserPosition + }); this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]); if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) { _this.continueHolding(); @@ -57,14 +62,36 @@ }, releaseEquip: function() { - Overlays.editOverlay(_this.searchSphere, {visible: false}); + Overlays.editOverlay(_this.searchSphere, { + visible: false + }); + + // Once user releases eraser, wait a bit then put marker back to its original position and rotation + Script.setTimeout(function() { + var userData = getEntityUserData(_this.entityID); + Entities.editEntity(_this.entityID, { + position: userData.originalPosition, + rotation: userData.originalRotation, + velocity: { + x: 0, + y: -0.01, + z: 0 + } + }); + }, _this.ERASER_RESET_WAIT_TIME); }, + + preload: function(entityID) { _this.entityID = entityID; _this.searchSphere = Overlays.addOverlay('sphere', { size: _this.ERASER_TO_STROKE_SEARCH_RADIUS, - color: {red: 200, green: 10, blue: 10}, + color: { + red: 200, + green: 10, + blue: 10 + }, alpha: 0.2, solid: true, visible: false diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index de5d615dec..64b906dda1 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -92,7 +92,8 @@ var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards); if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) { - var whiteboardRotation = Entities.getEntityProperties(intersection.entityID, "rotation").rotation; + _this.currentWhiteboard = intersection.entityID; + var whiteboardRotation = Entities.getEntityProperties(_this.currentWhiteboard, "rotation").rotation; _this.whiteboardNormal = Quat.getFront(whiteboardRotation); Overlays.editOverlay(_this.laserPointer, { visible: true, @@ -128,7 +129,8 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 500 + lifetime: 500, + // parentID: _this.currentWhiteboard }); _this.linePoints = []; @@ -161,7 +163,6 @@ for (var i = 0; i < _this.linePoints.length; i++) { // Create a temp array of stroke widths for calligraphy effect - start and end should be less wide var pointsFromCenter = Math.abs(_this.linePoints.length / 2 - i); - print("EBL POINTS CENTER " + pointsFromCenter) var pointWidth = map(pointsFromCenter, 0, this.linePoints.length / 2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min); strokeWidths.push(pointWidth); } diff --git a/examples/homeContent/whiteboardV2/whiteboardSpawner.js b/examples/homeContent/whiteboardV2/whiteboardSpawner.js index eb0886229a..32c207499a 100644 --- a/examples/homeContent/whiteboardV2/whiteboardSpawner.js +++ b/examples/homeContent/whiteboardV2/whiteboardSpawner.js @@ -80,15 +80,16 @@ var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings whiteboardBackSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(moveForwardDistance, Quat.getFront(whiteboardRotation))); whiteboardSurfaceSettings.position = whiteboardBackSurfacePosition; -var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); +var whiteboardBackDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings); var WHITEBOARD_RACK_DEPTH = 1.9; var ERASER_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/eraser-2.fbx"; -var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js"); +var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js?v43"); var eraserPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(WHITEBOARD_RACK_DEPTH, Quat.getFront(whiteboardRotation))); eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getRight(whiteboardRotation))); +var eraserRotation = markerRotation; var eraser = Entities.addEntity({ type: "Model", @@ -101,7 +102,7 @@ var eraser = Entities.addEntity({ y: 0.0393, z: 0.2083 }, - rotation: markerRotation, + rotation: eraserRotation, dynamic: true, gravity: { x: 0, @@ -114,6 +115,8 @@ var eraser = Entities.addEntity({ z: 0 }, userData: JSON.stringify({ + originalPosition: eraserPosition, + originalRotation: eraserRotation, wearable: { joints: { RightHand: [{ From 5762c33cfebb87b56bcacd172cc572759b995115 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 26 Feb 2016 15:07:22 -0800 Subject: [PATCH 118/292] strokes are now parented to whiteboard surface --- .../homeContent/whiteboardV2/markerEntityScript.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index 64b906dda1..d06d5cf8e9 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -107,7 +107,9 @@ _this.resetStroke(); } } else { - _this.resetStroke(); + if (_this.currentStroke) { + _this.resetStroke(); + } Overlays.editOverlay(_this.laserPointer, { visible: false @@ -130,7 +132,6 @@ textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, lifetime: 500, - // parentID: _this.currentWhiteboard }); _this.linePoints = []; @@ -174,13 +175,20 @@ }); if (_this.linePoints.length > MAX_POINTS_PER_STROKE) { + Entities.editEntity(_this.currentStroke, { + parentID: _this.currentWhiteboard + }); _this.currentStroke = null; _this.oldPosition = position; } }, - resetStroke: function() { + + Entities.editEntity(_this.currentStroke, { + parentID: _this.currentWhiteboard + }); _this.currentStroke = null; + _this.oldPosition = null; }, From 2b03e16bec9b202e302c6ab4daf3c7513382cd8c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 12:48:09 +1300 Subject: [PATCH 119/292] Increase the title's focus shadow offset --- interface/resources/qml/windows-uit/DefaultFrame.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/windows-uit/DefaultFrame.qml b/interface/resources/qml/windows-uit/DefaultFrame.qml index 4e4c2df8f2..04905656ce 100644 --- a/interface/resources/qml/windows-uit/DefaultFrame.qml +++ b/interface/resources/qml/windows-uit/DefaultFrame.qml @@ -99,8 +99,8 @@ Frame { DropShadow { source: titleText anchors.fill: titleText - horizontalOffset: 1 - verticalOffset: 1 + horizontalOffset: 2 + verticalOffset: 2 samples: 2 color: hifi.colors.baseGrayShadow60 visible: (window && window.focus) From 98eb94ecefcc6d82903c371f4f3eb3dff2dbb42e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 13:30:49 +1300 Subject: [PATCH 120/292] Fix up capitalization of other settings dialogs --- interface/src/ui/PreferencesDialog.cpp | 46 ++++++++++++-------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index badf780f06..9f416f3117 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -36,8 +36,7 @@ void setupPreferences() { { auto getter = [=]()->QString {return myAvatar->getDisplayName(); }; auto setter = [=](const QString& value) { myAvatar->setDisplayName(value); }; - const QString label = "Avatar display name (optional)"; - auto preference = new EditPreference(AVATAR_BASICS, label, getter, setter); + auto preference = new EditPreference(AVATAR_BASICS, "Avatar display name (optional)", getter, setter); preference->setPlaceholderText("Not showing a name"); preferences->addPreference(preference); } @@ -45,8 +44,7 @@ void setupPreferences() { { auto getter = [=]()->QString {return myAvatar->getCollisionSoundURL(); }; auto setter = [=](const QString& value) { myAvatar->setCollisionSoundURL(value); }; - const QString label = "Avatar collision sound URL (optional)"; - auto preference = new EditPreference(AVATAR_BASICS, label, getter, setter); + auto preference = new EditPreference(AVATAR_BASICS, "Avatar collision sound URL (optional)", getter, setter); preference->setPlaceholderText("Enter the URL of a sound to play when you bump into something"); preferences->addPreference(preference); } @@ -54,13 +52,13 @@ void setupPreferences() { { auto getter = [=]()->QString { return myAvatar->getFullAvatarURLFromPreferences().toString(); }; auto setter = [=](const QString& value) { myAvatar->useFullAvatarURL(value, ""); }; - auto preference = new AvatarPreference(AVATAR_BASICS, "Appearance: ", getter, setter); + auto preference = new AvatarPreference(AVATAR_BASICS, "Appearance", getter, setter); preferences->addPreference(preference); } { auto getter = [=]()->bool {return myAvatar->getSnapTurn(); }; auto setter = [=](bool value) { myAvatar->setSnapTurn(value); }; - preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Snap Turn when in HMD", getter, setter)); + preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Snap turn when in HMD", getter, setter)); } { auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); }; @@ -90,7 +88,7 @@ void setupPreferences() { { auto getter = []()->float { return DependencyManager::get()->getDesktopLODDecreaseFPS(); }; auto setter = [](float value) { DependencyManager::get()->setDesktopLODDecreaseFPS(value); }; - auto preference = new SpinnerPreference(LOD_TUNING, "Minimum Desktop FPS", getter, setter); + auto preference = new SpinnerPreference(LOD_TUNING, "Minimum desktop FPS", getter, setter); preference->setMin(0); preference->setMax(120); preference->setStep(1); @@ -138,7 +136,7 @@ void setupPreferences() { { auto getter = [=]()->float { return myAvatar->getUniformScale(); }; auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell? - auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter); + auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter); preference->setMin(0.01f); preference->setMax(99.9f); preference->setDecimals(2); @@ -170,7 +168,7 @@ void setupPreferences() { { auto getter = [=]()->QString { return myAvatar->getAnimGraphUrl().toString(); }; auto setter = [=](const QString& value) { myAvatar->setAnimGraphUrl(value); }; - auto preference = new EditPreference(AVATAR_TUNING, "Avatar Animation JSON", getter, setter); + auto preference = new EditPreference(AVATAR_TUNING, "Avatar animation JSON", getter, setter); preference->setPlaceholderText("default"); preferences->addPreference(preference); } @@ -179,7 +177,7 @@ void setupPreferences() { { auto getter = [=]()->float { return myAvatar->getPitchSpeed(); }; auto setter = [=](float value) { myAvatar->setPitchSpeed(value); }; - auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera Pitch Speed (degrees/second)", getter, setter); + auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera pitch speed (degrees/second)", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); preferences->addPreference(preference); @@ -187,7 +185,7 @@ void setupPreferences() { { auto getter = [=]()->float { return myAvatar->getYawSpeed(); }; auto setter = [=](float value) { myAvatar->setYawSpeed(value); }; - auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera Yaw Speed (degrees/second)", getter, setter); + auto preference = new SpinnerPreference(AVATAR_CAMERA, "Camera yaw speed (degrees/second)", getter, setter); preference->setMin(1.0f); preference->setMax(360.0f); preferences->addPreference(preference); @@ -197,13 +195,13 @@ void setupPreferences() { { auto getter = []()->bool {return DependencyManager::get()->getReceivedAudioStream().getDynamicJitterBuffers(); }; auto setter = [](bool value) { DependencyManager::get()->getReceivedAudioStream().setDynamicJitterBuffers(value); }; - preferences->addPreference(new CheckPreference(AUDIO, "Enable Dynamic Jitter Buffers", getter, setter)); + preferences->addPreference(new CheckPreference(AUDIO, "Enable dynamic jitter buffers", getter, setter)); } { auto getter = []()->float { return DependencyManager::get()->getReceivedAudioStream().getDesiredJitterBufferFrames(); }; auto setter = [](float value) { DependencyManager::get()->getReceivedAudioStream().setStaticDesiredJitterBufferFrames(value); }; - auto preference = new SpinnerPreference(AUDIO, "Static Jitter Buffer Frames", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Static jitter buffer frames", getter, setter); preference->setMin(0); preference->setMax(10000); preference->setStep(1); @@ -212,7 +210,7 @@ void setupPreferences() { { auto getter = []()->float { return DependencyManager::get()->getReceivedAudioStream().getMaxFramesOverDesired(); }; auto setter = [](float value) { DependencyManager::get()->getReceivedAudioStream().setMaxFramesOverDesired(value); }; - auto preference = new SpinnerPreference(AUDIO, "Max Frames Over Desired", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Max frames over desired", getter, setter); preference->setMax(10000); preference->setStep(1); preferences->addPreference(preference); @@ -220,12 +218,12 @@ void setupPreferences() { { auto getter = []()->bool {return DependencyManager::get()->getReceivedAudioStream().getUseStDevForJitterCalc(); }; auto setter = [](bool value) { DependencyManager::get()->getReceivedAudioStream().setUseStDevForJitterCalc(value); }; - preferences->addPreference(new CheckPreference(AUDIO, "Use Stddev for Dynamic Jitter Calc", getter, setter)); + preferences->addPreference(new CheckPreference(AUDIO, "Use standard deviation for dynamic jitter calc", getter, setter)); } { auto getter = []()->float { return DependencyManager::get()->getReceivedAudioStream().getWindowStarveThreshold(); }; auto setter = [](float value) { DependencyManager::get()->getReceivedAudioStream().setWindowStarveThreshold(value); }; - auto preference = new SpinnerPreference(AUDIO, "Window A Starve Threshold", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Window A starve threshold", getter, setter); preference->setMax(10000); preference->setStep(1); preferences->addPreference(preference); @@ -233,7 +231,7 @@ void setupPreferences() { { auto getter = []()->float { return DependencyManager::get()->getReceivedAudioStream().getWindowSecondsForDesiredCalcOnTooManyStarves(); }; auto setter = [](float value) { DependencyManager::get()->getReceivedAudioStream().setWindowSecondsForDesiredCalcOnTooManyStarves(value); }; - auto preference = new SpinnerPreference(AUDIO, "Window A (raise desired on N starves) Seconds)", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Window A (raise desired on N starves) seconds", getter, setter); preference->setMax(10000); preference->setStep(1); preferences->addPreference(preference); @@ -241,7 +239,7 @@ void setupPreferences() { { auto getter = []()->float { return DependencyManager::get()->getReceivedAudioStream().getWindowSecondsForDesiredReduction(); }; auto setter = [](float value) { DependencyManager::get()->getReceivedAudioStream().setWindowSecondsForDesiredReduction(value); }; - auto preference = new SpinnerPreference(AUDIO, "Window B (desired ceiling) Seconds", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Window B (desired ceiling) seconds", getter, setter); preference->setMax(10000); preference->setStep(1); preferences->addPreference(preference); @@ -249,12 +247,12 @@ void setupPreferences() { { auto getter = []()->bool {return DependencyManager::get()->getReceivedAudioStream().getRepetitionWithFade(); }; auto setter = [](bool value) { DependencyManager::get()->getReceivedAudioStream().setRepetitionWithFade(value); }; - preferences->addPreference(new CheckPreference(AUDIO, "Repetition with Fade", getter, setter)); + preferences->addPreference(new CheckPreference(AUDIO, "Repetition with fade", getter, setter)); } { auto getter = []()->float { return DependencyManager::get()->getOutputBufferSize(); }; auto setter = [](float value) { DependencyManager::get()->setOutputBufferSize(value); }; - auto preference = new SpinnerPreference(AUDIO, "Output Buffer Initial Size (frames)", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Output buffer initial size (frames)", getter, setter); preference->setMin(1); preference->setMax(20); preference->setStep(1); @@ -263,13 +261,13 @@ void setupPreferences() { { auto getter = []()->bool {return DependencyManager::get()->getOutputStarveDetectionEnabled(); }; auto setter = [](bool value) { DependencyManager::get()->setOutputStarveDetectionEnabled(value); }; - auto preference = new CheckPreference(AUDIO, "Output Starve Detection (Automatic Buffer Size Increase)", getter, setter); + auto preference = new CheckPreference(AUDIO, "Output starve detection (automatic buffer size increase)", getter, setter); preferences->addPreference(preference); } { auto getter = []()->float { return DependencyManager::get()->getOutputStarveDetectionThreshold(); }; auto setter = [](float value) { DependencyManager::get()->setOutputStarveDetectionThreshold(value); }; - auto preference = new SpinnerPreference(AUDIO, "Output Starve Detection Threshold", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Output starve detection threshold", getter, setter); preference->setMin(1); preference->setMax(500); preference->setStep(1); @@ -278,7 +276,7 @@ void setupPreferences() { { auto getter = []()->float { return DependencyManager::get()->getOutputStarveDetectionPeriod(); }; auto setter = [](float value) { DependencyManager::get()->setOutputStarveDetectionPeriod(value); }; - auto preference = new SpinnerPreference(AUDIO, "Output Starve Detection Period (ms)", getter, setter); + auto preference = new SpinnerPreference(AUDIO, "Output starve detection period (ms)", getter, setter); preference->setMin(1); preference->setMax((float)999999999); preference->setStep(1); @@ -325,7 +323,7 @@ void setupPreferences() { { auto getter = [ambientOcclusionConfig]()->QString { return ambientOcclusionConfig->getPreset(); }; auto setter = [ambientOcclusionConfig](QString preset) { ambientOcclusionConfig->setPreset(preset); }; - auto preference = new ComboBoxPreference(RENDER, "Ambient Occlusion", getter, setter); + auto preference = new ComboBoxPreference(RENDER, "Ambient occlusion", getter, setter); preference->setItems(ambientOcclusionConfig->getPresetList()); preferences->addPreference(preference); } From cfcde5032ccb9a9f99a98ddf65bad3e9f55643d7 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 26 Feb 2016 16:32:29 -0800 Subject: [PATCH 121/292] Post merge with Zach work for environment map --- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 7c5c9d1a06..3ffdb2d47b 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -323,7 +323,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo /* if (_skyboxTexture) { program = _directionalSkyboxLightShadow; locations = _directionalSkyboxLightShadowLocations; - } else {*/ + } else*/ { program = _directionalAmbientSphereLightShadow; locations = _directionalAmbientSphereLightShadowLocations; } @@ -331,7 +331,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo /* if (_skyboxTexture) { program = _directionalSkyboxLight; locations = _directionalSkyboxLightLocations; - } else {*/ + } else*/ { program = _directionalAmbientSphereLight; locations = _directionalAmbientSphereLightLocations; } From 1a331fcdacbbd00bb124d0d86a4bae74914dc449 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 13:52:21 +1300 Subject: [PATCH 122/292] Style basic text field --- .../preferences/EditablePreference.qml | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/dialogs/preferences/EditablePreference.qml b/interface/resources/qml/dialogs/preferences/EditablePreference.qml index ddd5600bca..3b0f7802ea 100644 --- a/interface/resources/qml/dialogs/preferences/EditablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/EditablePreference.qml @@ -1,11 +1,22 @@ +// +// EditablePreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 + +import "../../dialogs" +import "../../controls-uit" Preference { id: root property real spacing: 8 - height: labelText.height + dataTextField.height + spacing + height: dataTextField.controlHeight + spacing Component.onCompleted: { dataTextField.text = preference.value; @@ -16,22 +27,16 @@ Preference { preference.save(); } - Text { - id: labelText - color: enabled ? "black" : "gray" - text: root.label - } - TextField { id: dataTextField placeholderText: preference.placeholderText - style: TextFieldStyle { renderType: Text.QtRendering } + label: root.label + colorScheme: hifi.colorSchemes.dark + anchors { - top: labelText.bottom left: parent.left right: parent.right - topMargin: root.spacing - rightMargin: root.spacing + bottomMargin: spacing } } } From 7fd88793dc3b41578680797152426b8a94c2a55b Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Fri, 26 Feb 2016 16:41:37 -0800 Subject: [PATCH 123/292] drag relative to plane where pointer collided selection box --- examples/edit.js | 5 ++- examples/libraries/entitySelectionTool.js | 39 +++++++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 50a66ea31f..fc04a0b26f 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -758,7 +758,8 @@ function findClickedEntity(event) { var foundEntity = result.entityID; return { pickRay: pickRay, - entityID: foundEntity + entityID: foundEntity, + intersection: result.intersection }; } @@ -978,6 +979,8 @@ function mouseClickEvent(event) { if (!event.isShifted) { selectionManager.setSelections([foundEntity]); + Vec3.print("found object, intersection = ", result.intersection); + selectionManager.setPickPlanePosition(result.intersection); } else { selectionManager.addEntity(foundEntity, true); } diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index c1675ef044..6a7247aa57 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -16,6 +16,11 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; SPACE_LOCAL = "local"; SPACE_WORLD = "world"; +function objectTranslationPlanePoint(position, dimensions) { + var newPosition = { x: position.x, y: position.y, z: position.z }; + newPosition.y -= dimensions.y / 2.0; + return newPosition; +} SelectionManager = (function() { var that = {}; @@ -82,6 +87,11 @@ SelectionManager = (function() { y: 0, z: 0 }; + that.pickPlanePosition = { + x: 0, + y: 0, + z: 0 + }; that.saveProperties = function() { that.savedProperties = {}; @@ -109,6 +119,13 @@ SelectionManager = (function() { that._update(); }; + that.setPickPlanePosition = function(position) { + that.pickPlanePosition.x = position.x; + that.pickPlanePosition.y = position.y; + that.pickPlanePosition.z = position.z; + Vec3.print("that.pickPlanePosition = ", that.pickPlanePosition); + }; + that.addEntity = function(entityID, toggleSelection) { if (entityID) { var idx = -1; @@ -2252,15 +2269,17 @@ SelectionDisplay = (function() { var constrainMajorOnly = false; var startPosition = null; var duplicatedEntityIDs = null; + var translateXZTool = { mode: 'TRANSLATE_XZ', + pickPlanePosition: { x: 0, y: 0, z: 0 }, onBegin: function(event) { SelectionManager.saveProperties(); startPosition = SelectionManager.worldPosition; var dimensions = SelectionManager.worldDimensions; var pickRay = Camera.computePickRay(event.x, event.y); - initialXZPick = rayPlaneIntersection(pickRay, startPosition, { + initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { x: 0, y: 1, z: 0 @@ -2300,13 +2319,23 @@ SelectionDisplay = (function() { onMove: function(event) { pickRay = Camera.computePickRay(event.x, event.y); - var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { + var pick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { x: 0, y: 1, z: 0 }); + var vector = Vec3.subtract(pick, initialXZPick); + Vec3.print("Pick Plane Position", translateXZTool.pickPlanePosition); + + /* + if (pickRay.origin.y < this.pickPlanePosition.y) { + vector.x *= -1.0; + vector.z *= -1.0; + } */ + + // If shifted, constrain to one axis if (event.isShifted) { if (Math.abs(vector.x) > Math.abs(vector.z)) { @@ -2645,11 +2674,6 @@ SelectionDisplay = (function() { pickRayPosition, planeNormal); - // Overlays.editOverlay(normalLine, { - // start: initialPosition, - // end: Vec3.sum(Vec3.multiply(100000, planeNormal), initialPosition), - // }); - SelectionManager.saveProperties(); }; @@ -4093,6 +4117,7 @@ SelectionDisplay = (function() { switch (result.overlayID) { case selectionBox: activeTool = translateXZTool; + translateXZTool.pickPlanePosition = result.intersection; mode = translateXZTool.mode; activeTool.onBegin(event); somethingClicked = true; From 47504a068ee43969869c3e426c2ba2427b7316b3 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Fri, 26 Feb 2016 16:50:37 -0800 Subject: [PATCH 124/292] remove unused code --- examples/edit.js | 2 -- examples/libraries/entitySelectionTool.js | 21 --------------------- 2 files changed, 23 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index fc04a0b26f..0e252bdf86 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -979,8 +979,6 @@ function mouseClickEvent(event) { if (!event.isShifted) { selectionManager.setSelections([foundEntity]); - Vec3.print("found object, intersection = ", result.intersection); - selectionManager.setPickPlanePosition(result.intersection); } else { selectionManager.addEntity(foundEntity, true); } diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 6a7247aa57..015e169908 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -87,11 +87,6 @@ SelectionManager = (function() { y: 0, z: 0 }; - that.pickPlanePosition = { - x: 0, - y: 0, - z: 0 - }; that.saveProperties = function() { that.savedProperties = {}; @@ -119,13 +114,6 @@ SelectionManager = (function() { that._update(); }; - that.setPickPlanePosition = function(position) { - that.pickPlanePosition.x = position.x; - that.pickPlanePosition.y = position.y; - that.pickPlanePosition.z = position.z; - Vec3.print("that.pickPlanePosition = ", that.pickPlanePosition); - }; - that.addEntity = function(entityID, toggleSelection) { if (entityID) { var idx = -1; @@ -2327,15 +2315,6 @@ SelectionDisplay = (function() { var vector = Vec3.subtract(pick, initialXZPick); - Vec3.print("Pick Plane Position", translateXZTool.pickPlanePosition); - - /* - if (pickRay.origin.y < this.pickPlanePosition.y) { - vector.x *= -1.0; - vector.z *= -1.0; - } */ - - // If shifted, constrain to one axis if (event.isShifted) { if (Math.abs(vector.x) > Math.abs(vector.z)) { From 50ebbe362de46e24ce2e1f07cbff8b0c51022dfb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 27 Feb 2016 14:06:33 +1300 Subject: [PATCH 125/292] Style avatar browser field --- .../dialogs/preferences/AvatarPreference.qml | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml index a92392799d..20029a1cd7 100644 --- a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml +++ b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml @@ -1,15 +1,26 @@ +// +// AvatarPreference.qml +// +// Created by Bradley Austin Davis on 22 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 + +import "../../dialogs" +import "../../controls-uit" Preference { id: root - property alias buttonText: button.text property alias text: dataTextField.text + property alias buttonText: button.text property alias placeholderText: dataTextField.placeholderText - property real spacing: 8 + property real spacing: 0 property var browser; - height: labelText.height + Math.max(dataTextField.height, button.height) + spacing + height: Math.max(dataTextField.controlHeight, button.height) + spacing Component.onCompleted: { dataTextField.text = preference.value; @@ -41,24 +52,18 @@ Preference { preference.save(); } - Text { - id: labelText - color: enabled ? "black" : "gray" - text: root.label - } - TextField { id: dataTextField placeholderText: root.placeholderText text: preference.value - style: TextFieldStyle { renderType: Text.QtRendering } + label: root.label anchors { - top: labelText.bottom left: parent.left right: button.left - topMargin: root.spacing - rightMargin: root.spacing + rightMargin: hifi.dimensions.contentSpacing.x + bottomMargin: spacing } + colorScheme: hifi.colorSchemes.dark } Component { From 89885805d22ddf3a2c952533a8d97206d95de26e Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 26 Feb 2016 18:34:33 -0800 Subject: [PATCH 126/292] OpenVR: Added hysteresis to the touch pad dead spot This should make using the Vive touch pad for movement more reliable. --- plugins/openvr/src/ViveControllerManager.cpp | 38 ++++++++++++-------- plugins/openvr/src/ViveControllerManager.h | 37 +++++++++++++++---- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 749c9ea2e4..0de8f6891d 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -234,8 +234,8 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); if (!jointsCaptured) { - handleHandController(leftHandDeviceIndex, inputCalibrationData, true); - handleHandController(rightHandDeviceIndex, inputCalibrationData, false); + handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true); + handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); } int numTrackedControllers = 0; @@ -248,7 +248,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle _trackedControllers = numTrackedControllers; } -void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) { +void ViveControllerManager::InputDevice::handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) { if (_system->IsTrackedDeviceConnected(deviceIndex) && _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller && @@ -258,7 +258,7 @@ void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceInd const mat4& mat = _trackedDevicePoseMat4[deviceIndex]; const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex]; const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex]; - handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand); + handlePoseEvent(deltaTime, inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand); vr::VRControllerState_t controllerState = vr::VRControllerState_t(); if (_system->GetControllerState(deviceIndex, &controllerState)) { @@ -267,12 +267,12 @@ void ViveControllerManager::InputDevice::handleHandController(uint32_t deviceInd for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); bool pressed = 0 != (controllerState.ulButtonPressed & mask); - handleButtonEvent(i, pressed, isLeftHand); + handleButtonEvent(deltaTime, i, pressed, isLeftHand); } // process each axis for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); + handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand); } } } @@ -284,36 +284,44 @@ void ViveControllerManager::InputDevice::focusOutEvent() { }; // These functions do translation from the Steam IDs to the standard controller IDs -void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand) { +void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand) { //FIX ME? It enters here every frame: probably we want to enter only if an event occurs axis += vr::k_EButton_Axis0; using namespace controller; + if (axis == vr::k_EButton_SteamVR_Touchpad) { - _axisStateMap[isLeftHand ? LX : RX] = x; - _axisStateMap[isLeftHand ? LY : RY] = y; + glm::vec2 stick(x, y); + if (isLeftHand) { + stick = _filteredLeftStick.process(deltaTime, stick); + } else { + stick = _filteredRightStick.process(deltaTime, stick); + } + _axisStateMap[isLeftHand ? LX : RX] = stick.x; + _axisStateMap[isLeftHand ? LY : RY] = stick.y; } else if (axis == vr::k_EButton_SteamVR_Trigger) { _axisStateMap[isLeftHand ? LT : RT] = x; } } // These functions do translation from the Steam IDs to the standard controller IDs -void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand) { +void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) { if (!pressed) { return; } + using namespace controller; if (button == vr::k_EButton_ApplicationMenu) { - _buttonPressedMap.insert(isLeftHand ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); + _buttonPressedMap.insert(isLeftHand ? LEFT_PRIMARY_THUMB : RIGHT_PRIMARY_THUMB); } else if (button == vr::k_EButton_Grip) { - _buttonPressedMap.insert(isLeftHand ? controller::LB : controller::RB); + _buttonPressedMap.insert(isLeftHand ? LB : RB); } else if (button == vr::k_EButton_SteamVR_Trigger) { - _buttonPressedMap.insert(isLeftHand ? controller::LT : controller::RT); + _buttonPressedMap.insert(isLeftHand ? LT : RT); } else if (button == vr::k_EButton_SteamVR_Touchpad) { - _buttonPressedMap.insert(isLeftHand ? controller::LS : controller::RS); + _buttonPressedMap.insert(isLeftHand ? LS : RS); } } -void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, +void ViveControllerManager::InputDevice::handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand) { // When the sensor-to-world rotation is identity the coordinate axes look like this: diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 2240a528a9..480fbfeb90 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -58,12 +58,39 @@ private: virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; - void handleHandController(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); - void handleButtonEvent(uint32_t button, bool pressed, bool isLeftHand); - void handleAxisEvent(uint32_t axis, float x, float y, bool isLeftHand); - void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, + void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); + void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand); + void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand); + void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand); + class FilteredStick { + public: + glm::vec2 process(float deltaTime, const glm::vec2& stick) { + // Use a timer to prevent the stick going to back to zero. + // This to work around the noisy touch pad that will flash back to zero breifly + const float ZERO_HYSTERESIS_PERIOD = 0.2f; // 200 ms + if (glm::length(stick) == 0.0f) { + if (_timer <= 0.0f) { + return glm::vec2(0.0f, 0.0f); + } else { + _timer -= deltaTime; + return _stick; + } + } else { + _timer = ZERO_HYSTERESIS_PERIOD; + _stick = stick; + return stick; + } + } + protected: + float _timer { 0.0f }; + glm::vec2 _stick { 0.0f, 0.0f }; + }; + + FilteredStick _filteredLeftStick; + FilteredStick _filteredRightStick; + int _trackedControllers { 0 }; vr::IVRSystem*& _system; friend class ViveControllerManager; @@ -71,8 +98,6 @@ private: void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); - - bool _registeredWithInputMapper { false }; bool _modelLoaded { false }; model::Geometry _modelGeometry; From e403c990d96f8c174ecb97b82e0ed906b7ed5159 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 27 Feb 2016 17:13:09 -0800 Subject: [PATCH 127/292] make fade non-linear --- examples/depthReticle.js | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index a8afb80df2..4b649f49b6 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -14,10 +14,9 @@ var APPARENT_2D_OVERLAY_DEPTH = 1.0; var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant var lastDepthCheckTime = Date.now(); var desiredDepth = APPARENT_2D_OVERLAY_DEPTH; -var wasDepth = Reticle.depth; // depth at the time we changed our desired depth -var desiredDepthLastSet = lastDepthCheckTime; // time we changed our desired depth var TIME_BETWEEN_DEPTH_CHECKS = 100; -var TIME_TO_FADE_DEPTH = 50; +var MINIMUM_DEPTH_ADJUST = 0.01; +var NON_LINEAR_DIVISOR = 2; Script.update.connect(function(deltaTime) { var now = Date.now(); @@ -53,30 +52,21 @@ Script.update.connect(function(deltaTime) { // If the desired depth has changed, reset our fade start time if (desiredDepth != newDesiredDepth) { - desiredDepthLastSet = now; desiredDepth = newDesiredDepth; - wasDepth = Reticle.depth; } } // move the reticle toward the desired depth if (desiredDepth != Reticle.depth) { - // determine the time between now, and when we set our determined our desiredDepth - var elapsed = now - desiredDepthLastSet; - var distanceToFade = desiredDepth - wasDepth; - var percentElapsed = Math.min(1, elapsed / TIME_TO_FADE_DEPTH); - - // special case to handle no fade settings - if (TIME_TO_FADE_DEPTH == 0) { - percentElapsed = 1; - } - var depthDelta = distanceToFade * percentElapsed; - - var newDepth = wasDepth + depthDelta; - if (percentElapsed == 1) { + // cut distance between desiredDepth and current depth in half until we're close enough + var distanceToAdjustThisCycle = (desiredDepth - Reticle.depth) / NON_LINEAR_DIVISOR; + if (Math.abs(distanceToAdjustThisCycle) < MINIMUM_DEPTH_ADJUST) { newDepth = desiredDepth; + } else { + newDepth = Reticle.depth + distanceToAdjustThisCycle; } + Reticle.setDepth(newDepth); } }); From 188cf3694b83f36a6808bac3659ff7f1958f2f99 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 27 Feb 2016 17:31:35 -0800 Subject: [PATCH 128/292] fix rotation of depth reticle --- interface/src/ui/ApplicationCompositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 99f0b4fdc4..59d794d7cb 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -301,7 +301,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int // look at borrowed from overlays float elevation = -asinf(relativePosition.y / glm::length(relativePosition)); float azimuth = atan2f(relativePosition.x, relativePosition.z); - glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, 0, -1)); // this extra *quat(vec3(0,0,-1)) was required to get the quad to flip this seems like we could optimize + glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, -PI, 0)); // this extra *quat(vec3(0,-PI,0)) was required to get the quad to flip this seems like we could optimize Transform transform; transform.setTranslation(relativePosition); From 1d681a24618fa4bfe35f55de4eae40006a0970c7 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Sun, 28 Feb 2016 12:00:13 -0800 Subject: [PATCH 129/292] Add angular size and azimuth limits to object XZ translation --- examples/edit.js | 22 ++++++++- examples/libraries/entitySelectionTool.js | 56 +++++++++++++++++++++-- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 0e252bdf86..d77e017c47 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -711,9 +711,27 @@ var intersection; var SCALE_FACTOR = 200.0; -function rayPlaneIntersection(pickRay, point, normal) { +function rayPlaneIntersection(pickRay, point, normal) { // + // + // This version of the test returns the intersection of a line with a plane + // + var collides = Vec3.dot(pickRay.direction, normal); + var d = -Vec3.dot(point, normal); - var t = -(Vec3.dot(pickRay.origin, normal) + d) / Vec3.dot(pickRay.direction, normal); + var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides; + + return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); +} + +function rayPlaneIntersection2(pickRay, point, normal) { + // + // This version of the test returns false if the ray is directed away from the plane + // + var collides = Vec3.dot(pickRay.direction, normal); + if (collides > 0.0) return false; + + var d = -Vec3.dot(point, normal); + var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides; return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); } diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 015e169908..0308a092ed 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -2261,6 +2261,10 @@ SelectionDisplay = (function() { var translateXZTool = { mode: 'TRANSLATE_XZ', pickPlanePosition: { x: 0, y: 0, z: 0 }, + greatestDimension: 0.0, + startingDistance: 0.0, + startingAzimuth: 0.0, + lastVector: { x: 0, y: 0, z: 0 }, onBegin: function(event) { SelectionManager.saveProperties(); startPosition = SelectionManager.worldPosition; @@ -2304,17 +2308,56 @@ SelectionDisplay = (function() { visible: false }); }, + azimuth: function(origin, intersection) { + return (origin.y - intersection.y) / Vec3.distance(origin, intersection); + }, onMove: function(event) { + var wantDebug = false; pickRay = Camera.computePickRay(event.x, event.y); - var pick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { + var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, { x: 0, y: 1, z: 0 }); + // If the pick ray doesn't hit the pick plane in this direction, do nothing. + // this will happen when someone drags across the horizon from the side they started on. + if (!pick) { + if (wantDebug) { + print("Pick ray does not intersect XZ plane."); + } + return; + } + var vector = Vec3.subtract(pick, initialXZPick); + // If the mouse is too close to the horizon of the pick plane, stop moving + var MIN_AZIMUTH = 0.02; // Radians + var azimuth = translateXZTool.azimuth(pickRay.origin, pick); + if ((translateXZTool.startingAzimuth > 0.0 && azimuth < MIN_AZIMUTH) || + (translateXZTool.startingAzimuth < 0.0 && azimuth > MIN_AZIMUTH)) { + //vector = translateXZTool.lastVector; + if (wantDebug) { + print("Azimuth = " + azimuth); + } + return; + } + + // If the angular size of the object is too small, stop moving + var MIN_ANGULAR_SIZE = 0.01; // Radians + if (translateXZTool.greatestDimension > 0) { + var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick)); + if (wantDebug) { + print("Angular size = " + angularSize); + } + if (angularSize < MIN_ANGULAR_SIZE) { + return; + } + } + + translateXZTool.lastVector = vector; + // If shifted, constrain to one axis if (event.isShifted) { if (Math.abs(vector.x) > Math.abs(vector.z)) { @@ -2376,7 +2419,7 @@ SelectionDisplay = (function() { grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), cornerPosition); - var wantDebug = false; + for (var i = 0; i < SelectionManager.selections.length; i++) { var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; @@ -3754,7 +3797,7 @@ SelectionDisplay = (function() { }; that.mousePressEvent = function(event) { - + if (!event.isLeftButton) { // if another mouse button than left is pressed ignore it return false; @@ -4097,6 +4140,13 @@ SelectionDisplay = (function() { case selectionBox: activeTool = translateXZTool; translateXZTool.pickPlanePosition = result.intersection; + translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), + SelectionManager.worldDimensions.z); + print("longest dimension" + translateXZTool.greatestDimension); + translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); + print("starting distance" + translateXZTool.startingDistance); + translateXZTool.startingAzimuth = translateXZTool.azimuth(pickRay.origin, translateXZTool.pickPlanePosition); + print("starting azimuth" + translateXZTool.startingAzimuth); mode = translateXZTool.mode; activeTool.onBegin(event); somethingClicked = true; From 5bf8670bc2e3f6def32d4fddf237b1c1c490a040 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 28 Feb 2016 12:15:26 -0800 Subject: [PATCH 130/292] fix SpatiallyNestable::getChildren --- examples/controllers/handControllerGrab.js | 3 ++- libraries/entities/src/EntityScriptingInterface.cpp | 4 +++- libraries/shared/src/SpatiallyNestable.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 45d27cbbb9..2bddc5d677 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1,3 +1,4 @@ +"use strict"; // handControllerGrab.js // // Created by Eric Levin on 9/2/15 @@ -1766,7 +1767,7 @@ function MyController(hand) { var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, handJointIndex); children.forEach(function(childID) { - print("disconnecting stray child of hand: " + childID); + print("disconnecting stray child of hand: (" + _this.hand + ") " + childID); Entities.editEntity(childID, {parentID: NULL_UUID}); }); } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4857fb8529..26f73eb65a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1084,7 +1084,9 @@ QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& pare return; } parent->forEachChild([&](SpatiallyNestablePointer child) { - result.push_back(child->getID()); + if (child->getParentJointIndex() == jointIndex) { + result.push_back(child->getID()); + } }); }); return result; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 557b25d9b2..2704a8bc21 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -682,7 +682,7 @@ QList SpatiallyNestable::getChildren() const { _childrenLock.withReadLock([&] { foreach(SpatiallyNestableWeakPointer childWP, _children.values()) { SpatiallyNestablePointer child = childWP.lock(); - if (child) { + if (child && child->_parentKnowsMe && child->getParentID() == getID()) { children << child; } } From e9aed839205ec314733215c2febf1be85caa508b Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Sun, 28 Feb 2016 12:41:40 -0800 Subject: [PATCH 131/292] suppress debug messages --- examples/edit.js | 14 +++++--- examples/libraries/entitySelectionTool.js | 42 +++++++++++++---------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index d77e017c47..54311a8c42 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -945,6 +945,7 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { + var wantDebug = false; if (isActive && event.isLeftButton) { var result = findClickedEntity(event); if (result === null) { @@ -959,11 +960,15 @@ function mouseClickEvent(event) { var properties = Entities.getEntityProperties(foundEntity); if (isLocked(properties)) { - print("Model locked " + properties.id); + if (wantDebug) { + print("Model locked " + properties.id); + } } else { var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal); + if (wantDebug) { + print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal); + } // P P - Model // /| A - Palm // / | d B - unit vector toward tip @@ -1000,8 +1005,9 @@ function mouseClickEvent(event) { } else { selectionManager.addEntity(foundEntity, true); } - - print("Model selected: " + foundEntity); + if (wantDebug) { + print("Model selected: " + foundEntity); + } selectionDisplay.select(selectedEntityID, event); if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 0308a092ed..3627a0a05e 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -2264,7 +2264,6 @@ SelectionDisplay = (function() { greatestDimension: 0.0, startingDistance: 0.0, startingAzimuth: 0.0, - lastVector: { x: 0, y: 0, z: 0 }, onBegin: function(event) { SelectionManager.saveProperties(); startPosition = SelectionManager.worldPosition; @@ -2337,7 +2336,6 @@ SelectionDisplay = (function() { var azimuth = translateXZTool.azimuth(pickRay.origin, pick); if ((translateXZTool.startingAzimuth > 0.0 && azimuth < MIN_AZIMUTH) || (translateXZTool.startingAzimuth < 0.0 && azimuth > MIN_AZIMUTH)) { - //vector = translateXZTool.lastVector; if (wantDebug) { print("Azimuth = " + azimuth); } @@ -2356,8 +2354,6 @@ SelectionDisplay = (function() { } } - translateXZTool.lastVector = vector; - // If shifted, constrain to one axis if (event.isShifted) { if (Math.abs(vector.x) > Math.abs(vector.z)) { @@ -3797,7 +3793,7 @@ SelectionDisplay = (function() { }; that.mousePressEvent = function(event) { - + var wantDebug = false; if (!event.isLeftButton) { // if another mouse button than left is pressed ignore it return false; @@ -3823,7 +3819,7 @@ SelectionDisplay = (function() { if (result.intersects) { - var wantDebug = false; + if (wantDebug) { print("something intersects... "); print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]"); @@ -3920,7 +3916,10 @@ SelectionDisplay = (function() { if (!somethingClicked) { - print("rotate handle case..."); + if (wantDebug) { + print("rotate handle case..."); + } + // After testing our stretch handles, then check out rotate handles Overlays.editOverlay(yawHandle, { @@ -3988,15 +3987,17 @@ SelectionDisplay = (function() { break; default: - print("mousePressEvent()...... " + overlayNames[result.overlayID]); + if (wantDebug) { + print("mousePressEvent()...... " + overlayNames[result.overlayID]); + } mode = "UNKNOWN"; break; } } - - print(" somethingClicked:" + somethingClicked); - print(" mode:" + mode); - + if (wantDebug) { + print(" somethingClicked:" + somethingClicked); + print(" mode:" + mode); + } if (somethingClicked) { @@ -4142,17 +4143,22 @@ SelectionDisplay = (function() { translateXZTool.pickPlanePosition = result.intersection; translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), SelectionManager.worldDimensions.z); - print("longest dimension" + translateXZTool.greatestDimension); - translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); - print("starting distance" + translateXZTool.startingDistance); - translateXZTool.startingAzimuth = translateXZTool.azimuth(pickRay.origin, translateXZTool.pickPlanePosition); - print("starting azimuth" + translateXZTool.startingAzimuth); + if (wantDebug) { + print("longest dimension: " + translateXZTool.greatestDimension); + translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); + print("starting distance: " + translateXZTool.startingDistance); + translateXZTool.startingAzimuth = translateXZTool.azimuth(pickRay.origin, translateXZTool.pickPlanePosition); + print(" starting azimuth: " + translateXZTool.startingAzimuth); + } + mode = translateXZTool.mode; activeTool.onBegin(event); somethingClicked = true; break; default: - print("mousePressEvent()...... " + overlayNames[result.overlayID]); + if (wantDebug) { + print("mousePressEvent()...... " + overlayNames[result.overlayID]); + } mode = "UNKNOWN"; break; } From 8de4a5907861d689c450bfc4f5ab45d9bb57e917 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sun, 28 Feb 2016 13:06:49 -0800 Subject: [PATCH 132/292] add support for auto-hide reticle and seek lookat on auto-show of reticle --- examples/autoHideReticle.js | 70 ++++++++++++++++++++++ interface/src/ui/ApplicationCompositor.cpp | 26 ++++---- 2 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 examples/autoHideReticle.js diff --git a/examples/autoHideReticle.js b/examples/autoHideReticle.js new file mode 100644 index 0000000000..172dd9b9f7 --- /dev/null +++ b/examples/autoHideReticle.js @@ -0,0 +1,70 @@ +// autoHideReticle.js +// examples +// +// Created by Brad Hefta-Gaub on 2/23/16. +// Copyright 2016 High Fidelity, Inc. +// +// This script will auto-hide the reticle on inactivity... and then if it detects movement after being hidden +// it will automatically move the reticle to the look at position +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var MINIMUM_SEEK_DISTANCE = 0.01; +var NON_LINEAR_DIVISOR = 2; + +var lastMouseMove = Date.now(); +var HIDE_STATIC_MOUSE_AFTER = 5000; // 5 seconds +var seekToLookAt = false; + +Controller.mouseMoveEvent.connect(function(mouseEvent) { + lastMouseMove = Date.now(); + + // if the reticle is hidden, show it... + if (!Reticle.visible) { + Reticle.visible = true; + if (HMD.active) { + seekToLookAt = true; + } + } +}); + + + +Script.update.connect(function(deltaTime) { + + // if we're currently seeking the lookAt move the mouse toward the lookat + if (HMD.active && seekToLookAt) { + var lookAt2D = HMD.getHUDLookAtPosition2D(); + var currentReticlePosition = Reticle.position; + var distanceBetweenX = lookAt2D.x - Reticle.position.x; + var distanceBetweenY = lookAt2D.y - Reticle.position.y; + var moveX = distanceBetweenX / NON_LINEAR_DIVISOR; + var moveY = distanceBetweenY / NON_LINEAR_DIVISOR; + var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY }; + var closeEnoughX = false; + var closeEnoughY = false; + if (moveX < MINIMUM_SEEK_DISTANCE) { + newPosition.x = lookAt2D.x; + closeEnoughX = true; + } + if (moveY < MINIMUM_SEEK_DISTANCE) { + newPosition.y = lookAt2D.y; + closeEnoughY = true; + } + if (closeEnoughX && closeEnoughY) { + seekToLookAt = false; + } + Reticle.position = newPosition; + } + + // if we haven't moved in a long period of time, hide the reticle + if (Reticle.visible) { + var now = Date.now(); + var timeSinceLastMouseMove = now - lastMouseMove; + if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { + Reticle.visible = false; + } + } +}); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 59d794d7cb..e8e6a0a956 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -212,19 +212,21 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); //draw the mouse pointer - // Get the mouse coordinates and convert to NDC [-1, 1] - vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas... - vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); - // Invert the Y axis - mousePosition.y *= -1.0f; + if (getReticleVisible()) { + // Get the mouse coordinates and convert to NDC [-1, 1] + vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas... + vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize); + // Invert the Y axis + mousePosition.y *= -1.0f; - Transform model; - model.setTranslation(vec3(mousePosition, 0)); - vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; - model.setScale(vec3(mouseSize, 1.0f)); - batch.setModelTransform(model); - bindCursorTexture(batch); - geometryCache->renderUnitQuad(batch, vec4(1)); + Transform model; + model.setTranslation(vec3(mousePosition, 0)); + vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; + model.setScale(vec3(mouseSize, 1.0f)); + batch.setModelTransform(model); + bindCursorTexture(batch); + geometryCache->renderUnitQuad(batch, vec4(1)); + } }); } From a933935e2d6af70dea252a2707efa2d3ce8d7675 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 28 Feb 2016 15:13:49 -0800 Subject: [PATCH 133/292] lock mutex in clearEntitiesInernal() --- libraries/entities/src/SimpleEntitySimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 693d80b27d..6bf25f767d 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -127,6 +127,7 @@ void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { } void SimpleEntitySimulation::clearEntitiesInternal() { + QMutexLocker lock(&_mutex); _entitiesWithSimulationOwner.clear(); _entitiesThatNeedSimulationOwner.clear(); } From cee79c8274865f2dcd6653798832fe58fae8ae29 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Sun, 28 Feb 2016 15:44:23 -0800 Subject: [PATCH 134/292] Fixed bug in rayPlane test --- examples/edit.js | 5 +++-- examples/libraries/entitySelectionTool.js | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 54311a8c42..d39a20c2e3 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -728,9 +728,10 @@ function rayPlaneIntersection2(pickRay, point, normal) { // This version of the test returns false if the ray is directed away from the plane // var collides = Vec3.dot(pickRay.direction, normal); - if (collides > 0.0) return false; - var d = -Vec3.dot(point, normal); + if (((collides > 0.0) && (d > 0.0)) || ((collides < 0.0) && (d < 0.0))) { + return false; + } var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides; return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 3627a0a05e..1834962e77 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -2334,10 +2334,13 @@ SelectionDisplay = (function() { // If the mouse is too close to the horizon of the pick plane, stop moving var MIN_AZIMUTH = 0.02; // Radians var azimuth = translateXZTool.azimuth(pickRay.origin, pick); + if (wantDebug) { + print("Start Azimuth: " + translateXZTool.startingAzimuth + ", Azimuth: " + azimuth); + } if ((translateXZTool.startingAzimuth > 0.0 && azimuth < MIN_AZIMUTH) || - (translateXZTool.startingAzimuth < 0.0 && azimuth > MIN_AZIMUTH)) { + (translateXZTool.startingAzimuth < 0.0 && azimuth > -MIN_AZIMUTH)) { if (wantDebug) { - print("Azimuth = " + azimuth); + print("too close to horizon!"); } return; } From 4009f03c384a553dcb708941958f84df30da410f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 08:38:53 -0800 Subject: [PATCH 135/292] move autohide/show behavior to depthReticle, make it a default script --- examples/autoHideReticle.js | 70 ------------------------------------ examples/defaultScripts.js | 1 + examples/depthReticle.js | 71 ++++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 71 deletions(-) delete mode 100644 examples/autoHideReticle.js diff --git a/examples/autoHideReticle.js b/examples/autoHideReticle.js deleted file mode 100644 index 172dd9b9f7..0000000000 --- a/examples/autoHideReticle.js +++ /dev/null @@ -1,70 +0,0 @@ -// autoHideReticle.js -// examples -// -// Created by Brad Hefta-Gaub on 2/23/16. -// Copyright 2016 High Fidelity, Inc. -// -// This script will auto-hide the reticle on inactivity... and then if it detects movement after being hidden -// it will automatically move the reticle to the look at position -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var MINIMUM_SEEK_DISTANCE = 0.01; -var NON_LINEAR_DIVISOR = 2; - -var lastMouseMove = Date.now(); -var HIDE_STATIC_MOUSE_AFTER = 5000; // 5 seconds -var seekToLookAt = false; - -Controller.mouseMoveEvent.connect(function(mouseEvent) { - lastMouseMove = Date.now(); - - // if the reticle is hidden, show it... - if (!Reticle.visible) { - Reticle.visible = true; - if (HMD.active) { - seekToLookAt = true; - } - } -}); - - - -Script.update.connect(function(deltaTime) { - - // if we're currently seeking the lookAt move the mouse toward the lookat - if (HMD.active && seekToLookAt) { - var lookAt2D = HMD.getHUDLookAtPosition2D(); - var currentReticlePosition = Reticle.position; - var distanceBetweenX = lookAt2D.x - Reticle.position.x; - var distanceBetweenY = lookAt2D.y - Reticle.position.y; - var moveX = distanceBetweenX / NON_LINEAR_DIVISOR; - var moveY = distanceBetweenY / NON_LINEAR_DIVISOR; - var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY }; - var closeEnoughX = false; - var closeEnoughY = false; - if (moveX < MINIMUM_SEEK_DISTANCE) { - newPosition.x = lookAt2D.x; - closeEnoughX = true; - } - if (moveY < MINIMUM_SEEK_DISTANCE) { - newPosition.y = lookAt2D.y; - closeEnoughY = true; - } - if (closeEnoughX && closeEnoughY) { - seekToLookAt = false; - } - Reticle.position = newPosition; - } - - // if we haven't moved in a long period of time, hide the reticle - if (Reticle.visible) { - var now = Date.now(); - var timeSinceLastMouseMove = now - lastMouseMove; - if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { - Reticle.visible = false; - } - } -}); diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 35af5f4eae..2c024c5bf0 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -22,3 +22,4 @@ Script.load("grab.js"); Script.load("directory.js"); Script.load("dialTone.js"); Script.load("attachedEntitiesManager.js"); +Script.load("depthReticle.js"); diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 4b649f49b6..820125a3c7 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -5,6 +5,8 @@ // Copyright 2016 High Fidelity, Inc. // // When used in HMD, this script will make the reticle depth track to any clickable item in view. +// This script also handles auto-hiding the reticle after inactivity, as well as having the reticle +// seek the look at position upon waking up. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -17,8 +19,63 @@ var desiredDepth = APPARENT_2D_OVERLAY_DEPTH; var TIME_BETWEEN_DEPTH_CHECKS = 100; var MINIMUM_DEPTH_ADJUST = 0.01; var NON_LINEAR_DIVISOR = 2; +var MINIMUM_SEEK_DISTANCE = 0.01; -Script.update.connect(function(deltaTime) { +var lastMouseMove = Date.now(); +var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds +var shouldSeekToLookAt = false; + +Controller.mouseMoveEvent.connect(function(mouseEvent) { + lastMouseMove = Date.now(); + + // if the reticle is hidden, show it... + if (!Reticle.visible) { + Reticle.visible = true; + if (HMD.active) { + shouldSeekToLookAt = true; + } + } +}); + +function seekToLookAt() { + // if we're currently seeking the lookAt move the mouse toward the lookat + if (shouldSeekToLookAt) { + var lookAt2D = HMD.getHUDLookAtPosition2D(); + var currentReticlePosition = Reticle.position; + var distanceBetweenX = lookAt2D.x - Reticle.position.x; + var distanceBetweenY = lookAt2D.y - Reticle.position.y; + var moveX = distanceBetweenX / NON_LINEAR_DIVISOR; + var moveY = distanceBetweenY / NON_LINEAR_DIVISOR; + var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY }; + var closeEnoughX = false; + var closeEnoughY = false; + if (moveX < MINIMUM_SEEK_DISTANCE) { + newPosition.x = lookAt2D.x; + closeEnoughX = true; + } + if (moveY < MINIMUM_SEEK_DISTANCE) { + newPosition.y = lookAt2D.y; + closeEnoughY = true; + } + if (closeEnoughX && closeEnoughY) { + shouldSeekToLookAt = false; + } + Reticle.position = newPosition; + } +} + +function autoHideReticle() { + // if we haven't moved in a long period of time, hide the reticle + if (Reticle.visible) { + var now = Date.now(); + var timeSinceLastMouseMove = now - lastMouseMove; + if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { + Reticle.visible = false; + } + } +} + +function checkReticleDepth() { var now = Date.now(); var timeSinceLastDepthCheck = now - lastDepthCheckTime; if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) { @@ -56,6 +113,9 @@ Script.update.connect(function(deltaTime) { } } +} + +function moveToDesiredDepth() { // move the reticle toward the desired depth if (desiredDepth != Reticle.depth) { @@ -69,4 +129,13 @@ Script.update.connect(function(deltaTime) { Reticle.setDepth(newDepth); } +} + +Script.update.connect(function(deltaTime) { + autoHideReticle(); // auto hide reticle for desktop or HMD mode + if (HMD.active) { + seekToLookAt(); // handle moving the reticle toward the look at + checkReticleDepth(); // make sure reticle is at correct depth + moveToDesiredDepth(); // move the fade the reticle to the desired depth + } }); From 08eacc436f3d45251c5abb3a18728838e50be87a Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 10:13:01 -0800 Subject: [PATCH 136/292] Fixed rayPlane test again --- examples/edit.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index d39a20c2e3..59e1f74d20 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -729,12 +729,12 @@ function rayPlaneIntersection2(pickRay, point, normal) { // var collides = Vec3.dot(pickRay.direction, normal); var d = -Vec3.dot(point, normal); - if (((collides > 0.0) && (d > 0.0)) || ((collides < 0.0) && (d < 0.0))) { - return false; - } var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides; - - return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); + if (t < 0.0) { + return false; + } else { + return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); + } } function findClickedEntity(event) { From d1bc31afb64f17001b4c38332c09943f511b50fb Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 10:16:34 -0800 Subject: [PATCH 137/292] azimuth function is really just a ratio --- examples/libraries/entitySelectionTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 1834962e77..1be6030f6e 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -2332,7 +2332,7 @@ SelectionDisplay = (function() { var vector = Vec3.subtract(pick, initialXZPick); // If the mouse is too close to the horizon of the pick plane, stop moving - var MIN_AZIMUTH = 0.02; // Radians + var MIN_AZIMUTH = 0.02; // largest dimension of object divided by distance to it var azimuth = translateXZTool.azimuth(pickRay.origin, pick); if (wantDebug) { print("Start Azimuth: " + translateXZTool.startingAzimuth + ", Azimuth: " + azimuth); From 42f6ede43cee55399012a097abe585244b401e9c Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 10:22:24 -0800 Subject: [PATCH 138/292] azimuth = elevation, duh --- examples/libraries/entitySelectionTool.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 1be6030f6e..95e695aa9c 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -2263,7 +2263,7 @@ SelectionDisplay = (function() { pickPlanePosition: { x: 0, y: 0, z: 0 }, greatestDimension: 0.0, startingDistance: 0.0, - startingAzimuth: 0.0, + startingElevation: 0.0, onBegin: function(event) { SelectionManager.saveProperties(); startPosition = SelectionManager.worldPosition; @@ -2307,7 +2307,7 @@ SelectionDisplay = (function() { visible: false }); }, - azimuth: function(origin, intersection) { + elevation: function(origin, intersection) { return (origin.y - intersection.y) / Vec3.distance(origin, intersection); }, onMove: function(event) { @@ -2332,13 +2332,13 @@ SelectionDisplay = (function() { var vector = Vec3.subtract(pick, initialXZPick); // If the mouse is too close to the horizon of the pick plane, stop moving - var MIN_AZIMUTH = 0.02; // largest dimension of object divided by distance to it - var azimuth = translateXZTool.azimuth(pickRay.origin, pick); + var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it + var elevation = translateXZTool.elevation(pickRay.origin, pick); if (wantDebug) { - print("Start Azimuth: " + translateXZTool.startingAzimuth + ", Azimuth: " + azimuth); + print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation); } - if ((translateXZTool.startingAzimuth > 0.0 && azimuth < MIN_AZIMUTH) || - (translateXZTool.startingAzimuth < 0.0 && azimuth > -MIN_AZIMUTH)) { + if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) || + (translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) { if (wantDebug) { print("too close to horizon!"); } @@ -4150,8 +4150,8 @@ SelectionDisplay = (function() { print("longest dimension: " + translateXZTool.greatestDimension); translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); print("starting distance: " + translateXZTool.startingDistance); - translateXZTool.startingAzimuth = translateXZTool.azimuth(pickRay.origin, translateXZTool.pickPlanePosition); - print(" starting azimuth: " + translateXZTool.startingAzimuth); + translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); + print(" starting elevation: " + translateXZTool.startingElevation); } mode = translateXZTool.mode; From bb9d1556c6e148f19449ab0398655da9b8a90085 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 29 Feb 2016 11:07:02 -0800 Subject: [PATCH 139/292] when breaking a parenting loop, make an effort to keep the object near where it was when the loop was created --- libraries/shared/src/SpatiallyNestable.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 1a897021f1..56532c04f4 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -519,7 +519,13 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, i success = false; // someone created a loop. break it... qDebug() << "Parenting loop detected."; - getThisPointer()->setParentID(QUuid()); + SpatiallyNestablePointer _this = getThisPointer(); + _this->setParentID(QUuid()); + bool setPositionSuccess; + AACube aaCube = getQueryAACube(setPositionSuccess); + if (setPositionSuccess) { + _this->setPosition(aaCube.calcCenter()); + } return jointInWorldFrame; } From a32452db8be85e56438500dd6cb4b1201a8e6abd Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 1 Mar 2016 10:41:43 +1300 Subject: [PATCH 140/292] Change Running Scripts reload, close, and tree buttons when pressed Provides visual feedback to user. --- interface/resources/qml/controls-uit/Table.qml | 6 ++++-- interface/resources/qml/controls-uit/Tree.qml | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/controls-uit/Table.qml b/interface/resources/qml/controls-uit/Table.qml index fc6c310612..de6950c07e 100644 --- a/interface/resources/qml/controls-uit/Table.qml +++ b/interface/resources/qml/controls-uit/Table.qml @@ -133,13 +133,14 @@ TableView { HiFiGlyphs { id: reloadButton text: hifi.glyphs.reloadSmall - color: parent.color + color: reloadButtonArea.pressed ? hifi.colors.white : parent.color anchors { top: parent.top right: stopButton.left verticalCenter: parent.verticalCenter } MouseArea { + id: reloadButtonArea anchors { fill: parent; margins: -2 } onClicked: reloadScript(model.url) } @@ -149,13 +150,14 @@ TableView { HiFiGlyphs { id: stopButton text: hifi.glyphs.closeSmall - color: parent.color + color: stopButtonArea.pressed ? hifi.colors.white : parent.color anchors { top: parent.top right: parent.right verticalCenter: parent.verticalCenter } MouseArea { + id: stopButtonArea anchors { fill: parent; margins: -2 } onClicked: stopScript(model.url) } diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index d100cdcd44..454218b116 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -56,14 +56,23 @@ TreeView { branchDelegate: HiFiGlyphs { text: styleData.isExpanded ? hifi.glyphs.disclosureCollapse : hifi.glyphs.disclosureExpand - size: hifi.fontSizes.tableText * 2.5 // tableText is in points; proportionately scale to pixels + size: hifi.fontSizes.tableText * 2.5 color: colorScheme == hifi.colorSchemes.light - ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) - : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + ? (styleData.selected + ? hifi.colors.black + : (iconArea.pressed ? hifi.colors.white : hifi.colors.baseGrayHighlight)) + : (styleData.selected + ? hifi.colors.black + : (iconArea.pressed ? hifi.colors.white : hifi.colors.lightGrayText)) anchors { left: parent ? parent.left : undefined leftMargin: hifi.dimensions.tablePadding / 2 } + MouseArea { + id: iconArea + anchors.fill: parent + propagateComposedEvents: true + } } handle: Item { From b442075205800eb730bd7b14a3a7e02607cbbbd0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 29 Feb 2016 14:22:08 -0800 Subject: [PATCH 141/292] Add initial seq number to handshake --- libraries/networking/src/udt/Connection.cpp | 14 ++++++++++--- libraries/networking/src/udt/SendQueue.cpp | 22 +++++++++++++-------- libraries/networking/src/udt/SendQueue.h | 2 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 1ab8441ba3..cb197f15c7 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -731,15 +731,20 @@ void Connection::processNAK(std::unique_ptr controlPacket) { } void Connection::processHandshake(std::unique_ptr controlPacket) { + SequenceNumber initialSequenceNumber; + controlPacket->readPrimitive(&initialSequenceNumber); - if (!_hasReceivedHandshake || _hasReceivedData) { + if (!_hasReceivedHandshake || initialSequenceNumber != _initialReceiveSequenceNumber) { // server sent us a handshake - we need to assume this means state should be reset // as long as we haven't received a handshake yet or we have and we've received some data resetReceiveState(); + _initialReceiveSequenceNumber = initialSequenceNumber; } // immediately respond with a handshake ACK - static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, 0); + static auto handshakeACK = ControlPacket::create(ControlPacket::HandshakeACK, sizeof(SequenceNumber)); + handshakeACK->seek(0); + handshakeACK->writePrimitive(initialSequenceNumber); _parentSocket->writeBasePacket(*handshakeACK, _destination); // indicate that handshake has been received @@ -749,8 +754,11 @@ void Connection::processHandshake(std::unique_ptr controlPacket) void Connection::processHandshakeACK(std::unique_ptr controlPacket) { // if we've decided to clean up the send queue then this handshake ACK should be ignored, it's useless if (_sendQueue) { + SequenceNumber initialSequenceNumber; + controlPacket->readPrimitive(&initialSequenceNumber); + // hand off this handshake ACK to the send queue so it knows it can start sending - getSendQueue().handshakeACK(); + getSendQueue().handshakeACK(initialSequenceNumber); // indicate that handshake ACK was received _hasReceivedHandshakeACK = true; diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 77b0c53da7..5c6db5adf3 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -202,7 +202,11 @@ void SendQueue::sendHandshake() { std::unique_lock handshakeLock { _handshakeMutex }; if (!_hasReceivedHandshakeACK) { // we haven't received a handshake ACK from the client, send another now - static const auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, 0); + static const auto handshakePacket = ControlPacket::create(ControlPacket::Handshake, sizeof(SequenceNumber)); + + handshakePacket->seek(0); + + handshakePacket->writePrimitive(_initialSequenceNumber); _socket->writeBasePacket(*handshakePacket, _destination); // we wait for the ACK or the re-send interval to expire @@ -211,14 +215,16 @@ void SendQueue::sendHandshake() { } } -void SendQueue::handshakeACK() { - { - std::lock_guard locker { _handshakeMutex }; - _hasReceivedHandshakeACK = true; +void SendQueue::handshakeACK(SequenceNumber initialSequenceNumber) { + if (initialSequenceNumber == _initialSequenceNumber) { + { + std::lock_guard locker { _handshakeMutex }; + _hasReceivedHandshakeACK = true; + } + + // Notify on the handshake ACK condition + _handshakeACKCondition.notify_one(); } - - // Notify on the handshake ACK condition - _handshakeACKCondition.notify_one(); } SequenceNumber SendQueue::getNextSequenceNumber() { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 29ad7c6d73..0390f2ff1f 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -71,7 +71,7 @@ public slots: void ack(SequenceNumber ack); void nak(SequenceNumber start, SequenceNumber end); void overrideNAKListFromPacket(ControlPacket& packet); - void handshakeACK(); + void handshakeACK(SequenceNumber initialSequenceNumber); signals: void packetSent(int dataSize, int payloadSize); From 2229e397fa1112f2d76a2219afd09ad0b53a0208 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 29 Feb 2016 14:22:26 -0800 Subject: [PATCH 142/292] Move seq num initialization to handshake --- libraries/networking/src/udt/Connection.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index cb197f15c7..fdf8375ff3 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -411,12 +411,6 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in // refuse to process any packets until we've received the handshake return false; } - - if (!_hasReceivedData) { - _initialReceiveSequenceNumber = sequenceNumber; - _lastReceivedSequenceNumber = sequenceNumber - 1; - _lastSentACK = sequenceNumber - 1; - } _isReceivingData = _hasReceivedData = true; @@ -739,6 +733,8 @@ void Connection::processHandshake(std::unique_ptr controlPacket) // as long as we haven't received a handshake yet or we have and we've received some data resetReceiveState(); _initialReceiveSequenceNumber = initialSequenceNumber; + _lastReceivedSequenceNumber = initialSequenceNumber - 1; + _lastSentACK = initialSequenceNumber - 1; } // immediately respond with a handshake ACK From 57a6cbc9dd024ca5b5327424fa71eeb14ac4cfd1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 29 Feb 2016 14:22:49 -0800 Subject: [PATCH 143/292] Remove _hasReceivedData --- libraries/networking/src/udt/Connection.cpp | 4 ++-- libraries/networking/src/udt/Connection.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index fdf8375ff3..04edc8bb55 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -412,7 +412,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in return false; } - _isReceivingData = _hasReceivedData = true; + _isReceivingData = true; // mark our last receive time as now (to push the potential expiry farther) _lastReceiveTime = p_high_resolution_clock::now(); @@ -810,7 +810,7 @@ void Connection::resetReceiveState() { // the _nakInterval need not be reset, that will happen on loss // clear sync variables - _isReceivingData = _hasReceivedData = false; + _isReceivingData = false; _connectionStart = p_high_resolution_clock::now(); _acksDuringSYN = 1; diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 2f2252a139..bf56a468aa 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -129,7 +129,6 @@ private: p_high_resolution_clock::time_point _lastReceiveTime; // holds the last time we received anything from sender bool _isReceivingData { false }; // flag used for expiry of receipt portion of connection - bool _hasReceivedData { false }; // flag used for reset of connection state on second handshake bool _isActive { true }; // flag used for inactivity of connection SequenceNumber _initialReceiveSequenceNumber; // Randomized by peer SendQueue on creation, identifies connection during re-connect requests From dc4c4e8c945ff284919e04877d2ffaa5c8a31425 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 14:24:43 -0800 Subject: [PATCH 144/292] some tweaks to auto-hide --- examples/depthReticle.js | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 820125a3c7..14a5ba5ff3 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -22,11 +22,18 @@ var NON_LINEAR_DIVISOR = 2; var MINIMUM_SEEK_DISTANCE = 0.01; var lastMouseMove = Date.now(); +var lastMouseX = Reticle.position.x; +var lastMouseY = Reticle.position.y; var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds var shouldSeekToLookAt = false; +var fastMouseMoves = 0; +var averageMouseVelocity = 0; +var WEIGHTING = 1/20; // simple moving average over last 20 samples +var ONE_MINUS_WEIGHTING = 1 - WEIGHTING; +var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50; Controller.mouseMoveEvent.connect(function(mouseEvent) { - lastMouseMove = Date.now(); + var now = Date.now(); // if the reticle is hidden, show it... if (!Reticle.visible) { @@ -34,12 +41,30 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) { if (HMD.active) { shouldSeekToLookAt = true; } + } else { + // even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it) + // then they are probably looking for it, and we should move into seekToLookAt mode + if (HMD.active && !shouldSeekToLookAt) { + var dx = Reticle.position.x - lastMouseX; + var dy = Reticle.position.y - lastMouseY; + var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move + var mouseMoveDistance = Math.sqrt((dx*dx) + (dy*dy)); + var mouseVelocity = mouseMoveDistance / dt; + averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * mouseVelocity); + if (averageMouseVelocity > AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO) { + shouldSeekToLookAt = true; + } + } } + lastMouseMove = now; + lastMouseX = mouseEvent.x; + lastMouseY = mouseEvent.y; }); function seekToLookAt() { // if we're currently seeking the lookAt move the mouse toward the lookat if (shouldSeekToLookAt) { + averageMouseVelocity = 0; // reset this, these never count for movement... var lookAt2D = HMD.getHUDLookAtPosition2D(); var currentReticlePosition = Reticle.position; var distanceBetweenX = lookAt2D.x - Reticle.position.x; @@ -57,16 +82,17 @@ function seekToLookAt() { newPosition.y = lookAt2D.y; closeEnoughY = true; } + Reticle.position = newPosition; if (closeEnoughX && closeEnoughY) { shouldSeekToLookAt = false; } - Reticle.position = newPosition; } } function autoHideReticle() { - // if we haven't moved in a long period of time, hide the reticle - if (Reticle.visible) { + // if we haven't moved in a long period of time, and we're not pointing at some + // system overlay (like a window), then hide the reticle + if (Reticle.visible && !Reticle.pointingAtSystemOverlay) { var now = Date.now(); var timeSinceLastMouseMove = now - lastMouseMove; if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) { From 04f512c99bc6ba6ee79b7240b483f263a4ca0e61 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 29 Feb 2016 14:58:25 -0800 Subject: [PATCH 145/292] Add extra debug to udt connection --- libraries/networking/src/udt/Connection.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 04edc8bb55..e6a15aa6a0 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -731,6 +731,12 @@ void Connection::processHandshake(std::unique_ptr controlPacket) if (!_hasReceivedHandshake || initialSequenceNumber != _initialReceiveSequenceNumber) { // server sent us a handshake - we need to assume this means state should be reset // as long as we haven't received a handshake yet or we have and we've received some data + +#ifdef UDT_CONNECTION_DEBUG + if (initialSequenceNumber != _initialReceiveSequenceNumber) { + qCDebug(networking) << "Resetting receive state, received a new initial sequence number in handshake"; + } +#endif resetReceiveState(); _initialReceiveSequenceNumber = initialSequenceNumber; _lastReceivedSequenceNumber = initialSequenceNumber - 1; From 548a672df9780d52e7619b9f20b1068f6f250e34 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 29 Feb 2016 15:31:38 -0800 Subject: [PATCH 146/292] Update DomainList version to 18 --- libraries/networking/src/udt/PacketHeaders.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 4e6418279d..5f86c35e7f 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,6 +38,8 @@ const QSet RELIABLE_PACKETS = QSet(); PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { + case PacketType::DomainList: + return 18; case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: From 33fe2e9b36de111a215ea559ef28f70d1fa130b7 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Mon, 29 Feb 2016 16:11:08 -0800 Subject: [PATCH 147/292] Update markerEntityScript.js --- examples/homeContent/whiteboardV2/markerEntityScript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/homeContent/whiteboardV2/markerEntityScript.js b/examples/homeContent/whiteboardV2/markerEntityScript.js index d06d5cf8e9..19907b283c 100644 --- a/examples/homeContent/whiteboardV2/markerEntityScript.js +++ b/examples/homeContent/whiteboardV2/markerEntityScript.js @@ -131,7 +131,7 @@ position: position, textures: _this.MARKER_TEXTURE_URL, color: _this.markerColor, - lifetime: 500, + lifetime: 5000, }); _this.linePoints = []; @@ -216,4 +216,4 @@ // entity scripts always need to return a newly constructed object of our type return new MarkerTip(); -}); \ No newline at end of file +}); From 0e17506137b22c043429773b6e545c29fdc72e6a Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 16:21:06 -0800 Subject: [PATCH 148/292] hand controller doesn't take mouse if set down, renamed file. --- ...dRotationTest.js => handControllerMouse.js} | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) rename examples/controllers/{reticleHandRotationTest.js => handControllerMouse.js} (83%) diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/handControllerMouse.js similarity index 83% rename from examples/controllers/reticleHandRotationTest.js rename to examples/controllers/handControllerMouse.js index 631486d1a3..f42d95e819 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/handControllerMouse.js @@ -1,5 +1,5 @@ // -// reticleHandRotationTest.js +// handControllerMouse.js // examples/controllers // // Created by Brad Hefta-Gaub on 2015/12/15 @@ -11,6 +11,10 @@ var DEBUGGING = false; +var angularVelocityTrailingAverage = 0.0; // Global trailing average used to decide whether to move reticle at all +var lastX = 0; +var lastY = 0; + Math.clamp=function(a,b,c) { return Math.max(b,Math.min(c,a)); } @@ -76,7 +80,7 @@ Script.update.connect(function(deltaTime) { } // Velocity filter the hand rotation used to position reticle so that it is easier to target small things with the hand controllers - var VELOCITY_FILTER_GAIN = 1.0; + var VELOCITY_FILTER_GAIN = 0.5; filteredRotatedLeft = Vec3.mix(filteredRotatedLeft, rotatedLeft, Math.clamp(Vec3.length(poseLeft.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0)); filteredRotatedRight = Vec3.mix(filteredRotatedRight, rotatedRight, Math.clamp(Vec3.length(poseRight.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0)); var rotated = Vec3.mix(filteredRotatedLeft, filteredRotatedRight, leftRightBias); @@ -96,11 +100,17 @@ Script.update.connect(function(deltaTime) { var y = screenSizeY * yRatio; // don't move the reticle with the hand controllers unless the controllers are actually being moved - var MINIMUM_CONTROLLER_ANGULAR_VELOCITY = 0.0001; + // take a time average of angular velocity, and don't move mouse at all if it's below threshold + + var AVERAGING_INTERVAL = 0.95; + var MINIMUM_CONTROLLER_ANGULAR_VELOCITY = 0.03; var angularVelocityMagnitude = Vec3.length(poseLeft.angularVelocity) * (1.0 - leftRightBias) + Vec3.length(poseRight.angularVelocity) * leftRightBias; + angularVelocityTrailingAverage = angularVelocityTrailingAverage * AVERAGING_INTERVAL + angularVelocityMagnitude * (1.0 - AVERAGING_INTERVAL); - if (!(xRatio == 0.5 && yRatio == 0) && (angularVelocityMagnitude > MINIMUM_CONTROLLER_ANGULAR_VELOCITY)) { + if (!(xRatio == 0.5 && yRatio == 0) && (angularVelocityTrailingAverage > MINIMUM_CONTROLLER_ANGULAR_VELOCITY) && ((x != lastX) || (y != lastY))) { moveReticleAbsolute(x, y); + lastX = x; + lastY = y; } }); From 86249cc9db6dbfa3c9f2154aa906565101f676bf Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 16:23:03 -0800 Subject: [PATCH 149/292] add hand controller mouse to default scripts --- examples/defaultScripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 35af5f4eae..d612e617e1 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -17,6 +17,7 @@ Script.load("inspect.js"); Script.load("notifications.js"); Script.load("users.js"); Script.load("controllers/handControllerGrab.js"); +Script.load("controllers/handControllerMouse.js"); Script.load("controllers/squeezeHands.js"); Script.load("grab.js"); Script.load("directory.js"); From b89b6be210011acbdecf7329c7e0eaf7a31784cc Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 16:45:00 -0800 Subject: [PATCH 150/292] look for hydra first --- examples/controllers/handControllerMouse.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/controllers/handControllerMouse.js b/examples/controllers/handControllerMouse.js index f42d95e819..d353afab5e 100644 --- a/examples/controllers/handControllerMouse.js +++ b/examples/controllers/handControllerMouse.js @@ -35,12 +35,13 @@ function moveReticleAbsolute(x, y) { var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); -mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); +if (Controller.Hardware.hydra !== undefined) { + mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); + mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); +} + mapping.enable(); - - function debugPrint(message) { if (DEBUGGING) { print(message); From 99bd0f3d1341ce4bdee1049912d44b567796d92c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 29 Feb 2016 16:49:35 -0800 Subject: [PATCH 151/292] MyAvatar: fixes for eye look at Users in desktop mode should now see the eyes change focus between the left eye, right eye and the mouth. Users in mirror mode, or third person camera, should more accurately determine which avatar to look at. --- interface/src/avatar/MyAvatar.cpp | 40 ++++++++++++------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fc715eebe9..1b04fa4fa4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -849,7 +849,7 @@ void MyAvatar::updateLookAtTargetAvatar() { avatar->setIsLookAtTarget(false); if (!avatar->isMyAvatar() && avatar->isInitialized() && (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) { - float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition)); + float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - getHead()->getEyePosition())); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; _targetAvatarPosition = avatarPointer->getPosition(); @@ -864,36 +864,26 @@ void MyAvatar::updateLookAtTargetAvatar() { // Let's get everything to world space: glm::vec3 avatarLeftEye = getHead()->getLeftEyePosition(); glm::vec3 avatarRightEye = getHead()->getRightEyePosition(); - // When not in HMD, these might both answer identity (i.e., the bridge of the nose). That's ok. - // By my inpsection of the code and live testing, getEyeOffset and getEyePose are the same. (Application hands identity as offset matrix.) - // This might be more work than needed for any given use, but as we explore different formulations, we go mad if we don't work in world space. - glm::mat4 leftEye = qApp->getEyeOffset(Eye::Left); - glm::mat4 rightEye = qApp->getEyeOffset(Eye::Right); - glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); - glm::vec3 rightEyeHeadLocal = glm::vec3(rightEye[3]); - auto humanSystem = qApp->getViewFrustum(); - glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal); - glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal); // First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point. // (We will be adding that offset to the camera position, after making some other adjustments.) glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition(); - // Scale by proportional differences between avatar and human. - float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye); - float avatarEyeSeparation = glm::length(avatarLeftEye - avatarRightEye); - gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; + // scale gazeOffset by IPD, if wearing an HMD. + if (qApp->isHMDMode()) { + glm::mat4 leftEye = qApp->getEyeOffset(Eye::Left); + glm::mat4 rightEye = qApp->getEyeOffset(Eye::Right); + glm::vec3 leftEyeHeadLocal = glm::vec3(leftEye[3]); + glm::vec3 rightEyeHeadLocal = glm::vec3(rightEye[3]); + auto humanSystem = qApp->getViewFrustum(); + glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal); + glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal); - // If the camera is also not oriented with the head, adjust by getting the offset in head-space... - /* Not needed (i.e., code is a no-op), but I'm leaving the example code here in case something like this is needed someday. - glm::quat avatarHeadOrientation = getHead()->getOrientation(); - glm::vec3 gazeOffsetLocalToHead = glm::inverse(avatarHeadOrientation) * gazeOffset; - // ... and treat that as though it were in camera space, bringing it back to world space. - // But camera is fudged to make the picture feel like the avatar's orientation. - glm::quat humanOrientation = humanSystem->getOrientation(); // or just avatar getOrienation() ? - gazeOffset = humanOrientation * gazeOffsetLocalToHead; - glm::vec3 corrected = humanSystem->getPosition() + gazeOffset; - */ + // Scale by proportional differences between avatar and human. + float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye); + float avatarEyeSeparation = glm::length(avatarLeftEye - avatarRightEye); + gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; + } // And now we can finally add that offset to the camera. glm::vec3 corrected = qApp->getViewFrustum()->getPosition() + gazeOffset; From efe53c1a85a037f60078ddc267c595fe5ddf5a40 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Mon, 29 Feb 2016 17:12:43 -0800 Subject: [PATCH 152/292] actually don't add to default yet --- examples/defaultScripts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index d612e617e1..35af5f4eae 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -17,7 +17,6 @@ Script.load("inspect.js"); Script.load("notifications.js"); Script.load("users.js"); Script.load("controllers/handControllerGrab.js"); -Script.load("controllers/handControllerMouse.js"); Script.load("controllers/squeezeHands.js"); Script.load("grab.js"); Script.load("directory.js"); From 460582239a804a2a4dc069e30e7ebf5a50217537 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 29 Feb 2016 18:02:50 -0800 Subject: [PATCH 153/292] Avatar eye look at fixes for HMDs There were three things that were causing issues with eye look at vectors while wearing an HMD. 1) The matrix returned by AvatarUpdate->getHeadPose() was in the wrong space, it should be in avatar space. it was actually returning a matrix in sensor/room space. 2) The lookAtPosition was incorrect while wearing an HMD and with no avatars to look at. 3) The eye rotation limits in Rig::updateEyeJoint were relative to the model's zero orientation, NOT relative to the head. this was causing the eyes to hit limits when the avatar head turned. --- interface/src/Application.cpp | 4 ++-- interface/src/avatar/AvatarUpdate.cpp | 9 ++++++++- libraries/animation/src/Rig.cpp | 13 ++++++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21377fa945..586e7ee8e5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2946,9 +2946,9 @@ void Application::updateMyAvatarLookAtPosition() { } else { // I am not looking at anyone else, so just look forward if (isHMD) { - glm::mat4 headPose = _avatarUpdate->getHeadPose() ; + glm::mat4 headPose = _avatarUpdate->getHeadPose(); glm::quat headRotation = glm::quat_cast(headPose); - lookAtSpot = _myCamera.getPosition() + + lookAtSpot = myAvatar->getPosition() + myAvatar->getOrientation() * (headRotation * glm::vec3(0.0f, 0.0f, -TREE_SCALE)); } else { lookAtSpot = myAvatar->getHead()->getEyePosition() + diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 68a13ba227..4881e3eaec 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -31,7 +31,14 @@ void AvatarUpdate::synchronousProcess() { // Keep our own updated value, so that our asynchronous code can consult it. _isHMDMode = qApp->isHMDMode(); auto frameCount = qApp->getFrameCount(); - _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(frameCount); + + QSharedPointer manager = DependencyManager::get(); + MyAvatar* myAvatar = manager->getMyAvatar(); + assert(myAvatar); + + // transform the head pose from the displayPlugin into avatar coordinates. + glm::mat4 invAvatarMat = glm::inverse(createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition())); + _headPose = invAvatarMat * (myAvatar->getSensorToWorldMatrix() * qApp->getActiveDisplayPlugin()->getHeadPose(frameCount)); if (!isThreaded()) { process(); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 3952dc5b40..7bab4dfc1d 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1067,14 +1067,21 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation); glm::mat4 worldToRig = glm::inverse(rigToWorld); glm::vec3 zAxis = glm::normalize(_internalPoseSet._absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot)); - glm::quat q = rotationBetween(IDENTITY_FRONT, zAxis); + + glm::quat desiredQuat = rotationBetween(IDENTITY_FRONT, zAxis); + glm::quat headQuat; + int headIndex = _animSkeleton->nameToJointIndex("Head"); + if (headIndex >= 0) { + headQuat = _internalPoseSet._absolutePoses[headIndex].rot; + } + glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat); // limit rotation const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - q = glm::angleAxis(glm::clamp(glm::angle(q), -MAX_ANGLE, MAX_ANGLE), glm::axis(q)); + deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat)); // directly set absolutePose rotation - _internalPoseSet._absolutePoses[index].rot = q; + _internalPoseSet._absolutePoses[index].rot = deltaQuat * headQuat; } } From 630c61e61da2009ff1460dc0d286dee18f1cca73 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 29 Feb 2016 18:54:43 -0800 Subject: [PATCH 154/292] Reflection is working correctly with the PBR property, ship t --- .../src/EntityTreeRenderer.cpp | 2 ++ libraries/model/src/model/Light.cpp | 13 +++++++++-- libraries/model/src/model/Light.h | 7 +++++- libraries/model/src/model/Material.h | 2 +- libraries/model/src/model/Stage.cpp | 3 +++ libraries/model/src/model/Stage.h | 1 + libraries/model/src/model/TextureMap.cpp | 4 ++-- libraries/render-utils/src/DeferredBuffer.slh | 8 ++++++- .../render-utils/src/DeferredGlobalLight.slh | 23 ++++++++++++++----- .../render-utils/src/DeferredLighting.slh | 2 +- .../src/DeferredLightingEffect.cpp | 20 +++++++++------- .../render-utils/src/MaterialTextures.slh | 4 ++-- .../src/SceneScriptingInterface.cpp | 5 ++++ .../src/SceneScriptingInterface.h | 1 + 14 files changed, 71 insertions(+), 24 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index bc1f614f79..ccf5036fa1 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -325,6 +325,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetGPUTexture()->getIrradiance()) { sceneKeyLight->setAmbientSphere(_ambientTexture->getGPUTexture()->getIrradiance()); + sceneKeyLight->setAmbientMap(_ambientTexture->getGPUTexture()); isAmbientTextureSet = true; } } else { @@ -360,6 +361,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetIrradiance()) { sceneKeyLight->setAmbientSphere(texture->getIrradiance()); + sceneKeyLight->setAmbientMap(texture); isAmbientTextureSet = true; } } else { diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 92f53ad4c6..1497ceba86 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -141,6 +141,15 @@ void Light::setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset) { editSchema()._ambientSphere.assignPreset(preset); } -void Light::setAmbientMapNumMips(int numMips) { - editSchema()._ambientMapNumMips = numMips; +void Light::setAmbientMap(gpu::TexturePointer ambientMap) { + _ambientMap = ambientMap; + if (ambientMap) { + setAmbientMapNumMips(_ambientMap->evalNumMips()); + } else { + setAmbientMapNumMips(0); + } +} + +void Light::setAmbientMapNumMips(int numMips) { + editSchema()._ambientMapNumMips = (float)numMips; } diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 1ec47f7eea..1db73f4093 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -108,6 +108,9 @@ public: const gpu::SphericalHarmonics& getAmbientSphere() const { return getSchema()._ambientSphere; } void setAmbientSpherePreset(gpu::SphericalHarmonics::Preset preset); + void setAmbientMap(gpu::TexturePointer ambientMap); + gpu::TexturePointer getAmbientMap() const { return _ambientMap; } + void setAmbientMapNumMips(int numMips); int getAmbientMapNumMips() const { return getSchema()._ambientMapNumMips; } @@ -123,7 +126,7 @@ public: Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f}; Vec4 _shadow{0.0f}; - int _ambientMapNumMips{ 0 }; + float _ambientMapNumMips{ 0 }; Vec3 _control{ 0.0f, 0.0f, 0.0f }; gpu::SphericalHarmonics _ambientSphere; @@ -137,6 +140,8 @@ protected: UniformBufferView _schemaBuffer; Transform _transform; + gpu::TexturePointer _ambientMap; + const Schema& getSchema() const { return _schemaBuffer.get(); } Schema& editSchema() { return _schemaBuffer.edit(); } diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index cdc3e4dc39..81a55eea8a 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -277,7 +277,7 @@ public: const TextureMaps& getTextureMaps() const { return _textureMaps; } // conversion from legacy material properties to PBR equivalent - static float shininessToRoughness(float shininess) { return 1.0f - shininess / 128.0f; } + static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; } protected: diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index c976e5c396..23503ef6fb 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -212,6 +212,9 @@ void SunSkyStage::setSunAmbientSphere(const gpu::SHPointer& sphere) { _sunLight->setAmbientSpherePreset(DEFAULT_AMBIENT_SPHERE); } } +void SunSkyStage::setSunAmbientMap(const gpu::TexturePointer& map) { + _sunLight->setAmbientMap(map); +} void SunSkyStage::setSunDirection(const Vec3& direction) { if (!isSunModelEnabled()) { diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 31772d5e48..d9fa81b16f 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -150,6 +150,7 @@ public: void setSunAmbientIntensity(float intensity) { _sunLight->setAmbientIntensity(intensity); } float getSunAmbientIntensity() const { return getSunLight()->getAmbientIntensity(); } void setSunAmbientSphere(const gpu::SHPointer& sphere); + void setSunAmbientMap(const gpu::TexturePointer& map); // The sun direction is expressed in the world space void setSunDirection(const Vec3& direction); diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index c775443425..d0416ec3b5 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -593,8 +593,8 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f); f++; } - - // GEnerate irradiance while we are at it + + // Generate irradiance while we are at it theTexture->generateIrradiance(); } } diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index cc5780e425..5a3c941ce3 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -115,7 +115,13 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { frag.metallic = frag.diffuseVal.a; frag.diffuse = frag.diffuseVal.xyz; - frag.specular = vec3(frag.metallic); + if (frag.metallic <= 0.5) { + frag.metallic = 0.0; + frag.specular = vec3(0.03); // Default Di-electric fresnel value + } else { + frag.specular = vec3(frag.diffuseVal.xyz); + frag.metallic = 1.0; + } frag.obscurance = min(frag.specularVal.w, frag.obscurance); return frag; diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index f0231dbb9e..0f92f8df2c 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -35,8 +35,12 @@ vec4 evalSkyboxLight(vec3 direction, float lod) { // Get light Light light = getLight(); - - vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, vec3(metallic), roughness); + vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value + if (metallic > 0.5) { + fresnel = albedo; + metallic = 1.0; + } + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, metallic, fresnel, roughness); vec3 color = vec3(albedo * shading.w + shading.rgb) * min(shadowAttenuation, obscurance) * getLightColor(light) * getLightIntensity(light); color += emissive; <@endfunc@> @@ -52,21 +56,28 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc <@func declareEvalAmbientSphereGlobalColor()@> vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { <$prepareGlobalLight()$> - color += albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); + color += (1 - (metallic * 0.5)) * albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); return color; } <@endfunc@> <@func declareEvalSkyboxGlobalColor()@> <$declareSkyboxMap()$> + +vec3 fresnelSchlickAmbient(vec3 fresnelColor, vec3 lightDir, vec3 halfDir, float gloss) { + return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * pow(1.0f - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); +} + vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { <$prepareGlobalLight()$> - + color += (1 - metallic) * albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); + vec3 direction = -reflect(fragEyeDir, fragNormal); float levels = getLightAmbientMapNumMips(light); - float lod = min(1.0 + floor((roughness) * levels), levels); + float lod = min(floor((roughness) * levels), levels); vec4 skyboxLight = evalSkyboxLight(direction, lod); - color += albedo * skyboxLight.rgb * skyboxLight.a * obscurance * getLightAmbientIntensity(light); + vec3 ambientFresnel = fresnelSchlickAmbient(fresnel, fragEyeDir, fragNormal, 1 - roughness); + color += ambientFresnel * skyboxLight.rgb * obscurance * getLightAmbientIntensity(light); return color; } diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index ca3989256a..d02f9e3345 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -37,7 +37,7 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float m float power = specularDistribution(roughness, fragNormal, halfDir); vec3 specular = power * fresnelColor * diffuse; - return vec4(specular, diffuse * (1 - fresnelColor.x)); + return vec4(specular, (1.0 - metallic) * diffuse * (1 - fresnelColor.x)); } <@endfunc@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 3ffdb2d47b..a05c8c4cc7 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -320,18 +320,19 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo // Setup the global directional pass pipeline { if (_shadowMapEnabled) { - /* if (_skyboxTexture) { + //if (_skyboxTexture) { + if (_skyboxTexture) { program = _directionalSkyboxLightShadow; locations = _directionalSkyboxLightShadowLocations; - } else*/ { + } else { program = _directionalAmbientSphereLightShadow; locations = _directionalAmbientSphereLightShadowLocations; } } else { - /* if (_skyboxTexture) { + if (_skyboxTexture) { program = _directionalSkyboxLight; locations = _directionalSkyboxLightLocations; - } else*/ { + } else { program = _directionalAmbientSphereLight; locations = _directionalAmbientSphereLightLocations; } @@ -501,8 +502,9 @@ void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBuff batch.setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); } - if (_skyboxTexture && (skyboxCubemapUnit >= 0)) { - batch.setResourceTexture(skyboxCubemapUnit, _skyboxTexture); + // if (_skyboxTexture && (skyboxCubemapUnit >= 0)) { + if (globalLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { + batch.setResourceTexture(skyboxCubemapUnit, globalLight->getAmbientMap()); } } @@ -569,10 +571,12 @@ void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light, co globalLight->setAmbientIntensity(light->getAmbientIntensity()); globalLight->setAmbientSphere(light->getAmbientSphere()); - _skyboxTexture = skyboxTexture; + // _skyboxTexture = skyboxTexture; + _skyboxTexture = (light->getAmbientMap() ? light->getAmbientMap() : _skyboxTexture); // Update the available mipmap levels - globalLight->setAmbientMapNumMips((_skyboxTexture ? _skyboxTexture->evalNumMips() : 0)); + globalLight->setAmbientMap((light->getAmbientMap() ? light->getAmbientMap() : _skyboxTexture)); + // globalLight->setAmbientMapNumMips((_skyboxTexture ? _skyboxTexture->evalNumMips() : 0)); } model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 5372419465..fb253e3f6d 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -23,7 +23,7 @@ vec4 fetchAlbedoMap(vec2 uv) { <@if withRoughness@> uniform sampler2D roughnessMap; float fetchRoughnessMap(vec2 uv) { - return pow(texture(roughnessMap, uv).r, 2.2); + return (texture(roughnessMap, uv).r); } <@endif@> @@ -37,7 +37,7 @@ vec3 fetchNormalMap(vec2 uv) { <@if withMetallic@> uniform sampler2D specularMap; float fetchMetallicMap(vec2 uv) { - return pow(texture(specularMap, uv).r, 2.2); + return (texture(specularMap, uv).r); } <@endif@> diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 079cfff2c7..3883b948df 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -81,6 +81,11 @@ void SceneScripting::KeyLight::setAmbientSphere(const gpu::SHPointer& sphere) { _skyStage->setSunAmbientSphere(sphere); } +void SceneScripting::KeyLight::setAmbientMap(const gpu::TexturePointer& map) { + _skyStage->setSunAmbientMap(map); +} + + glm::vec3 SceneScripting::KeyLight::getDirection() const { return _skyStage->getSunDirection(); } diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 12681b1887..e8ea2e0217 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -84,6 +84,7 @@ namespace SceneScripting { // AmbientTexture is unscriptable - it must be set through the zone entity void setAmbientSphere(const gpu::SHPointer& sphere); void resetAmbientSphere() { setAmbientSphere(nullptr); } + void setAmbientMap(const gpu::TexturePointer& map); protected: model::SunSkyStagePointer _skyStage; From 2c3fdc995f70c9b0e4245d440dd89d629aaacbf1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 20:23:06 -0800 Subject: [PATCH 155/292] Away improvements --- examples/away.js | 21 +++++++++--- interface/src/Application.cpp | 38 ++++++++++++++++++---- interface/src/Application.h | 7 ++++ interface/src/ui/ApplicationCompositor.cpp | 14 +++++++- interface/src/ui/ApplicationCompositor.h | 10 ++++++ 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/examples/away.js b/examples/away.js index 18a3fddfce..f22f9662a7 100644 --- a/examples/away.js +++ b/examples/away.js @@ -106,6 +106,12 @@ function goAway() { MyAvatar.setEnableMeshVisible(false); // just for our own display, without changing point of view playAwayAnimation(); // animation is still seen by others showOverlay(); + + // tell the Reticle, we want to stop capturing the mouse until we come back + Reticle.allowMouseCapture = false; + if (HMD.active) { + Reticle.visible = false; + } } function goActive() { if (!isAway) { @@ -119,13 +125,20 @@ function goActive() { MyAvatar.setEnableMeshVisible(true); // IWBNI we respected Developer->Avatar->Draw Mesh setting. stopAwayAnimation(); hideOverlay(); + + // tell the Reticle, we are ready to capture the mouse again and it should be visible + Reticle.allowMouseCapture = true; + Reticle.visible = true; + if (HMD.active) { + Reticle.position = HMD.getHUDLookAtPosition2D(); + } } function maybeGoActive(event) { if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) return; } - if (!isAway && (event.text === '.')) { + if (!isAway && (event.text == 'ESC')) { goAway(); } else { goActive(); @@ -141,10 +154,8 @@ function maybeGoAway() { } } - // If the mouse has gone from captured, to non-captured state, - // then it likely means the person is still in the HMD, but has - // tabbed away from the application (meaning they don't have mouse - // control) and they likely want to go into an away state + // If the mouse has gone from captured, to non-captured state, then it likely means the person is still in the HMD, but + // tabbed away from the application (meaning they don't have mouse control) and they likely want to go into an away state if (Reticle.mouseCaptured !== wasMouseCaptured) { wasMouseCaptured = !wasMouseCaptured; if (!wasMouseCaptured) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21377fa945..15b1836173 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -661,15 +661,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _glWidget->setFocusPolicy(Qt::StrongFocus); _glWidget->setFocus(); + #ifdef Q_OS_MAC - // OSX doesn't seem to provide for hiding the cursor only on the GL widget - _window->setCursor(Qt::BlankCursor); + auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget #else - // On windows and linux, hiding the top level cursor also means it's invisible - // when hovering over the window menu, which is a pain, so only hide it for - // the GL surface - _glWidget->setCursor(Qt::BlankCursor); + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // window menu, which is a pain, so only hide it for the GL surface + auto cursorTarget = _glWidget; #endif + cursorTarget->setCursor(Qt::BlankCursor); // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); @@ -981,6 +981,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _idleTimer->start(0); } + +void Application::checkChangeCursor() { + QMutexLocker locker(&_changeCursorLock); + if (_cursorNeedsChanging) { +#ifdef Q_OS_MAC + auto cursorTarget = _window; // OSX doesn't seem to provide for hiding the cursor only on the GL widget +#else + // On windows and linux, hiding the top level cursor also means it's invisible when hovering over the + // window menu, which is a pain, so only hide it for the GL surface + auto cursorTarget = _glWidget; +#endif + cursorTarget->setCursor(_desiredCursor); + + _cursorNeedsChanging = false; + } +} + +void Application::showCursor(const QCursor& cursor) { + QMutexLocker locker(&_changeCursorLock); + _desiredCursor = cursor; + _cursorNeedsChanging = true; +} + void Application::aboutToQuit() { emit beforeAboutToQuit(); @@ -2431,6 +2454,9 @@ void Application::idle(uint64_t now) { return; // bail early, nothing to do here. } + + checkChangeCursor(); + Stats::getInstance()->updateStats(); AvatarInputs::getInstance()->update(); diff --git a/interface/src/Application.h b/interface/src/Application.h index d205ce8041..b5a0894c3a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -120,6 +120,8 @@ public: QSize getDeviceSize() const; bool hasFocus() const; + void showCursor(const QCursor& cursor); + bool isThrottleRendering() const; Camera* getCamera() { return &_myCamera; } @@ -515,6 +517,11 @@ private: QTimer* _idleTimer { nullptr }; bool _fakedMouseEvent { false }; + + void checkChangeCursor(); + mutable QMutex _changeCursorLock { QMutex::Recursive }; + QCursor _desiredCursor{ Qt::BlankCursor }; + bool _cursorNeedsChanging { false }; }; #endif // hifi_Application_h diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 59d794d7cb..ff37d07e15 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -335,9 +335,21 @@ QPointF ApplicationCompositor::getMouseEventPosition(QMouseEvent* event) { bool ApplicationCompositor::shouldCaptureMouse() const { // if we're in HMD mode, and some window of ours is active, but we're not currently showing a popup menu - return qApp->isHMDMode() && QApplication::activeWindow() && !Menu::isSomeSubmenuShown(); + return _allowMouseCapture && qApp->isHMDMode() && QApplication::activeWindow() && !Menu::isSomeSubmenuShown(); } +void ApplicationCompositor::setAllowMouseCapture(bool capture) { + if (qApp->isHMDMode()) { + if (capture) { + qApp->showCursor(Qt::BlankCursor); + } else { + qApp->showCursor(Qt::ArrowCursor); + } + } + _allowMouseCapture = capture; +} + + void ApplicationCompositor::handleLeaveEvent() { if (shouldCaptureMouse()) { diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index 32835ace5a..324250deb1 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -106,6 +106,9 @@ public: bool shouldCaptureMouse() const; + bool getAllowMouseCapture() const { return _allowMouseCapture; } + void setAllowMouseCapture(bool capture); + /// if the reticle is pointing to a system overlay (a dialog box for example) then the function returns true otherwise false bool getReticleOverDesktop() const; void setReticleOverDesktop(bool value) { _isOverDesktop = value; } @@ -162,6 +165,8 @@ private: bool _reticleOverQml { false }; + bool _allowMouseCapture { true }; + ReticleInterface* _reticleInterface; }; @@ -173,12 +178,17 @@ class ReticleInterface : public QObject { Q_PROPERTY(float depth READ getDepth WRITE setDepth) Q_PROPERTY(glm::vec2 maximumPosition READ getMaximumPosition) Q_PROPERTY(bool mouseCaptured READ isMouseCaptured) + Q_PROPERTY(bool allowMouseCapture READ getAllowMouseCapture WRITE setAllowMouseCapture) Q_PROPERTY(bool pointingAtSystemOverlay READ isPointingAtSystemOverlay) public: ReticleInterface(ApplicationCompositor* outer) : QObject(outer), _compositor(outer) {} Q_INVOKABLE bool isMouseCaptured() { return _compositor->shouldCaptureMouse(); } + + Q_INVOKABLE bool getAllowMouseCapture() { return _compositor->getAllowMouseCapture(); } + Q_INVOKABLE void setAllowMouseCapture(bool value) { return _compositor->setAllowMouseCapture(value); } + Q_INVOKABLE bool isPointingAtSystemOverlay() { return !_compositor->getReticleOverDesktop(); } Q_INVOKABLE bool getVisible() { return _compositor->getReticleVisible(); } From 95c92f7a2793b47dc928120430cd6f8bec88ed24 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 20:35:25 -0800 Subject: [PATCH 156/292] tweak depthReticle to work better with away --- examples/depthReticle.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/depthReticle.js b/examples/depthReticle.js index 14a5ba5ff3..14215bff3d 100644 --- a/examples/depthReticle.js +++ b/examples/depthReticle.js @@ -35,8 +35,8 @@ var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50; Controller.mouseMoveEvent.connect(function(mouseEvent) { var now = Date.now(); - // if the reticle is hidden, show it... - if (!Reticle.visible) { + // if the reticle is hidden, and we're not in away mode... + if (!Reticle.visible && Reticle.allowMouseCapture) { Reticle.visible = true; if (HMD.active) { shouldSeekToLookAt = true; @@ -44,7 +44,7 @@ Controller.mouseMoveEvent.connect(function(mouseEvent) { } else { // even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it) // then they are probably looking for it, and we should move into seekToLookAt mode - if (HMD.active && !shouldSeekToLookAt) { + if (HMD.active && !shouldSeekToLookAt && Reticle.allowMouseCapture) { var dx = Reticle.position.x - lastMouseX; var dy = Reticle.position.y - lastMouseY; var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move From 501d23021ffef607d83e75c7c15916dfd2c90f21 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 20:53:18 -0800 Subject: [PATCH 157/292] slight improvement to Away to have the paused overlay follow your view in HMD --- examples/away.js | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/examples/away.js b/examples/away.js index f22f9662a7..9b84f46742 100644 --- a/examples/away.js +++ b/examples/away.js @@ -13,7 +13,9 @@ // // Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key. // See MAIN CONTROL, below, for what "paused" actually does. -var OVERLAY_RATIO = 1920 / 1080; +var OVERLAY_WIDTH = 1920; +var OVERLAY_HEIGHT = 1080; +var OVERLAY_RATIO = OVERLAY_WIDTH / OVERLAY_HEIGHT; var OVERLAY_DATA = { imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", color: {red: 255, green: 255, blue: 255}, @@ -69,16 +71,25 @@ function showOverlay() { // Update for current screen size, keeping overlay proportions constant. screen = Controller.getViewportDimensions(), screenRatio = screen.x / screen.y; - if (screenRatio < OVERLAY_RATIO) { - properties.width = screen.x; - properties.height = screen.x / OVERLAY_RATIO; - properties.x = 0; - properties.y = (screen.y - properties.height) / 2; + + if (HMD.active) { + var lookAt = HMD.getHUDLookAtPosition2D(); + properties.width = OVERLAY_WIDTH; + properties.height = OVERLAY_HEIGHT; + properties.x = lookAt.x - OVERLAY_WIDTH / 2; + properties.y = lookAt.y - OVERLAY_HEIGHT / 2; } else { - properties.height = screen.y; - properties.width = screen.y * OVERLAY_RATIO; - properties.y = 0; - properties.x = (screen.x - properties.width) / 2; + if (screenRatio < OVERLAY_RATIO) { + properties.width = screen.x; + properties.height = screen.x / OVERLAY_RATIO; + properties.x = 0; + properties.y = (screen.y - properties.height) / 2; + } else { + properties.height = screen.y; + properties.width = screen.y * OVERLAY_RATIO; + properties.y = 0; + properties.x = (screen.x - properties.width) / 2; + } } Overlays.editOverlay(overlay, properties); } @@ -87,6 +98,17 @@ function hideOverlay() { } hideOverlay(); +function maybeMoveOverlay() { + if (HMD.active && isAway) { + var lookAt = HMD.getHUDLookAtPosition2D(); + var properties = {visible: true}; + properties.width = OVERLAY_WIDTH; + properties.height = OVERLAY_HEIGHT; + properties.x = lookAt.x - OVERLAY_WIDTH / 2; + properties.y = lookAt.y - OVERLAY_HEIGHT / 2; + Overlays.editOverlay(overlay, properties); + } +} // MAIN CONTROL var wasMuted, isAway; @@ -164,6 +186,8 @@ function maybeGoAway() { } } +Script.update.connect(maybeMoveOverlay); + Script.update.connect(maybeGoAway); Controller.mousePressEvent.connect(goActive); Controller.keyPressEvent.connect(maybeGoActive); From 52c38e56a493b0a1b02457808e19ca35ad7e4e8c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 29 Feb 2016 21:25:25 -0800 Subject: [PATCH 158/292] make the HMD away overlay 3d --- examples/away.js | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/examples/away.js b/examples/away.js index 9b84f46742..69d2f3fd12 100644 --- a/examples/away.js +++ b/examples/away.js @@ -22,6 +22,19 @@ var OVERLAY_DATA = { alpha: 1 }; +var OVERLAY_DATA_HMD = { + position: { x: 0, y: 0, z: 0}, + width: OVERLAY_WIDTH, + height: OVERLAY_HEIGHT, + url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1, + scale: 2, + isFacingAvatar: true, + drawInFront: true +}; + + // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect // using an animation graph with a state that we turn on and off through the animation var defined with that state. @@ -66,19 +79,17 @@ function stopAwayAnimation() { // OVERLAY var overlay = Overlays.addOverlay("image", OVERLAY_DATA); +var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD); function showOverlay() { - var properties = {visible: true}, - // Update for current screen size, keeping overlay proportions constant. - screen = Controller.getViewportDimensions(), - screenRatio = screen.x / screen.y; + var properties = {visible: true}; if (HMD.active) { - var lookAt = HMD.getHUDLookAtPosition2D(); - properties.width = OVERLAY_WIDTH; - properties.height = OVERLAY_HEIGHT; - properties.x = lookAt.x - OVERLAY_WIDTH / 2; - properties.y = lookAt.y - OVERLAY_HEIGHT / 2; + Overlays.editOverlay(overlayHMD, { visible: true, position : HMD.getHUDLookAtPosition3D() }); } else { + // Update for current screen size, keeping overlay proportions constant. + var screen = Controller.getViewportDimensions(), + screenRatio = screen.x / screen.y; + if (screenRatio < OVERLAY_RATIO) { properties.width = screen.x; properties.height = screen.x / OVERLAY_RATIO; @@ -90,23 +101,18 @@ function showOverlay() { properties.y = 0; properties.x = (screen.x - properties.width) / 2; } + Overlays.editOverlay(overlay, properties); } - Overlays.editOverlay(overlay, properties); } function hideOverlay() { Overlays.editOverlay(overlay, {visible: false}); + Overlays.editOverlay(overlayHMD, {visible: false}); } hideOverlay(); function maybeMoveOverlay() { if (HMD.active && isAway) { - var lookAt = HMD.getHUDLookAtPosition2D(); - var properties = {visible: true}; - properties.width = OVERLAY_WIDTH; - properties.height = OVERLAY_HEIGHT; - properties.x = lookAt.x - OVERLAY_WIDTH / 2; - properties.y = lookAt.y - OVERLAY_HEIGHT / 2; - Overlays.editOverlay(overlay, properties); + Overlays.editOverlay(overlayHMD, { position : HMD.getHUDLookAtPosition3D() }); } } From 50437307833ddc953d329612b973a9e556117f53 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Mar 2016 09:13:35 -0800 Subject: [PATCH 159/292] New audio peak limiter library. Fast lookahead log-domain peak limiter intended to replace all hard-clipping in the audio pipeline. Converts float audio input (where level may exceed 0dBFS) to 16-bit audio output using very high quality dynamic-range compression and dithering. --- libraries/audio/src/AudioLimiter.cpp | 778 +++++++++++++++++++++++++++ libraries/audio/src/AudioLimiter.h | 32 ++ 2 files changed, 810 insertions(+) create mode 100644 libraries/audio/src/AudioLimiter.cpp create mode 100644 libraries/audio/src/AudioLimiter.h diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp new file mode 100644 index 0000000000..2e10298441 --- /dev/null +++ b/libraries/audio/src/AudioLimiter.cpp @@ -0,0 +1,778 @@ +// +// AudioLimiter.cpp +// libraries/audio/src +// +// Created by Ken Cooke on 2/11/15. +// Copyright 2016 High Fidelity, Inc. +// + +#include +#include + +#include "AudioLimiter.h" + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifdef _MSC_VER + +#include +#define MUL64(a,b) __emul((a), (b)) +#define MULHI(a,b) ((int)(MUL64(a, b) >> 32)) +#define MULQ31(a,b) ((int)(MUL64(a, b) >> 31)) + +#else + +#define MUL64(a,b) ((long long)(a) * (b)) +#define MULHI(a,b) ((int)(MUL64(a, b) >> 32)) +#define MULQ31(a,b) ((int)(MUL64(a, b) >> 31)) + +#endif // _MSC_VER + +// +// on x86 architecture, assume that SSE2 is present +// +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) + +#include +// convert float to int using round-to-nearest +static inline int32_t floatToInt(float x) { + return _mm_cvt_ss2si(_mm_load_ss(&x)); +} + +#else + +// convert float to int using round-to-nearest +static inline int32_t floatToInt(float x) { + x += (x < 0.0f ? -0.5f : 0.5f); // round + return (int32_t)x; +} + +#endif // _M_IX86 + +static const double FIXQ31 = 2147483648.0; // convert float to Q31 +static const double DB_TO_LOG2 = 0.16609640474436813; // convert dB to log2 + +// convert dB to amplitude +static double dBToGain(double dB) { + return pow(10.0, dB / 20.0); +} + +// convert milliseconds to first-order time constant +static int32_t msToTc(double ms, double sampleRate) { + double tc = exp(-1000.0 / (ms * sampleRate)); + return (int32_t)(FIXQ31 * tc); // Q31 +} + +// log2 domain values are Q26 +static const int LOG2_INTBITS = 5; +static const int LOG2_FRACBITS = 31 - LOG2_INTBITS; + +// log2 domain headroom bits above 0dB +static const int LOG2_HEADROOM = 15; + +// log2 domain offsets so error < 0 +static const int32_t LOG2_BIAS = 347; +static const int32_t EXP2_BIAS = 64; + +// +// P(x) = log2(1+x) for x=[0,1] +// scaled by 1, 0.5, 0.25 +// +static const int LOG2_TABBITS = 4; +static const int32_t log2Table[1 << LOG2_TABBITS][3] = { + { -0x56dfe26d, 0x5c46daff, 0x00000000 }, + { -0x4d397571, 0x5bae58e7, 0x00025a75 }, + { -0x4518f84b, 0x5aabcac4, 0x000a62db }, + { -0x3e3075ec, 0x596168c0, 0x0019d0e6 }, + { -0x384486e9, 0x57e769c7, 0x00316109 }, + { -0x332742ba, 0x564f1461, 0x00513776 }, + { -0x2eb4bad4, 0x54a4cdfe, 0x00791de2 }, + { -0x2ad07c6c, 0x52f18320, 0x00a8aa46 }, + { -0x2763c4d6, 0x513ba123, 0x00df574c }, + { -0x245c319b, 0x4f87c5c4, 0x011c9399 }, + { -0x21aac79f, 0x4dd93bef, 0x015fcb52 }, + { -0x1f433872, 0x4c325584, 0x01a86ddc }, + { -0x1d1b54b4, 0x4a94ac6e, 0x01f5f13e }, + { -0x1b2a9f81, 0x4901524f, 0x0247d3f2 }, + { -0x1969fa57, 0x4778f3a7, 0x029d9dbf }, + { -0x17d36370, 0x45fbf1e8, 0x02f6dfe8 }, +}; + +// +// P(x) = exp2(x) for x=[0,1] +// scaled by 2, 1, 0.5 +// +// Uses exp2(-x) = exp2(1-x)/2 +// +static const int EXP2_TABBITS = 4; +static const int32_t exp2Table[1 << EXP2_TABBITS][3] = { + { 0x3ed838c8, 0x58b574b7, 0x40000000 }, + { 0x41a0821c, 0x5888db8f, 0x4000b2b7 }, + { 0x4488548d, 0x582bcbc6, 0x40039be1 }, + { 0x4791158a, 0x579a1128, 0x400a71ae }, + { 0x4abc3a53, 0x56cf3089, 0x4017212e }, + { 0x4e0b48af, 0x55c66396, 0x402bd31b }, + { 0x517fd7a7, 0x547a946d, 0x404af0ec }, + { 0x551b9049, 0x52e658f9, 0x40772a57 }, + { 0x58e02e75, 0x5103ee08, 0x40b37b31 }, + { 0x5ccf81b1, 0x4ecd321f, 0x410331b5 }, + { 0x60eb6e09, 0x4c3ba007, 0x4169f548 }, + { 0x6535ecf9, 0x49484909, 0x41ebcdaf }, + { 0x69b10e5b, 0x45ebcede, 0x428d2acd }, + { 0x6e5ef96c, 0x421e5d48, 0x4352ece7 }, + { 0x7341edcb, 0x3dd7a354, 0x44426d7b }, + { 0x785c4499, 0x390ecc3a, 0x456188bd }, +}; + +// +// Count Leading Zeros +// defined to match ARM CLZ and x86 LZCNT +// +static int CLZ(uint32_t x) { + int e = 0; + + if (x == 0) return 32; + + if (x < 0x00010000) { + x <<= 16; + e += 16; + } + if (x < 0x01000000) { + x <<= 8; + e += 8; + } + if (x < 0x10000000) { + x <<= 4; + e += 4; + } + if (x < 0x40000000) { + x <<= 2; + e += 2; + } + if (x < 0x80000000) { + e += 1; + } + return e; +} + +// +// Compute -log2(x) for x=[0,1] in Q31, result in Q26 +// x = 0 returns -log2(1) +// x < 0 undefined +// +// |error| < 347 ulp, smooth +// +static int32_t fixlog2(int32_t x) { + + // normalize to [0x80000000, 0xffffffff] + int e = CLZ(x); + x <<= e; + e -= e >> LOG2_INTBITS; // if e==32, e=31 + + // x - 1.0 + x &= 0x7fffffff; + + int k = x >> (31 - LOG2_TABBITS); + + // polynomial for log2(1+x) over x=[0,1] + int32_t c0 = log2Table[k][0]; + int32_t c1 = log2Table[k][1]; + int32_t c2 = log2Table[k][2]; + + c1 += MULHI(c0, x); + c2 += MULHI(c1, x); + + // reconstruct result in Q26 + return (e << LOG2_FRACBITS) - (c2 >> 3); +} + +static const int IEEE754_MANT_BITS = 23; +static const int IEEE754_EXPN_BIAS = 127; + +// +// Peak detection and -log2(x) for float input (mono) +// x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff +// x > 2^LOG2_HEADROOM undefined +// +static int32_t peaklog2(float* input) { + + // float as integer bits + int32_t u = *(int32_t*)input; + + // absolute value + int32_t peak = u & 0x7fffffff; + + // split into e and x - 1.0 + int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; + + // saturate + if (e > 31) return 0x7fffffff; + + int k = x >> (31 - EXP2_TABBITS); + + // polynomial for log2(1+x) over x=[0,1] + int32_t c0 = log2Table[k][0]; + int32_t c1 = log2Table[k][1]; + int32_t c2 = log2Table[k][2]; + + c1 += MULHI(c0, x); + c2 += MULHI(c1, x); + + // reconstruct result in Q26 + return (e << LOG2_FRACBITS) - (c2 >> 3); +} + +// +// Peak detection and -log2(x) for float input (stereo) +// x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff +// x > 2^LOG2_HEADROOM undefined +// +static int32_t peaklog2(float* input0, float* input1) { + + // float as integer bits + int32_t u0 = *(int32_t*)input0; + int32_t u1 = *(int32_t*)input1; + + // max absolute value + u0 &= 0x7fffffff; + u1 &= 0x7fffffff; + int32_t peak = MAX(u0, u1); + + // split into e and x - 1.0 + int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; + int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; + + // saturate + if (e > 31) return 0x7fffffff; + + int k = x >> (31 - EXP2_TABBITS); + + // polynomial for log2(1+x) over x=[0,1] + int32_t c0 = log2Table[k][0]; + int32_t c1 = log2Table[k][1]; + int32_t c2 = log2Table[k][2]; + + c1 += MULHI(c0, x); + c2 += MULHI(c1, x); + + // reconstruct result in Q26 + return (e << LOG2_FRACBITS) - (c2 >> 3); +} + +// +// Compute exp2(-x) for x=[0,32] in Q26, result in Q31 +// x < 0 undefined +// +// |error| < 1387 ulp, smooth +// +static int32_t fixexp2(int32_t x) { + + // split into e and 1.0 - x + int32_t e = x >> LOG2_FRACBITS; + x = ~(x << LOG2_INTBITS) & 0x7fffffff; + + int k = x >> (31 - EXP2_TABBITS); + + // polynomial for exp2(x) + int32_t c0 = exp2Table[k][0]; + int32_t c1 = exp2Table[k][1]; + int32_t c2 = exp2Table[k][2]; + + c1 += MULHI(c0, x); + c2 += MULHI(c1, x); + + // reconstruct result in Q31 + return c2 >> e; +} + +// fast TPDF dither in [-1.0f, 1.0f] +static inline float dither() { + static uint32_t rz = 0; + rz = rz * 69069 + 1; + int32_t r0 = rz & 0xffff; + int32_t r1 = rz >> 16; + return (int32_t)(r0 - r1) * (1/65536.0f); +} + +// +// Peak-hold lowpass filter +// +// Bandlimits the gain control signal to greatly reduce the modulation distortion, +// while still reaching the peak attenuation after exactly N-1 samples of delay. +// N completely determines the limiter attack time. +// +template +class PeakFilterT { + + static_assert((N & (N - 1)) == 0, "N must be a power of 2"); + static_assert((CIC1 - 1) + (CIC2 - 1) == (N - 1), "Total CIC delay must be N-1"); + + int32_t _buffer[2*N] = {}; // shared FIFO + int _index = 0; + + int32_t _acc1 = 0; // CIC1 integrator + int32_t _acc2 = 0; // CIC2 integrator + +public: + + PeakFilterT() { + + // fill history + for (int n = 0; n < N-1; n++) { + process(0x7fffffff); + } + } + + int32_t process(int32_t x) { + + const int MASK = 2*N - 1; // buffer wrap + int i = _index; + + // Fast peak-hold using a running-min filter. Finds the peak (min) value + // in the sliding window of N-1 samples, using only log2(N) comparisons. + // Hold time of N-1 samples exactly cancels the step response of FIR filter. + + for (int n = 1; n < N; n <<= 1) { + + _buffer[i] = x; + i = (i + n) & MASK; + x = MIN(x, _buffer[i]); + } + + // Fast FIR attack/lowpass filter using a 2-stage CIC filter. + // The step response reaches final value after N-1 samples. + + const int32_t CICGAIN = 0xffffffff / (CIC1 * CIC2); // Q32 + x = MULHI(x, CICGAIN); + + _buffer[i] = _acc1; + _acc1 += x; // integrator + i = (i + CIC1 - 1) & MASK; + x = _acc1 - _buffer[i]; // comb + + _buffer[i] = _acc2; + _acc2 += x; // integrator + i = (i + CIC2 - 1) & MASK; + x = _acc2 - _buffer[i]; // comb + + _index = (i + 1) & MASK; // skip unused tap + return x; + } +}; + +// +// Specializations that define the optimum lowpass filter for each length. +// +template class PeakFilter; + +template<> class PeakFilter< 16> : public PeakFilterT< 16, 7, 10> {}; +template<> class PeakFilter< 32> : public PeakFilterT< 32, 14, 19> {}; +template<> class PeakFilter< 64> : public PeakFilterT< 64, 27, 38> {}; +template<> class PeakFilter<128> : public PeakFilterT<128, 53, 76> {}; +template<> class PeakFilter<256> : public PeakFilterT<256, 106, 151> {}; + +// +// N-1 sample delay (mono) +// +template +class MonoDelay { + + static_assert((N & (N - 1)) == 0, "N must be a power of 2"); + + float _buffer[N] = {}; + int _index = 0; + +public: + void process(float& x) { + + const int MASK = N - 1; // buffer wrap + int i = _index; + + _buffer[i] = x; + + i = (i + (N - 1)) & MASK; + + x = _buffer[i]; + + _index = i; + } +}; + +// +// N-1 sample delay (stereo) +// +template +class StereoDelay { + + static_assert((N & (N - 1)) == 0, "N must be a power of 2"); + + float _buffer[2*N] = {}; + int _index = 0; + +public: + void process(float& x0, float& x1) { + + const int MASK = 2*N - 1; // buffer wrap + int i = _index; + + _buffer[i+0] = x0; + _buffer[i+1] = x1; + + i = (i + 2*(N - 1)) & MASK; + + x0 = _buffer[i+0]; + x1 = _buffer[i+1]; + + _index = i; + } +}; + +// +// Limiter (common) +// +class LimiterImpl { +public: + + static const int NARC = 64; + int32_t _holdTable[NARC]; + int32_t _releaseTable[NARC]; + + int32_t _rmsAttack = 0x7fffffff; + int32_t _rmsRelease = 0x7fffffff; + int32_t _arcRelease = 0x7fffffff; + + int32_t _threshold = 0; + int32_t _attn = 0; + int32_t _rms = 0; + int32_t _arc = 0; + + int _sampleRate; + float _outGain = 0.0f; + + LimiterImpl(int sampleRate); + + void setThreshold(float threshold); + void setRelease(float release); + + int32_t envelope(int32_t attn); + + virtual void process(float* input, int16_t* output, int numFrames) = 0; +}; + +LimiterImpl::LimiterImpl(int sampleRate) { + + sampleRate = MAX(sampleRate, 8000); + sampleRate = MIN(sampleRate, 96000); + _sampleRate = sampleRate; + + // defaults + setThreshold(0.0); + setRelease(250.0); +} + +// +// Set the limiter threshold (dB) +// Brickwall limiting will begin when the signal exceeds the threshold. +// Makeup gain is applied, to reach but never exceed the output ceiling. +// +void LimiterImpl::setThreshold(float threshold) { + + const double OUT_CEILING = -0.3; + const double Q31_TO_Q15 = 32768 / 2147483648.0; + + // log2/exp2 self-test + assert(fixlog2(0x00000000) == (31 << LOG2_FRACBITS)); + assert(fixlog2(0x7fffffff) == ( 0 << LOG2_FRACBITS) + 1); + assert(fixexp2(0x7fffffff) == 0x00000000); + assert(fixexp2(0x00000000) == 0x7fffffff); + + // limiter threshold = -48dB to 0dB + threshold = MAX(threshold, -48.0f); + threshold = MIN(threshold, 0.0f); + + // limiter threshold in log2 domain + _threshold = (int32_t)(-threshold * DB_TO_LOG2 * (1 << LOG2_FRACBITS)); + _threshold += LOG2_BIAS + EXP2_BIAS; + _threshold += LOG2_HEADROOM << LOG2_FRACBITS; + + // makeup gain and conversion to 16-bit + _outGain = (float)(dBToGain(OUT_CEILING - threshold) * Q31_TO_Q15); +} + +// +// Set the limiter release time (milliseconds) +// This is a base value that scales the adaptive hold and release algorithms. +// +void LimiterImpl::setRelease(float release) { + + const double MAXHOLD = 0.100; // max hold = 100ms + const double MINREL = 0.025; // min release = 0.025 * release + const int NHOLD = 16; // adaptive hold to adaptive release transition + + // limiter release = 50 to 5000ms + release = MAX(release, 50.0f); + release = MIN(release, 5000.0f); + + int32_t maxRelease = msToTc(release, _sampleRate); + + _rmsAttack = msToTc(0.1 * release, _sampleRate); + _rmsRelease = maxRelease; + + // Compute ARC tables, working from low peak/rms to high peak/rms. + // + // At low peak/rms, release = max and hold is progressive to max + // At high peak/rms, hold = 0 and release is progressive to min + + double x = MAXHOLD * _sampleRate; + double xstep = x / NHOLD; // 1.0 to 1.0/NHOLD + + int i = 0; + for (; i < NHOLD; i++) { + + // max release + _releaseTable[i] = maxRelease; + + // progressive hold + _holdTable[i] = (int32_t)((maxRelease - 0x7fffffff) / x); + _holdTable[i] = MIN(_holdTable[i], -1); // prevent 0 on long releases + + x -= xstep; + x = MAX(x, 1.0); + } + + x = release; + xstep = release * (1.0-MINREL) / (NARC-NHOLD-1); // 1.0 to MINREL + + for (; i < NARC; i++) { + + // progressive release + _releaseTable[i] = msToTc(x, _sampleRate); + + // min hold + _holdTable[i] = (_releaseTable[i] - 0x7fffffff); // 1 sample + + x -= xstep; + } +} + +// +// Limiter envelope processing +// zero attack, adaptive hold and release +// +int32_t LimiterImpl::envelope(int32_t attn) { + + // table of (1/attn) for 1dB to 6dB, rounded to prevent overflow + static const int16_t invTable[64] = { + 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, + 0x6000, 0x6000, 0x5d17, 0x5555, 0x4ec4, 0x4924, 0x4444, 0x4000, + 0x3c3c, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, + 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000, + 0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, + 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555, + 0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, + 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000, + }; + + if (attn < _attn) { + + // RELEASE + // update release before use, to implement hold = 0 + + _arcRelease += _holdTable[_arc]; // update progressive hold + _arcRelease = MAX(_arcRelease, _releaseTable[_arc]); // saturate at final value + + attn += MULQ31((_attn - attn), _arcRelease); // apply release + + } else { + + // ATTACK + // update ARC with normalized peak/rms + // + // arc = (attn-rms)*6/1 for attn < 1dB + // arc = (attn-rms)*6/attn for attn = 1dB to 6dB + // arc = (attn-rms)*6/6 for attn > 6dB + + int bits = MIN(attn >> 20, 0x3f); // saturate 1/attn at 6dB + _arc = MAX(attn - _rms, 0); // peak/rms = (attn-rms) + _arc = MULHI(_arc, invTable[bits]); // normalized peak/rms = (attn-rms)/attn + _arc = MIN(_arc, NARC - 1); // saturate at 6dB + + _arcRelease = 0x7fffffff; // reset release + } + _attn = attn; + + // Update the RMS estimate after release is applied. + // The feedback loop with adaptive hold will damp any sustained modulation distortion. + + int32_t tc = (attn > _rms) ? _rmsAttack : _rmsRelease; + _rms = attn + MULQ31((_rms - attn), tc); + + return attn; +} + +// +// Limiter (mono) +// +template +class LimiterMono : public LimiterImpl { + + PeakFilter _filter; + MonoDelay _delay; + +public: + LimiterMono(int sampleRate) : LimiterImpl(sampleRate) {}; + + void process(float* input, int16_t* output, int numFrames); +}; + +template +void LimiterMono::process(float* input, int16_t* output, int numFrames) +{ + for (int n = 0; n < numFrames; n++) { + + // peak detect and convert to log2 domain + int32_t peak = peaklog2(&input[n]); + + // compute limiter attenuation + int32_t attn = MAX(_threshold - peak, 0); + + // apply envelope + attn = envelope(attn); + + // convert from log2 domain + attn = fixexp2(attn); + + // lowpass filter + attn = _filter.process(attn); + float gain = attn * _outGain; + + // delay audio + float x = input[n]; + _delay.process(x); + + // apply gain + x *= gain; + + // apply dither + x += dither(); + + // store 16-bit output + output[n] = (int16_t)floatToInt(x); + } +} + +// +// Limiter (stereo) +// +template +class LimiterStereo : public LimiterImpl { + + PeakFilter _filter; + StereoDelay _delay; + +public: + LimiterStereo(int sampleRate) : LimiterImpl(sampleRate) {}; + + // interleaved stereo input/output + void process(float* input, int16_t* output, int numFrames); +}; + +template +void LimiterStereo::process(float* input, int16_t* output, int numFrames) +{ + for (int n = 0; n < numFrames; n++) { + + // peak detect and convert to log2 domain + int32_t peak = peaklog2(&input[2*n+0], &input[2*n+1]); + + // compute limiter attenuation + int32_t attn = MAX(_threshold - peak, 0); + + // apply envelope + attn = envelope(attn); + + // convert from log2 domain + attn = fixexp2(attn); + + // lowpass filter + attn = _filter.process(attn); + float gain = attn * _outGain; + + // delay audio + float x0 = input[2*n+0]; + float x1 = input[2*n+1]; + _delay.process(x0, x1); + + // apply gain + x0 *= gain; + x1 *= gain; + + // apply dither + float d = dither(); + x0 += d; + x1 += d; + + // store 16-bit output + output[2*n+0] = (int16_t)floatToInt(x0); + output[2*n+1] = (int16_t)floatToInt(x1); + } +} + +// +// Public API +// + +AudioLimiter::AudioLimiter(int sampleRate, int numChannels) { + + if (numChannels == 1) { + + // ~1.5ms lookahead for all rates + if (sampleRate < 16000) { + _impl = new LimiterMono<16>(sampleRate); + } else if (sampleRate < 32000) { + _impl = new LimiterMono<32>(sampleRate); + } else if (sampleRate < 64000) { + _impl = new LimiterMono<64>(sampleRate); + } else { + _impl = new LimiterMono<128>(sampleRate); + } + + } else if (numChannels == 2) { + + // ~1.5ms lookahead for all rates + if (sampleRate < 16000) { + _impl = new LimiterStereo<16>(sampleRate); + } else if (sampleRate < 32000) { + _impl = new LimiterStereo<32>(sampleRate); + } else if (sampleRate < 64000) { + _impl = new LimiterStereo<64>(sampleRate); + } else { + _impl = new LimiterStereo<128>(sampleRate); + } + + } else { + assert(0); // unsupported + } +} + +AudioLimiter::~AudioLimiter() { + delete _impl; +} + +void AudioLimiter::render(float* input, int16_t* output, int numFrames) { + _impl->process(input, output, numFrames); +} + +void AudioLimiter::setThreshold(float threshold) { + _impl->setThreshold(threshold); +}; + +void AudioLimiter::setRelease(float release) { + _impl->setRelease(release); +}; diff --git a/libraries/audio/src/AudioLimiter.h b/libraries/audio/src/AudioLimiter.h new file mode 100644 index 0000000000..5ddc642635 --- /dev/null +++ b/libraries/audio/src/AudioLimiter.h @@ -0,0 +1,32 @@ +// +// AudioLimiter.h +// libraries/audio/src +// +// Created by Ken Cooke on 2/11/15. +// Copyright 2016 High Fidelity, Inc. +// + +#ifndef hifi_AudioLimiter_h +#define hifi_AudioLimiter_h + +#include "stdint.h" + +class LimiterImpl; + +class AudioLimiter { +public: + + AudioLimiter(int sampleRate, int numChannels); + ~AudioLimiter(); + + void render(float* input, int16_t* output, int numFrames); + + void setThreshold(float threshold); + void setRelease(float release); + +private: + + LimiterImpl* _impl; +}; + +#endif // hifi_AudioLimiter_h From 6d9fe967da84cd00a0e8eacb1b1033d928756f56 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Mar 2016 10:16:41 -0800 Subject: [PATCH 160/292] Fix compiler warnings --- libraries/audio/src/AudioLimiter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index 2e10298441..4f6b8c3054 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -497,12 +497,12 @@ void LimiterImpl::setThreshold(float threshold) { threshold = MIN(threshold, 0.0f); // limiter threshold in log2 domain - _threshold = (int32_t)(-threshold * DB_TO_LOG2 * (1 << LOG2_FRACBITS)); + _threshold = (int32_t)(-(double)threshold * DB_TO_LOG2 * (1 << LOG2_FRACBITS)); _threshold += LOG2_BIAS + EXP2_BIAS; _threshold += LOG2_HEADROOM << LOG2_FRACBITS; // makeup gain and conversion to 16-bit - _outGain = (float)(dBToGain(OUT_CEILING - threshold) * Q31_TO_Q15); + _outGain = (float)(dBToGain(OUT_CEILING - (double)threshold) * Q31_TO_Q15); } // @@ -519,9 +519,9 @@ void LimiterImpl::setRelease(float release) { release = MAX(release, 50.0f); release = MIN(release, 5000.0f); - int32_t maxRelease = msToTc(release, _sampleRate); + int32_t maxRelease = msToTc((double)release, _sampleRate); - _rmsAttack = msToTc(0.1 * release, _sampleRate); + _rmsAttack = msToTc(0.1 * (double)release, _sampleRate); _rmsRelease = maxRelease; // Compute ARC tables, working from low peak/rms to high peak/rms. @@ -547,7 +547,7 @@ void LimiterImpl::setRelease(float release) { } x = release; - xstep = release * (1.0-MINREL) / (NARC-NHOLD-1); // 1.0 to MINREL + xstep = x * (1.0-MINREL) / (NARC-NHOLD-1); // 1.0 to MINREL for (; i < NARC; i++) { From 90bf3989783aead4b6965be8eb6f210f055285b9 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Mar 2016 10:24:13 -0800 Subject: [PATCH 161/292] Fix compiler warnings --- libraries/audio/src/AudioLimiter.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index 4f6b8c3054..1fa2b46c1b 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -133,7 +133,7 @@ static const int32_t exp2Table[1 << EXP2_TABBITS][3] = { // Count Leading Zeros // defined to match ARM CLZ and x86 LZCNT // -static int CLZ(uint32_t x) { +static inline int CLZ(uint32_t x) { int e = 0; if (x == 0) return 32; @@ -167,7 +167,7 @@ static int CLZ(uint32_t x) { // // |error| < 347 ulp, smooth // -static int32_t fixlog2(int32_t x) { +static inline int32_t fixlog2(int32_t x) { // normalize to [0x80000000, 0xffffffff] int e = CLZ(x); @@ -199,7 +199,7 @@ static const int IEEE754_EXPN_BIAS = 127; // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff // x > 2^LOG2_HEADROOM undefined // -static int32_t peaklog2(float* input) { +static inline int32_t peaklog2(float* input) { // float as integer bits int32_t u = *(int32_t*)input; @@ -233,7 +233,7 @@ static int32_t peaklog2(float* input) { // x < 2^(31-LOG2_HEADROOM) returns 0x7fffffff // x > 2^LOG2_HEADROOM undefined // -static int32_t peaklog2(float* input0, float* input1) { +static inline int32_t peaklog2(float* input0, float* input1) { // float as integer bits int32_t u0 = *(int32_t*)input0; @@ -271,7 +271,7 @@ static int32_t peaklog2(float* input0, float* input1) { // // |error| < 1387 ulp, smooth // -static int32_t fixexp2(int32_t x) { +static inline int32_t fixexp2(int32_t x) { // split into e and 1.0 - x int32_t e = x >> LOG2_FRACBITS; @@ -486,12 +486,6 @@ void LimiterImpl::setThreshold(float threshold) { const double OUT_CEILING = -0.3; const double Q31_TO_Q15 = 32768 / 2147483648.0; - // log2/exp2 self-test - assert(fixlog2(0x00000000) == (31 << LOG2_FRACBITS)); - assert(fixlog2(0x7fffffff) == ( 0 << LOG2_FRACBITS) + 1); - assert(fixexp2(0x7fffffff) == 0x00000000); - assert(fixexp2(0x00000000) == 0x7fffffff); - // limiter threshold = -48dB to 0dB threshold = MAX(threshold, -48.0f); threshold = MIN(threshold, 0.0f); From ba7b5c6e23529c540242a4c8377c3200c7883c2d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 1 Mar 2016 10:43:49 -0800 Subject: [PATCH 162/292] some improvements --- examples/away.js | 78 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/examples/away.js b/examples/away.js index 69d2f3fd12..8d561f2623 100644 --- a/examples/away.js +++ b/examples/away.js @@ -17,13 +17,16 @@ var OVERLAY_WIDTH = 1920; var OVERLAY_HEIGHT = 1080; var OVERLAY_RATIO = OVERLAY_WIDTH / OVERLAY_HEIGHT; var OVERLAY_DATA = { + width: OVERLAY_WIDTH, + height: OVERLAY_HEIGHT, imageURL: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", color: {red: 255, green: 255, blue: 255}, alpha: 1 }; +var lastOverlayPosition = { x: 0, y: 0, z: 0}; var OVERLAY_DATA_HMD = { - position: { x: 0, y: 0, z: 0}, + position: lastOverlayPosition, width: OVERLAY_WIDTH, height: OVERLAY_HEIGHT, url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png", @@ -31,10 +34,9 @@ var OVERLAY_DATA_HMD = { alpha: 1, scale: 2, isFacingAvatar: true, - drawInFront: true + drawInFront: true }; - // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect // using an animation graph with a state that we turn on and off through the animation var defined with that state. @@ -80,28 +82,39 @@ function stopAwayAnimation() { // OVERLAY var overlay = Overlays.addOverlay("image", OVERLAY_DATA); var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD); + +function moveCloserToCamera(positionAtHUD) { + // we don't actually want to render at the slerped look at... instead, we want to render + // slightly closer to the camera than that. + var MOVE_CLOSER_TO_CAMERA_BY = -0.25; + var cameraFront = Quat.getFront(Camera.orientation); + var closerToCamera = Vec3.multiply(cameraFront, MOVE_CLOSER_TO_CAMERA_BY); // slightly closer to camera + var slightlyCloserPosition = Vec3.sum(positionAtHUD, closerToCamera); + + return slightlyCloserPosition; +} + function showOverlay() { var properties = {visible: true}; if (HMD.active) { - Overlays.editOverlay(overlayHMD, { visible: true, position : HMD.getHUDLookAtPosition3D() }); - } else { - // Update for current screen size, keeping overlay proportions constant. - var screen = Controller.getViewportDimensions(), - screenRatio = screen.x / screen.y; + // make sure desktop version is hidden + Overlays.editOverlay(overlay, { visible: false }); - if (screenRatio < OVERLAY_RATIO) { - properties.width = screen.x; - properties.height = screen.x / OVERLAY_RATIO; - properties.x = 0; - properties.y = (screen.y - properties.height) / 2; - } else { - properties.height = screen.y; - properties.width = screen.y * OVERLAY_RATIO; - properties.y = 0; - properties.x = (screen.x - properties.width) / 2; - } - Overlays.editOverlay(overlay, properties); + lastOverlayPosition = HMD.getHUDLookAtPosition3D(); + var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition); + Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon }); + } else { + // make sure HMD is hidden + Overlays.editOverlay(overlayHMD, { visible: false }); + + // Update for current screen size, keeping overlay proportions constant. + var screen = Controller.getViewportDimensions(); + + // keep the overlay it's natural size and always center it... + Overlays.editOverlay(overlay, { visible: true, + x: ((screen.x - OVERLAY_WIDTH) / 2), + y: ((screen.y - OVERLAY_HEIGHT) / 2) }); } } function hideOverlay() { @@ -111,8 +124,29 @@ function hideOverlay() { hideOverlay(); function maybeMoveOverlay() { - if (HMD.active && isAway) { - Overlays.editOverlay(overlayHMD, { position : HMD.getHUDLookAtPosition3D() }); + if (isAway) { + // if we switched from HMD to Desktop, make sure to hide our HUD overlay and show the + // desktop overlay + if (!HMD.active) { + showOverlay(); // this will also recenter appropriately + } + + if (HMD.active) { + // Note: instead of moving it directly to the lookAt, we will move it slightly toward the + // new look at. This will result in a more subtle slerp toward the look at and reduce jerkiness + var EASE_BY_RATIO = 0.1; + var lookAt = HMD.getHUDLookAtPosition3D(); + var lookAtChange = Vec3.subtract(lookAt, lastOverlayPosition); + var halfWayBetweenOldAndLookAt = Vec3.multiply(lookAtChange, EASE_BY_RATIO); + var newOverlayPosition = Vec3.sum(lastOverlayPosition, halfWayBetweenOldAndLookAt); + lastOverlayPosition = newOverlayPosition; + + var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition); + Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon }); + + // make sure desktop version is hidden + Overlays.editOverlay(overlay, { visible: false }); + } } } From 89920370dbd74f22355a1121c09ac73f8f16f0f2 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Mar 2016 10:53:08 -0800 Subject: [PATCH 163/292] A bunch of typo fixes after review --- examples/utilities/tools/render/debugFramebuffer.js | 4 ++-- libraries/model/src/model/Light.cpp | 2 +- libraries/model/src/model/Light.h | 6 +++--- libraries/model/src/model/Material.h | 2 +- libraries/render-utils/src/DeferredGlobalLight.slh | 2 +- libraries/render-utils/src/DeferredLightingEffect.cpp | 7 ++----- libraries/render-utils/src/MeshPartPayload.cpp | 1 - 7 files changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/utilities/tools/render/debugFramebuffer.js b/examples/utilities/tools/render/debugFramebuffer.js index 4aad8f9488..e764cf52d8 100644 --- a/examples/utilities/tools/render/debugFramebuffer.js +++ b/examples/utilities/tools/render/debugFramebuffer.js @@ -1,5 +1,5 @@ // -// debug.js +// ddebugFramBuffer.js // examples/utilities/tools/render // // Sam Gateau created on 2/18/2016. @@ -10,8 +10,8 @@ // var DDB = Render.RenderDeferredTask.DebugDeferredBuffer; -DDB.enabled = true; oldConfig = DDB.toJSON(); +DDB.enabled = true; // Set up the qml ui diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 1497ceba86..1762b0a9fb 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -150,6 +150,6 @@ void Light::setAmbientMap(gpu::TexturePointer ambientMap) { } } -void Light::setAmbientMapNumMips(int numMips) { +void Light::setAmbientMapNumMips(uint16_t numMips) { editSchema()._ambientMapNumMips = (float)numMips; } diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 1db73f4093..3b320e08fd 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -111,8 +111,8 @@ public: void setAmbientMap(gpu::TexturePointer ambientMap); gpu::TexturePointer getAmbientMap() const { return _ambientMap; } - void setAmbientMapNumMips(int numMips); - int getAmbientMapNumMips() const { return getSchema()._ambientMapNumMips; } + void setAmbientMapNumMips(uint16_t numMips); + uint16_t getAmbientMapNumMips() const { return (uint16_t) getSchema()._ambientMapNumMips; } // Schema to access the attribute values of the light class Schema { @@ -126,7 +126,7 @@ public: Vec4 _spot{0.0f, 0.0f, 0.0f, 0.0f}; Vec4 _shadow{0.0f}; - float _ambientMapNumMips{ 0 }; + float _ambientMapNumMips{ 0.0f }; Vec3 _control{ 0.0f, 0.0f, 0.0f }; gpu::SphericalHarmonics _ambientSphere; diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 81a55eea8a..b22f8a3f42 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -252,7 +252,7 @@ public: class Schema { public: glm::vec3 _emissive{ 0.0f }; // No Emissive - float _opacity{ 1.f }; // Opacity = 1 => Not Transparent + float _opacity{ 1.0f }; // Opacity = 1 => Not Transparent glm::vec3 _albedo{ 0.5f }; // Grey albedo => isAlbedo float _roughness{ 1.0f }; // Roughness = 1 => Not Glossy diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 0f92f8df2c..341b9da9e8 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -65,7 +65,7 @@ vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, floa <$declareSkyboxMap()$> vec3 fresnelSchlickAmbient(vec3 fresnelColor, vec3 lightDir, vec3 halfDir, float gloss) { - return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * pow(1.0f - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); + return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * pow(1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); } vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a05c8c4cc7..faa11584dd 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -92,7 +92,7 @@ void DeferredLightingEffect::init() { // Add the global light to the light stage (for later shadow rendering) _lightStage.addLight(lp); - lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f)); + lp->setDirection(glm::vec3(-1.0f)); lp->setColor(glm::vec3(1.0f)); lp->setIntensity(1.0f); lp->setType(model::Light::SUN); @@ -502,7 +502,6 @@ void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBuff batch.setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); } - // if (_skyboxTexture && (skyboxCubemapUnit >= 0)) { if (globalLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { batch.setResourceTexture(skyboxCubemapUnit, globalLight->getAmbientMap()); } @@ -571,12 +570,10 @@ void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light, co globalLight->setAmbientIntensity(light->getAmbientIntensity()); globalLight->setAmbientSphere(light->getAmbientSphere()); - // _skyboxTexture = skyboxTexture; _skyboxTexture = (light->getAmbientMap() ? light->getAmbientMap() : _skyboxTexture); // Update the available mipmap levels - globalLight->setAmbientMap((light->getAmbientMap() ? light->getAmbientMap() : _skyboxTexture)); - // globalLight->setAmbientMapNumMips((_skyboxTexture ? _skyboxTexture->evalNumMips() : 0)); + globalLight->setAmbientMap(_skyboxTexture); } model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index bcddc72fa4..166b14333f 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -414,7 +414,6 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); - //bool hasSpecular = drawMaterialKey.isGlossMap(); bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); From 3cde9721743da428f4dfc25aaeb34f1dde3d9e5e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Mar 2016 11:07:22 -0800 Subject: [PATCH 164/292] Rig: issue warnings for missing joints Also, Removed Rig::computeEyesInRigFrame, it was causing warnings because it was looking up Eye and Head joints for all models, not just avatars. --- interface/src/avatar/MyAvatar.cpp | 20 ----------- libraries/animation/src/Rig.cpp | 60 ++++++++++++++----------------- libraries/animation/src/Rig.h | 4 +-- 3 files changed, 29 insertions(+), 55 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1b04fa4fa4..db4b900a3c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1766,25 +1766,6 @@ glm::quat MyAvatar::getWorldBodyOrientation() const { return glm::quat_cast(_sensorToWorldMatrix * _bodySensorMatrix); } -#if 0 -// derive avatar body position and orientation from the current HMD Sensor location. -// results are in sensor space -glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { - if (_rig) { - // orientation - const glm::quat hmdOrientation = getHMDSensorOrientation(); - const glm::quat yaw = cancelOutRollAndPitch(hmdOrientation); - // position - // we flip about yAxis when going from "root" to "avatar" frame - // and we must also apply "yaw" to get into HMD frame - glm::quat rotY180 = glm::angleAxis((float)M_PI, glm::vec3(0.0f, 1.0f, 0.0f)); - glm::vec3 eyesInAvatarFrame = rotY180 * yaw * _rig->getEyesInRootFrame(); - glm::vec3 bodyPos = getHMDSensorPosition() - eyesInAvatarFrame; - return createMatFromQuatAndPos(yaw, bodyPos); - } - return glm::mat4(); -} -#else // old school meat hook style glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { @@ -1825,7 +1806,6 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { return createMatFromQuatAndPos(hmdOrientationYawOnly, bodyPos); } -#endif glm::vec3 MyAvatar::getPositionForAudio() { switch (_audioListenerMode) { diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 7bab4dfc1d..02968e3665 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -173,8 +173,6 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff _animSkeleton = std::make_shared(geometry); - computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses()); - _internalPoseSet._relativePoses.clear(); _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); @@ -201,8 +199,6 @@ void Rig::reset(const FBXGeometry& geometry) { _geometryOffset = AnimPose(geometry.offset); _animSkeleton = std::make_shared(geometry); - computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses()); - _internalPoseSet._relativePoses.clear(); _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); @@ -237,10 +233,20 @@ int Rig::getJointStateCount() const { return (int)_internalPoseSet._relativePoses.size(); } +static const uint32_t MAX_JOINT_NAME_WARNING_COUNT = 100; + int Rig::indexOfJoint(const QString& jointName) const { if (_animSkeleton) { - return _animSkeleton->nameToJointIndex(jointName); + int result = _animSkeleton->nameToJointIndex(jointName); + + // This is a content error, so we should issue a warning. + if (result < 0 && _jointNameWarningCount < MAX_JOINT_NAME_WARNING_COUNT) { + qCWarning(animation) << "Rig: Missing joint" << jointName << "in avatar model"; + _jointNameWarningCount++; + } + return result; } else { + // This is normal and can happen when the avatar model has not been dowloaded/loaded yet. return -1; } } @@ -444,26 +450,6 @@ void Rig::calcAnimAlpha(float speed, const std::vector& referenceSpeeds, *alphaOut = alpha; } -void Rig::computeEyesInRootFrame(const AnimPoseVec& poses) { - // TODO: use cached eye/hips indices for these calculations - int numPoses = (int)poses.size(); - int hipsIndex = _animSkeleton->nameToJointIndex(QString("Hips")); - int headIndex = _animSkeleton->nameToJointIndex(QString("Head")); - if (hipsIndex > 0 && headIndex > 0) { - int rightEyeIndex = _animSkeleton->nameToJointIndex(QString("RightEye")); - int leftEyeIndex = _animSkeleton->nameToJointIndex(QString("LeftEye")); - if (numPoses > rightEyeIndex && numPoses > leftEyeIndex && rightEyeIndex > 0 && leftEyeIndex > 0) { - glm::vec3 rightEye = _animSkeleton->getAbsolutePose(rightEyeIndex, poses).trans; - glm::vec3 leftEye = _animSkeleton->getAbsolutePose(leftEyeIndex, poses).trans; - glm::vec3 hips = _animSkeleton->getAbsolutePose(hipsIndex, poses).trans; - _eyesInRootFrame = 0.5f * (rightEye + leftEye) - hips; - } else { - glm::vec3 hips = _animSkeleton->getAbsolutePose(hipsIndex, poses).trans; - _eyesInRootFrame = 0.5f * (DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) - hips; - } - } -} - void Rig::setEnableInverseKinematics(bool enable) { _enableInverseKinematics = enable; } @@ -893,8 +879,6 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) { for (auto& trigger : triggersOut) { _animVars.setTrigger(trigger); } - - computeEyesInRootFrame(_internalPoseSet._relativePoses); } applyOverridePoses(); @@ -1070,7 +1054,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm glm::quat desiredQuat = rotationBetween(IDENTITY_FRONT, zAxis); glm::quat headQuat; - int headIndex = _animSkeleton->nameToJointIndex("Head"); + int headIndex = indexOfJoint("Head"); if (headIndex >= 0) { headQuat = _internalPoseSet._absolutePoses[headIndex].rot; } @@ -1093,7 +1077,11 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { const float MIN_LENGTH = 1.0e-4f; // project the hips onto the xz plane. - auto hipsTrans = _internalPoseSet._absolutePoses[_animSkeleton->nameToJointIndex("Hips")].trans; + int hipsIndex = indexOfJoint("Hips"); + glm::vec3 hipsTrans; + if (hipsIndex >= 0) { + hipsTrans = _internalPoseSet._absolutePoses[hipsIndex].trans; + } const glm::vec2 bodyCircleCenter(hipsTrans.x, hipsTrans.z); if (params.isLeftEnabled) { @@ -1278,7 +1266,11 @@ void Rig::computeAvatarBoundingCapsule( AnimPose geometryToRig = _modelOffset * _geometryOffset; - AnimPose hips = geometryToRig * _animSkeleton->getAbsoluteBindPose(_animSkeleton->nameToJointIndex("Hips")); + AnimPose hips(glm::vec3(1), glm::quat(), glm::vec3()); + int hipsIndex = indexOfJoint("Hips"); + if (hipsIndex >= 0) { + hips = geometryToRig * _animSkeleton->getAbsoluteBindPose(hipsIndex); + } AnimVariantMap animVars; glm::quat handRotation = glm::angleAxis(PI, Vectors::UNIT_X); animVars.set("leftHandPosition", hips.trans); @@ -1288,8 +1280,8 @@ void Rig::computeAvatarBoundingCapsule( animVars.set("rightHandRotation", handRotation); animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition); - int rightFootIndex = _animSkeleton->nameToJointIndex("RightFoot"); - int leftFootIndex = _animSkeleton->nameToJointIndex("LeftFoot"); + int rightFootIndex = indexOfJoint("RightFoot"); + int leftFootIndex = indexOfJoint("LeftFoot"); if (rightFootIndex != -1 && leftFootIndex != -1) { glm::vec3 foot = Vectors::ZERO; glm::quat footRotation = glm::angleAxis(0.5f * PI, Vectors::UNIT_X); @@ -1321,7 +1313,7 @@ void Rig::computeAvatarBoundingCapsule( // HACK to reduce the radius of the bounding capsule to be tight with the torso, we only consider joints // from the head to the hips when computing the rest of the bounding capsule. - int index = _animSkeleton->nameToJointIndex(QString("Head")); + int index = indexOfJoint("Head"); while (index != -1) { const FBXJointShapeInfo& shapeInfo = geometry.joints.at(index).shapeInfo; AnimPose pose = finalPoses[index]; @@ -1344,3 +1336,5 @@ void Rig::computeAvatarBoundingCapsule( glm::vec3 rigCenter = (geometryToRig * (0.5f * (totalExtents.maximum + totalExtents.minimum))); localOffsetOut = rigCenter - (geometryToRig * rootPosition); } + + diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 9c5b014d55..3d5d44b844 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -231,8 +231,6 @@ public: void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); void calcAnimAlpha(float speed, const std::vector& referenceSpeeds, float* alphaOut) const; - void computeEyesInRootFrame(const AnimPoseVec& poses); - AnimPose _modelOffset; // model to rig space AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets) @@ -305,6 +303,8 @@ public: bool _lastEnableInverseKinematics { true }; bool _enableInverseKinematics { true }; + mutable uint32_t _jointNameWarningCount { 0 }; + private: QMap _stateHandlers; int _nextStateHandlerId { 0 }; From babf48ac5756131734cf6c2bcc0cae4a2a660f00 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Mar 2016 11:17:03 -0800 Subject: [PATCH 165/292] MyAvatar: take IPD scale into account when computing corrected eye lookAt --- interface/src/avatar/MyAvatar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index db4b900a3c..2f6f99ba90 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -879,8 +879,11 @@ void MyAvatar::updateLookAtTargetAvatar() { glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal); glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal); + auto hmdInterface = DependencyManager::get(); + float ipdScale = hmdInterface->getIPDScale(); + // Scale by proportional differences between avatar and human. - float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye); + float humanEyeSeparationInModelSpace = glm::length(humanLeftEye - humanRightEye) * ipdScale; float avatarEyeSeparation = glm::length(avatarLeftEye - avatarRightEye); gazeOffset = gazeOffset * humanEyeSeparationInModelSpace / avatarEyeSeparation; } From 506e46faeeaa3f7d16dc9f6eaffe4c5c116b3a85 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Mar 2016 11:21:14 -0800 Subject: [PATCH 166/292] MyAvatar: fix for missing include --- interface/src/avatar/MyAvatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2f6f99ba90..46bc128605 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -19,6 +19,7 @@ #include +#include #include #include #include From cc9c87d281a88a82de7551abfebcfd7e0952d3ae Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Mar 2016 11:31:02 -0800 Subject: [PATCH 167/292] Fix packet version mismatch not showing for domain packets --- interface/src/Application.cpp | 11 +++-------- interface/src/Application.h | 2 +- libraries/networking/src/DomainHandler.cpp | 2 ++ libraries/networking/src/DomainHandler.h | 1 + 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 89ec196fad..a2fdd3c8ac 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -549,7 +549,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : const DomainHandler& domainHandler = nodeList->getDomainHandler(); connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); - connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); + connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); @@ -3987,13 +3987,8 @@ void Application::handleDomainConnectionDeniedPacket(QSharedPointer()->getDomainHandler().getUUID(); - - if (accountManager.isLoggedIn() && !domainID.isNull()) { - _notifiedPacketVersionMismatchThisDomain = false; - } +void Application::resettingDomain() { + _notifiedPacketVersionMismatchThisDomain = false; } void Application::nodeAdded(SharedNodePointer node) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 8cc2a33038..98c5937f70 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -285,7 +285,7 @@ private slots: void idle(uint64_t now); void aboutToQuit(); - void connectedToDomain(const QString& hostname); + void resettingDomain(); void audioMuteToggled(); void faceTrackerMuteToggled(); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index db775983e1..bf27789c54 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -98,6 +98,8 @@ void DomainHandler::softReset() { } void DomainHandler::hardReset() { + emit resetting(); + softReset(); qCDebug(networking) << "Hard reset in NodeList DomainHandler."; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index f60ac2fbe6..957f52144b 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -104,6 +104,7 @@ signals: // It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on void completedSocketDiscovery(); + void resetting(); void connectedToDomain(const QString& hostname); void disconnectedFromDomain(); From aa63dcc9d2930e4100dd0626348d73e0dd05ebda Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Mar 2016 11:31:13 -0800 Subject: [PATCH 168/292] Add PacketType qMetaType --- libraries/networking/src/udt/PacketHeaders.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 5f86c35e7f..15042708c4 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -16,6 +16,10 @@ #include #include + +Q_DECLARE_METATYPE(PacketType); +static int packetTypeMetaTypeId = qRegisterMetaType(); + const QSet NON_VERIFIED_PACKETS = QSet() << PacketType::NodeJsonStats << PacketType::EntityQuery << PacketType::OctreeDataNack << PacketType::EntityEditNack From 2c1762526d3e859b3560db56491a48aec1316cdc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 25 Feb 2016 16:44:27 -0800 Subject: [PATCH 169/292] Move all resource requests to the same thread --- assignment-client/src/Agent.cpp | 18 ++----- interface/src/Application.cpp | 24 ++------- libraries/networking/src/AssetClient.cpp | 14 +++--- libraries/networking/src/AssetClient.h | 5 +- .../networking/src/AssetResourceRequest.h | 2 +- .../networking/src/FileResourceRequest.h | 2 +- .../networking/src/HTTPResourceRequest.cpp | 30 +++++++++--- .../networking/src/HTTPResourceRequest.h | 7 ++- libraries/networking/src/ResourceManager.cpp | 49 +++++++++++++++---- libraries/networking/src/ResourceManager.h | 7 +++ libraries/networking/src/ResourceRequest.cpp | 11 +++-- libraries/networking/src/ResourceRequest.h | 8 +-- 12 files changed, 106 insertions(+), 71 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3ff7eafd6b..ccf296865a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -55,14 +55,6 @@ Agent::Agent(ReceivedMessage& message) : { DependencyManager::get()->setPacketSender(&_entityEditSender); - auto assetClient = DependencyManager::set(); - - QThread* assetThread = new QThread; - assetThread->setObjectName("Asset Thread"); - assetClient->moveToThread(assetThread); - connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); - assetThread->start(); - DependencyManager::registerInheritance(); DependencyManager::set(); @@ -81,6 +73,8 @@ Agent::Agent(ReceivedMessage& message) : { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); + + ResourceManager::init(); } void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -470,13 +464,9 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); - - // cleanup the AssetClient thread - QThread* assetThread = DependencyManager::get()->thread(); - DependencyManager::destroy(); - assetThread->quit(); - assetThread->wait(); // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); + + ResourceManager::cleanup(); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 15b1836173..8e2b2175fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -370,7 +370,6 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -528,13 +527,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : audioThread->start(); - // Setup AssetClient - auto assetClient = DependencyManager::get(); - QThread* assetThread = new QThread; - assetThread->setObjectName("Asset Thread"); - assetClient->moveToThread(assetThread); - connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); - assetThread->start(); + ResourceManager::init(); // Setup MessagesClient auto messagesClient = DependencyManager::get(); @@ -644,13 +637,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&identityPacketTimer, &QTimer::timeout, getMyAvatar(), &MyAvatar::sendIdentityPacket); identityPacketTimer.start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); - QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkDiskCache* cache = new QNetworkDiskCache(); - cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); - cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); - networkAccessManager.setCache(cache); - ResourceCache::setRequestLimit(3); _glWidget = new GLCanvas(); @@ -1129,12 +1115,6 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); - // cleanup the AssetClient thread - QThread* assetThread = DependencyManager::get()->thread(); - DependencyManager::destroy(); - assetThread->quit(); - assetThread->wait(); - QThread* nodeThread = DependencyManager::get()->thread(); // remove the NodeList from the DependencyManager @@ -1150,6 +1130,8 @@ Application::~Application() { ConnexionClient::getInstance().destroy(); #endif + ResourceManager::cleanup(); + qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 4e7e7f24ba..203d4d9ba6 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -47,22 +47,20 @@ AssetClient::AssetClient() { } void AssetClient::init() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "init", Qt::BlockingQueuedConnection); - } - + Q_ASSERT(QThread::currentThread() == thread()); + // Setup disk cache if not already - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + auto& networkAccessManager = NetworkAccessManager::getInstance(); if (!networkAccessManager.cache()) { QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); cachePath = !cachePath.isEmpty() ? cachePath : "interfaceCache"; - + QNetworkDiskCache* cache = new QNetworkDiskCache(); cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE); cache->setCacheDirectory(cachePath); networkAccessManager.setCache(cache); - qCDebug(asset_client) << "AssetClient disk cache setup at" << cachePath - << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; + qDebug() << "ResourceManager disk cache setup at" << cachePath + << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 58790ef926..67ce4daa8f 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -43,13 +43,14 @@ class AssetClient : public QObject, public Dependency { Q_OBJECT public: AssetClient(); - - Q_INVOKABLE void init(); Q_INVOKABLE AssetRequest* createRequest(const QString& hash, const QString& extension); Q_INVOKABLE AssetUpload* createUpload(const QString& filename); Q_INVOKABLE AssetUpload* createUpload(const QByteArray& data, const QString& extension); +public slots: + void init(); + private slots: void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 0024426be0..4d2ea56ca4 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -20,7 +20,7 @@ class AssetResourceRequest : public ResourceRequest { Q_OBJECT public: - AssetResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + AssetResourceRequest(const QUrl& url) : ResourceRequest(url) { } ~AssetResourceRequest(); protected: diff --git a/libraries/networking/src/FileResourceRequest.h b/libraries/networking/src/FileResourceRequest.h index 4ff0d2ecf2..547b754cb5 100644 --- a/libraries/networking/src/FileResourceRequest.h +++ b/libraries/networking/src/FileResourceRequest.h @@ -19,7 +19,7 @@ class FileResourceRequest : public ResourceRequest { Q_OBJECT public: - FileResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + FileResourceRequest(const QUrl& url) : ResourceRequest(url) { } protected: virtual void doSend() override; diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index 34c9c1dad2..11ab436933 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -28,6 +28,25 @@ HTTPResourceRequest::~HTTPResourceRequest() { } } +void HTTPResourceRequest::setupTimer() { + Q_ASSERT(!_sendTimer); + static const int TIMEOUT_MS = 10000; + + _sendTimer = new QTimer(); + connect(this, &QObject::destroyed, _sendTimer, &QTimer::deleteLater); + connect(_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); + + _sendTimer->setSingleShot(true); + _sendTimer->start(TIMEOUT_MS); +} + +void HTTPResourceRequest::cleanupTimer() { + Q_ASSERT(_sendTimer); + _sendTimer->disconnect(this); + _sendTimer->deleteLater(); + _sendTimer = nullptr; +} + void HTTPResourceRequest::doSend() { QNetworkRequest networkRequest(_url); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); @@ -42,18 +61,15 @@ void HTTPResourceRequest::doSend() { connect(_reply, &QNetworkReply::finished, this, &HTTPResourceRequest::onRequestFinished); connect(_reply, &QNetworkReply::downloadProgress, this, &HTTPResourceRequest::onDownloadProgress); - connect(&_sendTimer, &QTimer::timeout, this, &HTTPResourceRequest::onTimeout); - static const int TIMEOUT_MS = 10000; - _sendTimer.setSingleShot(true); - _sendTimer.start(TIMEOUT_MS); + setupTimer(); } void HTTPResourceRequest::onRequestFinished() { Q_ASSERT(_state == InProgress); Q_ASSERT(_reply); - _sendTimer.stop(); + cleanupTimer(); switch(_reply->error()) { case QNetworkReply::NoError: @@ -80,7 +96,7 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT Q_ASSERT(_state == InProgress); // We've received data, so reset the timer - _sendTimer.start(); + _sendTimer->start(); emit progress(bytesReceived, bytesTotal); } @@ -91,6 +107,8 @@ void HTTPResourceRequest::onTimeout() { _reply->abort(); _reply->deleteLater(); _reply = nullptr; + + cleanupTimer(); _result = Timeout; _state = Finished; diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h index f0d3bb82d9..cc628d8855 100644 --- a/libraries/networking/src/HTTPResourceRequest.h +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -21,7 +21,7 @@ class HTTPResourceRequest : public ResourceRequest { Q_OBJECT public: - HTTPResourceRequest(QObject* parent, const QUrl& url) : ResourceRequest(parent, url) { } + HTTPResourceRequest(const QUrl& url) : ResourceRequest(url) { } ~HTTPResourceRequest(); protected: @@ -33,7 +33,10 @@ private slots: void onRequestFinished(); private: - QTimer _sendTimer; + void setupTimer(); + void cleanupTimer(); + + QTimer* _sendTimer { nullptr }; QNetworkReply* _reply { nullptr }; }; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index f195011290..1d41266f3a 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -11,12 +11,20 @@ #include "ResourceManager.h" -#include "AssetResourceRequest.h" -#include "FileResourceRequest.h" -#include "HTTPResourceRequest.h" +#include +#include +#include #include + +#include "AssetResourceRequest.h" +#include "FileResourceRequest.h" +#include "HTTPResourceRequest.h" +#include "NetworkAccessManager.h" + + +QThread ResourceManager::_thread; ResourceManager::PrefixMap ResourceManager::_prefixMap; QMutex ResourceManager::_prefixMapLock; @@ -67,18 +75,41 @@ QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) { return url; } +void ResourceManager::init() { + _thread.setObjectName("Ressource Manager Thread"); + + auto assetClient = DependencyManager::set(); + assetClient->moveToThread(&_thread); + QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init); + + _thread.start(); +} + +void ResourceManager::cleanup() { + // cleanup the AssetClient thread + DependencyManager::destroy(); + _thread.quit(); + _thread.wait(); +} + ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { auto normalizedURL = normalizeURL(url); auto scheme = normalizedURL.scheme(); + + ResourceRequest* request = nullptr; + if (scheme == URL_SCHEME_FILE) { - return new FileResourceRequest(parent, normalizedURL); + request = new FileResourceRequest(normalizedURL); } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { - return new HTTPResourceRequest(parent, normalizedURL); + request = new HTTPResourceRequest(normalizedURL); } else if (scheme == URL_SCHEME_ATP) { - return new AssetResourceRequest(parent, normalizedURL); + request = new AssetResourceRequest(normalizedURL); + } else { + qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url(); + return nullptr; } + Q_ASSERT(request); - qDebug() << "Unknown scheme (" << scheme << ") for URL: " << url.url(); - - return nullptr; + request->moveToThread(&_thread); + return request; } diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index c010c67f9b..162892abaf 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -29,8 +29,15 @@ public: static void setUrlPrefixOverride(const QString& prefix, const QString& replacement); static QString normalizeURL(const QString& urlString); static QUrl normalizeURL(const QUrl& url); + static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url); + + static void init(); + static void cleanup(); + private: + static QThread _thread; + using PrefixMap = std::map; static PrefixMap _prefixMap; diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index c6880636ea..e6402d6b25 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -11,12 +11,15 @@ #include "ResourceRequest.h" -ResourceRequest::ResourceRequest(QObject* parent, const QUrl& url) : - QObject(parent), - _url(url) { -} +#include + +ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { } void ResourceRequest::send() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); + return; + } Q_ASSERT(_state == NotStarted); _state = InProgress; diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index b229951a49..f940221d9d 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -20,7 +20,7 @@ class ResourceRequest : public QObject { Q_OBJECT public: - ResourceRequest(QObject* parent, const QUrl& url); + ResourceRequest(const QUrl& url); enum State { NotStarted = 0, @@ -38,7 +38,6 @@ public: NotFound }; - void send(); QByteArray getData() { return _data; } State getState() const { return _state; } Result getResult() const { return _result; } @@ -47,8 +46,11 @@ public: void setCacheEnabled(bool value) { _cacheEnabled = value; } +public slots: + void send(); + signals: - void progress(uint64_t bytesReceived, uint64_t bytesTotal); + void progress(qint64 bytesReceived, qint64 bytesTotal); void finished(); protected: From 40d307a37b4e15be29fa94153e8bf12ce2ebc4ea Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 10:37:19 -0800 Subject: [PATCH 170/292] Temporary fix to disk cache editor crash --- interface/src/Application.cpp | 6 ++---- interface/src/ui/DiskCacheEditor.cpp | 8 ++++---- libraries/networking/src/AssetClient.cpp | 9 +++++++++ libraries/networking/src/AssetClient.h | 1 + 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8e2b2175fe..36c882647f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1072,10 +1072,8 @@ void Application::cleanupBeforeQuit() { } void Application::emptyLocalCache() { - if (auto cache = NetworkAccessManager::getInstance().cache()) { - qDebug() << "DiskCacheEditor::clear(): Clearing disk cache."; - cache->clear(); - } + auto assetClient = DependencyManager::get(); + QMetaObject::invokeMethod(assetClient.data(), "clearCache", Qt::QueuedConnection); } Application::~Application() { diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index d3a40e6439..e2f64d8817 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -122,6 +122,7 @@ void DiskCacheEditor::refresh() { } return QString("%0 %1").arg(number).arg(UNITS[i]); }; + return; QNetworkDiskCache* cache = qobject_cast(NetworkAccessManager::getInstance().cache()); if (_path) { @@ -135,6 +136,7 @@ void DiskCacheEditor::refresh() { } } +#include void DiskCacheEditor::clear() { QMessageBox::StandardButton buttonClicked = OffscreenUi::question(_dialog, "Clearing disk cache", @@ -142,10 +144,8 @@ void DiskCacheEditor::clear() { "are you sure you want to do that?", QMessageBox::Ok | QMessageBox::Cancel); if (buttonClicked == QMessageBox::Ok) { - if (auto cache = NetworkAccessManager::getInstance().cache()) { - qDebug() << "DiskCacheEditor::clear(): Clearing disk cache."; - cache->clear(); - } + auto assetClient = DependencyManager::get(); + QMetaObject::invokeMethod(assetClient.data() , "clearCache", Qt::QueuedConnection); } refresh(); } diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 203d4d9ba6..28fb31fdfd 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -64,6 +64,15 @@ void AssetClient::init() { } } +void AssetClient::clearCache() { + Q_ASSERT(QThread::currentThread() == thread()); + + if (auto cache = NetworkAccessManager::getInstance().cache()) { + qDebug() << "AssetClient::clearCache(): Clearing disk cache."; + cache->clear(); + } +} + bool haveAssetServer() { auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 67ce4daa8f..93b54d6df3 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -50,6 +50,7 @@ public: public slots: void init(); + void clearCache(); private slots: void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); From 6a4b93a4e7d4af8ae081375042ce0e7109d3c725 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 11:22:28 -0800 Subject: [PATCH 171/292] Proper fix for DiskCacheInfo --- assignment-client/src/Agent.cpp | 8 ++-- interface/src/Application.cpp | 4 +- interface/src/ui/DiskCacheEditor.cpp | 54 +++++++++++------------- interface/src/ui/DiskCacheEditor.h | 3 ++ libraries/networking/src/AssetClient.cpp | 16 +++++++ libraries/networking/src/AssetClient.h | 2 + 6 files changed, 52 insertions(+), 35 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ccf296865a..1955b8f0c8 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -55,6 +55,8 @@ Agent::Agent(ReceivedMessage& message) : { DependencyManager::get()->setPacketSender(&_entityEditSender); + ResourceManager::init(); + DependencyManager::registerInheritance(); DependencyManager::set(); @@ -73,8 +75,6 @@ Agent::Agent(ReceivedMessage& message) : { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); - - ResourceManager::init(); } void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -464,9 +464,9 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); + + ResourceManager::cleanup(); // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); - - ResourceManager::cleanup(); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 36c882647f..bc98245f32 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1113,6 +1113,8 @@ Application::~Application() { DependencyManager::destroy(); DependencyManager::destroy(); + ResourceManager::cleanup(); + QThread* nodeThread = DependencyManager::get()->thread(); // remove the NodeList from the DependencyManager @@ -1128,8 +1130,6 @@ Application::~Application() { ConnexionClient::getInstance().destroy(); #endif - ResourceManager::cleanup(); - qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index e2f64d8817..a098616e0b 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -9,23 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "DiskCacheEditor.h" #include #include #include #include #include -#include +#include #include -#include +#include -#include "DiskCacheEditor.h" #include "OffscreenUi.h" DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) { - } QWindow* DiskCacheEditor::windowHandle() { @@ -33,7 +31,6 @@ QWindow* DiskCacheEditor::windowHandle() { } void DiskCacheEditor::toggle() { - qDebug() << "DiskCacheEditor::toggle()"; if (!_dialog) { makeDialog(); } @@ -88,17 +85,15 @@ void DiskCacheEditor::makeDialog() { Q_CHECK_PTR(_maxSize); _maxSize->setAlignment(Qt::AlignLeft); layout->addWidget(_maxSize, 2, 1, 1, 3); - + refresh(); - - - QPushButton* refreshCacheButton = new QPushButton(_dialog); - Q_CHECK_PTR(refreshCacheButton); - refreshCacheButton->setText("Refresh"); - refreshCacheButton->setToolTip("Reload the cache stats."); - connect(refreshCacheButton, SIGNAL(clicked()), SLOT(refresh())); - layout->addWidget(refreshCacheButton, 3, 2); - + + _refreshTimer = new QTimer(_dialog); + _refreshTimer->setInterval(100); + _refreshTimer->setSingleShot(false); + QObject::connect(_refreshTimer, &QTimer::timeout, this, &DiskCacheEditor::refresh); + _refreshTimer->start(); + QPushButton* clearCacheButton = new QPushButton(_dialog); Q_CHECK_PTR(clearCacheButton); clearCacheButton->setText("Clear"); @@ -108,7 +103,13 @@ void DiskCacheEditor::makeDialog() { } void DiskCacheEditor::refresh() { - static const std::function stringify = [](qint64 number) { + auto assetClient = DependencyManager::get(); + QMetaObject::invokeMethod(assetClient.data() , "cacheInfoRequest", Qt::QueuedConnection, + Q_ARG(QObject*, this), Q_ARG(QString, "update")); +} + +void DiskCacheEditor::update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) { + static const auto stringify = [](qint64 number) { static const QStringList UNITS = QStringList() << "B" << "KB" << "MB" << "GB"; static const qint64 CHUNK = 1024; QString unit; @@ -122,30 +123,25 @@ void DiskCacheEditor::refresh() { } return QString("%0 %1").arg(number).arg(UNITS[i]); }; - return; - QNetworkDiskCache* cache = qobject_cast(NetworkAccessManager::getInstance().cache()); if (_path) { - _path->setText(cache->cacheDirectory()); + _path->setText(cacheDirectory); } if (_size) { - _size->setText(stringify(cache->cacheSize())); + _size->setText(stringify(cacheSize)); } if (_maxSize) { - _maxSize->setText(stringify(cache->maximumCacheSize())); + _maxSize->setText(stringify(maximumCacheSize)); } } -#include void DiskCacheEditor::clear() { - QMessageBox::StandardButton buttonClicked = - OffscreenUi::question(_dialog, "Clearing disk cache", - "You are about to erase all the content of the disk cache, " - "are you sure you want to do that?", - QMessageBox::Ok | QMessageBox::Cancel); + auto buttonClicked = OffscreenUi::question(_dialog, "Clearing disk cache", + "You are about to erase all the content of the disk cache, " + "are you sure you want to do that?", + QMessageBox::Ok | QMessageBox::Cancel); if (buttonClicked == QMessageBox::Ok) { auto assetClient = DependencyManager::get(); QMetaObject::invokeMethod(assetClient.data() , "clearCache", Qt::QueuedConnection); } - refresh(); } diff --git a/interface/src/ui/DiskCacheEditor.h b/interface/src/ui/DiskCacheEditor.h index 5d673c4285..8d1b84fa8d 100644 --- a/interface/src/ui/DiskCacheEditor.h +++ b/interface/src/ui/DiskCacheEditor.h @@ -18,6 +18,7 @@ class QDialog; class QLabel; class QWindow; +class QTimer; class DiskCacheEditor : public QObject { Q_OBJECT @@ -32,6 +33,7 @@ public slots: private slots: void refresh(); + void update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize); void clear(); private: @@ -41,6 +43,7 @@ private: QPointer _path; QPointer _size; QPointer _maxSize; + QPointer _refreshTimer; }; #endif // hifi_DiskCacheEditor_h \ No newline at end of file diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 28fb31fdfd..66b89f78a3 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -64,12 +64,28 @@ void AssetClient::init() { } } + +void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) { + Q_ASSERT(QThread::currentThread() == thread()); + + if (auto* cache = qobject_cast(NetworkAccessManager::getInstance().cache())) { + QMetaObject::invokeMethod(reciever, slot.toStdString().data(), Qt::QueuedConnection, + Q_ARG(QString, cache->cacheDirectory()), + Q_ARG(qint64, cache->cacheSize()), + Q_ARG(qint64, cache->maximumCacheSize())); + } else { + qCWarning(asset_client) << "No disk cache to get info from."; + } +} + void AssetClient::clearCache() { Q_ASSERT(QThread::currentThread() == thread()); if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; cache->clear(); + } else { + qCWarning(asset_client) << "No disk cache to clear."; } } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 93b54d6df3..f66fe8adcc 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -50,6 +50,8 @@ public: public slots: void init(); + + void cacheInfoRequest(QObject* reciever, QString slot); void clearCache(); private slots: From f0ccada945afcacafc755666f7a5b1160f2b5cdf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 15:51:32 -0800 Subject: [PATCH 172/292] Fix for Ubuntu --- interface/src/ui/DiskCacheEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index a098616e0b..0ec7e79191 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -91,7 +91,7 @@ void DiskCacheEditor::makeDialog() { _refreshTimer = new QTimer(_dialog); _refreshTimer->setInterval(100); _refreshTimer->setSingleShot(false); - QObject::connect(_refreshTimer, &QTimer::timeout, this, &DiskCacheEditor::refresh); + QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh); _refreshTimer->start(); QPushButton* clearCacheButton = new QPushButton(_dialog); From 4944d0a8d0205c093bd65b9bcd325f96f318e6fc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 26 Feb 2016 16:06:57 -0800 Subject: [PATCH 173/292] Handle threading inside AssetServer --- interface/src/Application.cpp | 7 +------ interface/src/Application.h | 2 -- interface/src/ui/DiskCacheEditor.cpp | 9 +++------ interface/src/ui/DiskCacheEditor.h | 4 ++-- libraries/networking/src/AssetClient.cpp | 12 ++++++++++-- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bc98245f32..bc04e111b0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1071,11 +1071,6 @@ void Application::cleanupBeforeQuit() { DependencyManager::destroy(); } -void Application::emptyLocalCache() { - auto assetClient = DependencyManager::get(); - QMetaObject::invokeMethod(assetClient.data(), "clearCache", Qt::QueuedConnection); -} - Application::~Application() { EntityTreePointer tree = getEntities()->getTree(); tree->setSimulation(NULL); @@ -3061,7 +3056,7 @@ void Application::reloadResourceCaches() { _viewFrustum.setOrientation(glm::quat()); queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); - emptyLocalCache(); + DependencyManager::get()->clearCache(); DependencyManager::get()->refreshAll(); DependencyManager::get()->refreshAll(); diff --git a/interface/src/Application.h b/interface/src/Application.h index b5a0894c3a..7c92331d43 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -330,8 +330,6 @@ private: void cleanupBeforeQuit(); - void emptyLocalCache(); - void update(float deltaTime); void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue); diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index 0ec7e79191..f2720df22a 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -103,12 +103,10 @@ void DiskCacheEditor::makeDialog() { } void DiskCacheEditor::refresh() { - auto assetClient = DependencyManager::get(); - QMetaObject::invokeMethod(assetClient.data() , "cacheInfoRequest", Qt::QueuedConnection, - Q_ARG(QObject*, this), Q_ARG(QString, "update")); + DependencyManager::get()->cacheInfoRequest(this, "cacheInfoCallback"); } -void DiskCacheEditor::update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) { +void DiskCacheEditor::cacheInfoCallback(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize) { static const auto stringify = [](qint64 number) { static const QStringList UNITS = QStringList() << "B" << "KB" << "MB" << "GB"; static const qint64 CHUNK = 1024; @@ -141,7 +139,6 @@ void DiskCacheEditor::clear() { "are you sure you want to do that?", QMessageBox::Ok | QMessageBox::Cancel); if (buttonClicked == QMessageBox::Ok) { - auto assetClient = DependencyManager::get(); - QMetaObject::invokeMethod(assetClient.data() , "clearCache", Qt::QueuedConnection); + DependencyManager::get()->clearCache(); } } diff --git a/interface/src/ui/DiskCacheEditor.h b/interface/src/ui/DiskCacheEditor.h index 8d1b84fa8d..3f8fa1a883 100644 --- a/interface/src/ui/DiskCacheEditor.h +++ b/interface/src/ui/DiskCacheEditor.h @@ -33,9 +33,9 @@ public slots: private slots: void refresh(); - void update(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize); + void cacheInfoCallback(QString cacheDirectory, qint64 cacheSize, qint64 maximumCacheSize); void clear(); - + private: void makeDialog(); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 66b89f78a3..e70863f0b6 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -66,7 +66,12 @@ void AssetClient::init() { void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) { - Q_ASSERT(QThread::currentThread() == thread()); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "cacheInfoRequest", Qt::QueuedConnection, + Q_ARG(QObject*, reciever), Q_ARG(QString, slot)); + return; + } + if (auto* cache = qobject_cast(NetworkAccessManager::getInstance().cache())) { QMetaObject::invokeMethod(reciever, slot.toStdString().data(), Qt::QueuedConnection, @@ -79,7 +84,10 @@ void AssetClient::cacheInfoRequest(QObject* reciever, QString slot) { } void AssetClient::clearCache() { - Q_ASSERT(QThread::currentThread() == thread()); + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "clearCache", Qt::QueuedConnection); + return; + } if (auto cache = NetworkAccessManager::getInstance().cache()) { qDebug() << "AssetClient::clearCache(): Clearing disk cache."; From 14ae35e741a17d7f4998810f03fe068edc7c61fe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Mar 2016 12:00:23 -0800 Subject: [PATCH 174/292] CR --- interface/src/ui/DiskCacheEditor.cpp | 4 +++- libraries/networking/src/AssetClient.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/DiskCacheEditor.cpp b/interface/src/ui/DiskCacheEditor.cpp index f2720df22a..ed85b87d63 100644 --- a/interface/src/ui/DiskCacheEditor.cpp +++ b/interface/src/ui/DiskCacheEditor.cpp @@ -88,8 +88,10 @@ void DiskCacheEditor::makeDialog() { refresh(); + + static const int REFRESH_INTERVAL = 100; // msec _refreshTimer = new QTimer(_dialog); - _refreshTimer->setInterval(100); + _refreshTimer->setInterval(REFRESH_INTERVAL); _refreshTimer->setSingleShot(false); QObject::connect(_refreshTimer.data(), &QTimer::timeout, this, &DiskCacheEditor::refresh); _refreshTimer->start(); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index e70863f0b6..9591828fef 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -60,7 +60,7 @@ void AssetClient::init() { cache->setCacheDirectory(cachePath); networkAccessManager.setCache(cache); qDebug() << "ResourceManager disk cache setup at" << cachePath - << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; + << "(size:" << MAXIMUM_CACHE_SIZE / BYTES_PER_GIGABYTES << "GB)"; } } From 261f5c45de459ea4a4433e7f9420d4e773ae31e1 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Mar 2016 12:07:28 -0800 Subject: [PATCH 175/292] Fix compiler warnings --- libraries/audio/src/AudioLimiter.cpp | 73 +++------------------------- 1 file changed, 6 insertions(+), 67 deletions(-) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index 1fa2b46c1b..bb3d8b7a76 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -83,6 +83,8 @@ static const int32_t EXP2_BIAS = 64; // P(x) = log2(1+x) for x=[0,1] // scaled by 1, 0.5, 0.25 // +// |error| < 347 ulp, smooth +// static const int LOG2_TABBITS = 4; static const int32_t log2Table[1 << LOG2_TABBITS][3] = { { -0x56dfe26d, 0x5c46daff, 0x00000000 }, @@ -106,9 +108,10 @@ static const int32_t log2Table[1 << LOG2_TABBITS][3] = { // // P(x) = exp2(x) for x=[0,1] // scaled by 2, 1, 0.5 -// // Uses exp2(-x) = exp2(1-x)/2 // +// |error| < 1387 ulp, smooth +// static const int EXP2_TABBITS = 4; static const int32_t exp2Table[1 << EXP2_TABBITS][3] = { { 0x3ed838c8, 0x58b574b7, 0x40000000 }, @@ -129,68 +132,6 @@ static const int32_t exp2Table[1 << EXP2_TABBITS][3] = { { 0x785c4499, 0x390ecc3a, 0x456188bd }, }; -// -// Count Leading Zeros -// defined to match ARM CLZ and x86 LZCNT -// -static inline int CLZ(uint32_t x) { - int e = 0; - - if (x == 0) return 32; - - if (x < 0x00010000) { - x <<= 16; - e += 16; - } - if (x < 0x01000000) { - x <<= 8; - e += 8; - } - if (x < 0x10000000) { - x <<= 4; - e += 4; - } - if (x < 0x40000000) { - x <<= 2; - e += 2; - } - if (x < 0x80000000) { - e += 1; - } - return e; -} - -// -// Compute -log2(x) for x=[0,1] in Q31, result in Q26 -// x = 0 returns -log2(1) -// x < 0 undefined -// -// |error| < 347 ulp, smooth -// -static inline int32_t fixlog2(int32_t x) { - - // normalize to [0x80000000, 0xffffffff] - int e = CLZ(x); - x <<= e; - e -= e >> LOG2_INTBITS; // if e==32, e=31 - - // x - 1.0 - x &= 0x7fffffff; - - int k = x >> (31 - LOG2_TABBITS); - - // polynomial for log2(1+x) over x=[0,1] - int32_t c0 = log2Table[k][0]; - int32_t c1 = log2Table[k][1]; - int32_t c2 = log2Table[k][2]; - - c1 += MULHI(c0, x); - c2 += MULHI(c1, x); - - // reconstruct result in Q26 - return (e << LOG2_FRACBITS) - (c2 >> 3); -} - static const int IEEE754_MANT_BITS = 23; static const int IEEE754_EXPN_BIAS = 127; @@ -214,7 +155,7 @@ static inline int32_t peaklog2(float* input) { // saturate if (e > 31) return 0x7fffffff; - int k = x >> (31 - EXP2_TABBITS); + int k = x >> (31 - LOG2_TABBITS); // polynomial for log2(1+x) over x=[0,1] int32_t c0 = log2Table[k][0]; @@ -251,7 +192,7 @@ static inline int32_t peaklog2(float* input0, float* input1) { // saturate if (e > 31) return 0x7fffffff; - int k = x >> (31 - EXP2_TABBITS); + int k = x >> (31 - LOG2_TABBITS); // polynomial for log2(1+x) over x=[0,1] int32_t c0 = log2Table[k][0]; @@ -269,8 +210,6 @@ static inline int32_t peaklog2(float* input0, float* input1) { // Compute exp2(-x) for x=[0,32] in Q26, result in Q31 // x < 0 undefined // -// |error| < 1387 ulp, smooth -// static inline int32_t fixexp2(int32_t x) { // split into e and 1.0 - x From 9fb318570bcb0bcfd2e8392ad1a7c0f649774fd3 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Mar 2016 12:24:44 -0800 Subject: [PATCH 176/292] Ajusting the pure Ambient SH lighting pass and more review issues --- libraries/fbx/src/FBXReader.cpp | 6 ++-- .../render-utils/src/DeferredGlobalLight.slh | 29 +++++++++++++++---- .../render-utils/src/DeferredLighting.slh | 2 +- .../render-utils/src/MaterialTextures.slh | 4 +-- libraries/render/src/render/ShapePipeline.cpp | 4 +-- libraries/render/src/render/ShapePipeline.h | 2 +- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 1778e06894..500f856450 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -882,7 +882,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS propertyName = "P"; index = 4; } - if (properties && !material.isPBSMaterial) { + if (!material.isPBSMaterial && properties) { foreach (const FBXNode& property, subobject.children) { if (property.name == propertyName) { if (property.properties.at(0) == "DiffuseColor") { @@ -917,7 +917,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS #endif } } - } else if (properties && material.isPBSMaterial) { + } else if (material.isPBSMaterial && properties) { std::vector unknowns; foreach(const FBXNode& property, subobject.children) { if (property.name == propertyName) { @@ -1095,7 +1095,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } else if (type.contains("emissive")) { emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("tex_emissive_map")) { - roughnessTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + emissiveTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("ambient")) { ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("tex_ao_map")) { diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 341b9da9e8..71bc2dc6d0 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -45,6 +45,12 @@ vec4 evalSkyboxLight(vec3 direction, float lod) { color += emissive; <@endfunc@> +<@func declareAmbientFresnel()@> +vec3 fresnelSchlickAmbient(vec3 fresnelColor, vec3 lightDir, vec3 halfDir, float gloss) { + return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * pow(1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); +} +<@endfunc@> + <@func declareEvalAmbientGlobalColor()@> vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { <$prepareGlobalLight()$> @@ -54,24 +60,35 @@ vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obsc <@endfunc@> <@func declareEvalAmbientSphereGlobalColor()@> +<$declareAmbientFresnel()$> + vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { <$prepareGlobalLight()$> - color += (1 - (metallic * 0.5)) * albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); + + // Diffuse from ambient + color += (1 - metallic) * albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); + + // Specular highlight from ambient + vec3 direction = -reflect(fragEyeDir, fragNormal); + vec3 skyboxLight = evalSphericalLight(getLightAmbientSphere(light), direction).xyz; + vec3 ambientFresnel = fresnelSchlickAmbient(fresnel, fragEyeDir, fragNormal, 1 - roughness); + color += ambientFresnel * skyboxLight.rgb * obscurance * getLightAmbientIntensity(light); + return color; } <@endfunc@> <@func declareEvalSkyboxGlobalColor()@> <$declareSkyboxMap()$> - -vec3 fresnelSchlickAmbient(vec3 fresnelColor, vec3 lightDir, vec3 halfDir, float gloss) { - return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * pow(1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); -} +<$declareAmbientFresnel()$> vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, float metallic, vec3 emissive, float roughness) { <$prepareGlobalLight()$> + + // Diffuse from ambient color += (1 - metallic) * albedo * evalSphericalLight(getLightAmbientSphere(light), fragNormal).xyz * obscurance * getLightAmbientIntensity(light); - + + // Specular highlight from ambient vec3 direction = -reflect(fragEyeDir, fragNormal); float levels = getLightAmbientMapNumMips(light); float lod = min(floor((roughness) * levels), levels); diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index d02f9e3345..b33371b10d 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -15,7 +15,7 @@ <@func declareEvalPBRShading()@> vec3 fresnelSchlick(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) { - return fresnelColor + (1.0f - fresnelColor) * pow(1.0f - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); + return fresnelColor + (1.0 - fresnelColor) * pow(1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5); } float specularDistribution(float roughness, vec3 normal, vec3 halfDir) { diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index fb253e3f6d..8904ae34b2 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -35,9 +35,9 @@ vec3 fetchNormalMap(vec2 uv) { <@endif@> <@if withMetallic@> -uniform sampler2D specularMap; +uniform sampler2D metallicMap; float fetchMetallicMap(vec2 uv) { - return (texture(specularMap, uv).r); + return (texture(metallicMap, uv).r); } <@endif@> diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index f20b5144d3..6974a7e385 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -56,7 +56,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::ALBEDO_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::ROUGHNESS_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); - slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::METALLIC_MAP)); + slotBindings.insert(gpu::Shader::Binding(std::string("metallicMap"), Slot::METALLIC_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::EMISSIVE_LIGHTMAP_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), Slot::OCCLUSION_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::LIGHT_BUFFER)); @@ -71,7 +71,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap"); locations->roughnessTextureUnit = program->getTextures().findLocation("roughnessMap"); locations->normalTextureUnit = program->getTextures().findLocation("normalMap"); - locations->specularTextureUnit = program->getTextures().findLocation("specularMap"); + locations->metallicTextureUnit = program->getTextures().findLocation("metallicMap"); locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); locations->occlusionTextureUnit = program->getTextures().findLocation("occlusionMap"); locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 963a3c76d4..0f795aadde 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -212,7 +212,7 @@ public: int albedoTextureUnit; int normalTextureUnit; int roughnessTextureUnit; - int specularTextureUnit; + int metallicTextureUnit; int emissiveTextureUnit; int occlusionTextureUnit; int emissiveParams; From a309a2e08f7fe09bf70bbe2faffe3f515c78b15b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 09:24:57 +1300 Subject: [PATCH 177/292] Style slider controls --- .../resources/qml/controls-uit/Slider.qml | 98 +++++++++++++++++++ .../dialogs/preferences/SliderPreference.qml | 23 ++++- .../qml/styles-uit/HifiConstants.qml | 11 +++ 3 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 interface/resources/qml/controls-uit/Slider.qml diff --git a/interface/resources/qml/controls-uit/Slider.qml b/interface/resources/qml/controls-uit/Slider.qml new file mode 100644 index 0000000000..ea4058f2be --- /dev/null +++ b/interface/resources/qml/controls-uit/Slider.qml @@ -0,0 +1,98 @@ +// +// Slider.qml +// +// Created by David Rowe on 27 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" +import "../controls-uit" as HifiControls + +Slider { + id: slider + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property string label: "" + property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height : 0) + + height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. + y: sliderLabel.visible ? sliderLabel.height : 0 + + style: SliderStyle { + + groove: Rectangle { + implicitWidth: 50 + implicitHeight: hifi.dimensions.sliderGrooveHeight + radius: height / 2 + color: isLightColorScheme ? hifi.colors.sliderGutterLight : hifi.colors.sliderGutterDark + + Rectangle { + width: parent.height - 2 + height: slider.value * slider.width - 1 + radius: height / 2 + anchors { + top: parent.top + topMargin: width + 1 + left: parent.left + leftMargin: 1 + } + transformOrigin: Item.TopLeft + rotation: -90 + gradient: Gradient { + GradientStop { position: 0.0; color: hifi.colors.blueAccent } + GradientStop { position: 1.0; color: hifi.colors.primaryHighlight } + } + } + } + + handle: Rectangle { + implicitWidth: hifi.dimensions.sliderHandleSize + implicitHeight: hifi.dimensions.sliderHandleSize + radius: height / 2 + border.width: 1 + border.color: isLightColorScheme ? hifi.colors.sliderBorderLight : hifi.colors.sliderBorderDark + gradient: Gradient { + GradientStop { + position: 0.0 + color: pressed || hovered + ? (isLightColorScheme ? hifi.colors.sliderDarkStart : hifi.colors.sliderLightStart ) + : (isLightColorScheme ? hifi.colors.sliderLightStart : hifi.colors.sliderDarkStart ) + } + GradientStop { + position: 1.0 + color: pressed || hovered + ? (isLightColorScheme ? hifi.colors.sliderDarkFinish : hifi.colors.sliderLightFinish ) + : (isLightColorScheme ? hifi.colors.sliderLightFinish : hifi.colors.sliderDarkFinish ) + } + } + + Rectangle { + height: parent.height - 2 + width: height + radius: height / 2 + anchors.centerIn: parent + color: hifi.colors.transparent + border.width: 1 + border.color: hifi.colors.black + } + } + } + + HifiControls.Label { + id: sliderLabel + text: slider.label + colorScheme: slider.colorScheme + anchors.left: parent.left + anchors.bottom: parent.top + anchors.bottomMargin: 2 + visible: label != "" + } +} diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index 0865b49dd0..57042a653a 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -1,10 +1,22 @@ +// +// SpinBoxPreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 + +import "../../dialogs" +import "../../controls-uit" Preference { id: root property alias slider: slider - height: slider.height + height: slider.controlHeight Component.onCompleted: { slider.value = preference.value; @@ -15,9 +27,9 @@ Preference { preference.save(); } - Text { - text: root.label - color: enabled ? "black" : "gray" + Label { + text: root.label + ":" + colorScheme: hifi.colorSchemes.dark anchors.verticalCenter: slider.verticalCenter } @@ -26,5 +38,6 @@ Preference { value: preference.value width: 130 anchors { right: parent.right } + colorScheme: hifi.colorSchemes.dark } } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 26899686f1..d74ba48f29 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -54,6 +54,7 @@ Item { readonly property color white50: "#80ffffff" readonly property color white30: "#4dffffff" readonly property color white25: "#40ffffff" + readonly property color transparent: "#00ffffff" // Control specific colors readonly property color tableRowLightOdd: white50 @@ -68,6 +69,14 @@ Item { readonly property color checkboxDarkFinish: "#6b6a6b" readonly property color checkboxChecked: primaryHighlight readonly property color checkboxCheckedBorder: "#36cdff" + readonly property color sliderGutterLight: "#d4d4d4" + readonly property color sliderGutterDark: "#252525" + readonly property color sliderBorderLight: "#afafaf" + readonly property color sliderBorderDark: "#7d7d7d" + readonly property color sliderLightStart: "#ffffff" + readonly property color sliderLightFinish: "#afafaf" + readonly property color sliderDarkStart: "#7d7d7d" + readonly property color sliderDarkFinish: "#6b6a6b" } Item { @@ -84,6 +93,8 @@ Item { readonly property vector2d contentMargin: Qt.vector2d(12, 24) readonly property vector2d contentSpacing: Qt.vector2d(8, 12) readonly property real textPadding: 8 + readonly property real sliderHandleSize: 18 + readonly property real sliderGrooveHeight: 8 readonly property real spinnerSize: 20 readonly property real tablePadding: 12 readonly property real tableRowHeight: largeScreen ? 26 : 23 From c5cb3543ebb6df8088edfd16c57deb6e43f0e1c4 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 1 Mar 2016 12:29:32 -0800 Subject: [PATCH 178/292] Cache inline textures under fbx --- .../src/model-networking/ModelCache.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2f8e04890c..107d91ec3b 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -305,13 +305,17 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas } static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) { + // Create a local url to cache inline textures + auto localBaseUrl = QUrl(textureBaseUrl.url() + "/"); + auto textureCache = DependencyManager::get(); NetworkMaterial* networkMaterial = new NetworkMaterial(); networkMaterial->_material = material._material; if (!material.diffuseTexture.filename.isEmpty()) { - networkMaterial->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content); + const auto& baseUrl = material.diffuseTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; + networkMaterial->diffuseTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content); networkMaterial->diffuseTextureName = material.diffuseTexture.name; auto diffuseMap = model::TextureMapPointer(new model::TextureMap()); @@ -321,7 +325,8 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); } if (!material.normalTexture.filename.isEmpty()) { - networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content); + const auto& baseUrl = material.normalTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; + networkMaterial->normalTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content); networkMaterial->normalTextureName = material.normalTexture.name; auto normalMap = model::TextureMapPointer(new model::TextureMap()); @@ -330,7 +335,8 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); } if (!material.specularTexture.filename.isEmpty()) { - networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content); + const auto& baseUrl = material.specularTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; + networkMaterial->specularTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content); networkMaterial->specularTextureName = material.specularTexture.name; auto glossMap = model::TextureMapPointer(new model::TextureMap()); @@ -339,7 +345,8 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap); } if (!material.emissiveTexture.filename.isEmpty()) { - networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), LIGHTMAP_TEXTURE, material.emissiveTexture.content); + const auto& baseUrl = material.emissiveTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; + networkMaterial->emissiveTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.emissiveTexture.filename)), LIGHTMAP_TEXTURE, material.emissiveTexture.content); networkMaterial->emissiveTextureName = material.emissiveTexture.name; From 19c83e869f41d3d62efc3652e6c4aba94da79546 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 1 Mar 2016 12:31:26 -0800 Subject: [PATCH 179/292] Add helper to buildNetworkMaterial --- .../src/model-networking/ModelCache.cpp | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 107d91ec3b..a2e3516690 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -309,53 +309,45 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const auto localBaseUrl = QUrl(textureBaseUrl.url() + "/"); auto textureCache = DependencyManager::get(); - NetworkMaterial* networkMaterial = new NetworkMaterial(); + NetworkMaterial* networkMaterial = new NetworkMaterial(); networkMaterial->_material = material._material; + auto setupMaterialTexture = [&](const FBXTexture& texture, + TextureType type, model::MaterialKey::MapChannel channel, + NetworkTexturePointer& networkTexture, QString& networkTextureName){ + const auto& baseUrl = texture.content.isEmpty() ? textureBaseUrl : localBaseUrl; + networkTexture = textureCache->getTexture(baseUrl.resolved(QUrl(texture.filename)), type, texture.content); + networkTextureName = texture.name; + + auto map = std::make_shared(); + map->setTextureSource(networkTexture->_textureSource); + material._material->setTextureMap(channel, map); + return map; + }; + if (!material.diffuseTexture.filename.isEmpty()) { - const auto& baseUrl = material.diffuseTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; - networkMaterial->diffuseTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content); - networkMaterial->diffuseTextureName = material.diffuseTexture.name; - - auto diffuseMap = model::TextureMapPointer(new model::TextureMap()); - diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource); + auto diffuseMap = setupMaterialTexture(material.diffuseTexture, + DEFAULT_TEXTURE, model::MaterialKey::DIFFUSE_MAP, + networkMaterial->diffuseTexture, networkMaterial->diffuseTextureName); diffuseMap->setTextureTransform(material.diffuseTexture.transform); - - material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); } if (!material.normalTexture.filename.isEmpty()) { - const auto& baseUrl = material.normalTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; - networkMaterial->normalTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content); - networkMaterial->normalTextureName = material.normalTexture.name; - - auto normalMap = model::TextureMapPointer(new model::TextureMap()); - normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource); - - material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); + setupMaterialTexture(material.normalTexture, + (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), model::MaterialKey::NORMAL_MAP, + networkMaterial->normalTexture, networkMaterial->normalTextureName); } if (!material.specularTexture.filename.isEmpty()) { - const auto& baseUrl = material.specularTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; - networkMaterial->specularTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content); - networkMaterial->specularTextureName = material.specularTexture.name; - - auto glossMap = model::TextureMapPointer(new model::TextureMap()); - glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource); - - material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap); + setupMaterialTexture(material.specularTexture, + SPECULAR_TEXTURE, model::MaterialKey::GLOSS_MAP, + networkMaterial->specularTexture, networkMaterial->specularTextureName); } if (!material.emissiveTexture.filename.isEmpty()) { - const auto& baseUrl = material.emissiveTexture.content.isEmpty() ? textureBaseUrl : localBaseUrl; - networkMaterial->emissiveTexture = textureCache->getTexture(baseUrl.resolved(QUrl(material.emissiveTexture.filename)), LIGHTMAP_TEXTURE, material.emissiveTexture.content); - networkMaterial->emissiveTextureName = material.emissiveTexture.name; - - - auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); - lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource); + auto lightmapMap = setupMaterialTexture(material.emissiveTexture, + LIGHTMAP_TEXTURE, model::MaterialKey::LIGHTMAP_MAP, + networkMaterial->emissiveTexture, networkMaterial->emissiveTextureName); lightmapMap->setTextureTransform(material.emissiveTexture.transform); lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y); - - material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); } return networkMaterial; From bc7d7a3dae12a09816a8d285afeb97dd249370f5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Mar 2016 12:43:06 -0800 Subject: [PATCH 180/292] adding chapters --- .../fireworksLaunchButtonEntityScript.js | 21 +++++++++++++ .../chapter1/fireworksLaunchButtonSpawner.js | 30 +++++++++++++++++++ .../fireworksLaunchButtonEntityScript.js | 21 +++++++++++++ .../chapter2/fireworksLaunchButtonSpawner.js | 30 +++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js create mode 100644 examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js create mode 100644 examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js create mode 100644 examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js diff --git a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js new file mode 100644 index 0000000000..1f361656f1 --- /dev/null +++ b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js @@ -0,0 +1,21 @@ +// Chapter 1: fireworksLaunchButtonEntityScript.js + + (function() { + Script.include("../../libraries/utils.js"); + var _this; + Fireworks = function() { + _this = this; + }; + + Fireworks.prototype = { + + preload: function(entityID) { + _this.entityID = entityID; + + } + + }; + + // entity scripts always need to return a newly constructed object of our type + return new Fireworks(); + }); diff --git a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js new file mode 100644 index 0000000000..a4969aa8ed --- /dev/null +++ b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js @@ -0,0 +1,30 @@ + + // Chapter1 : fireworksLaumchButtonSpawner.js + + var orientation = Camera.getOrientation(); + orientation = Quat.safeEulerAngles(orientation); + orientation.x = 0; + orientation = Quat.fromVec3Degrees(orientation); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(orientation))); + + var SCRIPT_URL = Script.resolvePath("fireworksLaunchButtonEntityScript.js"); + var MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Launch-Button.fbx"; + var launchButton = Entities.addEntity({ + type: "Model", + name: "hifi-launch-button", + modelURL: MODEL_URL, + position: center, + dimensions: { + x: 0.98, + y: 1.16, + z: 0.98 + }, + script: SCRIPT_URL, + }) + + + function cleanup() { + Entities.deleteEntity(launchButton); + } + + Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js new file mode 100644 index 0000000000..1f361656f1 --- /dev/null +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js @@ -0,0 +1,21 @@ +// Chapter 1: fireworksLaunchButtonEntityScript.js + + (function() { + Script.include("../../libraries/utils.js"); + var _this; + Fireworks = function() { + _this = this; + }; + + Fireworks.prototype = { + + preload: function(entityID) { + _this.entityID = entityID; + + } + + }; + + // entity scripts always need to return a newly constructed object of our type + return new Fireworks(); + }); diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js new file mode 100644 index 0000000000..a4969aa8ed --- /dev/null +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js @@ -0,0 +1,30 @@ + + // Chapter1 : fireworksLaumchButtonSpawner.js + + var orientation = Camera.getOrientation(); + orientation = Quat.safeEulerAngles(orientation); + orientation.x = 0; + orientation = Quat.fromVec3Degrees(orientation); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(orientation))); + + var SCRIPT_URL = Script.resolvePath("fireworksLaunchButtonEntityScript.js"); + var MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Launch-Button.fbx"; + var launchButton = Entities.addEntity({ + type: "Model", + name: "hifi-launch-button", + modelURL: MODEL_URL, + position: center, + dimensions: { + x: 0.98, + y: 1.16, + z: 0.98 + }, + script: SCRIPT_URL, + }) + + + function cleanup() { + Entities.deleteEntity(launchButton); + } + + Script.scriptEnding.connect(cleanup); \ No newline at end of file From 5a3f74d51bc8861e14cf054c8e98f566eb86874a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 09:53:10 +1300 Subject: [PATCH 181/292] Style drop-down combo box for Developer > Graphics... --- .../resources/qml/controls-uit/ComboBox.qml | 98 +++++++++++++++++++ .../preferences/ComboBoxPreference.qml | 43 ++++---- .../qml/styles-uit/HifiConstants.qml | 6 ++ 3 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 interface/resources/qml/controls-uit/ComboBox.qml diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml new file mode 100644 index 0000000000..dcac1264ec --- /dev/null +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -0,0 +1,98 @@ +// +// ComboBox.qml +// +// Created by David Rowe on 27 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" +import "../controls-uit" as HifiControls + +// FIXME: Currently supports only the "Drop Down Box" case in the UI Toolkit doc; +// Should either be made to also support the "Combo Box" case or drop-down and combo box should be separate controls. + +// FIXME: Style dropped-down items per UI Toolkit Drop Down Box. +// http://stackoverflow.com/questions/27089779/qml-combobox-item-dropdownmenu-style/27217209#27217209 + +ComboBox { + id: comboBox + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property string label: "" + property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height : 0) + + height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. + + y: comboBoxLabel.visible ? comboBoxLabel.height : 0 + + style: ComboBoxStyle { + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font { + family: firaSansSemiBold.name + pixelSize: hifi.fontSizes.textFieldInput + } + + background: Rectangle { + gradient: Gradient { + GradientStop { + position: 0.2 + color: pressed + ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + : (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart) + } + GradientStop { + position: 1.0 + color: pressed + ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + : (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish) + } + } + + HiFiGlyphs { + text: hifi.glyphs.backward // Adapt backward triangle to be downward triangle + rotation: -90 + y: -2 + size: hifi.dimensions.spinnerSize + color: pressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.baseGray + anchors { + right: parent.right + rightMargin: 3 + verticalCenter: parent.verticalCenter + } + } + + Rectangle { + width: 1 + height: parent.height + color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray + anchors { + top: parent.top + right: parent.right + rightMargin: parent.height + } + } + } + + textColor: pressed ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText ) + selectedTextColor: hifi.colors.baseGray + selectionColor: hifi.colors.primaryHighlight + } + + HifiControls.Label { + id: comboBoxLabel + text: comboBox.label + colorScheme: comboBox.colorScheme + anchors.left: parent.left + anchors.bottom: parent.top + anchors.bottomMargin: 4 + visible: label != "" + } +} diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index 9f323ace63..be5c017bbd 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -1,37 +1,42 @@ +// +// ComboBoxPreference.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 + +import "../../controls-uit" Preference { id: root - property real spacing: 8 - height: labelText.height + dataComboBox.height + spacing + property alias comboBox: comboBox + height: comboBox.controlHeight Component.onCompleted: { - dataComboBox.currentIndex = dataComboBox.find(preference.value); + comboBox.currentIndex = comboBox.find(preference.value); } function save() { - preference.value = dataComboBox.currentText; + preference.value = comboBox.currentText; preference.save(); } - Text { - id: labelText - color: enabled ? "black" : "gray" - text: root.label + Label { + text: root.label + ":" + colorScheme: hifi.colorSchemes.dark + anchors.verticalCenter: comboBox.verticalCenter } ComboBox { - id: dataComboBox + id: comboBox model: preference.items - style: ComboBoxStyle { renderType: Text.QtRendering } - anchors { - top: labelText.bottom - left: parent.left - right: parent.right - topMargin: root.spacing - rightMargin: root.spacing - } + width: 150 + anchors { right: parent.right } + colorScheme: hifi.colorSchemes.dark } } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index d74ba48f29..5e377d9e91 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -77,6 +77,12 @@ Item { readonly property color sliderLightFinish: "#afafaf" readonly property color sliderDarkStart: "#7d7d7d" readonly property color sliderDarkFinish: "#6b6a6b" + readonly property color dropDownPressedLight: "#d4d4d4" + readonly property color dropDownPressedDark: "#afafaf" + readonly property color dropDownLightStart: "#ffffff" + readonly property color dropDownLightFinish: "#afafaf" + readonly property color dropDownDarkStart: "#7d7d7d" + readonly property color dropDownDarkFinish: "#6b6a6b" } Item { From f44cf3903c1d5c9b962db4923d139429bb82311c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Feb 2016 17:09:13 -0800 Subject: [PATCH 182/292] re-instate verified domain ownership for full automatic networking This reverts commit 34408c8144a7797012a705f8fdde9c2de085e8cc. --- assignment-client/src/octree/OctreeServer.cpp | 4 - .../resources/web/settings/js/settings.js | 2 +- domain-server/src/DomainGatekeeper.cpp | 1 - domain-server/src/DomainServer.cpp | 167 ++++++--- domain-server/src/DomainServer.h | 6 +- ice-server/CMakeLists.txt | 14 + ice-server/src/IceServer.cpp | 161 ++++++-- ice-server/src/IceServer.h | 14 +- interface/src/Application.cpp | 51 +-- interface/src/Application.h | 5 - interface/src/CrashHandler.cpp | 36 +- interface/src/CrashHandler.h | 2 +- .../scripting/WindowScriptingInterface.cpp | 2 +- libraries/networking/src/AccountManager.cpp | 353 +++++++++++++----- libraries/networking/src/AccountManager.h | 29 +- .../networking/src/DataServerAccountInfo.cpp | 102 +++-- .../networking/src/DataServerAccountInfo.h | 20 +- libraries/networking/src/DomainHandler.cpp | 39 +- libraries/networking/src/DomainHandler.h | 7 + libraries/networking/src/LimitedNodeList.cpp | 4 - libraries/networking/src/LimitedNodeList.h | 2 +- libraries/networking/src/NodeList.cpp | 54 ++- .../networking/src/RSAKeypairGenerator.cpp | 6 +- .../networking/src/RSAKeypairGenerator.h | 20 +- .../networking/src/udt/PacketHeaders.cpp | 4 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- 26 files changed, 752 insertions(+), 356 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 31cab68cdf..aedf451924 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -236,10 +236,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) : { _averageLoopTime.updateAverage(0); qDebug() << "Octree server starting... [" << this << "]"; - - // make sure the AccountManager has an Auth URL for payment redemptions - - AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); } OctreeServer::~OctreeServer() { diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 7dc94421be..fae07ace45 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -778,7 +778,7 @@ function chooseFromHighFidelityDomains(clickedButton) { function createTemporaryDomain() { swal({ title: 'Create temporary place name', - text: "This will create a temporary place name and domain ID (valid for 30 days)" + text: "This will create a temporary place name and domain ID" + " so other users can easily connect to your domain.

" + "In order to make your domain reachable, this will also enable full automatic networking.", showCancelButton: true, diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 3e4ee7b758..f385f5c489 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -331,7 +331,6 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, QCryptographicHash::Sha256); if (rsaPublicKey) { - QByteArray decryptedArray(RSA_size(rsaPublicKey), 0); int decryptResult = RSA_verify(NID_sha256, reinterpret_cast(usernameWithToken.constData()), usernameWithToken.size(), diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9e13c8e6fa..f0df67a6f6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -96,7 +96,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : // make sure we hear about newly connected nodes from our gatekeeper connect(&_gatekeeper, &DomainGatekeeper::connectedNode, this, &DomainServer::handleConnectedNode); - if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth() && optionallySetupAssignmentPayment()) { + if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth()) { // we either read a certificate and private key or were not passed one // and completed login or did not need to @@ -198,7 +198,6 @@ bool DomainServer::optionallySetupOAuth() { } AccountManager& accountManager = AccountManager::getInstance(); - accountManager.disableSettingsFilePersistence(); accountManager.setAuthURL(_oauthProviderURL); _oauthClientID = settingsMap.value(OAUTH_CLIENT_ID_OPTION).toString(); @@ -372,20 +371,12 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { packetReceiver.registerListener(PacketType::ICEPing, &_gatekeeper, "processICEPingPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, &_gatekeeper, "processICEPingReplyPacket"); packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_gatekeeper, "processICEPeerInformationPacket"); + packetReceiver.registerListener(PacketType::ICEServerHeartbeatDenied, this, "processICEServerHeartbeatDenialPacket"); // add whatever static assignments that have been parsed to the queue addStaticAssignmentsToQueue(); } -bool DomainServer::didSetupAccountManagerWithAccessToken() { - if (AccountManager::getInstance().hasValidAccessToken()) { - // we already gave the account manager a valid access token - return true; - } - - return resetAccountManagerAccessToken(); -} - const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token"; bool DomainServer::resetAccountManagerAccessToken() { @@ -401,9 +392,13 @@ bool DomainServer::resetAccountManagerAccessToken() { if (accessTokenVariant && accessTokenVariant->canConvert(QMetaType::QString)) { accessToken = accessTokenVariant->toString(); } else { - qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present." - << "Set an access token via the web interface, in your user or master config" + qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present."; + qDebug() << "Set an access token via the web interface, in your user or master config" << "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN"; + + // clear any existing access token from AccountManager + AccountManager::getInstance().setAccessTokenForCurrentAuthURL(QString()); + return false; } } else { @@ -429,34 +424,6 @@ bool DomainServer::resetAccountManagerAccessToken() { } } -bool DomainServer::optionallySetupAssignmentPayment() { - const QString PAY_FOR_ASSIGNMENTS_OPTION = "pay-for-assignments"; - const QVariantMap& settingsMap = _settingsManager.getSettingsMap(); - - if (settingsMap.contains(PAY_FOR_ASSIGNMENTS_OPTION) && - settingsMap.value(PAY_FOR_ASSIGNMENTS_OPTION).toBool() && - didSetupAccountManagerWithAccessToken()) { - - qDebug() << "Assignments will be paid for via" << qPrintable(_oauthProviderURL.toString()); - - // assume that the fact we are authing against HF data server means we will pay for assignments - // setup a timer to send transactions to pay assigned nodes every 30 seconds - QTimer* creditSetupTimer = new QTimer(this); - connect(creditSetupTimer, &QTimer::timeout, this, &DomainServer::setupPendingAssignmentCredits); - - const qint64 CREDIT_CHECK_INTERVAL_MSECS = 5 * 1000; - creditSetupTimer->start(CREDIT_CHECK_INTERVAL_MSECS); - - QTimer* nodePaymentTimer = new QTimer(this); - connect(nodePaymentTimer, &QTimer::timeout, this, &DomainServer::sendPendingTransactionsToServer); - - const qint64 TRANSACTION_SEND_INTERVAL_MSECS = 30 * 1000; - nodePaymentTimer->start(TRANSACTION_SEND_INTERVAL_MSECS); - } - - return true; -} - void DomainServer::setupAutomaticNetworking() { auto nodeList = DependencyManager::get(); @@ -467,9 +434,9 @@ void DomainServer::setupAutomaticNetworking() { setupICEHeartbeatForFullNetworking(); } - if (!didSetupAccountManagerWithAccessToken()) { - qDebug() << "Cannot send heartbeat to data server without an access token."; - qDebug() << "Add an access token to your config file or via the web interface."; + if (!resetAccountManagerAccessToken()) { + qDebug() << "Will not send heartbeat to Metaverse API without an access token."; + qDebug() << "If this is not a temporary domain add an access token to your config file or via the web interface."; return; } @@ -526,6 +493,19 @@ void DomainServer::setupICEHeartbeatForFullNetworking() { // we need this DS to know what our public IP is - start trying to figure that out now limitedNodeList->startSTUNPublicSocketUpdate(); + // to send ICE heartbeats we'd better have a private key locally with an uploaded public key + auto& accountManager = AccountManager::getInstance(); + auto domainID = accountManager.getAccountInfo().getDomainID(); + + // if we have an access token and we don't have a private key or the current domain ID has changed + // we should generate a new keypair + if (!accountManager.getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) { + accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID()); + } + + // hookup to the signal from account manager that tells us when keypair is available + connect(&accountManager, &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange); + if (!_iceHeartbeatTimer) { // setup a timer to heartbeat with the ice-server every so often _iceHeartbeatTimer = new QTimer { this }; @@ -1082,11 +1062,76 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) { domainUpdateJSON.toUtf8()); } -// TODO: have data-web respond with ice-server hostname to use - void DomainServer::sendHeartbeatToIceServer() { if (!_iceServerSocket.getAddress().isNull()) { - DependencyManager::get()->sendHeartbeatToIceServer(_iceServerSocket); + + auto& accountManager = AccountManager::getInstance(); + auto limitedNodeList = DependencyManager::get(); + + if (!accountManager.getAccountInfo().hasPrivateKey()) { + qWarning() << "Cannot send an ice-server heartbeat without a private key for signature."; + qWarning() << "Waiting for keypair generation to complete before sending ICE heartbeat."; + + if (!limitedNodeList->getSessionUUID().isNull()) { + accountManager.generateNewDomainKeypair(limitedNodeList->getSessionUUID()); + } else { + qWarning() << "Attempting to send ICE server heartbeat with no domain ID. This is not supported"; + } + + return; + } + + // NOTE: I'd love to specify the correct size for the packet here, but it's a little trickey with + // QDataStream and the possibility of IPv6 address for the sockets. + if (!_iceServerHeartbeatPacket) { + _iceServerHeartbeatPacket = NLPacket::create(PacketType::ICEServerHeartbeat); + } + + bool shouldRecreatePacket = false; + + if (_iceServerHeartbeatPacket->getPayloadSize() > 0) { + // if either of our sockets have changed we need to re-sign the heartbeat + // first read the sockets out from the current packet + _iceServerHeartbeatPacket->seek(0); + QDataStream heartbeatStream(_iceServerHeartbeatPacket.get()); + + QUuid senderUUID; + HifiSockAddr publicSocket, localSocket; + heartbeatStream >> senderUUID >> publicSocket >> localSocket; + + if (senderUUID != limitedNodeList->getSessionUUID() + || publicSocket != limitedNodeList->getPublicSockAddr() + || localSocket != limitedNodeList->getLocalSockAddr()) { + shouldRecreatePacket = true; + } + } else { + shouldRecreatePacket = true; + } + + if (shouldRecreatePacket) { + // either we don't have a heartbeat packet yet or some combination of sockets, ID and keypair have changed + // and we need to make a new one + + // reset the position in the packet before writing + _iceServerHeartbeatPacket->reset(); + + // write our plaintext data to the packet + QDataStream heartbeatDataStream(_iceServerHeartbeatPacket.get()); + heartbeatDataStream << limitedNodeList->getSessionUUID() + << limitedNodeList->getPublicSockAddr() << limitedNodeList->getLocalSockAddr(); + + // setup a QByteArray that points to the plaintext data + auto plaintext = QByteArray::fromRawData(_iceServerHeartbeatPacket->getPayload(), _iceServerHeartbeatPacket->getPayloadSize()); + + // generate a signature for the plaintext data in the packet + auto signature = accountManager.getAccountInfo().signPlaintext(plaintext); + + // pack the signature with the data + heartbeatDataStream << signature; + } + + // send the heartbeat packet to the ice server now + limitedNodeList->sendUnreliablePacket(*_iceServerHeartbeatPacket, _iceServerSocket); } } @@ -1970,3 +2015,31 @@ void DomainServer::processNodeDisconnectRequestPacket(QSharedPointer message) { + static const int NUM_HEARTBEAT_DENIALS_FOR_KEYPAIR_REGEN = 3; + + static int numHeartbeatDenials = 0; + if (++numHeartbeatDenials > NUM_HEARTBEAT_DENIALS_FOR_KEYPAIR_REGEN) { + qDebug() << "Received" << NUM_HEARTBEAT_DENIALS_FOR_KEYPAIR_REGEN << "heartbeat denials from ice-server" + << "- re-generating keypair now"; + + // we've hit our threshold of heartbeat denials, trigger a keypair re-generation + auto limitedNodeList = DependencyManager::get(); + AccountManager::getInstance().generateNewDomainKeypair(limitedNodeList->getSessionUUID()); + + // reset our number of heartbeat denials + numHeartbeatDenials = 0; + } +} + +void DomainServer::handleKeypairChange() { + if (_iceServerHeartbeatPacket) { + // reset the payload size of the ice-server heartbeat packet - this causes the packet to be re-generated + // the next time we go to send an ice-server heartbeat + _iceServerHeartbeatPacket->setPayloadSize(0); + + // send a heartbeat to the ice server immediately + sendHeartbeatToIceServer(); + } +} diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 326ca3e1a8..3a83e8696b 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -61,6 +61,7 @@ public slots: void processNodeJSONStatsPacket(QSharedPointer packetList, SharedNodePointer sendingNode); void processPathQueryPacket(QSharedPointer packet); void processNodeDisconnectRequestPacket(QSharedPointer message); + void processICEServerHeartbeatDenialPacket(QSharedPointer message); private slots: void aboutToQuit(); @@ -78,16 +79,16 @@ private slots: void handleTempDomainError(QNetworkReply& requestReply); void queuedQuit(QString quitMessage, int exitCode); + + void handleKeypairChange(); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); - bool optionallySetupAssignmentPayment(); void optionallyGetTemporaryName(const QStringList& arguments); - bool didSetupAccountManagerWithAccessToken(); bool resetAccountManagerAccessToken(); void setupAutomaticNetworking(); @@ -153,6 +154,7 @@ private: DomainServerSettingsManager _settingsManager; HifiSockAddr _iceServerSocket; + std::unique_ptr _iceServerHeartbeatPacket; QTimer* _iceHeartbeatTimer { nullptr }; // this looks like it dangles when created but it's parented to the DomainServer diff --git a/ice-server/CMakeLists.txt b/ice-server/CMakeLists.txt index cfec3c966c..e5bdffe2e2 100644 --- a/ice-server/CMakeLists.txt +++ b/ice-server/CMakeLists.txt @@ -6,3 +6,17 @@ setup_hifi_project(Network) # link the shared hifi libraries link_hifi_libraries(embedded-webserver networking shared) package_libraries_for_deployment() + +# find OpenSSL +find_package(OpenSSL REQUIRED) + +if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include") + # this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto + message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings." + "\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.") +endif () + +include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") + +# append OpenSSL to our list of libraries to link +target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES}) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 2baa7a13a7..f38923b873 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -9,14 +9,21 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include "IceServer.h" + +#include +#include + +#include +#include +#include +#include #include +#include #include #include -#include "IceServer.h" - const int CLEAR_INACTIVE_PEERS_INTERVAL_MSECS = 1 * 1000; const int PEER_SILENCE_THRESHOLD_MSECS = 5 * 1000; @@ -45,7 +52,6 @@ IceServer::IceServer(int argc, char* argv[]) : QTimer* inactivePeerTimer = new QTimer(this); connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers); inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS); - } bool IceServer::packetVersionMatch(const udt::Packet& packet) { @@ -70,9 +76,14 @@ void IceServer::processPacket(std::unique_ptr packet) { if (nlPacket->getType() == PacketType::ICEServerHeartbeat) { SharedNetworkPeer peer = addOrUpdateHeartbeatingPeer(*nlPacket); - - // so that we can send packets to the heartbeating peer when we need, we need to activate a socket now - peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr()); + if (peer) { + // so that we can send packets to the heartbeating peer when we need, we need to activate a socket now + peer->activateMatchingOrNewSymmetricSocket(nlPacket->getSenderSockAddr()); + } else { + // we couldn't verify this peer - respond back to them so they know they may need to perform keypair re-generation + static auto deniedPacket = NLPacket::create(PacketType::ICEServerHeartbeatDenied); + _serverSocket.writePacket(*deniedPacket, nlPacket->getSenderSockAddr()); + } } else if (nlPacket->getType() == PacketType::ICEServerQuery) { QDataStream heartbeatStream(nlPacket.get()); @@ -114,31 +125,135 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(NLPacket& packet) { // pull the UUID, public and private sock addrs for this peer QUuid senderUUID; HifiSockAddr publicSocket, localSocket; + QByteArray signature; QDataStream heartbeatStream(&packet); - - heartbeatStream >> senderUUID; - heartbeatStream >> publicSocket >> localSocket; + heartbeatStream >> senderUUID >> publicSocket >> localSocket; - // make sure we have this sender in our peer hash - SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID); + auto signedPlaintext = QByteArray::fromRawData(packet.getPayload(), heartbeatStream.device()->pos()); + heartbeatStream >> signature; - if (!matchingPeer) { - // if we don't have this sender we need to create them now - matchingPeer = QSharedPointer::create(senderUUID, publicSocket, localSocket); - _activePeers.insert(senderUUID, matchingPeer); + // make sure this is a verified heartbeat before performing any more processing + if (isVerifiedHeartbeat(senderUUID, signedPlaintext, signature)) { + // make sure we have this sender in our peer hash + SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID); - qDebug() << "Added a new network peer" << *matchingPeer; + if (!matchingPeer) { + // if we don't have this sender we need to create them now + matchingPeer = QSharedPointer::create(senderUUID, publicSocket, localSocket); + _activePeers.insert(senderUUID, matchingPeer); + + qDebug() << "Added a new network peer" << *matchingPeer; + } else { + // we already had the peer so just potentially update their sockets + matchingPeer->setPublicSocket(publicSocket); + matchingPeer->setLocalSocket(localSocket); + } + + // update our last heard microstamp for this network peer to now + matchingPeer->setLastHeardMicrostamp(usecTimestampNow()); + + return matchingPeer; } else { - // we already had the peer so just potentially update their sockets - matchingPeer->setPublicSocket(publicSocket); - matchingPeer->setLocalSocket(localSocket); + // not verified, return the empty peer object + return SharedNetworkPeer(); + } +} + +bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature) { + // check if we have a private key for this domain ID - if we do not then fire off the request for it + auto it = _domainPublicKeys.find(domainID); + if (it != _domainPublicKeys.end()) { + + // attempt to verify the signature for this heartbeat + const unsigned char* publicKeyData = reinterpret_cast(it->second.constData()); + + // first load up the public key into an RSA struct + RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, it->second.size()); + + if (rsaPublicKey) { + auto hashedPlaintext = QCryptographicHash::hash(plaintext, QCryptographicHash::Sha256); + int verificationResult = RSA_verify(NID_sha256, + reinterpret_cast(hashedPlaintext.constData()), + hashedPlaintext.size(), + reinterpret_cast(signature.constData()), + signature.size(), + rsaPublicKey); + + // free up the public key and remove connection token before we return + RSA_free(rsaPublicKey); + + if (verificationResult == 1) { + // this is the only success case - we return true here to indicate that the heartbeat is verified + return true; + } else { + qDebug() << "Failed to verify heartbeat for" << domainID << "- re-requesting public key from API."; + } + + } else { + // we can't let this user in since we couldn't convert their public key to an RSA key we could use + qWarning() << "Could not convert in-memory public key for" << domainID << "to usable RSA public key."; + qWarning() << "Re-requesting public key from API"; + } } - // update our last heard microstamp for this network peer to now - matchingPeer->setLastHeardMicrostamp(usecTimestampNow()); + // we could not verify this heartbeat (missing public key, could not load public key, bad actor) + // ask the metaverse API for the right public key and return false to indicate that this is not verified + requestDomainPublicKey(domainID); - return matchingPeer; + return false; +} + +void IceServer::requestDomainPublicKey(const QUuid& domainID) { + // send a request to the metaverse API for the public key for this domain + QNetworkAccessManager* manager = new QNetworkAccessManager { this }; + connect(manager, &QNetworkAccessManager::finished, this, &IceServer::publicKeyReplyFinished); + + QUrl publicKeyURL { NetworkingConstants::METAVERSE_SERVER_URL }; + QString publicKeyPath = QString("/api/v1/domains/%1/public_key").arg(uuidStringWithoutCurlyBraces(domainID)); + publicKeyURL.setPath(publicKeyPath); + + QNetworkRequest publicKeyRequest { publicKeyURL }; + publicKeyRequest.setAttribute(QNetworkRequest::User, domainID); + + qDebug() << "Requesting public key for domain with ID" << domainID; + + manager->get(publicKeyRequest); +} + +void IceServer::publicKeyReplyFinished(QNetworkReply* reply) { + // get the domain ID from the QNetworkReply attribute + QUuid domainID = reply->request().attribute(QNetworkRequest::User).toUuid(); + + if (reply->error() == QNetworkReply::NoError) { + // pull out the public key and store it for this domain + + // the response should be JSON + QJsonDocument responseDocument = QJsonDocument::fromJson(reply->readAll()); + + static const QString DATA_KEY = "data"; + static const QString PUBLIC_KEY_KEY = "public_key"; + static const QString STATUS_KEY = "status"; + static const QString SUCCESS_VALUE = "success"; + + auto responseObject = responseDocument.object(); + if (responseObject[STATUS_KEY].toString() == SUCCESS_VALUE) { + auto dataObject = responseObject[DATA_KEY].toObject(); + if (dataObject.contains(PUBLIC_KEY_KEY)) { + _domainPublicKeys[domainID] = QByteArray::fromBase64(dataObject[PUBLIC_KEY_KEY].toString().toUtf8()); + } else { + qWarning() << "There was no public key present in response for domain with ID" << domainID; + } + } else { + qWarning() << "The metaverse API did not return success for public key request for domain with ID" << domainID; + } + + } else { + // there was a problem getting the public key for the domain + // log it since it will be re-requested on the next heartbeat + + qWarning() << "Error retreiving public key for domain with ID" << domainID << "-" << reply->errorString(); + } } void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) { diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index f1c2c06b65..81234b2c3c 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -16,13 +16,15 @@ #include #include +#include + #include #include #include #include #include -typedef QHash NetworkPeerHash; +class QNetworkReply; class IceServer : public QCoreApplication, public HTTPRequestHandler { Q_OBJECT @@ -31,6 +33,7 @@ public: bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false); private slots: void clearInactivePeers(); + void publicKeyReplyFinished(QNetworkReply* reply); private: bool packetVersionMatch(const udt::Packet& packet); void processPacket(std::unique_ptr packet); @@ -38,10 +41,19 @@ private: SharedNetworkPeer addOrUpdateHeartbeatingPeer(NLPacket& incomingPacket); void sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr); + bool isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature); + void requestDomainPublicKey(const QUuid& domainID); + QUuid _id; udt::Socket _serverSocket; + + using NetworkPeerHash = QHash; NetworkPeerHash _activePeers; + HTTPManager _httpManager; + + using DomainPublicKeyHash = std::unordered_map; + DomainPublicKeyHash _domainPublicKeys; }; #endif // hifi_IceServer_h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 244a0a82cf..fe1e0bbbcd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -544,7 +544,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); - connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; @@ -581,6 +580,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle); // set the account manager's root URL and trigger a login request if we don't have the access token + accountManager.setIsAgent(true); accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); UserActivityLogger::getInstance().launch(applicationVersion()); @@ -889,9 +889,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : SpacemouseManager::getInstance().init(); #endif - auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket"); - // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, @@ -3955,29 +3952,10 @@ void Application::clearDomainOctreeDetails() { void Application::domainChanged(const QString& domainHostname) { updateWindowTitle(); clearDomainOctreeDetails(); - _domainConnectionRefusals.clear(); // disable physics until we have enough information about our new location to not cause craziness. _physicsEnabled = false; } -void Application::handleDomainConnectionDeniedPacket(QSharedPointer message) { - // Read deny reason from packet - quint16 reasonSize; - message->readPrimitive(&reasonSize); - QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize)); - - // output to the log so the user knows they got a denied connection request - // and check and signal for an access token so that we can make sure they are logged in - qCDebug(interfaceapp) << "The domain-server denied a connection request: " << reason; - qCDebug(interfaceapp) << "You may need to re-log to generate a keypair so you can provide a username signature."; - - if (!_domainConnectionRefusals.contains(reason)) { - _domainConnectionRefusals.append(reason); - emit domainConnectionRefused(reason); - } - - AccountManager::getInstance().checkAndSignalForAccessToken(); -} void Application::resettingDomain() { _notifiedPacketVersionMismatchThisDomain = false; @@ -4517,33 +4495,6 @@ void Application::openUrl(const QUrl& url) { } } -void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject) { - // from the domain-handler, figure out the satoshi cost per voxel and per meter cubed - const QString VOXEL_SETTINGS_KEY = "voxels"; - const QString PER_VOXEL_COST_KEY = "per-voxel-credits"; - const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits"; - const QString VOXEL_WALLET_UUID = "voxel-wallet"; - - const QJsonObject& voxelObject = domainSettingsObject[VOXEL_SETTINGS_KEY].toObject(); - - qint64 satoshisPerVoxel = 0; - qint64 satoshisPerMeterCubed = 0; - QUuid voxelWalletUUID; - - if (!domainSettingsObject.isEmpty()) { - float perVoxelCredits = (float) voxelObject[PER_VOXEL_COST_KEY].toDouble(); - float perMeterCubedCredits = (float) voxelObject[PER_METER_CUBED_COST_KEY].toDouble(); - - satoshisPerVoxel = (qint64) floorf(perVoxelCredits * SATOSHIS_PER_CREDIT); - satoshisPerMeterCubed = (qint64) floorf(perMeterCubedCredits * SATOSHIS_PER_CREDIT); - - voxelWalletUUID = QUuid(voxelObject[VOXEL_WALLET_UUID].toString()); - } - - qCDebug(interfaceapp) << "Octree edits costs are" << satoshisPerVoxel << "per octree cell and" << satoshisPerMeterCubed << "per meter cubed"; - qCDebug(interfaceapp) << "Destination wallet UUID for edit payments is" << voxelWalletUUID; -} - void Application::loadDialog() { auto scriptEngines = DependencyManager::get(); QString fileNameString = OffscreenUi::getOpenFileName( diff --git a/interface/src/Application.h b/interface/src/Application.h index 852e3e86a6..c16175a333 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -227,7 +227,6 @@ signals: void svoImportRequested(const QString& url); void checkBackgroundDownloads(); - void domainConnectionRefused(const QString& reason); void fullAvatarURLChanged(const QString& newValue, const QString& modelName); @@ -297,9 +296,6 @@ private slots: void activeChanged(Qt::ApplicationState state); - void domainSettingsReceived(const QJsonObject& domainSettingsObject); - void handleDomainConnectionDeniedPacket(QSharedPointer message); - void notifyPacketVersionMismatch(); void loadSettings(); @@ -476,7 +472,6 @@ private: typedef bool (Application::* AcceptURLMethod)(const QString &); static const QHash _acceptedExtensions; - QList _domainConnectionRefusals; glm::uvec2 _renderResolution; int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS; diff --git a/interface/src/CrashHandler.cpp b/interface/src/CrashHandler.cpp index ce5facb580..f9cd7679ae 100644 --- a/interface/src/CrashHandler.cpp +++ b/interface/src/CrashHandler.cpp @@ -22,11 +22,8 @@ #include #include -#include "DataServerAccountInfo.h" #include "Menu.h" -Q_DECLARE_METATYPE(DataServerAccountInfo) - static const QString RUNNING_MARKER_FILENAME = "Interface.running"; void CrashHandler::checkForAndHandleCrash() { @@ -57,7 +54,7 @@ CrashHandler::Action CrashHandler::promptUserForAction() { layout->addWidget(label); QRadioButton* option1 = new QRadioButton("Reset all my settings"); - QRadioButton* option2 = new QRadioButton("Reset my settings but retain login and avatar info."); + QRadioButton* option2 = new QRadioButton("Reset my settings but retain avatar info."); QRadioButton* option3 = new QRadioButton("Continue with my current settings"); option3->setChecked(true); layout->addWidget(option1); @@ -79,7 +76,7 @@ CrashHandler::Action CrashHandler::promptUserForAction() { return CrashHandler::DELETE_INTERFACE_INI; } if (option2->isChecked()) { - return CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO; + return CrashHandler::RETAIN_AVATAR_INFO; } } @@ -88,7 +85,7 @@ CrashHandler::Action CrashHandler::promptUserForAction() { } void CrashHandler::handleCrash(CrashHandler::Action action) { - if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO) { + if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_AVATAR_INFO) { // CrashHandler::DO_NOTHING or unexpected value return; } @@ -101,18 +98,13 @@ void CrashHandler::handleCrash(CrashHandler::Action action) { const QString DISPLAY_NAME_KEY = "displayName"; const QString FULL_AVATAR_URL_KEY = "fullAvatarURL"; const QString FULL_AVATAR_MODEL_NAME_KEY = "fullAvatarModelName"; - const QString ACCOUNTS_GROUP = "accounts"; QString displayName; QUrl fullAvatarURL; QString fullAvatarModelName; QUrl address; - QMap accounts; - if (action == CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO) { - // Read login and avatar info - - qRegisterMetaType("DataServerAccountInfo"); - qRegisterMetaTypeStreamOperators("DataServerAccountInfo"); + if (action == CrashHandler::RETAIN_AVATAR_INFO) { + // Read avatar info // Location and orientation settings.beginGroup(ADDRESS_MANAGER_GROUP); @@ -125,13 +117,6 @@ void CrashHandler::handleCrash(CrashHandler::Action action) { fullAvatarURL = settings.value(FULL_AVATAR_URL_KEY).toUrl(); fullAvatarModelName = settings.value(FULL_AVATAR_MODEL_NAME_KEY).toString(); settings.endGroup(); - - // Accounts - settings.beginGroup(ACCOUNTS_GROUP); - foreach(const QString& key, settings.allKeys()) { - accounts.insert(key, settings.value(key).value()); - } - settings.endGroup(); } // Delete Interface.ini @@ -140,8 +125,8 @@ void CrashHandler::handleCrash(CrashHandler::Action action) { settingsFile.remove(); } - if (action == CrashHandler::RETAIN_LOGIN_AND_AVATAR_INFO) { - // Write login and avatar info + if (action == CrashHandler::RETAIN_AVATAR_INFO) { + // Write avatar info // Location and orientation settings.beginGroup(ADDRESS_MANAGER_GROUP); @@ -154,13 +139,6 @@ void CrashHandler::handleCrash(CrashHandler::Action action) { settings.setValue(FULL_AVATAR_URL_KEY, fullAvatarURL); settings.setValue(FULL_AVATAR_MODEL_NAME_KEY, fullAvatarModelName); settings.endGroup(); - - // Accounts - settings.beginGroup(ACCOUNTS_GROUP); - foreach(const QString& key, accounts.keys()) { - settings.setValue(key, QVariant::fromValue(accounts.value(key))); - } - settings.endGroup(); } } diff --git a/interface/src/CrashHandler.h b/interface/src/CrashHandler.h index fc754cf1ac..61361b6107 100644 --- a/interface/src/CrashHandler.h +++ b/interface/src/CrashHandler.h @@ -25,7 +25,7 @@ public: private: enum Action { DELETE_INTERFACE_INI, - RETAIN_LOGIN_AND_AVATAR_INFO, + RETAIN_AVATAR_INFO, DO_NOTHING }; diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index b8c82498a1..4c9c0df1cb 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -25,7 +25,7 @@ WindowScriptingInterface::WindowScriptingInterface() { const DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged); - connect(qApp, &Application::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); + connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); connect(qApp, &Application::svoImportRequested, [this](const QString& urlString) { static const QMetaMethod svoImportRequestedSignal = diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 4ded2216d0..d0838c4a8f 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -12,10 +12,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -60,13 +62,12 @@ JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, co updateReciever(updateReceiver), updateSlot(updateSlot) { + } AccountManager::AccountManager() : _authURL(), - _pendingCallbackMap(), - _accountInfo(), - _shouldPersistToSettingsFile(true) + _pendingCallbackMap() { qRegisterMetaType("OAuthAccessToken"); qRegisterMetaTypeStreamOperators("OAuthAccessToken"); @@ -80,9 +81,6 @@ AccountManager::AccountManager() : qRegisterMetaType("QHttpMultiPart*"); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); - - // once we have a profile in account manager make sure we generate a new keypair - connect(this, &AccountManager::profileChanged, this, &AccountManager::generateNewKeypair); } const QString DOUBLE_SLASH_SUBSTITUTE = "slashslash"; @@ -93,16 +91,9 @@ void AccountManager::logout() { emit balanceChanged(0); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); - - if (_shouldPersistToSettingsFile) { - QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE)); - QStringList path = QStringList() << ACCOUNTS_GROUP << keyURLString; - Setting::Handle(path).remove(); - - qCDebug(networking) << "Removed account info for" << _authURL << "from in-memory accounts and .ini file"; - } else { - qCDebug(networking) << "Cleared data server account info in account manager."; - } + + // remove this account from the account settings file + removeAccountFromFile(); emit logoutComplete(); // the username has changed to blank @@ -124,35 +115,83 @@ void AccountManager::accountInfoBalanceChanged(qint64 newBalance) { emit balanceChanged(newBalance); } +QString accountFilePath() { + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/AccountInfo.bin"; +} + +QVariantMap accountMapFromFile(bool& success) { + QFile accountFile { accountFilePath() }; + + if (accountFile.open(QIODevice::ReadOnly)) { + // grab the current QVariantMap from the settings file + QDataStream readStream(&accountFile); + QVariantMap accountMap; + + readStream >> accountMap; + + // close the file now that we have read the data + accountFile.close(); + + success = true; + + return accountMap; + } else { + // failed to open file, return empty QVariantMap + // there was only an error if the account file existed when we tried to load it + success = !accountFile.exists(); + + return QVariantMap(); + } +} + void AccountManager::setAuthURL(const QUrl& authURL) { if (_authURL != authURL) { _authURL = authURL; qCDebug(networking) << "AccountManager URL for authenticated requests has been changed to" << qPrintable(_authURL.toString()); - if (_shouldPersistToSettingsFile) { + // check if there are existing access tokens to load from settings + QFile accountsFile { accountFilePath() }; + bool loadedMap = false; + auto accountsMap = accountMapFromFile(loadedMap); + + if (accountsFile.exists() && loadedMap) { + // pull out the stored account info and store it in memory + _accountInfo = accountsMap[_authURL.toString()].value(); + + qCDebug(networking) << "Found metaverse API account information for" << qPrintable(_authURL.toString()); + } else { + // we didn't have a file - see if we can migrate old settings and store them in the new file + // check if there are existing access tokens to load from settings Settings settings; settings.beginGroup(ACCOUNTS_GROUP); - + foreach(const QString& key, settings.allKeys()) { // take a key copy to perform the double slash replacement QString keyCopy(key); QUrl keyURL(keyCopy.replace(DOUBLE_SLASH_SUBSTITUTE, "//")); - + if (keyURL == _authURL) { // pull out the stored access token and store it in memory _accountInfo = settings.value(key).value(); - qCDebug(networking) << "Found a data-server access token for" << qPrintable(keyURL.toString()); - - // profile info isn't guaranteed to be saved too - if (_accountInfo.hasProfile()) { - emit profileChanged(); - } else { - requestProfile(); - } + + qCDebug(networking) << "Migrated an access token for" << qPrintable(keyURL.toString()) + << "from previous settings file"; } } + + if (_accountInfo.getAccessToken().token.isEmpty()) { + qCWarning(networking) << "Unable to load account file. No existing account settings will be loaded."; + } else { + // persist the migrated settings to file + persistAccountToFile(); + } + } + + if (_isAgent && !_accountInfo.getAccessToken().token.isEmpty() && !_accountInfo.hasProfile()) { + // we are missing profile information, request it now + requestProfile(); } // tell listeners that the auth endpoint has changed @@ -299,9 +338,11 @@ void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { } else { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { - qCDebug(networking) << "Received JSON response from data-server that has no matching callback."; + qCDebug(networking) << "Received JSON response from metaverse API that has no matching callback."; qCDebug(networking) << QJsonDocument::fromJson(requestReply->readAll()); } + + requestReply->deleteLater(); } } @@ -317,22 +358,69 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { _pendingCallbackMap.remove(requestReply); } else { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { - qCDebug(networking) << "Received error response from data-server that has no matching callback."; + qCDebug(networking) << "Received error response from metaverse API that has no matching callback."; qCDebug(networking) << "Error" << requestReply->error() << "-" << requestReply->errorString(); qCDebug(networking) << requestReply->readAll(); } + + requestReply->deleteLater(); } } -void AccountManager::persistAccountToSettings() { - if (_shouldPersistToSettingsFile) { - // store this access token into the local settings - QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE)); - QStringList path = QStringList() << ACCOUNTS_GROUP << keyURLString; - Setting::Handle(path).set(QVariant::fromValue(_accountInfo)); +bool writeAccountMapToFile(const QVariantMap& accountMap) { + // re-open the file and truncate it + QFile accountFile { accountFilePath() }; + if (accountFile.open(QIODevice::WriteOnly)) { + QDataStream writeStream(&accountFile); + + // persist the updated account QVariantMap to file + writeStream << accountMap; + + // close the file with the newly persisted settings + accountFile.close(); + + return true; + } else { + return false; } } +void AccountManager::persistAccountToFile() { + + qCDebug(networking) << "Persisting AccountManager accounts to" << accountFilePath(); + + bool wasLoaded = false; + auto accountMap = accountMapFromFile(wasLoaded); + + if (wasLoaded) { + // replace the current account information for this auth URL in the account map + accountMap[_authURL.toString()] = QVariant::fromValue(_accountInfo); + + // re-open the file and truncate it + if (writeAccountMapToFile(accountMap)) { + return; + } + } + + qCWarning(networking) << "Could not load accounts file - unable to persist account information to file."; +} + +void AccountManager::removeAccountFromFile() { + bool wasLoaded = false; + auto accountMap = accountMapFromFile(wasLoaded); + + if (wasLoaded) { + accountMap.remove(_authURL.toString()); + if (writeAccountMapToFile(accountMap)) { + qCDebug(networking) << "Removed account info for" << _authURL << "from settings file."; + return; + } + } + + qCWarning(networking) << "Count not load accounts file - unable to remove account information for" << _authURL + << "from settings file."; +} + bool AccountManager::hasValidAccessToken() { if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) { @@ -359,16 +447,19 @@ bool AccountManager::checkAndSignalForAccessToken() { } void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) { - // clear our current DataServerAccountInfo - _accountInfo = DataServerAccountInfo(); - - // start the new account info with a new OAuthAccessToken + // replace the account info access token with a new OAuthAccessToken OAuthAccessToken newOAuthToken; newOAuthToken.token = accessToken; - - qCDebug(networking) << "Setting new account manager access token. F2C:" << accessToken.left(2) << "L2C:" << accessToken.right(2); + + if (!accessToken.isEmpty()) { + qCDebug(networking) << "Setting new AccountManager OAuth token. F2C:" << accessToken.left(2) << "L2C:" << accessToken.right(2); + } else if (!_accountInfo.getAccessToken().token.isEmpty()) { + qCDebug(networking) << "Clearing AccountManager OAuth token."; + } _accountInfo.setAccessToken(newOAuthToken); + + persistAccountToFile(); } void AccountManager::requestAccessToken(const QString& login, const QString& password) { @@ -423,7 +514,7 @@ void AccountManager::requestAccessTokenFinished() { emit loginComplete(rootURL); - persistAccountToSettings(); + persistAccountToFile(); requestProfile(); } @@ -469,7 +560,7 @@ void AccountManager::requestProfileFinished() { emit usernameChanged(_accountInfo.getUsername()); // store the whole profile into the local settings - persistAccountToSettings(); + persistAccountToFile(); } else { // TODO: error handling @@ -482,57 +573,141 @@ void AccountManager::requestProfileError(QNetworkReply::NetworkError error) { qCDebug(networking) << "AccountManager requestProfileError - " << error; } -void AccountManager::generateNewKeypair() { - // setup a new QThread to generate the keypair on, in case it takes a while - QThread* generateThread = new QThread(this); - generateThread->setObjectName("Account Manager Generator Thread"); - - // setup a keypair generator - RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator(); - - connect(generateThread, &QThread::started, keypairGenerator, &RSAKeypairGenerator::generateKeypair); - connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair); - connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, - this, &AccountManager::handleKeypairGenerationError); - connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit); - connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater); - - keypairGenerator->moveToThread(generateThread); - - qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA key-pair."; - generateThread->start(); +void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainID) { + + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "generateNewKeypair", Q_ARG(bool, isUserKeypair), Q_ARG(QUuid, domainID)); + return; + } + + if (!isUserKeypair && domainID.isNull()) { + qCWarning(networking) << "AccountManager::generateNewKeypair called for domain keypair with no domain ID. Will not generate keypair."; + return; + } + + // make sure we don't already have an outbound keypair generation request + if (!_isWaitingForKeypairResponse) { + _isWaitingForKeypairResponse = true; + + // clear the current private key + qDebug() << "Clearing current private key in DataServerAccountInfo"; + _accountInfo.setPrivateKey(QByteArray()); + + // setup a new QThread to generate the keypair on, in case it takes a while + QThread* generateThread = new QThread(this); + generateThread->setObjectName("Account Manager Generator Thread"); + + // setup a keypair generator + RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator; + + if (!isUserKeypair) { + keypairGenerator->setDomainID(domainID); + _accountInfo.setDomainID(domainID); + } + + // start keypair generation when the thread starts + connect(generateThread, &QThread::started, keypairGenerator, &RSAKeypairGenerator::generateKeypair); + + // handle success or failure of keypair generation + connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair); + connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, + this, &AccountManager::handleKeypairGenerationError); + + connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit); + connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater); + + keypairGenerator->moveToThread(generateThread); + + qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair."; + generateThread->start(); + } } -void AccountManager::processGeneratedKeypair(const QByteArray& publicKey, const QByteArray& privateKey) { +void AccountManager::processGeneratedKeypair() { - qCDebug(networking) << "Generated 2048-bit RSA key-pair. Storing private key and uploading public key."; - - // set the private key on our data-server account info - _accountInfo.setPrivateKey(privateKey); - persistAccountToSettings(); - - // upload the public key so data-web has an up-to-date key - const QString PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key"; - - // setup a multipart upload to send up the public key - QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); - - QHttpPart keyPart; - keyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); - keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, - QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); - keyPart.setBody(publicKey); - - requestMultiPart->append(keyPart); - - sendRequest(PUBLIC_KEY_UPDATE_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QByteArray(), requestMultiPart); - - // get rid of the keypair generator now that we don't need it anymore - sender()->deleteLater(); + qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now."; + + RSAKeypairGenerator* keypairGenerator = qobject_cast(sender()); + + if (keypairGenerator) { + // hold the private key to later set our metaverse API account info if upload succeeds + _pendingPrivateKey = keypairGenerator->getPrivateKey(); + + // upload the public key so data-web has an up-to-date key + const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key"; + const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key"; + + QString uploadPath; + if (keypairGenerator->getDomainID().isNull()) { + uploadPath = USER_PUBLIC_KEY_UPDATE_PATH; + } else { + uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(keypairGenerator->getDomainID())); + } + + // setup a multipart upload to send up the public key + QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + + QHttpPart keyPart; + keyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); + keyPart.setBody(keypairGenerator->getPublicKey()); + + requestMultiPart->append(keyPart); + + // setup callback parameters so we know once the keypair upload has succeeded or failed + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded"; + callbackParameters.errorCallbackReceiver = this; + callbackParameters.errorCallbackMethod = "publicKeyUploadFailed"; + + sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, + callbackParameters, QByteArray(), requestMultiPart); + + keypairGenerator->deleteLater(); + } else { + qCWarning(networking) << "Expected processGeneratedKeypair to be called by a live RSAKeypairGenerator" + << "but the casted sender is NULL. Will not process generated keypair."; + } +} + +void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) { + qDebug() << "Uploaded public key to Metaverse API. RSA keypair generation is completed."; + + // public key upload complete - store the matching private key and persist the account to settings + _accountInfo.setPrivateKey(_pendingPrivateKey); + _pendingPrivateKey.clear(); + persistAccountToFile(); + + // clear our waiting state + _isWaitingForKeypairResponse = false; + + emit newKeypair(); + + // delete the reply object now that we are done with it + reply.deleteLater(); +} + +void AccountManager::publicKeyUploadFailed(QNetworkReply& reply) { + // the public key upload has failed + qWarning() << "Public key upload failed from AccountManager" << reply.errorString(); + + // we aren't waiting for a response any longer + _isWaitingForKeypairResponse = false; + + // clear our pending private key + _pendingPrivateKey.clear(); + + // delete the reply object now that we are done with it + reply.deleteLater(); } void AccountManager::handleKeypairGenerationError() { - // for now there isn't anything we do with this except get the worker thread to clean up + qCritical() << "Error generating keypair - this is likely to cause authentication issues."; + + // reset our waiting state for keypair response + _isWaitingForKeypairResponse = false; + sender()->deleteLater(); } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 719279b0cf..0ebefafbed 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -62,12 +62,12 @@ public: QHttpMultiPart* dataMultiPart = NULL, const QVariantMap& propertyMap = QVariantMap()); + void setIsAgent(bool isAgent) { _isAgent = isAgent; } + const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); bool hasAuthEndpoint() { return !_authURL.isEmpty(); } - void disableSettingsFilePersistence() { _shouldPersistToSettingsFile = false; } - bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); } bool hasValidAccessToken(); Q_INVOKABLE bool checkAndSignalForAccessToken(); @@ -87,7 +87,9 @@ public slots: void logout(); void updateBalance(); void accountInfoBalanceChanged(qint64 newBalance); - void generateNewKeypair(); + void generateNewUserKeypair() { generateNewKeypair(); } + void generateNewDomainKeypair(const QUuid& domainID) { generateNewKeypair(false, domainID); } + signals: void authRequired(); void authEndpointChanged(); @@ -97,25 +99,36 @@ signals: void loginFailed(); void logoutComplete(); void balanceChanged(qint64 newBalance); + void newKeypair(); + private slots: void processReply(); void handleKeypairGenerationError(); - void processGeneratedKeypair(const QByteArray& publicKey, const QByteArray& privateKey); + void processGeneratedKeypair(); + void publicKeyUploadSucceeded(QNetworkReply& reply); + void publicKeyUploadFailed(QNetworkReply& reply); + void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid()); + private: AccountManager(); - AccountManager(AccountManager const& other); // not implemented - void operator=(AccountManager const& other); // not implemented + AccountManager(AccountManager const& other) = delete; + void operator=(AccountManager const& other) = delete; - void persistAccountToSettings(); + void persistAccountToFile(); + void removeAccountFromFile(); void passSuccessToCallback(QNetworkReply* reply); void passErrorToCallback(QNetworkReply* reply); QUrl _authURL; + QMap _pendingCallbackMap; DataServerAccountInfo _accountInfo; - bool _shouldPersistToSettingsFile; + bool _isAgent { false }; + + bool _isWaitingForKeypairResponse { false }; + QByteArray _pendingPrivateKey; }; #endif // hifi_AccountManager_h diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 5d633a8df1..9455fb1b88 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -25,19 +25,6 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif -DataServerAccountInfo::DataServerAccountInfo() : - _accessToken(), - _username(), - _xmppPassword(), - _discourseApiKey(), - _walletID(), - _balance(0), - _hasBalance(false), - _privateKey() -{ - -} - DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) : QObject() { _accessToken = otherInfo._accessToken; _username = otherInfo._username; @@ -47,6 +34,7 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI _balance = otherInfo._balance; _hasBalance = otherInfo._hasBalance; _privateKey = otherInfo._privateKey; + _domainID = otherInfo._domainID; } DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) { @@ -66,6 +54,7 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) { swap(_balance, otherInfo._balance); swap(_hasBalance, otherInfo._hasBalance); swap(_privateKey, otherInfo._privateKey); + swap(_domainID, otherInfo._domainID); } void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) { @@ -128,59 +117,62 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject } QByteArray DataServerAccountInfo::getUsernameSignature(const QUuid& connectionToken) { - - if (!_privateKey.isEmpty()) { - const char* privateKeyData = _privateKey.constData(); - RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL, - reinterpret_cast(&privateKeyData), - _privateKey.size()); - if (rsaPrivateKey) { - QByteArray lowercaseUsername = _username.toLower().toUtf8(); - QByteArray usernameWithToken = QCryptographicHash::hash(lowercaseUsername.append(connectionToken.toRfc4122()), - QCryptographicHash::Sha256); - - QByteArray usernameSignature(RSA_size(rsaPrivateKey), 0); - unsigned int usernameSignatureSize = 0; - - int encryptReturn = RSA_sign(NID_sha256, - reinterpret_cast(usernameWithToken.constData()), - usernameWithToken.size(), - reinterpret_cast(usernameSignature.data()), - &usernameSignatureSize, - rsaPrivateKey); - - // free the private key RSA struct now that we are done with it - RSA_free(rsaPrivateKey); + auto lowercaseUsername = _username.toLower().toUtf8(); + auto plaintext = lowercaseUsername.append(connectionToken.toRfc4122()); - if (encryptReturn == -1) { - qCDebug(networking) << "Error encrypting username signature."; - qCDebug(networking) << "Will re-attempt on next domain-server check in."; - } else { - qDebug(networking) << "Returning username" << _username << "signed with connection UUID" << uuidStringWithoutCurlyBraces(connectionToken); - return usernameSignature; - } - - } else { - qCDebug(networking) << "Could not create RSA struct from QByteArray private key."; - qCDebug(networking) << "Will re-attempt on next domain-server check in."; - } - } - return QByteArray(); + auto signature = signPlaintext(plaintext); + if (!signature.isEmpty()) { + qDebug(networking) << "Returning username" << _username + << "signed with connection UUID" << uuidStringWithoutCurlyBraces(connectionToken); + } else { + qCDebug(networking) << "Error signing username with connection token"; + qCDebug(networking) << "Will re-attempt on next domain-server check in."; + } + + return signature; } -void DataServerAccountInfo::setPrivateKey(const QByteArray& privateKey) { - _privateKey = privateKey; - +QByteArray DataServerAccountInfo::signPlaintext(const QByteArray& plaintext) { + if (!_privateKey.isEmpty()) { + const char* privateKeyData = _privateKey.constData(); + RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL, + reinterpret_cast(&privateKeyData), + _privateKey.size()); + if (rsaPrivateKey) { + QByteArray signature(RSA_size(rsaPrivateKey), 0); + unsigned int signatureBytes = 0; + + QByteArray hashedPlaintext = QCryptographicHash::hash(plaintext, QCryptographicHash::Sha256); + + int encryptReturn = RSA_sign(NID_sha256, + reinterpret_cast(hashedPlaintext.constData()), + hashedPlaintext.size(), + reinterpret_cast(signature.data()), + &signatureBytes, + rsaPrivateKey); + + // free the private key RSA struct now that we are done with it + RSA_free(rsaPrivateKey); + + if (encryptReturn != -1) { + return signature; + } + } else { + qCDebug(networking) << "Could not create RSA struct from QByteArray private key."; + } + } + return QByteArray(); } QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) { out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey - << info._walletID << info._privateKey; + << info._walletID << info._privateKey << info._domainID; + return out; } QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) { in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey - >> info._walletID >> info._privateKey; + >> info._walletID >> info._privateKey >> info._domainID; return in; } diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 9b80de5422..6223bc008e 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -23,7 +23,7 @@ const float SATOSHIS_PER_CREDIT = 100000000.0f; class DataServerAccountInfo : public QObject { Q_OBJECT public: - DataServerAccountInfo(); + DataServerAccountInfo() {}; DataServerAccountInfo(const DataServerAccountInfo& otherInfo); DataServerAccountInfo& operator=(const DataServerAccountInfo& otherInfo); @@ -42,10 +42,6 @@ public: const QUuid& getWalletID() const { return _walletID; } void setWalletID(const QUuid& walletID); - - QByteArray getUsernameSignature(const QUuid& connectionToken); - bool hasPrivateKey() const { return !_privateKey.isEmpty(); } - void setPrivateKey(const QByteArray& privateKey); qint64 getBalance() const { return _balance; } float getBalanceInSatoshis() const { return _balance / SATOSHIS_PER_CREDIT; } @@ -54,6 +50,15 @@ public: void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; } Q_INVOKABLE void setBalanceFromJSON(QNetworkReply& requestReply); + QByteArray getUsernameSignature(const QUuid& connectionToken); + bool hasPrivateKey() const { return !_privateKey.isEmpty(); } + void setPrivateKey(const QByteArray& privateKey) { _privateKey = privateKey; } + + QByteArray signPlaintext(const QByteArray& plaintext); + + void setDomainID(const QUuid& domainID) { _domainID = domainID; } + const QUuid& getDomainID() const { return _domainID; } + bool hasProfile() const; void setProfileInfoFromJSON(const QJsonObject& jsonObject); @@ -70,8 +75,9 @@ private: QString _xmppPassword; QString _discourseApiKey; QUuid _walletID; - qint64 _balance; - bool _hasBalance; + qint64 _balance { 0 }; + bool _hasBalance { false }; + QUuid _domainID; // if this holds account info for a domain, this holds the ID of that domain QByteArray _privateKey; }; diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index bf27789c54..b2eb0cd680 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -92,7 +92,9 @@ void DomainHandler::softReset() { disconnect(); clearSettings(); - + + _connectionDenialsSinceKeypairRegen = 0; + // cancel the failure timeout for any pending requests for settings QMetaObject::invokeMethod(&_settingsTimer, "stop"); } @@ -108,6 +110,9 @@ void DomainHandler::hardReset() { _hostname = QString(); _sockAddr.clear(); + _hasCheckedForAccessToken = false; + _domainConnectionRefusals.clear(); + // clear any pending path we may have wanted to ask the previous DS about _pendingPath.clear(); } @@ -349,3 +354,35 @@ void DomainHandler::processICEResponsePacket(QSharedPointer mes emit icePeerSocketsReceived(); } } + +void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer message) { + // Read deny reason from packet + quint16 reasonSize; + message->readPrimitive(&reasonSize); + QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize)); + + // output to the log so the user knows they got a denied connection request + // and check and signal for an access token so that we can make sure they are logged in + qCWarning(networking) << "The domain-server denied a connection request: " << reason; + qCWarning(networking) << "Make sure you are logged in."; + + if (!_domainConnectionRefusals.contains(reason)) { + _domainConnectionRefusals.append(reason); + emit domainConnectionRefused(reason); + } + + auto& accountManager = AccountManager::getInstance(); + + if (!_hasCheckedForAccessToken) { + accountManager.checkAndSignalForAccessToken(); + _hasCheckedForAccessToken = true; + } + + static const int CONNECTION_DENIALS_FOR_KEYPAIR_REGEN = 3; + + // force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts + if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) { + accountManager.generateNewUserKeypair(); + _connectionDenialsSinceKeypairRegen = 0; + } +} diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 957f52144b..03141d8fef 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -92,6 +92,7 @@ public slots: void processICEPingReplyPacket(QSharedPointer message); void processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket); void processICEResponsePacket(QSharedPointer icePacket); + void processDomainServerConnectionDeniedPacket(QSharedPointer message); private slots: void completedHostnameLookup(const QHostInfo& hostInfo); @@ -114,6 +115,8 @@ signals: void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); + void domainConnectionRefused(QString reason); + private: void sendDisconnectPacket(); void hardReset(); @@ -131,6 +134,10 @@ private: QJsonObject _settingsObject; QString _pendingPath; QTimer _settingsTimer; + + QStringList _domainConnectionRefusals; + bool _hasCheckedForAccessToken { false }; + int _connectionDenialsSinceKeypairRegen { 0 }; }; #endif // hifi_DomainHandler_h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index a3707d19ba..f236f9d596 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -902,10 +902,6 @@ void LimitedNodeList::updateLocalSockAddr() { } } -void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr) { - sendPacketToIceServer(PacketType::ICEServerHeartbeat, iceServerSockAddr, _sessionUUID); -} - void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID) { sendPacketToIceServer(PacketType::ICEServerQuery, iceServerSockAddr, clientID, peerID); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index fcad23da8f..de110c7e7f 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -143,6 +143,7 @@ public: bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; } const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; } + const HifiSockAddr& getPublicSockAddr() const { return _publicSockAddr; } const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; } void processKillNode(ReceivedMessage& message); @@ -161,7 +162,6 @@ public: std::unique_ptr constructICEPingPacket(PingType_t pingType, const QUuid& iceID); std::unique_ptr constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID); - void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr); void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID); SharedNodePointer findNodeWithAddr(const HifiSockAddr& addr); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 677a1ad1e6..02bb17e870 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -80,11 +80,16 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned // send a ping punch immediately connect(&_domainHandler, &DomainHandler::icePeerSocketsReceived, this, &NodeList::pingPunchForDomainServer); + auto &accountManager = AccountManager::getInstance(); + + // assume that we may need to send a new DS check in anytime a new keypair is generated + connect(&accountManager, &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn); + // clear out NodeList when login is finished - connect(&AccountManager::getInstance(), &AccountManager::loginComplete , this, &NodeList::reset); + connect(&accountManager, &AccountManager::loginComplete , this, &NodeList::reset); // clear our NodeList when logout is requested - connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset); + connect(&accountManager, &AccountManager::logoutComplete , this, &NodeList::reset); // anytime we get a new node we will want to attempt to punch to it connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch); @@ -105,6 +110,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); packetReceiver.registerListener(PacketType::DomainServerAddedNode, this, "processDomainServerAddedNode"); packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processDomainServerConnectionTokenPacket"); + packetReceiver.registerListener(PacketType::DomainConnectionDenied, &_domainHandler, "processDomainServerConnectionDeniedPacket"); packetReceiver.registerListener(PacketType::DomainSettings, &_domainHandler, "processSettingsPacketList"); packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_domainHandler, "processICEResponsePacket"); packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket"); @@ -265,6 +271,26 @@ void NodeList::sendDomainServerCheckIn() { } + // check if we're missing a keypair we need to verify ourselves with the domain-server + auto& accountManager = AccountManager::getInstance(); + const QUuid& connectionToken = _domainHandler.getConnectionToken(); + + // we assume that we're on the same box as the DS if it has the same local address and + // it didn't present us with a connection token to use for username signature + bool localhostDomain = _domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost + || (_domainHandler.getSockAddr().getAddress() == _localSockAddr.getAddress() && connectionToken.isNull()); + + bool requiresUsernameSignature = !_domainHandler.isConnected() && !connectionToken.isNull() && !localhostDomain; + + if (requiresUsernameSignature && !accountManager.getAccountInfo().hasPrivateKey()) { + qWarning() << "A keypair is required to present a username signature to the domain-server" + << "but no keypair is present. Waiting for keypair generation to complete."; + accountManager.generateNewUserKeypair(); + + // don't send the check in packet - wait for the keypair first + return; + } + auto domainPacket = NLPacket::create(domainPacketType); QDataStream packetStream(domainPacket.get()); @@ -289,23 +315,15 @@ void NodeList::sendDomainServerCheckIn() { // pack our data to send to the domain-server packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList(); - - // if this is a connect request, and we can present a username signature, send it along - if (!_domainHandler.isConnected() ) { - - DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo(); + + if (!_domainHandler.isConnected()) { + DataServerAccountInfo& accountInfo = accountManager.getAccountInfo(); packetStream << accountInfo.getUsername(); - - // get connection token from the domain-server - const QUuid& connectionToken = _domainHandler.getConnectionToken(); - - if (!connectionToken.isNull()) { - - const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature(connectionToken); - - if (!usernameSignature.isEmpty()) { - packetStream << usernameSignature; - } + + // if this is a connect request, and we can present a username signature, send it along + if (requiresUsernameSignature && accountManager.getAccountInfo().hasPrivateKey()) { + const QByteArray& usernameSignature = accountManager.getAccountInfo().getUsernameSignature(connectionToken); + packetStream << usernameSignature; } } diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index 53b9b27cc6..a98cf74564 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -85,12 +85,12 @@ void RSAKeypairGenerator::generateKeypair() { // we can cleanup the RSA struct before we continue on RSA_free(keyPair); - QByteArray publicKeyArray(reinterpret_cast(publicKeyDER), publicKeyLength); - QByteArray privateKeyArray(reinterpret_cast(privateKeyDER), privateKeyLength); + _publicKey = QByteArray { reinterpret_cast(publicKeyDER), publicKeyLength }; + _privateKey = QByteArray { reinterpret_cast(privateKeyDER), privateKeyLength }; // cleanup the publicKeyDER and publicKeyDER data OPENSSL_free(publicKeyDER); OPENSSL_free(privateKeyDER); - emit generatedKeypair(publicKeyArray, privateKeyArray); + emit generatedKeypair(); } diff --git a/libraries/networking/src/RSAKeypairGenerator.h b/libraries/networking/src/RSAKeypairGenerator.h index dd90313625..36f4a9550b 100644 --- a/libraries/networking/src/RSAKeypairGenerator.h +++ b/libraries/networking/src/RSAKeypairGenerator.h @@ -12,17 +12,31 @@ #ifndef hifi_RSAKeypairGenerator_h #define hifi_RSAKeypairGenerator_h -#include +#include +#include class RSAKeypairGenerator : public QObject { Q_OBJECT public: RSAKeypairGenerator(QObject* parent = 0); + + void setDomainID(const QUuid& domainID) { _domainID = domainID; } + const QUuid& getDomainID() const { return _domainID; } + + const QByteArray& getPublicKey() const { return _publicKey; } + const QByteArray& getPrivateKey() const { return _privateKey; } + public slots: void generateKeypair(); + signals: void errorGeneratingKeypair(); - void generatedKeypair(const QByteArray& publicKey, const QByteArray& privateKey); + void generatedKeypair(); + +private: + QUuid _domainID; + QByteArray _publicKey; + QByteArray _privateKey; }; -#endif // hifi_RSAKeypairGenerator_h \ No newline at end of file +#endif // hifi_RSAKeypairGenerator_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 27b74f270c..3ffbb867bf 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -34,7 +34,7 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::DomainServerAddedNode << PacketType::DomainServerConnectionToken << PacketType::DomainSettingsRequest << PacketType::DomainSettings << PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat - << PacketType::ICEPing << PacketType::ICEPingReply + << PacketType::ICEPing << PacketType::ICEPingReply << PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode << PacketType::DomainServerRemovedNode; @@ -51,6 +51,8 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::AvatarData: case PacketType::BulkAvatarData: return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); + case PacketType::ICEServerHeartbeat: + return 18; // ICE Server Heartbeat signing default: return 17; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0f586018db..7840ecb17e 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -90,7 +90,8 @@ public: DomainServerRemovedNode, MessagesData, MessagesSubscribe, - MessagesUnsubscribe + MessagesUnsubscribe, + ICEServerHeartbeatDenied }; }; From 248aa58d23fdba3883635f7a17dafee509aa2afb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Feb 2016 17:21:54 -0800 Subject: [PATCH 183/292] force statically linked OpenSSL on windows --- cmake/macros/InstallBesideConsole.cmake | 6 --- cmake/macros/ManuallyInstallSSLEay.cmake | 28 ------------ cmake/modules/FindOpenSSL.cmake | 56 ++++-------------------- interface/CMakeLists.txt | 4 -- 4 files changed, 8 insertions(+), 86 deletions(-) delete mode 100644 cmake/macros/ManuallyInstallSSLEay.cmake diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index 4c6087b877..ab3fa5dee4 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -65,10 +65,4 @@ macro(install_beside_console) endif() endif () - - # set variables used by manual ssleay library copy - set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR}) - set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) - manually_install_ssl_eay() - endmacro() diff --git a/cmake/macros/ManuallyInstallSSLEay.cmake b/cmake/macros/ManuallyInstallSSLEay.cmake deleted file mode 100644 index 41e7e9eaf3..0000000000 --- a/cmake/macros/ManuallyInstallSSLEay.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# -# ManuallyInstallSSLEay.cmake -# -# Created by Stephen Birarda on 1/15/16. -# 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 -# - -macro(manually_install_ssl_eay) - - # on windows we have had issues with targets missing ssleay library - # not convinced we actually need it (I assume it would show up in the dependency tree) - # but to be safe we install it manually beside the current target - if (WIN32) - # we need to find SSL_EAY_LIBRARY_* so we can install it beside this target - # so we have to call find_package(OpenSSL) here even though this target may not specifically need it - find_package(OpenSSL REQUIRED) - - install( - FILES "${OPENSSL_DLL_PATH}/ssleay32.dll" - DESTINATION ${TARGET_INSTALL_DIR} - COMPONENT ${TARGET_INSTALL_COMPONENT} - ) - endif() - -endmacro() diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 5cc48d2598..b91f33b753 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -81,20 +81,20 @@ if (WIN32 AND NOT CYGWIN) # We are using the libraries located in the VC subdir instead of the parent directory eventhough : # libeay32MD.lib is identical to ../libeay32.lib, and # ssleay32MD.lib is identical to ../ssleay32.lib - find_library(LIB_EAY_DEBUG NAMES libeay32MDd libeay32d - ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" + find_library(LIB_EAY_DEBUG NAMES libeay32MTd + ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static" ) - find_library(LIB_EAY_RELEASE NAMES libeay32MD libeay32 - ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" + find_library(LIB_EAY_RELEASE NAMES libeay32MT + ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static" ) - find_library(SSL_EAY_DEBUG NAMES ssleay32MDd ssleay32d - ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" + find_library(SSL_EAY_DEBUG NAMES ssleay32MTd + ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static" ) - find_library(SSL_EAY_RELEASE NAMES ssleay32MD ssleay32 ssl - ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "VC" "lib/VC" + find_library(SSL_EAY_RELEASE NAMES ssleay32MT + ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static" ) set(LIB_EAY_LIBRARY_DEBUG "${LIB_EAY_DEBUG}") @@ -107,39 +107,6 @@ if (WIN32 AND NOT CYGWIN) select_library_configurations(SSL_EAY) set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY}) - - find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS}) - - elseif (MINGW) - # same player, for MinGW - set(LIB_EAY_NAMES libeay32) - set(SSL_EAY_NAMES ssleay32) - - if (CMAKE_CROSSCOMPILING) - list(APPEND LIB_EAY_NAMES crypto) - list(APPEND SSL_EAY_NAMES ssl) - endif () - - find_library(LIB_EAY NAMES ${LIB_EAY_NAMES} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW" - ) - - find_library(SSL_EAY NAMES ${SSL_EAY_NAMES} - ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib" "lib/MinGW" - ) - - mark_as_advanced(SSL_EAY LIB_EAY) - set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY}) - unset(LIB_EAY_NAMES) - unset(SSL_EAY_NAMES) - else () - # Not sure what to pick for -say- intel, let's use the toplevel ones and hope someone report issues: - find_library(LIB_EAY NAMES libeay32 HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR} PATH_SUFFIXES lib) - - find_library(SSL_EAY NAMES ssleay32 HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_LIBDIR} PATH_SUFFIXES lib) - - mark_as_advanced(SSL_EAY LIB_EAY) - set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY}) endif() else() @@ -231,9 +198,6 @@ endif () include(FindPackageHandleStandardArgs) set(OPENSSL_REQUIREMENTS OPENSSL_LIBRARIES OPENSSL_INCLUDE_DIR) -if (WIN32) - list(APPEND OPENSSL_REQUIREMENTS OPENSSL_DLL_PATH) -endif () if (OPENSSL_VERSION) find_package_handle_standard_args(OpenSSL @@ -250,8 +214,4 @@ else () ) endif () -if (WIN32) - add_paths_to_fixup_libs(${OPENSSL_DLL_PATH}) -endif () - mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index b398778db7..35fbec76c8 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -266,9 +266,5 @@ add_bugsplat() if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") - set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR}) - set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT}) - manually_install_ssl_eay() - package_libraries_for_deployment() endif() From 72cbfe2dc7223b26884453d637041b9921e68d29 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Mar 2016 10:19:36 -0800 Subject: [PATCH 184/292] add a comment for static libraries specifically --- cmake/modules/FindOpenSSL.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index b91f33b753..7317516da7 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -67,10 +67,7 @@ find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AN if (WIN32 AND NOT CYGWIN) if (MSVC) - # /MD and /MDd are the standard values - if someone wants to use - # others, the libnames have to change here too - # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b - # TODO: handle /MT and static lib + # In Visual C++ naming convention each of these four kinds of Windows libraries has it's standard suffix: # * MD for dynamic-release # * MDd for dynamic-debug @@ -81,6 +78,9 @@ if (WIN32 AND NOT CYGWIN) # We are using the libraries located in the VC subdir instead of the parent directory eventhough : # libeay32MD.lib is identical to ../libeay32.lib, and # ssleay32MD.lib is identical to ../ssleay32.lib + + # The Kitware FindOpenSSL module has been modified here by High Fidelity to look specifically for static libraries + find_library(LIB_EAY_DEBUG NAMES libeay32MTd ${_OPENSSL_ROOT_HINTS_AND_PATHS} PATH_SUFFIXES "lib/VC/static" ) From d5a5ce8c70e74e51f9e047744bd7475f04c583b5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 1 Mar 2016 13:25:10 -0800 Subject: [PATCH 185/292] Refactor helper from lambda to static fn --- .../src/model-networking/ModelCache.cpp | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index a2e3516690..a3cc920a40 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -304,50 +304,50 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas return networkMesh; } -static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) { - // Create a local url to cache inline textures - auto localBaseUrl = QUrl(textureBaseUrl.url() + "/"); - +static model::TextureMapPointer setupNetworkTextureMap(const QUrl& textureBaseUrl, + const FBXTexture& texture, TextureType type, + NetworkTexturePointer& networkTexture, QString& networkTextureName) { auto textureCache = DependencyManager::get(); + // If content is inline, cache it under the fbx file, not its base url + const auto baseUrl = texture.content.isEmpty() ? textureBaseUrl : QUrl(textureBaseUrl.url() + "/"); + const auto filename = baseUrl.resolved(QUrl(texture.filename)); + + networkTexture = textureCache->getTexture(filename, type, texture.content); + networkTextureName = texture.name; + + auto map = std::make_shared(); + map->setTextureSource(networkTexture->_textureSource); + return map; +} + +static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) { NetworkMaterial* networkMaterial = new NetworkMaterial(); networkMaterial->_material = material._material; - auto setupMaterialTexture = [&](const FBXTexture& texture, - TextureType type, model::MaterialKey::MapChannel channel, - NetworkTexturePointer& networkTexture, QString& networkTextureName){ - const auto& baseUrl = texture.content.isEmpty() ? textureBaseUrl : localBaseUrl; - networkTexture = textureCache->getTexture(baseUrl.resolved(QUrl(texture.filename)), type, texture.content); - networkTextureName = texture.name; - - auto map = std::make_shared(); - map->setTextureSource(networkTexture->_textureSource); - material._material->setTextureMap(channel, map); - return map; - }; - if (!material.diffuseTexture.filename.isEmpty()) { - auto diffuseMap = setupMaterialTexture(material.diffuseTexture, - DEFAULT_TEXTURE, model::MaterialKey::DIFFUSE_MAP, + auto diffuseMap = setupNetworkTextureMap(textureBaseUrl, material.diffuseTexture, DEFAULT_TEXTURE, networkMaterial->diffuseTexture, networkMaterial->diffuseTextureName); diffuseMap->setTextureTransform(material.diffuseTexture.transform); + networkMaterial->_material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); } if (!material.normalTexture.filename.isEmpty()) { - setupMaterialTexture(material.normalTexture, - (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), model::MaterialKey::NORMAL_MAP, + auto normalMap = setupNetworkTextureMap(textureBaseUrl, material.normalTexture, + (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), networkMaterial->normalTexture, networkMaterial->normalTextureName); + networkMaterial->_material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); } if (!material.specularTexture.filename.isEmpty()) { - setupMaterialTexture(material.specularTexture, - SPECULAR_TEXTURE, model::MaterialKey::GLOSS_MAP, + auto glossMap = setupNetworkTextureMap(textureBaseUrl, material.specularTexture, SPECULAR_TEXTURE, networkMaterial->specularTexture, networkMaterial->specularTextureName); + networkMaterial->_material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap); } if (!material.emissiveTexture.filename.isEmpty()) { - auto lightmapMap = setupMaterialTexture(material.emissiveTexture, - LIGHTMAP_TEXTURE, model::MaterialKey::LIGHTMAP_MAP, + auto lightmapMap = setupNetworkTextureMap(textureBaseUrl, material.emissiveTexture, LIGHTMAP_TEXTURE, networkMaterial->emissiveTexture, networkMaterial->emissiveTextureName); lightmapMap->setTextureTransform(material.emissiveTexture.transform); lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y); + networkMaterial->_material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); } return networkMaterial; From 7179960bbfbe153d53e094b7117b5816c3902c32 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Mar 2016 14:18:38 -0800 Subject: [PATCH 186/292] chapter 2 --- .../fireworksLaunchButtonEntityScript.js | 65 ++++++++++++++++++- .../chapter2/fireworksLaunchButtonSpawner.js | 2 +- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js index 1f361656f1..142c8ffa96 100644 --- a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js @@ -1,16 +1,79 @@ -// Chapter 1: fireworksLaunchButtonEntityScript.js +// Chapter 2: fireworksLaunchButtonEntityScript.js (function() { Script.include("../../libraries/utils.js"); var _this; Fireworks = function() { _this = this; + _this.launchSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/missle+launch.wav"); }; Fireworks.prototype = { + startNearTrigger: function() { + _this.shootFirework(_this.position); + }, + + startFarTrigger: function() { + _this.shootFirework(_this.position); + }, + + clickReleaseOnEntity: function() { + _this.shootFirework(_this.position); + }, + + + + shootFirework: function(launchPosition) { + Audio.playSound(_this.launchSound, { + position: launchPosition, + volume: 0.5 + }); + + + var smoke = Entities.addEntity({ + type: "ParticleEffect", + position: _this.position, + velocity: {x: 0, y: 3, z: 0}, + lifespan: 10, + lifetime: 20, + isEmitting: true, + name: "Smoke Trail", + maxParticles: 3000, + emitRate: 80, + emitSpeed: 0, + speedSpread: 0, + polarStart: 0, + polarFinish: 0, + azimuthStart: -3.14, + azimuthFinish: 3.14, + emitAcceleration: { + x: 0, + y: 0.01, + z: 0 + }, + accelerationSpread: { + x: 0.01, + y: 0, + z: 0.01 + }, + radiusSpread: 0.03, + particleRadius: 0.3, + radiusStart: 0.06, + radiusFinish: 0.9, + alpha: 0.1, + alphaSpread: 0, + alphaStart: 0.7, + alphaFinish: 0, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true, + }); + + }, + preload: function(entityID) { _this.entityID = entityID; + _this.position = Entities.getEntityProperties(_this.entityID, "position").position; } diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js index a4969aa8ed..2fc4364c5a 100644 --- a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js @@ -1,5 +1,5 @@ - // Chapter1 : fireworksLaumchButtonSpawner.js + // Chapter 2 : fireworksLaumchButtonSpawner.js var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); From b346f36b898ae67d6c11831099ac179217333586 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Mar 2016 14:19:20 -0800 Subject: [PATCH 187/292] Fix compiler warnings --- libraries/audio/src/AudioLimiter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index bb3d8b7a76..d0ec76ec98 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -395,6 +395,7 @@ public: float _outGain = 0.0f; LimiterImpl(int sampleRate); + ~LimiterImpl() {} void setThreshold(float threshold); void setRelease(float release); From 04fd7bcdb2b3c4906d0518393c1c8e7bea2e9332 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Mar 2016 14:42:07 -0800 Subject: [PATCH 188/292] create the directory to hold account file if not present --- libraries/networking/src/AccountManager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index d0838c4a8f..af30132b70 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -115,8 +116,12 @@ void AccountManager::accountInfoBalanceChanged(qint64 newBalance) { emit balanceChanged(newBalance); } +QString accountFileDir() { + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); +} + QString accountFilePath() { - return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/AccountInfo.bin"; + return accountFileDir() + "/AccountInfo.bin"; } QVariantMap accountMapFromFile(bool& success) { @@ -370,6 +375,11 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { bool writeAccountMapToFile(const QVariantMap& accountMap) { // re-open the file and truncate it QFile accountFile { accountFilePath() }; + + // make sure the directory that will hold the account file exists + QDir accountFileDirectory { accountFileDir() }; + accountFileDirectory.mkpath("."); + if (accountFile.open(QIODevice::WriteOnly)) { QDataStream writeStream(&accountFile); From 5c64115b2642f34041e3224688c805cc8046ccda Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 1 Mar 2016 14:44:34 -0800 Subject: [PATCH 189/292] Use keyLight in DLE instead of _skyboxTexture --- interface/src/Application.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 2 ++ .../src/DeferredLightingEffect.cpp | 24 ++++++++----------- .../render-utils/src/DeferredLightingEffect.h | 4 +--- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21377fa945..82e44fa907 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3818,7 +3818,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // Setup the current Zone Entity lighting { auto stage = DependencyManager::get()->getSkyStage(); - DependencyManager::get()->setGlobalLight(stage->getSunLight(), stage->getSkybox()->getCubemap()); + DependencyManager::get()->setGlobalLight(stage->getSunLight()); } { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ccf5036fa1..85cbbbd328 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -273,6 +273,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrresetAmbientSphere(); + sceneKeyLight->setAmbientMap(nullptr); sceneKeyLight->setColor(_previousKeyLightColor); sceneKeyLight->setIntensity(_previousKeyLightIntensity); sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity); @@ -383,6 +384,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrresetAmbientSphere(); + sceneKeyLight->setAmbientMap(nullptr); } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index faa11584dd..82bd0e73d0 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -316,12 +316,12 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo { auto& program = _shadowMapEnabled ? _directionalLightShadow : _directionalLight; LightLocationsPtr locations = _shadowMapEnabled ? _directionalLightShadowLocations : _directionalLightLocations; + const auto& keyLight = _allocatedLights[_globalLights.front()]; // Setup the global directional pass pipeline { if (_shadowMapEnabled) { - //if (_skyboxTexture) { - if (_skyboxTexture) { + if (keyLight->getAmbientMap()) { program = _directionalSkyboxLightShadow; locations = _directionalSkyboxLightShadowLocations; } else { @@ -329,7 +329,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo locations = _directionalAmbientSphereLightShadowLocations; } } else { - if (_skyboxTexture) { + if (keyLight->getAmbientMap()) { program = _directionalSkyboxLight; locations = _directionalSkyboxLightLocations; } else { @@ -357,7 +357,7 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color); } - if (_skyboxTexture) { + if (keyLight->getAmbientMap()) { batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr); } } @@ -496,14 +496,14 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int skyboxCubemapUnit) { PerformanceTimer perfTimer("DLE->setupBatch()"); - auto globalLight = _allocatedLights[_globalLights.front()]; + auto keyLight = _allocatedLights[_globalLights.front()]; if (lightBufferUnit >= 0) { - batch.setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); + batch.setUniformBuffer(lightBufferUnit, keyLight->getSchemaBuffer()); } - if (globalLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { - batch.setResourceTexture(skyboxCubemapUnit, globalLight->getAmbientMap()); + if (keyLight->getAmbientMap() && (skyboxCubemapUnit >= 0)) { + batch.setResourceTexture(skyboxCubemapUnit, keyLight->getAmbientMap()); } } @@ -562,18 +562,14 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo } -void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light, const gpu::TexturePointer& skyboxTexture) { +void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) { auto globalLight = _allocatedLights.front(); globalLight->setDirection(light->getDirection()); globalLight->setColor(light->getColor()); globalLight->setIntensity(light->getIntensity()); globalLight->setAmbientIntensity(light->getAmbientIntensity()); globalLight->setAmbientSphere(light->getAmbientSphere()); - - _skyboxTexture = (light->getAmbientMap() ? light->getAmbientMap() : _skyboxTexture); - - // Update the available mipmap levels - globalLight->setAmbientMap(_skyboxTexture); + globalLight->setAmbientMap(light->getAmbientMap()); } model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 4ee3d9a565..63d8f4d175 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -49,7 +49,7 @@ public: void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int skyboxCubemapUnit); // update global lighting - void setGlobalLight(const model::LightPointer& light, const gpu::TexturePointer& skyboxTexture); + void setGlobalLight(const model::LightPointer& light); const LightStage& getLightStage() { return _lightStage; } void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; }; @@ -96,8 +96,6 @@ private: std::vector _pointLights; std::vector _spotLights; - gpu::TexturePointer _skyboxTexture; - // Class describing the uniform buffer with all the parameters common to the deferred shaders class DeferredTransform { public: From 16fbf60bae468ec4cd77e67949918671c18c6518 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 11:52:58 +1300 Subject: [PATCH 190/292] Update preferences dialog titles to match menu items --- interface/resources/qml/hifi/dialogs/AudioPreferencesDialog.qml | 2 +- .../resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml | 2 +- .../resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml | 2 +- interface/resources/qml/hifi/dialogs/LodPreferencesDialog.qml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/AudioPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/AudioPreferencesDialog.qml index 09b4e52a14..0c7c881bbf 100644 --- a/interface/resources/qml/hifi/dialogs/AudioPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AudioPreferencesDialog.qml @@ -6,7 +6,7 @@ import "../../dialogs" PreferencesDialog { id: root objectName: "AudioPreferencesDialog" - title: "Audio Preferences" + title: "Audio Settings" showCategories: ["Audio"] property var settings: Settings { category: root.objectName diff --git a/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml index bc5d827ead..86f195612c 100644 --- a/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AvatarPreferencesDialog.qml @@ -6,7 +6,7 @@ import "../../dialogs" PreferencesDialog { id: root objectName: "AvatarPreferencesDialog" - title: "Avatar Preferences" + title: "Avatar Settings" showCategories: [ "Avatar Basics", "Avatar Tuning", "Avatar Camera" ] property var settings: Settings { category: root.objectName diff --git a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml index dca3a8694c..d95bafd0a9 100644 --- a/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GraphicsPreferencesDialog.qml @@ -6,7 +6,7 @@ import "../../dialogs" PreferencesDialog { id: root objectName: "GraphicsPreferencesDialog" - title: "Graphics Preferences" + title: "Graphics Settings" showCategories: ["Graphics"] property var settings: Settings { category: root.objectName diff --git a/interface/resources/qml/hifi/dialogs/LodPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/LodPreferencesDialog.qml index 1c9016bcfa..43f9731efd 100644 --- a/interface/resources/qml/hifi/dialogs/LodPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/LodPreferencesDialog.qml @@ -6,7 +6,7 @@ import "../../dialogs" PreferencesDialog { id: root objectName: "LodPreferencesDialog" - title: "Level of Detail preferences" + title: "LOD Settings" showCategories: ["Level of Detail Tuning"] property var settings: Settings { category: root.objectName From 48aaac2971565bc1e062c83665409ce59680a979 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 1 Mar 2016 14:57:02 -0800 Subject: [PATCH 191/292] Render line3d without backface culling --- interface/src/ui/overlays/Line3DOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index c0a1c9e282..8a9ba98eeb 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -64,7 +64,7 @@ void Line3DOverlay::render(RenderArgs* args) { } const render::ShapeKey Line3DOverlay::getShapeKey() { - auto builder = render::ShapeKey::Builder(); + auto builder = render::ShapeKey::Builder().withoutCullFace(); if (getAlpha() != 1.0f) { builder.withTranslucent(); } From 77b371e37595d527c784fd3a7da15986afcca212 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 1 Mar 2016 15:00:19 -0800 Subject: [PATCH 192/292] fix away state when starting in HMD --- examples/away.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/away.js b/examples/away.js index 8d561f2623..82b9c881c6 100644 --- a/examples/away.js +++ b/examples/away.js @@ -206,8 +206,9 @@ function maybeGoActive(event) { goActive(); } } -var wasHmdActive = false; -var wasMouseCaptured = false; +var wasHmdActive = HMD.active; +var wasMouseCaptured = Reticle.mouseCaptured; + function maybeGoAway() { if (HMD.active !== wasHmdActive) { wasHmdActive = !wasHmdActive; From d1f4369a5f71e527dced5df2c7f1ecea8ff7fdf2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 12:00:29 +1300 Subject: [PATCH 193/292] Fix width of divider above buttons at bottom of settings dialogs --- interface/resources/qml/windows-uit/Window.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/windows-uit/Window.qml b/interface/resources/qml/windows-uit/Window.qml index 4bb376346d..429c6d5dcc 100644 --- a/interface/resources/qml/windows-uit/Window.qml +++ b/interface/resources/qml/windows-uit/Window.qml @@ -127,7 +127,7 @@ Fadable { // Scrollable window content. property var pane: Item { property bool isScrolling: scrollView.height < scrollView.contentItem.height - property int contentWidth: scrollView.width - (isScrolling ? 11 : 0) + property int contentWidth: scrollView.width - (isScrolling ? 10 : 0) property int scrollHeight: scrollView.height anchors.fill: parent From be446f4e962670f97639db5afc8e85ea30222ba6 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Mar 2016 15:36:09 -0800 Subject: [PATCH 194/292] MyAvatar: separate rotation, horizontal and vertical HMD follow --- interface/src/avatar/MyAvatar.cpp | 114 +++++++++++++++++++++++------- interface/src/avatar/MyAvatar.h | 19 ++++- 2 files changed, 106 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fc715eebe9..2b734a29c6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1884,58 +1884,122 @@ void MyAvatar::lateUpdatePalms() { static const float FOLLOW_TIME = 0.5f; -void MyAvatar::FollowHelper::deactivate() { - _timeRemaining = 0.0f; +MyAvatar::FollowHelper::FollowHelper() { + deactivate(); } -void MyAvatar::FollowHelper::activate() { +void MyAvatar::FollowHelper::deactivate() { + for (int i = 0; i < NumFollowTypes; i++) { + deactivate((FollowType)i); + } +} + +void MyAvatar::FollowHelper::deactivate(FollowType type) { + assert(type >= 0 && type < NumFollowTypes); + _timeRemaining[(int)type] = 0.0f; +} + +void MyAvatar::FollowHelper::activate(FollowType type) { + assert(type >= 0 && type < NumFollowTypes); // TODO: Perhaps, the follow time should be proportional to the displacement. - _timeRemaining = FOLLOW_TIME; + _timeRemaining[(int)type] = FOLLOW_TIME; +} + +bool MyAvatar::FollowHelper::isActive(FollowType type) const { + assert(type >= 0 && type < NumFollowTypes); + return _timeRemaining[(int)type] > 0.0f; } bool MyAvatar::FollowHelper::isActive() const { - return _timeRemaining > 0.0f; + for (int i = 0; i < NumFollowTypes; i++) { + if (isActive((FollowType)i)) { + return true; + } + } + return false; } -bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { - - const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 4.0f); - - glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); - if (glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD) { - return true; +float MyAvatar::FollowHelper::getMaxTimeRemaining() const { + float max = 0.0f; + for (int i = 0; i < NumFollowTypes; i++) { + if (_timeRemaining[i] > max) { + max = _timeRemaining[i]; + } } + return max; +} - const float CYLINDER_TOP = 0.1f; - const float CYLINDER_BOTTOM = -0.5f; - const float CYLINDER_RADIUS = 0.15f; +void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { + for (int i = 0; i < NumFollowTypes; i++) { + _timeRemaining[i] -= dt; + } +} + +bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { + const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 4.0f); + glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); + return glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; +} + +bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { + + const float CYLINDER_RADIUS = 0.15f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); glm::vec3 radialOffset(offset.x, 0.0f, offset.z); float radialDistance = glm::length(radialOffset); - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (radialDistance > CYLINDER_RADIUS); + return radialDistance > CYLINDER_RADIUS; +} + +bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { + + const float CYLINDER_TOP = 0.1f; + const float CYLINDER_BOTTOM = -1.0f; + + glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + glm::vec3 radialOffset(offset.x, 0.0f, offset.z); + float radialDistance = glm::length(radialOffset); + + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) { _desiredBodyMatrix = desiredBodyMatrix; - if (!isActive() && shouldActivate(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { - activate(); + if (!isActive(Rotation) && shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { + activate(Rotation); + } + if (!isActive(Horizontal) && shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { + activate(Horizontal); + } + if (!isActive(Vertical) && shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { + activate(Vertical); } - if (isActive()) { - glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix; - myAvatar.getCharacterController()->setFollowParameters(desiredWorldMatrix, _timeRemaining); - } else { - glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix; - myAvatar.getCharacterController()->setFollowParameters(currentWorldMatrix, 0.0f); + glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix; + glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix; + + AnimPose followWorldPose(currentWorldMatrix); + if (isActive(Rotation)) { + followWorldPose.rot = glmExtractRotation(desiredWorldMatrix); } + if (isActive(Horizontal)) { + glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix); + followWorldPose.trans.x = desiredTranslation.x; + followWorldPose.trans.z = desiredTranslation.z; + } + if (isActive(Vertical)) { + glm::vec3 desiredTranslation = extractTranslation(desiredWorldMatrix); + followWorldPose.trans.y = desiredTranslation.y; + } + + myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining()); } glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) { if (isActive()) { float dt = myAvatar.getCharacterController()->getFollowTime(); - _timeRemaining -= dt; + decrementTimeRemaining(dt); // apply follow displacement to the body matrix. glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 637baa3c22..3950e6895f 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -392,13 +392,28 @@ private: glm::mat4 _sensorToWorldMatrix; struct FollowHelper { + FollowHelper(); + + enum FollowType { + Rotation = 0, + Horizontal, + Vertical, + NumFollowTypes + }; glm::mat4 _desiredBodyMatrix; - float _timeRemaining { 0.0f }; + float _timeRemaining[NumFollowTypes]; void deactivate(); + void deactivate(FollowType type); void activate(); + void activate(FollowType type); bool isActive() const; - bool shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + bool isActive(FollowType followType) const; + float getMaxTimeRemaining() const; + void decrementTimeRemaining(float dt); + bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); }; From 2029532070edca6ec1067332d47dafc29bc3bcb9 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Mar 2016 15:44:20 -0800 Subject: [PATCH 195/292] chapter 3 --- .../fireworksLaunchButtonEntityScript.js | 156 ++++++++++++++++++ .../chapter3/fireworksLaunchButtonSpawner.js | 30 ++++ 2 files changed, 186 insertions(+) create mode 100644 examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js create mode 100644 examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js diff --git a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js new file mode 100644 index 0000000000..f4332eccb6 --- /dev/null +++ b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js @@ -0,0 +1,156 @@ +// Chapter 3: fireworksLaunchButtonEntityScript.js + + (function() { + Script.include("../../libraries/utils.js"); + var _this; + Fireworks = function() { + _this = this; + _this.launchSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/missle+launch.wav"); + _this.explosionSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/fireworksExplosion.wav"); + _this.TIME_TO_EXPLODE = 3000; + }; + + Fireworks.prototype = { + + startNearTrigger: function() { + _this.shootFirework(_this.position); + }, + + startFarTrigger: function() { + _this.shootFirework(_this.position); + }, + + clickReleaseOnEntity: function() { + _this.shootFirework(_this.position); + }, + + + + shootFirework: function(launchPosition) { + Audio.playSound(_this.launchSound, { + position: launchPosition, + volume: 0.5 + }); + + + var smoke = Entities.addEntity({ + type: "ParticleEffect", + position: _this.position, + velocity: {x: 0, y: 3, z: 0}, + linearDamping: 0, + lifespan: 10, + lifetime: 20, + isEmitting: true, + name: "Smoke Trail", + maxParticles: 3000, + emitRate: 80, + emitSpeed: 0, + speedSpread: 0, + polarStart: 0, + polarFinish: 0, + azimuthStart: -3.14, + azimuthFinish: 3.14, + emitAcceleration: { + x: 0, + y: 0.01, + z: 0 + }, + accelerationSpread: { + x: 0.01, + y: 0, + z: 0.01 + }, + radiusSpread: 0.03, + particleRadius: 0.3, + radiusStart: 0.06, + radiusFinish: 0.9, + alpha: 0.1, + alphaSpread: 0, + alphaStart: 0.7, + alphaFinish: 0, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true, + }); + + Script.setTimeout(function() { + var explodePosition = Entities.getEntityProperties(smoke, "position").position; + _this.explodeFirework(explodePosition); + }, _this.TIME_TO_EXPLODE); + + }, + + explodeFirework: function(explodePosition) { + Audio.playSound(_this.explosionSound, { + position: explodePosition + }); + var firework = Entities.addEntity({ + name: "fireworks emitter", + position: explodePosition, + type: "ParticleEffect", + colorStart: hslToRgb({ + h: Math.random(), + s: 0.5, + l: 0.7 + }), + color: hslToRgb({ + h: Math.random(), + s: 0.5, + l: 0.5 + }), + colorFinish: hslToRgb({ + h: Math.random(), + s: 0.5, + l: 0.7 + }), + maxParticles: 10000, + lifetime: 20, + lifespan: randFloat(1.5, 3), + emitRate: randInt(500, 5000), + emitSpeed: randFloat(0.5, 2), + speedSpread: 0.2, + emitOrientation: Quat.fromPitchYawRollDegrees(randInt(0, 360), randInt(0, 360), randInt(0, 360)), + polarStart: 1, + polarFinish: randFloat(1.2, 3), + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: randFloat(-1, -0.2), + z: 0 + }, + accelerationSpread: { + x: Math.random(), + y: 0, + z: Math.random() + }, + particleRadius: randFloat(0.001, 0.1), + radiusSpread: Math.random() * 0.1, + radiusStart: randFloat(0.001, 0.1), + radiusFinish: randFloat(0.001, 0.1), + alpha: randFloat(0.8, 1.0), + alphaSpread: randFloat(0.1, 0.2), + alphaStart: randFloat(0.7, 1.0), + alphaFinish: randFloat(0.7, 1.0), + textures: "http://ericrius1.github.io/PlatosCave/assets/star.png", + }); + + + Script.setTimeout(function() { + Entities.editEntity(firework, { + isEmitting: false + }); + }, randInt(500, 1000)); + + }, + + preload: function(entityID) { + _this.entityID = entityID; + _this.position = Entities.getEntityProperties(_this.entityID, "position").position; + + } + + }; + + // entity scripts always need to return a newly constructed object of our type + return new Fireworks(); + }); diff --git a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js new file mode 100644 index 0000000000..2fc4364c5a --- /dev/null +++ b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js @@ -0,0 +1,30 @@ + + // Chapter 2 : fireworksLaumchButtonSpawner.js + + var orientation = Camera.getOrientation(); + orientation = Quat.safeEulerAngles(orientation); + orientation.x = 0; + orientation = Quat.fromVec3Degrees(orientation); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(orientation))); + + var SCRIPT_URL = Script.resolvePath("fireworksLaunchButtonEntityScript.js"); + var MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/Launch-Button.fbx"; + var launchButton = Entities.addEntity({ + type: "Model", + name: "hifi-launch-button", + modelURL: MODEL_URL, + position: center, + dimensions: { + x: 0.98, + y: 1.16, + z: 0.98 + }, + script: SCRIPT_URL, + }) + + + function cleanup() { + Entities.deleteEntity(launchButton); + } + + Script.scriptEnding.connect(cleanup); \ No newline at end of file From 20bf07550ac9ec9f79a9509e6c53f3f7d881a518 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 13:10:52 +1300 Subject: [PATCH 196/292] Update to new HiFi-Glyphs font file --- interface/resources/fonts/hifi-glyphs.ttf | Bin 17612 -> 18804 bytes .../resources/qml/controls-uit/ComboBox.qml | 9 ++++----- .../resources/qml/controls-uit/SpinBox.qml | 10 +++++----- interface/resources/qml/controls-uit/Tree.qml | 2 +- .../qml/styles-uit/HifiConstants.qml | 5 ++++- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 54a23dce075abfda7b37b2d00bcc5efc6b956245..3e8e5e5b908dc5d7535e90a290bc9ab477b87f02 100644 GIT binary patch delta 3192 zcmZ8jdu&@*8UKC0Z`-l+@FR76^=f5h1st%WAAmexIDhJQeNX=w5C(yX;hdpoCHKuC z03QHI=5j_|=ld)IKrR5?xngb6^K-}h09^&}>q0rBfBv!54)9L^c%!HVB?Sfe(UAc+49!Q zFVZ+2U!I_U)PWvE(25-ZQivdhJ@(C*o;YR z#S~^RjqNy!N3avSup0>+!ba@DUhKnu?7%i`!3ajN3CC~%2bce38Bz}82p-0x7+bb- z$2X5pq&H7)otl~6e)N%@yLKlIZQQeW-~Jujwv3E!I(Fb7{A!>p7z%esv}n)z4ZRP= zQhogc@!`RtDZ_f9c@3W4Hj*A^1 z_(lJO|4IMf)poU8?N`UthgDO3NqxK1)A`lTmpX3-{MSC>zZJWdNK8oAgwanebq*(S zlCIDdNN~anASAjx@#J7M?v=Em!K617O?lidktQ$9&R&?k;%ckQ!#(cSx;#u*W*M(j zuD7{*hTl}4WD@`jHe)lrNpHdd6(En~plB-UO?i^3WHd5CUdbDkG*J=*b<*gPbs#*~ zqkX4s!|)67QSRP{|4R*9scot+taNm@UF_LljgK5W8d7`@2-_4Zn*~8!pbzN@L=Xcg zs`b)F3bRNO@nkCDb|nT9@o`GHU859F4JG2K4Ar~ z$T4fc>QlO8ONU_L?!7>Ln5JYZ>Gil>k{H#TB)Ytwc&g3ga*`Mh)uYmWza&Y`E|)r@^{6|;JnxgOinY1f*E{3T><$NwsJqqrzKDxe`wn4R>E>`s<^zEX1ch;MTCqe#c9jGeYG>bOPy)Xh$2L>i+0)EB*n zncyyNQ9DH#KTYntseknzX&lcxc!y%d+(IOpAWQGzcT!CM4nC&XsvYu%8K1gSupo^& zdYirv0qcM^Z^9jHNrgkAyT#>61mnr^It^;Q6xIHq{o>xWQmLt>rHOVi_!HGiUr*d3 z>TI>&TVb4A_SUGqQS0aNDplyjmqx=w%&1B(&nU%{Qk>kpq%oo3Yz>c);UXT%xbhBAVbq1PLG_j*=vX zLum>{Q}skj42Lwy#EZUsmX(kVc^}(1OOhd)Nz@f zpwqCS14)bl6j#aBOQCTZO#FXRrDTFhB?n3FaCCxFja0Ktg*}6bxGPLKj=RBeH*Uyw zyUf6|K6g)x(89Sm$;H_uTa(Sw=5{!pbd0;sao4$)x?R4`l&{P7loAp=qD7#VPK!vq z!dpe&e$wY-7YvUJc%ELQZ@_|Pc;E+Xvt-CgqLt|ZX^h*yulsz(ty|r&pn@g(0X+i|frfE+cqp7&+rYin zS*$jFq>=K?f!7BvO43EEAUIUJ{JLyc9fDxJDAD3lrE*zVk{wMaSY#)f9P*ODg5dB1 zo}(I_fgL`?f$mVW&Q5T=aXV=tsZoA*Hx5Q6)`U)qYLXZrNo4mEYsV-J%m#y#v%yd( zy5Fy=>OR%)-_#|`q8RLw1X=Ft5=BAk3W}m6Jr@ke`X+;2{To9+Q`H_VpsJnG_5N)^ zQ53~sP!L4X9_$h&K?pK^@!IF(b`k~a=BtwiDzTgjA=Q9g) zhFGoS4AbD3$|XZ6US2t!$p>i$-Zd$P~&| z!_k1TeCe!V){HDy$(QVveCYwB$uz3@B_qasE*Q<(Jkwt=jhL}m(NC4KcGF;9#i~WU zP_V5UYv9tUvUyH7v+|stIn5ApRa06h6&GqoR%k%Em@nmv`6WXx>WdAeWes`YLi_UN z$#(KB|8&wY2j`+)vCzSSjyTSxDXoo$cGmNpkcPdr4uP%#K3wkxjSI?I++-c)HU&xnE z%j^+d%a==1MmP0Z%)CDr&d_8P delta 1982 zcmZuy-EUK682`Qf+}iF7Mmx6g?Yd6#!ujqBj4|lO2I`t<3?ZnTweQ*!&KKvjuwhJh z;}_AyP-2K)=oLY)OfZq?g~lr{yyC*dV3fZA6NQ9$A?7{p#!NU()8F&{p67X==l47( zeRz%h{61-d0O-LQ!YIwnz4GG4fBrlU6u$y6da^h>hgHOY;zs~>FTQ+GTKw+Z_W(Hq z;MKCFyPsYE^)(<=0?5Ov?z>N(APf}W1JG49SC``ld#?hK`#@o+#`H?;-iHo=-vDT} z8f)s2gP|xu1_3-*v+64Y*OMuL@B%(Jow7c$JZu7yB7jdUeZ|EWhQ#4<`W<&*ZgCdIuSd?I(N3v(sce zo=L~Kk)0w+UfV_T&Rr32{+XmBziKHpn=)S$#po{dj!MLocN_Icl8{=%2tj*?n`-XB8ne#)r z?%7C5I4_h+|K9K0KAsyopPA?`MivEKD3yfS99bI~%L%#M&_G{0AqG9Xk|a6_3aRy0@%iv1m0DjGTYMj9Z#26_f!3@F6~sPKq*8_YWsfnN z3gUn$(F<&K$LQSJuy~Be8eFw4vJ#+8WWTIZkNL(G z7N}>kv@%I622a>%dW^Camy60{HR`cI1K-k3lMg}8cWzrh>5(Vtvg2KDPo-Bb&?UWm zp<|{LVLgK&_9!B4*jA%mVp5UlI__0uY8kd+8Oi)b}Xx58+AVU0ac_`PhaYci*K7MP@m~uxkd$XyTTV`LxxQaZq=mqLN|6f zp~ Date: Tue, 1 Mar 2016 16:34:58 -0800 Subject: [PATCH 197/292] Fix compiler warnings --- libraries/audio/src/AudioLimiter.cpp | 14 +++++++------- libraries/audio/src/AudioLimiter.h | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index d0ec76ec98..8e6639ddce 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -259,7 +259,6 @@ class PeakFilterT { int32_t _acc2 = 0; // CIC2 integrator public: - PeakFilterT() { // fill history @@ -376,7 +375,7 @@ public: // Limiter (common) // class LimiterImpl { -public: +protected: static const int NARC = 64; int32_t _holdTable[NARC]; @@ -394,8 +393,9 @@ public: int _sampleRate; float _outGain = 0.0f; +public: LimiterImpl(int sampleRate); - ~LimiterImpl() {} + virtual ~LimiterImpl() {} void setThreshold(float threshold); void setRelease(float release); @@ -560,7 +560,7 @@ class LimiterMono : public LimiterImpl { MonoDelay _delay; public: - LimiterMono(int sampleRate) : LimiterImpl(sampleRate) {}; + LimiterMono(int sampleRate) : LimiterImpl(sampleRate) {} void process(float* input, int16_t* output, int numFrames); }; @@ -611,7 +611,7 @@ class LimiterStereo : public LimiterImpl { StereoDelay _delay; public: - LimiterStereo(int sampleRate) : LimiterImpl(sampleRate) {}; + LimiterStereo(int sampleRate) : LimiterImpl(sampleRate) {} // interleaved stereo input/output void process(float* input, int16_t* output, int numFrames); @@ -705,8 +705,8 @@ void AudioLimiter::render(float* input, int16_t* output, int numFrames) { void AudioLimiter::setThreshold(float threshold) { _impl->setThreshold(threshold); -}; +} void AudioLimiter::setRelease(float release) { _impl->setRelease(release); -}; +} diff --git a/libraries/audio/src/AudioLimiter.h b/libraries/audio/src/AudioLimiter.h index 5ddc642635..96bfd610c2 100644 --- a/libraries/audio/src/AudioLimiter.h +++ b/libraries/audio/src/AudioLimiter.h @@ -15,7 +15,6 @@ class LimiterImpl; class AudioLimiter { public: - AudioLimiter(int sampleRate, int numChannels); ~AudioLimiter(); @@ -25,7 +24,6 @@ public: void setRelease(float release); private: - LimiterImpl* _impl; }; From 2dfc517d146eb2da172b887ea3af11600228bb4e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Mar 2016 16:45:36 -0800 Subject: [PATCH 198/292] MyAvatar: re-center vertically, on x & z drive keys --- interface/src/avatar/MyAvatar.cpp | 7 ++++--- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2b734a29c6..ac49514d09 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1097,7 +1097,8 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setTargetVelocity(getTargetVelocity()); _characterController.setPositionAndOrientation(getPosition(), getOrientation()); if (qApp->isHMDMode()) { - _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix); + bool hasDriveInput = fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f; + _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput); } else { _follow.deactivate(); } @@ -1964,7 +1965,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } -void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) { +void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { _desiredBodyMatrix = desiredBodyMatrix; if (!isActive(Rotation) && shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { activate(Rotation); @@ -1972,7 +1973,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Horizontal) && shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { activate(Horizontal); } - if (!isActive(Vertical) && shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix)) { + if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3950e6895f..731cba8153 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -414,7 +414,7 @@ private: bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix); + void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); }; FollowHelper _follow; From 05943ed35361e3b794822a3b255e1b2260413843 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Tue, 1 Mar 2016 16:50:58 -0800 Subject: [PATCH 199/292] Entity scripts keep of the which entity they are executing for. When the entity goes away, any created timers do, too. Also, loading interface scripts is not allowed from entity scripts. --- libraries/script-engine/src/ScriptEngine.cpp | 109 +++++++++++++++---- libraries/script-engine/src/ScriptEngine.h | 16 ++- 2 files changed, 104 insertions(+), 21 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 738e313f8f..9ee2c374c5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -485,10 +485,10 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin return; } RegisteredEventHandlers& handlersOnEntity = _registeredHandlers[entityID]; - QScriptValueList& handlersForEvent = handlersOnEntity[eventName]; + CallbackList& handlersForEvent = handlersOnEntity[eventName]; // QScriptValue does not have operator==(), so we can't use QList::removeOne and friends. So iterate. for (int i = 0; i < handlersForEvent.count(); ++i) { - if (handlersForEvent[i].equals(handler)) { + if (handlersForEvent[i].function.equals(handler)) { handlersForEvent.removeAt(i); return; // Design choice: since comparison is relatively expensive, just remove the first matching handler. } @@ -516,6 +516,13 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& // Connect up ALL the handlers to the global entities object's signals. // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) auto entities = DependencyManager::get(); + // Bug? These handlers are deleted when entityID is deleted, which is nice. + // But if they are created by an entity script on a different entity, should they also be deleted when the entity script unloads? + // E.g., suppose a bow has an entity script that causes arrows to be created with a potential lifetime greater than the bow, + // and that the entity script adds (e.g., collision) handlers to the arrows. Should those handlers fire if the bow is unloaded? + // Also, what about when the entity script is REloaded? + // For now, we are leaving them around. Changing that would require some non-trivial digging around to find the + // handlers that were added while a given currentEntityIdentifier was in place. I don't think this is dangerous. Just perhaps unexpected. -HRS connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { _registeredHandlers.remove(entityID); }); @@ -563,8 +570,9 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& if (!_registeredHandlers.contains(entityID)) { _registeredHandlers[entityID] = RegisteredEventHandlers(); } - QScriptValueList& handlersForEvent = _registeredHandlers[entityID][eventName]; - handlersForEvent << handler; // Note that the same handler can be added many times. See removeEntityEventHandler(). + CallbackList& handlersForEvent = _registeredHandlers[entityID][eventName]; + CallbackData handlerData = {handler, currentEntityIdentifier}; + handlersForEvent << handlerData; // Note that the same handler can be added many times. See removeEntityEventHandler(). } @@ -705,13 +713,30 @@ void ScriptEngine::run() { // NOTE: This is private because it must be called on the same thread that created the timers, which is why // we want to only call it in our own run "shutdown" processing. void ScriptEngine::stopAllTimers() { - QMutableHashIterator i(_timerFunctionMap); + QMutableHashIterator i(_timerFunctionMap); while (i.hasNext()) { i.next(); QTimer* timer = i.key(); stopTimer(timer); } } +void ScriptEngine::stopAllTimersForEntityScript(const EntityItemID& entityID) { + // We could maintain a separate map of entityID => QTimer, but someone will have to prove to me that it's worth the complexity. -HRS + QVector toDelete; + QMutableHashIterator i(_timerFunctionMap); + while (i.hasNext()) { + i.next(); + if (i.value().definingEntityIdentifier != entityID) { + continue; + } + QTimer* timer = i.key(); + toDelete << timer; // don't delete while we're iterating. save it. + } + for (auto timer:toDelete) { // now reap 'em + stopTimer(timer); + } + +} void ScriptEngine::stop() { if (!_isFinished) { @@ -743,13 +768,14 @@ void ScriptEngine::callAnimationStateHandler(QScriptValue callback, AnimVariantM QScriptValue javascriptParameters = parameters.animVariantMapToScriptValue(this, names, useNames); QScriptValueList callingArguments; callingArguments << javascriptParameters; + assert(currentEntityIdentifier.isInvalidID()); // No animation state handlers from entity scripts. QScriptValue result = callback.call(QScriptValue(), callingArguments); resultHandler(result); } void ScriptEngine::timerFired() { QTimer* callingTimer = reinterpret_cast(sender()); - QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); + CallbackData timerData = _timerFunctionMap.value(callingTimer); if (!callingTimer->isActive()) { // this timer is done, we can kill it @@ -758,11 +784,12 @@ void ScriptEngine::timerFired() { } // call the associated JS function, if it exists - if (timerFunction.isValid()) { - timerFunction.call(); + if (timerData.function.isValid()) { + callWithEnvironment(timerData.definingEntityIdentifier, timerData.function, timerData.function, QScriptValueList()); } } + QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { // create the timer, add it to the map, and start it QTimer* newTimer = new QTimer(this); @@ -773,7 +800,8 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int // make sure the timer stops when the script does connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); - _timerFunctionMap.insert(newTimer, function); + CallbackData timerData = {function, currentEntityIdentifier}; + _timerFunctionMap.insert(newTimer, timerData); newTimer->start(intervalMS); return newTimer; @@ -859,6 +887,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac } BatchLoader* loader = new BatchLoader(urls); + EntityItemID capturedEntityIdentifier = currentEntityIdentifier; auto evaluateScripts = [=](const QMap& data) { auto parentURL = _parentURL; @@ -870,13 +899,16 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac // Set the parent url so that path resolution will be relative // to this script's url during its initial evaluation _parentURL = url.toString(); - QScriptValue result = evaluate(contents, url.toString()); + auto operation = [&]() { + evaluate(contents, url.toString()); + }; + doWithEnvironment(capturedEntityIdentifier, operation); } } _parentURL = parentURL; if (callback.isFunction()) { - QScriptValue(callback).call(); + callWithEnvironment(capturedEntityIdentifier, QScriptValue(callback), QScriptValue(), QScriptValueList()); } loader->deleteLater(); @@ -917,6 +949,11 @@ void ScriptEngine::load(const QString& loadFile) { << "loadFile:" << loadFile << "parent script:" << getFilename(); return; // bail early } + if (!currentEntityIdentifier.isInvalidID()) { + qCWarning(scriptengine) << "Script.load() from entity script is ignored... " + << "loadFile:" << loadFile << "parent script:" << getFilename(); + return; // bail early + } QUrl url = resolvePath(loadFile); if (_isReloading) { @@ -933,7 +970,7 @@ void ScriptEngine::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { +void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHandlerArgs) { if (QThread::currentThread() != thread()) { qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); @@ -946,10 +983,13 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin if (!handlersOnEntity.contains(eventName)) { return; } - QScriptValueList handlersForEvent = handlersOnEntity[eventName]; + CallbackList handlersForEvent = handlersOnEntity[eventName]; if (!handlersForEvent.isEmpty()) { for (int i = 0; i < handlersForEvent.count(); ++i) { - handlersForEvent[i].call(QScriptValue(), eventHanderArgs); + // handlersForEvent[i] can tonain many handlers that may have each been added by different interface or entity scripts, + // and the entity scripts may be for entities other than the one this is a handler for. + // Fortunately, the definingEntityIdentifier captured the entity script id (if any) when the handler was added. + callWithEnvironment(handlersForEvent[i].definingEntityIdentifier, handlersForEvent[i].function, QScriptValue(), eventHandlerArgs); } } } @@ -1055,9 +1095,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co QString file = QUrl(scriptOrURL).toLocalFile(); lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); } + QScriptValue entityScriptConstructor, entityScriptObject; + auto initialization = [&]{ + entityScriptConstructor = evaluate(contents, fileName); + entityScriptObject = entityScriptConstructor.construct(); + }; + doWithEnvironment(entityID, initialization); - QScriptValue entityScriptConstructor = evaluate(contents, fileName); - QScriptValue entityScriptObject = entityScriptConstructor.construct(); EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; _entityScripts[entityID] = newDetails; if (isURL) { @@ -1087,6 +1131,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { if (_entityScripts.contains(entityID)) { callEntityScriptMethod(entityID, "unload"); _entityScripts.remove(entityID); + stopAllTimersForEntityScript(entityID); } } @@ -1142,6 +1187,32 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { recurseGuard = false; } +// Execute operation in the appropriate context for (the possibly empty) entityID. +// Even if entityID is supplied as currentEntityIdentifier, this still documents the source +// of the code being executed (e.g., if we ever sandbox different entity scripts, or provide different +// global values for different entity scripts). +void ScriptEngine::doWithEnvironment(const EntityItemID& entityID, std::function operation) { + EntityItemID oldIdentifier = currentEntityIdentifier; + currentEntityIdentifier = entityID; + +#if DEBUG_CURRENT_ENTITY + QScriptValue oldData = this->globalObject().property("debugEntityID"); + this->globalObject().setProperty("debugEntityID", entityID.toScriptValue(this)); // Make the entityID available to javascript as a global. + operation(); + this->globalObject().setProperty("debugEntityID", oldData); +#else + operation(); +#endif + + currentEntityIdentifier = oldIdentifier; +} +void ScriptEngine::callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args) { + auto operation = [&]() { + function.call(thisObject, args); + }; + doWithEnvironment(entityID, operation); +} + void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName, const QStringList& params) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING @@ -1168,7 +1239,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QScriptValueList args; args << entityID.toScriptValue(this); args << qScriptValueFromSequence(this, params); - entityScript.property(methodName).call(entityScript, args); + callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args); } } @@ -1200,7 +1271,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS QScriptValueList args; args << entityID.toScriptValue(this); args << event.toScriptValue(this); - entityScript.property(methodName).call(entityScript, args); + callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args); } } } @@ -1234,7 +1305,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS args << entityID.toScriptValue(this); args << otherID.toScriptValue(this); args << collisionToScriptValue(this, collision); - entityScript.property(methodName).call(entityScript, args); + callWithEnvironment(entityID, entityScript.property(methodName), entityScript, args); } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f89998d9f0..91d4c3f5a5 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -42,7 +42,14 @@ const QString NO_SCRIPT(""); const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); -typedef QHash RegisteredEventHandlers; +class CallbackData { +public: + QScriptValue function; + EntityItemID definingEntityIdentifier; +}; + +typedef QList CallbackList; +typedef QHash RegisteredEventHandlers; class EntityScriptDetails { public: @@ -169,7 +176,7 @@ protected: std::atomic _isRunning { false }; int _evaluatesPending { 0 }; bool _isInitialized { false }; - QHash _timerFunctionMap; + QHash _timerFunctionMap; QSet _includedURLs; bool _wantSignals { true }; QHash _entityScripts; @@ -181,6 +188,7 @@ protected: bool evaluatePending() const { return _evaluatesPending > 0; } void timerFired(); void stopAllTimers(); + void stopAllTimersForEntityScript(const EntityItemID& entityID); void refreshFileScript(const EntityItemID& entityID); void setParentURL(const QString& parentURL) { _parentURL = parentURL; } @@ -203,6 +211,10 @@ protected: void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); + EntityItemID currentEntityIdentifier {}; // Contains the defining entity script entity id during execution, if any. Empty for interface script execution. + void doWithEnvironment(const EntityItemID& entityID, std::function operation); + void callWithEnvironment(const EntityItemID& entityID, QScriptValue function, QScriptValue thisObject, QScriptValueList args); + friend class ScriptEngines; static std::atomic _stoppingAllScripts; }; From 35973d4e30d0567096fb10fa1c725b61a5826447 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Mar 2016 17:02:34 -0800 Subject: [PATCH 200/292] re-use same socketed node for subsequent connections --- domain-server/src/DomainGatekeeper.cpp | 36 +++++++++++++++++++------- domain-server/src/DomainGatekeeper.h | 3 ++- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index f385f5c489..94e79416a5 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -258,9 +258,26 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect if (onlyEditorsAreRezzers) { canRez = isAllowedEditor; } + + QUuid hintNodeID; + + // in case this is a node that's failing to connect + // double check we don't have a node whose sockets match exactly already in the list + limitedNodeList->eachNodeBreakable([&nodeConnection, &hintNodeID](const SharedNodePointer& node){ + if (node->getPublicSocket() == nodeConnection.publicSockAddr + && node->getLocalSocket() == nodeConnection.localSockAddr) { + // we have a node that already has these exact sockets - this occurs if a node + // is unable to connect to the domain + hintNodeID = node->getUUID(); + + return false; + } + + return true; + }); - // add the new node - SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection); + // add the connecting node (or re-use the matched one from eachNodeBreakable above) + SharedNodePointer newNode = addVerifiedNodeFromConnectRequest(nodeConnection, hintNodeID); // set the edit rights for this user newNode->setIsAllowedEditor(isAllowedEditor); @@ -279,28 +296,29 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect return newNode; } -SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection) { +SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection, + QUuid nodeID) { HifiSockAddr discoveredSocket = nodeConnection.senderSockAddr; SharedNetworkPeer connectedPeer = _icePeers.value(nodeConnection.connectUUID); - QUuid nodeUUID; - if (connectedPeer) { // this user negotiated a connection with us via ICE, so re-use their ICE client ID - nodeUUID = nodeConnection.connectUUID; + nodeID = nodeConnection.connectUUID; if (connectedPeer->getActiveSocket()) { // set their discovered socket to whatever the activated socket on the network peer object was discoveredSocket = *connectedPeer->getActiveSocket(); } } else { - // we got a connectUUID we didn't recognize, just add the node with a new UUID - nodeUUID = QUuid::createUuid(); + // we got a connectUUID we didn't recognize, either use the hinted node ID or randomly generate a new one + if (nodeID.isNull()) { + nodeID = QUuid::createUuid(); + } } auto limitedNodeList = DependencyManager::get(); - SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeUUID, nodeConnection.nodeType, + SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeID, nodeConnection.nodeType, nodeConnection.publicSockAddr, nodeConnection.localSockAddr); // So that we can send messages to this node at will - we need to activate the correct socket on this node now diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index 2fc4be380c..c4ac32fabf 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -59,7 +59,8 @@ private: SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection, const QString& username, const QByteArray& usernameSignature); - SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection); + SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection, + QUuid nodeID = QUuid()); bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr); From aed2ad72d13556b7ecffcbcbd43260e8f7581f23 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Mar 2016 17:09:57 -0800 Subject: [PATCH 201/292] Using another formula for the specularDistribution giving much better results --- libraries/render-utils/src/DeferredLighting.slh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index 95c77ef2f0..2e06deb0af 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -20,19 +20,19 @@ vec3 fresnelSchlick(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) { float specularDistribution(float roughness, vec3 normal, vec3 halfDir) { float ndoth = clamp(dot(halfDir, normal), 0.0, 1.0); - float gloss2 = pow(roughness, 4); + float gloss2 = pow(0.001 + roughness, 4); float denom = (ndoth * ndoth*(gloss2 - 1) + 1); float power = gloss2 / (3.14159 * denom * denom); return power; } -/* + // Frag Shading returns the diffuse amount as W and the specular rgb as xyz vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) { // Diffuse Lighting From 6e80665107c29c4d294509b66e9f77cbf9e73684 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Mar 2016 17:45:16 -0800 Subject: [PATCH 202/292] MyAvatar: reduced rotation re-center threshold to 30 degrees Also, warning fix for Linux. --- interface/src/avatar/MyAvatar.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ac49514d09..ed5d2b0430 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1937,7 +1937,7 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { } bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { - const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 4.0f); + const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); return glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; } @@ -1959,9 +1959,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co const float CYLINDER_BOTTOM = -1.0f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - glm::vec3 radialOffset(offset.x, 0.0f, offset.z); - float radialDistance = glm::length(radialOffset); - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } From e79427bb3b330338183f3c988810e90257c39506 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 19:41:50 +1300 Subject: [PATCH 203/292] Make some settings dialogs have collapsible sections --- .../resources/qml/controls-uit/ComboBox.qml | 4 +- .../resources/qml/controls-uit/Slider.qml | 4 +- .../resources/qml/controls-uit/SpinBox.qml | 4 +- .../qml/controls-uit/StaticSection.qml | 124 +++++++++++++----- .../resources/qml/controls-uit/TextField.qml | 4 +- interface/resources/qml/controls-uit/Tree.qml | 2 +- .../qml/dialogs/PreferencesDialog.qml | 10 +- .../qml/dialogs/preferences/Section.qml | 3 +- .../qml/hifi/dialogs/RunningScripts.qml | 4 + .../qml/styles-uit/HifiConstants.qml | 31 ++--- 10 files changed, 125 insertions(+), 65 deletions(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index 81cf53a842..c8fba7079c 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -27,11 +27,11 @@ ComboBox { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property string label: "" - property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height : 0) + property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0) height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. - y: comboBoxLabel.visible ? comboBoxLabel.height : 0 + y: comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0 style: ComboBoxStyle { FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } diff --git a/interface/resources/qml/controls-uit/Slider.qml b/interface/resources/qml/controls-uit/Slider.qml index ea4058f2be..cf59e1d989 100644 --- a/interface/resources/qml/controls-uit/Slider.qml +++ b/interface/resources/qml/controls-uit/Slider.qml @@ -21,10 +21,10 @@ Slider { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property string label: "" - property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height : 0) + property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0) height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. - y: sliderLabel.visible ? sliderLabel.height : 0 + y: sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0 style: SliderStyle { diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index d1061bca0b..f603a584b3 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -21,14 +21,14 @@ SpinBox { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property string label: "" - property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height : 0) + property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0) FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } font.family: firaSansSemiBold.name font.pixelSize: hifi.fontSizes.textFieldInput height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. - y: spinBoxLabel.visible ? spinBoxLabel.height : 0 + y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0 style: SpinBoxStyle { background: Rectangle { diff --git a/interface/resources/qml/controls-uit/StaticSection.qml b/interface/resources/qml/controls-uit/StaticSection.qml index a6c8199f48..bd5e6e2ee4 100644 --- a/interface/resources/qml/controls-uit/StaticSection.qml +++ b/interface/resources/qml/controls-uit/StaticSection.qml @@ -9,12 +9,15 @@ // import QtQuick 2.5 +import QtGraphicalEffects 1.0 import "../styles-uit" Column { property string name: "Static Section" property bool isFirst: false + property bool isCollapsible: false // Set at creation. + property bool isCollapsed: false spacing: hifi.dimensions.contentSpacing.y @@ -25,41 +28,94 @@ Column { rightMargin: hifi.dimensions.contentMargin.x } - VerticalSpacer { } - - Item { - visible: !isFirst - anchors.top: sectionName.top - - Rectangle { - width: frame.width - height: 1 - color: hifi.colors.baseGrayShadow - x: -hifi.dimensions.contentMargin.x - anchors.bottom: highlight.top - } - - Rectangle { - id: highlight - width: frame.width - height: 1 - color: hifi.colors.baseGrayHighlight - x: -hifi.dimensions.contentMargin.x - anchors.bottom: parent.top - } - } - - RalewayRegular { - id: sectionName - text: parent.name - size: hifi.fontSizes.sectionName - font.capitalization: Font.AllUppercase - color: hifi.colors.lightGrayText - verticalAlignment: Text.AlignBottom - height: { - if (!isFirst) { - hifi.dimensions.contentMargin.y + function toggleCollapsed() { + if (isCollapsible) { + isCollapsed = !isCollapsed; + for (var i = 1; i < children.length; i++) { + children[i].visible = !isCollapsed; } } } + + Item { + id: sectionName + height: (isCollapsible ? 4 : 3) * hifi.dimensions.contentSpacing.y + anchors.left: parent.left + anchors.right: parent.right + + Item { + visible: !isFirst + anchors.top: heading.top + + Rectangle { + id: shadow + width: frame.width + height: 1 + color: hifi.colors.baseGrayShadow + x: -hifi.dimensions.contentMargin.x + } + + Rectangle { + width: frame.width + height: 1 + color: hifi.colors.baseGrayHighlight + x: -hifi.dimensions.contentMargin.x + anchors.top: shadow.bottom + } + } + + Item { + id: heading + anchors { + left: parent.left + right: parent.right + top: parent.top + topMargin: hifi.dimensions.contentSpacing.y + } + height: 3 * hifi.dimensions.contentSpacing.y + + RalewayRegular { + id: title + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + size: hifi.fontSizes.sectionName + font.capitalization: Font.AllUppercase + text: name + color: hifi.colors.lightGrayText + } + + HiFiGlyphs { + anchors { + verticalCenter: title.verticalCenter + right: parent.right + rightMargin: -hifi.dimensions.contentMargin.x + } + y: -2 + size: hifi.fontSizes.carat + text: isCollapsed ? hifi.glyphs.caratR : hifi.glyphs.caratDn + color: hifi.colors.lightGrayText + visible: isCollapsible + } + + MouseArea { + anchors.fill: parent + onClicked: toggleCollapsed() + } + } + + LinearGradient { + visible: isCollapsible + width: frame.width + height: 4 + x: -hifi.dimensions.contentMargin.x + anchors.top: heading.bottom + start: Qt.point(0, 0) + end: Qt.point(0, 4) + gradient: Gradient { + GradientStop { position: 0.0; color: hifi.colors.darkGray } + GradientStop { position: 1.0; color: hifi.colors.baseGray } // Equivalent of darkGray0 over baseGray background. + } + cached: true + } + } } diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index 1d2d6a2298..42712e9d23 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -21,7 +21,7 @@ TextField { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property string label: "" - property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0) + property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0) placeholderText: textField.placeholderText @@ -30,7 +30,7 @@ TextField { font.pixelSize: hifi.fontSizes.textFieldInput height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered. - y: textFieldLabel.visible ? textFieldLabel.height : 0 + y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0 style: TextFieldStyle { textColor: isLightColorScheme diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 086fa0d458..0981999568 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -56,7 +56,7 @@ TreeView { branchDelegate: HiFiGlyphs { text: styleData.isExpanded ? hifi.glyphs.caratDn : hifi.glyphs.caratR - size: hifi.fontSizes.tableText * 2.5 + size: hifi.fontSizes.carat color: colorScheme == hifi.colorSchemes.light ? (styleData.selected ? hifi.colors.black diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index 2e69db10aa..40cc713397 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -75,14 +75,12 @@ Window { if (sections.length) { // Default sections to expanded/collapsed as appropriate for dialog. - if (title === "Avatar Preferences") { - sections[0].expanded = true; - if (sections.length === 1) { - sections[0].collapsable = false - } + if (sections.length === 1) { + sections[0].collapsable = false + sections[0].expanded = true } else { for (i = 0; i < sections.length; i++) { - sections[i].collapsable = false; + sections[i].collapsable = true; sections[i].expanded = true; } } diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index d6d5c71167..0d6f49e108 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -51,8 +51,9 @@ Preference { HiFiControls.StaticSection { id: contentContainer name: root.name - isFirst: root.isFirst + isCollapsible: root.collapsable + isCollapsed: !root.expanded anchors { left: parent.left diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index a174f4c4a7..d73d3dda89 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -114,6 +114,10 @@ Window { anchors.left: parent.left anchors.right: parent.right } + + HifiControls.VerticalSpacer { + height: 4 + } } HifiControls.StaticSection { diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index f13550b67d..5c50a4f6ae 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -110,21 +110,22 @@ Item { Item { id: fontSizes // In pixels - readonly property real overlayTitle: dimensions.largeScreen? 18 : 14 - readonly property real tabName: dimensions.largeScreen? 12 : 10 - readonly property real sectionName: dimensions.largeScreen? 12 : 10 - readonly property real inputLabel: dimensions.largeScreen? 14 : 10 - readonly property real textFieldInput: dimensions.largeScreen? 15 : 12 - readonly property real tableText: dimensions.largeScreen? 15 : 12 - readonly property real buttonLabel: dimensions.largeScreen? 13 : 9 - readonly property real iconButton: dimensions.largeScreen? 13 : 9 - readonly property real listItem: dimensions.largeScreen? 15 : 11 - readonly property real tabularData: dimensions.largeScreen? 15 : 11 - readonly property real logs: dimensions.largeScreen? 16 : 12 - readonly property real code: dimensions.largeScreen? 16 : 12 - readonly property real rootMenu: dimensions.largeScreen? 15 : 11 - readonly property real menuItem: dimensions.largeScreen? 15 : 11 - readonly property real shortcutText: dimensions.largeScreen? 13 : 9 + readonly property real overlayTitle: dimensions.largeScreen ? 18 : 14 + readonly property real tabName: dimensions.largeScreen ? 12 : 10 + readonly property real sectionName: dimensions.largeScreen ? 12 : 10 + readonly property real inputLabel: dimensions.largeScreen ? 14 : 10 + readonly property real textFieldInput: dimensions.largeScreen ? 15 : 12 + readonly property real tableText: dimensions.largeScreen ? 15 : 12 + readonly property real buttonLabel: dimensions.largeScreen ? 13 : 9 + readonly property real iconButton: dimensions.largeScreen ? 13 : 9 + readonly property real listItem: dimensions.largeScreen ? 15 : 11 + readonly property real tabularData: dimensions.largeScreen ? 15 : 11 + readonly property real logs: dimensions.largeScreen ? 16 : 12 + readonly property real code: dimensions.largeScreen ? 16 : 12 + readonly property real rootMenu: dimensions.largeScreen ? 15 : 11 + readonly property real menuItem: dimensions.largeScreen ? 15 : 11 + readonly property real shortcutText: dimensions.largeScreen ? 13 : 9 + readonly property real carat: dimensions.largeScreen ? 38 : 30 } Item { From 4d53dee29cb3f5f444688537e9d4e2a5c111b675 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 19:46:26 +1300 Subject: [PATCH 204/292] Rename section control --- .../controls-uit/{StaticSection.qml => ContentSection.qml} | 2 +- interface/resources/qml/dialogs/preferences/Section.qml | 2 +- interface/resources/qml/hifi/dialogs/RunningScripts.qml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename interface/resources/qml/controls-uit/{StaticSection.qml => ContentSection.qml} (99%) diff --git a/interface/resources/qml/controls-uit/StaticSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml similarity index 99% rename from interface/resources/qml/controls-uit/StaticSection.qml rename to interface/resources/qml/controls-uit/ContentSection.qml index bd5e6e2ee4..20137c28cb 100644 --- a/interface/resources/qml/controls-uit/StaticSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -1,5 +1,5 @@ // -// StaticSection.qml +// ContentSection.qml // // Created by David Rowe on 16 Feb 2016 // Copyright 2016 High Fidelity, Inc. diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index 0d6f49e108..81e9278903 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -48,7 +48,7 @@ Preference { Component.onCompleted: d.buildPreferences(); - HiFiControls.StaticSection { + HiFiControls.ContentSection { id: contentContainer name: root.name isFirst: root.isFirst diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index d73d3dda89..9e356582cf 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -87,7 +87,7 @@ Window { Column { width: pane.contentWidth - HifiControls.StaticSection { + HifiControls.ContentSection { name: "Currently Running" isFirst: true @@ -120,7 +120,7 @@ Window { } } - HifiControls.StaticSection { + HifiControls.ContentSection { name: "Load Scripts" Row { From 829c858b0427b7950dd895d4c2d2ca21004e3913 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 2 Mar 2016 22:18:12 +1300 Subject: [PATCH 205/292] Start on ComboBox again using Austin's HMD-compatible code --- .../resources/qml/controls-uit/ComboBox.qml | 197 ++++++++++++------ 1 file changed, 130 insertions(+), 67 deletions(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index c8fba7079c..40bbddc0fb 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -1,7 +1,7 @@ // // ComboBox.qml // -// Created by David Rowe on 27 Feb 2016 +// Created by Bradley Austin David on 27 Jan 2016 // Copyright 2016 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -12,86 +12,149 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "." as VrControls -// FIXME: Currently supports only the "Drop Down Box" case in the UI Toolkit doc; -// Should either be made to also support the "Combo Box" case or drop-down and combo box should be separate controls. +FocusScope { + id: root + property alias model: comboBox.model; + readonly property alias currentText: comboBox.currentText; + property alias currentIndex: comboBox.currentIndex; + implicitHeight: comboBox.height; + focus: true -// FIXME: Style dropped-down items per UI Toolkit Drop Down Box. -// http://stackoverflow.com/questions/27089779/qml-combobox-item-dropdownmenu-style/27217209#27217209 + readonly property ComboBox control: comboBox -ComboBox { - id: comboBox + Rectangle { + id: background + gradient: Gradient { + GradientStop {color: control.pressed ? "#bababa" : "#fefefe" ; position: 0} + GradientStop {color: control.pressed ? "#ccc" : "#e3e3e3" ; position: 1} + } + anchors.fill: parent + border.color: control.activeFocus ? "#47b" : "#999" + Rectangle { + anchors.fill: parent + radius: parent.radius + color: control.activeFocus ? "#47b" : "white" + opacity: control.hovered || control.activeFocus ? 0.1 : 0 + Behavior on opacity {NumberAnimation{ duration: 100 }} + } + } - property int colorScheme: hifi.colorSchemes.light - readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light - property string label: "" - property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0) + SystemPalette { id: palette } - height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. + ComboBox { + id: comboBox + anchors.fill: parent + visible: false + } - y: comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0 + Text { + id: textField + anchors { left: parent.left; leftMargin: 2; right: dropIcon.left; verticalCenter: parent.verticalCenter } + text: comboBox.currentText + elide: Text.ElideRight + } - style: ComboBoxStyle { - FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } - font { - family: firaSansSemiBold.name - pixelSize: hifi.fontSizes.textFieldInput + Item { + id: dropIcon + anchors { right: parent.right; verticalCenter: parent.verticalCenter } + width: 20 + height: textField.height + VrControls.FontAwesome { + anchors.centerIn: parent; size: 16; + text: "\uf0d7" + } + } + + MouseArea { + anchors.fill: parent + onClicked: toggleList(); + } + + function toggleList() { + if (popup.visible) { + hideList(); + } else { + showList(); + } + } + + function showList() { + var r = desktop.mapFromItem(root, 0, 0, root.width, root.height); + listView.currentIndex = root.currentIndex + scrollView.x = r.x; + scrollView.y = r.y + r.height; + var bottom = scrollView.y + scrollView.height; + if (bottom > desktop.height) { + scrollView.y -= bottom - desktop.height + 8; + } + popup.visible = true; + popup.forceActiveFocus(); + } + + function hideList() { + popup.visible = false; + } + + FocusScope { + id: popup + parent: desktop + anchors.fill: parent + z: desktop.zLevels.menu + visible: false + focus: true + + MouseArea { + anchors.fill: parent + onClicked: hideList(); } - background: Rectangle { - gradient: Gradient { - GradientStop { - position: 0.2 - color: pressed - ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) - : (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart) - } - GradientStop { - position: 1.0 - color: pressed - ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) - : (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish) - } - } + function previousItem() { listView.currentIndex = (listView.currentIndex + listView.count - 1) % listView.count; } + function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; } + function selectCurrentItem() { root.currentIndex = listView.currentIndex; hideList(); } - HiFiGlyphs { - text: hifi.glyphs.caratDn - size: hifi.dimensions.spinnerSize - color: pressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.baseGray - anchors { - top: parent.top - topMargin: -8 - right: parent.right - rightMargin: -6 - } - } + Keys.onUpPressed: previousItem(); + Keys.onDownPressed: nextItem(); + Keys.onSpacePressed: selectCurrentItem(); + Keys.onRightPressed: selectCurrentItem(); + Keys.onReturnPressed: selectCurrentItem(); + Keys.onEscapePressed: hideList(); - Rectangle { - width: 1 - height: parent.height - color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray - anchors { - top: parent.top - right: parent.right - rightMargin: parent.height + ScrollView { + id: scrollView + height: 480 + width: root.width + + ListView { + id: listView + height: textField.height * count * 1.4 + model: root.model + highlight: Rectangle{ + width: listView.currentItem ? listView.currentItem.width : 0 + height: listView.currentItem ? listView.currentItem.height : 0 + color: "red" + } + delegate: Rectangle { + width: root.width + height: popupText.implicitHeight * 1.4 + color: ListView.isCurrentItem ? palette.highlight : palette.base + Text { + anchors.verticalCenter: parent.verticalCenter + id: popupText + x: 3 + text: listView.model[index] + } + MouseArea { + id: popupHover + anchors.fill: parent; + hoverEnabled: true + onEntered: listView.currentIndex = index; + onClicked: popup.selectCurrentItem() + } } } } - - textColor: pressed ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText ) - selectedTextColor: hifi.colors.baseGray - selectionColor: hifi.colors.primaryHighlight } - HifiControls.Label { - id: comboBoxLabel - text: comboBox.label - colorScheme: comboBox.colorScheme - anchors.left: parent.left - anchors.bottom: parent.top - anchors.bottomMargin: 4 - visible: label != "" - } } From 98ad7852673843cfd53dce9d5dc99a76ad75aa3e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 00:04:15 +1300 Subject: [PATCH 206/292] Get ComboBox working --- .../resources/qml/controls-uit/ComboBox.qml | 28 +++++++++++++++---- .../preferences/ComboBoxPreference.qml | 21 ++++++++------ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index 40bbddc0fb..1382815462 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -12,18 +12,26 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 +import "../styles-uit" +import "../controls-uit" as HifiControls import "." as VrControls FocusScope { id: root + property alias model: comboBox.model; + property alias comboBox: comboBox readonly property alias currentText: comboBox.currentText; property alias currentIndex: comboBox.currentIndex; + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property string label: "" + property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0) + implicitHeight: comboBox.height; focus: true - readonly property ComboBox control: comboBox - Rectangle { id: background gradient: Gradient { @@ -61,9 +69,10 @@ FocusScope { anchors { right: parent.right; verticalCenter: parent.verticalCenter } width: 20 height: textField.height - VrControls.FontAwesome { - anchors.centerIn: parent; size: 16; - text: "\uf0d7" + HiFiGlyphs { + anchors.centerIn: parent + size: hifi.dimensions.spinnerSize + text: hifi.glyphs.caratDn } } @@ -157,4 +166,13 @@ FocusScope { } } + HifiControls.Label { + id: comboBoxLabel + text: root.label + colorScheme: root.colorScheme + anchors.left: parent.left + anchors.bottom: parent.top + anchors.bottomMargin: 4 + visible: label != "" + } } diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index be5c017bbd..c7f8bafca3 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -10,30 +10,33 @@ import QtQuick 2.5 -import "../../controls-uit" +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import "../../controls-uit" as HiFiControls +import "../../styles-uit" Preference { id: root - property alias comboBox: comboBox - height: comboBox.controlHeight + height: dataComboBox.controlHeight Component.onCompleted: { - comboBox.currentIndex = comboBox.find(preference.value); + dataComboBox.currentIndex = dataComboBox.comboBox.find(preference.value); } function save() { - preference.value = comboBox.currentText; + preference.value = dataComboBox.currentText; + //preference.value = comboBox.currentText; preference.save(); } - Label { + HiFiControls.Label { text: root.label + ":" colorScheme: hifi.colorSchemes.dark - anchors.verticalCenter: comboBox.verticalCenter + anchors.verticalCenter: dataComboBox.verticalCenter } - ComboBox { - id: comboBox + HiFiControls.ComboBox { + id: dataComboBox model: preference.items width: 150 anchors { right: parent.right } From c1f5bac86a878116cef49ec94b24ea3aca502c40 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 01:14:00 +1300 Subject: [PATCH 207/292] Style the ComboBox --- .../resources/qml/controls-uit/ComboBox.qml | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index 1382815462..3dcbd3c35a 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -29,24 +29,28 @@ FocusScope { property string label: "" property real controlHeight: height + (comboBoxLabel.visible ? comboBoxLabel.height + comboBoxLabel.anchors.bottomMargin : 0) + readonly property ComboBox control: comboBox + implicitHeight: comboBox.height; focus: true Rectangle { id: background gradient: Gradient { - GradientStop {color: control.pressed ? "#bababa" : "#fefefe" ; position: 0} - GradientStop {color: control.pressed ? "#ccc" : "#e3e3e3" ; position: 1} + GradientStop { + position: 0.2 + color: popup.visible + ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + : (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart) + } + GradientStop { + position: 1.0 + color: popup.visible + ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + : (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish) + } } anchors.fill: parent - border.color: control.activeFocus ? "#47b" : "#999" - Rectangle { - anchors.fill: parent - radius: parent.radius - color: control.activeFocus ? "#47b" : "white" - opacity: control.hovered || control.activeFocus ? 0.1 : 0 - Behavior on opacity {NumberAnimation{ duration: 100 }} - } } SystemPalette { id: palette } @@ -55,13 +59,21 @@ FocusScope { id: comboBox anchors.fill: parent visible: false + height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. } - Text { + FiraSansSemiBold { id: textField - anchors { left: parent.left; leftMargin: 2; right: dropIcon.left; verticalCenter: parent.verticalCenter } + anchors { + left: parent.left + leftMargin: hifi.dimensions.textPadding + right: dropIcon.left + verticalCenter: parent.verticalCenter + } + size: hifi.fontSizes.textFieldInput text: comboBox.currentText elide: Text.ElideRight + color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText ) } Item { @@ -73,10 +85,13 @@ FocusScope { anchors.centerIn: parent size: hifi.dimensions.spinnerSize text: hifi.glyphs.caratDn + color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText) } } MouseArea { + id: controlHover + hoverEnabled: true anchors.fill: parent onClicked: toggleList(); } @@ -133,26 +148,23 @@ FocusScope { ScrollView { id: scrollView height: 480 - width: root.width ListView { id: listView height: textField.height * count * 1.4 model: root.model - highlight: Rectangle{ - width: listView.currentItem ? listView.currentItem.width : 0 - height: listView.currentItem ? listView.currentItem.height : 0 - color: "red" - } delegate: Rectangle { - width: root.width + width: root.width + 4 height: popupText.implicitHeight * 1.4 - color: ListView.isCurrentItem ? palette.highlight : palette.base - Text { + color: popupHover.containsMouse ? hifi.colors.primaryHighlight : (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + FiraSansSemiBold { + anchors.left: parent.left + anchors.leftMargin: hifi.dimensions.textPadding anchors.verticalCenter: parent.verticalCenter id: popupText - x: 3 text: listView.model[index] + size: hifi.fontSizes.textFieldInput + color: hifi.colors.baseGray } MouseArea { id: popupHover From a51dd43dfff5ae2a5bc86d220a6f72cdf3851c80 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 01:56:02 +1300 Subject: [PATCH 208/292] Wrap labels --- interface/resources/qml/controls-uit/CheckBox.qml | 1 + .../qml/dialogs/preferences/ComboBoxPreference.qml | 8 +++++++- .../qml/dialogs/preferences/SliderPreference.qml | 8 +++++++- .../qml/dialogs/preferences/SpinBoxPreference.qml | 8 +++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 255151e4e0..bd16a33776 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -64,6 +64,7 @@ Original.CheckBox { text: control.text colorScheme: checkBox.colorScheme x: checkBox.boxSize / 2 + wrapMode: Text.Wrap } } } diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index c7f8bafca3..042d172bd0 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -32,7 +32,13 @@ Preference { HiFiControls.Label { text: root.label + ":" colorScheme: hifi.colorSchemes.dark - anchors.verticalCenter: dataComboBox.verticalCenter + anchors { + left: parent.left + right: dataComboBox.left + rightMargin: hifi.dimensions.contentSpacing.x + verticalCenter: dataComboBox.verticalCenter + } + wrapMode: Text.Wrap } HiFiControls.ComboBox { diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index 57042a653a..81eeddc9df 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -30,7 +30,13 @@ Preference { Label { text: root.label + ":" colorScheme: hifi.colorSchemes.dark - anchors.verticalCenter: slider.verticalCenter + anchors { + left: parent.left + right: slider.left + rightMargin: hifi.dimensions.contentSpacing.x + verticalCenter: spinner.verticalCenter + } + wrapMode: Text.Wrap } Slider { diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index 71b2f1f655..c77d0bd18b 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -29,7 +29,13 @@ Preference { Label { text: root.label + ":" colorScheme: hifi.colorSchemes.dark - anchors.verticalCenter: spinner.verticalCenter + anchors { + left: parent.left + right: spinner.left + rightMargin: hifi.dimensions.contentSpacing.x + verticalCenter: spinner.verticalCenter + } + wrapMode: Text.Wrap } SpinBox { From c3b47088c935786e4336c31d0f0957307fd4213a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 01:59:21 +1300 Subject: [PATCH 209/292] Fix slider vertical alignment --- .../resources/qml/dialogs/preferences/SliderPreference.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index 81eeddc9df..11bcc25716 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -34,7 +34,7 @@ Preference { left: parent.left right: slider.left rightMargin: hifi.dimensions.contentSpacing.x - verticalCenter: spinner.verticalCenter + verticalCenter: slider.verticalCenter } wrapMode: Text.Wrap } From 3ef4e45daefa735d0b2d2f2feb6b38208fb31f19 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 10:28:50 -0800 Subject: [PATCH 210/292] Flappy bird first draft --- examples/flappyBird.js | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 examples/flappyBird.js diff --git a/examples/flappyBird.js b/examples/flappyBird.js new file mode 100644 index 0000000000..95e018089e --- /dev/null +++ b/examples/flappyBird.js @@ -0,0 +1,71 @@ +// +// flappyBird.js +// +// Created by Clement 3/2/16 +// 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 +// + +// Constants + + + +// Class definitions +function Game() { + // public methods + this.start = function() { + if (!isRunning) { + setup(); + Script.update.connect(idle); + } + }; + + this.stop = function() { + if (isRunning) { + Script.update.disconnect(idle); + cleanup(); + } + }; + + // Private game state + var that = this; + var isRunning = false; + + // Game loop setup + function idle(deltaTime) { + inputs(); + update(deltaTime); + draw(); + }; + + // Private methods + function setup() { + print("setup"); + }; + function inputs() { + print("inputs"); + }; + function update(deltaTime) { + print("update: " + deltaTime); + }; + function draw() { + print("draw"); + }; + function cleanup() { + print("cleanup"); + }; +} + +// Script logic +function scriptStarting() { + var game = new Game(); + + Script.scriptEnding.connect(function() { + game.stop(); + }); + game.start(); +} + +scriptStarting(); \ No newline at end of file From 81f13afb4edf1eff97e2538a8474a90b88586679 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 10:24:42 +1300 Subject: [PATCH 211/292] Tweak look of combo box control --- .../resources/qml/controls-uit/ComboBox.qml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index 3dcbd3c35a..bad1524719 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -79,10 +79,21 @@ FocusScope { Item { id: dropIcon anchors { right: parent.right; verticalCenter: parent.verticalCenter } - width: 20 - height: textField.height + height: background.height + width: height + Rectangle { + width: 1 + height: parent.height + anchors.top: parent.top + anchors.left: parent.left + color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray + } HiFiGlyphs { - anchors.centerIn: parent + anchors { + top: parent.top + topMargin: -8 + horizontalCenter: parent.horizontalCenter + } size: hifi.dimensions.spinnerSize text: hifi.glyphs.caratDn color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText) From 6ae27fe1f9ad965e6c7a133a337736e3bf67ff69 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 15:53:13 -0800 Subject: [PATCH 212/292] More flappy bird work --- examples/flappyBird.js | 271 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 258 insertions(+), 13 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 95e018089e..63366a6c75 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -9,59 +9,304 @@ // // Constants +var OBJECTS_LIFETIME = 1; +var G = 4.0; - +Number.prototype.clamp = function(min, max) { + return Math.min(Math.max(this, min), max); +}; // Class definitions function Game() { // public methods this.start = function() { if (!isRunning) { + isRunning = true; setup(); Script.update.connect(idle); } - }; + } this.stop = function() { if (isRunning) { Script.update.disconnect(idle); cleanup(); + isRunning = false; } - }; + } + this.keyPressed = function(event) { + if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) { + isJumping = true; + startedPlaying = true; + } + } + + // Constants + var spaceDimensions = { x: 1.5, y: 0.8, z: 0.01 }; + var spaceDistance = 1.5; + var spaceYOffset = 0.6; + + var jumpVelocity = 1.0; // Private game state var that = this; + var entityManager = new EntityManager(); var isRunning = false; + var startedPlaying = false; + + var coolDown = 1; + var lastLost = -coolDown; + + var gameTime = 0; + + var isJumping = false; + + var space = null + var board = null; + + var bird = null; + var birdXPos = spaceDimensions.x / 2.0; + var birdDimensions = 0.05; + + // ALong Y axis + var birdPos = spaceDimensions.y / 2.0; + var birdVel = 0.0; + var birdAcc = -G; + + var pipes = new Array(); + var lastPipe = 0; + var pipesInterval = 0.5; + var pipesVelocity = 1.0; + var pipeWidth = 0.05; + var pipeLength = 0.4; // Game loop setup function idle(deltaTime) { inputs(); update(deltaTime); draw(); - }; + } - // Private methods function setup() { print("setup"); - }; + + space = { + position: getSpacePosition(), + orientation: getSpaceOrientation(), + dimensions: getSpaceDimensions() + } + + board = entityManager.add({ + type: "Box", + position: space.position, + rotation: space.orientation, + dimensions: space.dimensions, + color: { red: 100, green: 200, blue: 200 } + }); + + bird = entityManager.add({ + type: "Sphere", + position: to3DPosition({ x: birdXPos, y: birdPos }), + dimensions: { x: birdDimensions, y: birdDimensions, z: birdDimensions }, + color: { red: 0, green: 0, blue: 255 } + }); + } function inputs() { - print("inputs"); - }; + //print("inputs"); + } function update(deltaTime) { - print("update: " + deltaTime); - }; + //print("update: " + deltaTime); + + // Keep entities alive + gameTime += deltaTime; + entityManager.update(deltaTime); + + if (!startedPlaying && (gameTime - lastLost) < coolDown) { + return; + } + + // Update Bird + if (!startedPlaying && birdPos < spaceDimensions.y / 2.0) { + isJumping = true; + } + // Apply jumps + if (isJumping) { + birdVel = jumpVelocity; + isJumping = false; + } + // Apply gravity + birdPos += deltaTime * (birdVel + deltaTime * birdAcc / 2.0); + birdVel += deltaTime * birdAcc; + + + // Move pipes forward + pipes.forEach(function(element) { + element.position -= deltaTime * pipesVelocity; + }); + // Delete pipes over the end + var count = 0; + while(count < pipes.length && pipes[count].position <= 0.0) { + entityManager.remove(pipes[count].id); + count++; + } + if (count > 0) { + pipes = pipes.splice(count); + } + // Move pipes forward + if (startedPlaying && gameTime - lastPipe > pipesInterval) { + print("New pipe"); + var newPipe = entityManager.add({ + type: "Box", + position: to3DPosition({ x: space.dimensions.x, y: 0.2 }), + dimensions: { x: pipeWidth, y: pipeLength, z: pipeWidth }, + color: { red: 0, green: 255, blue: 0 } + }); + pipes.push({ id: newPipe, position: space.dimensions.x }); + lastPipe = gameTime; + } + + + // Check lost + var hasLost = birdPos < 0.0 || birdPos > space.dimensions.y; + if (!hasLost) { + pipes.forEach(function(element) { + var deltaX = Math.abs(element.position - birdXPos); + if (deltaX < (birdDimensions + pipeWidth) / 2.0) { + var deltaY = birdPos - pipeLength; + if (deltaY < 0 || deltaY < birdDimensions / 2.0) { + hasLost = true; + } + } + }); + } + + // Cleanup + if (hasLost) { + birdPos = spaceDimensions.y / 2.0; + birdVel = 0.0; + startedPlaying = false; + lastLost = gameTime; + + + // Clearing pipes + print("Clearing pipes: " + pipes.length); + pipes.forEach(function(element) { + entityManager.remove(element.id); + }); + pipes = new Array(); + } + } function draw() { - print("draw"); - }; + //print("draw"); + Entities.editEntity(bird, { position: to3DPosition({ x: birdXPos, y: birdPos }) }); + + pipes.forEach(function(element) { + Entities.editEntity(element.id, { position: to3DPosition({ x: element.position, y: 0.2 }) }); + }); + } function cleanup() { print("cleanup"); - }; + entityManager.removeAll(); + } + + // Private methods + function getSpacePosition() { + var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT); + var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward)); + return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP)); + } + function getSpaceOrientation() { + return MyAvatar.orientation; + } + function getSpaceDimensions() { + return spaceDimensions; + } + + + + function project(point, plane) { + var v = Vec3.subtract(point, plane.origin); + var dist = Vec3.dot(v, plane.normal); + return Vec3.subtract(point, Vec3.multiply(dist, v)); + } + function to3DPosition(position) { + var position2D = { + x: position.x - space.dimensions.x / 2.0, + y: position.y - space.dimensions.y / 2.0, + z: 0.0 + } + return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D)); + } + function to2DPosition(position) { + var position3D = project(position, { + origin: Vec3.subtract(space.position, { + x: space.dimensions.x / 2.0, + y: space.dimensions.y / 2.0, + z: 0.0 + }), + normal: Vec3.multiplyQbyV(space.orientation, Vec3.FRONT) + }); + + var position2D = { + x: position3D.x.clamp(0.0, space.dimensions.x), + y: position3D.y.clamp(0.0, space.dimensions.y) + } + return position2D; + } + +} + +function EntityManager() { + var entities = new Array(); + var lifetime = OBJECTS_LIFETIME; + + this.setLifetime = function(newLifetime) { + lifetime = newLifetime; + this.update(); + } + this.add = function(properties) { + // Add to scene + properties.lifetime = lifetime; + var entityID = Entities.addEntity(properties); + // Add to array + entities.push({ id: entityID, properties: properties }); + + return entityID; + } + this.update = function(deltaTime) { + entities.forEach(function(element) { + // Get entity's age + var properties = Entities.getEntityProperties(element.id, ["age"]); + // Update entity's lifetime + Entities.editEntity(element.id, { lifetime: properties.age + lifetime }); + }); + } + this.remove = function(entityID) { + // Remove from scene + Entities.deleteEntity(entityID); + + // Remove from array + entities = entities.filter(function(element) { + return element.id !== entityID; + }); + } + this.removeAll = function() { + // Remove all from scene + entities.forEach(function(element) { + Entities.deleteEntity(element.id); + }); + // Remove all from array + entities = new Array(); + } } // Script logic function scriptStarting() { var game = new Game(); + Controller.keyPressEvent.connect(function(event) { + game.keyPressed(event); + }); Script.scriptEnding.connect(function() { game.stop(); }); From 247f1ef0e8682ae2beadaba01065dda056c5a15c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 16:07:32 -0800 Subject: [PATCH 213/292] Make Bird its own Class --- examples/flappyBird.js | 87 +++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 63366a6c75..93335ee969 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -12,11 +12,60 @@ var OBJECTS_LIFETIME = 1; var G = 4.0; +var entityManager = new EntityManager(); + Number.prototype.clamp = function(min, max) { return Math.min(Math.max(this, min), max); }; // Class definitions +function Bird(DEFAULT_X, DEFAULT_Y, to3DPosition) { + var DIMENSION = 0.05; + var JUMP_VELOCITY = 1.0; + var xPosition = DEFAULT_X; + var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; + var color = { red: 0, green: 0, blue: 255 }; + + var yPosition = DEFAULT_Y; + var yVelocity = 0.0; + var yAcceleration = -G; + + this.position = function() { + return { x: xPosition, y: yPosition }; + } + this.size = function() { + return DIMENSION; + } + + var id = entityManager.add({ + type: "Sphere", + position: to3DPosition(this.position()), + dimensions: dimensions, + color: color + }); + + + this.jump = function() { + yVelocity = JUMP_VELOCITY; + } + this.update = function(deltaTime) { + yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); + yVelocity += deltaTime * yAcceleration; + } + this.draw = function() { + Entities.editEntity(id, { position: to3DPosition(this.position()) }); + } + this.reset = function() { + yPosition = DEFAULT_Y; + yVelocity = 0.0; + } +} + +function Pipe() { + +} + + function Game() { // public methods this.start = function() { @@ -50,7 +99,6 @@ function Game() { // Private game state var that = this; - var entityManager = new EntityManager(); var isRunning = false; var startedPlaying = false; @@ -65,13 +113,6 @@ function Game() { var board = null; var bird = null; - var birdXPos = spaceDimensions.x / 2.0; - var birdDimensions = 0.05; - - // ALong Y axis - var birdPos = spaceDimensions.y / 2.0; - var birdVel = 0.0; - var birdAcc = -G; var pipes = new Array(); var lastPipe = 0; @@ -104,12 +145,7 @@ function Game() { color: { red: 100, green: 200, blue: 200 } }); - bird = entityManager.add({ - type: "Sphere", - position: to3DPosition({ x: birdXPos, y: birdPos }), - dimensions: { x: birdDimensions, y: birdDimensions, z: birdDimensions }, - color: { red: 0, green: 0, blue: 255 } - }); + bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, to3DPosition); } function inputs() { //print("inputs"); @@ -126,17 +162,15 @@ function Game() { } // Update Bird - if (!startedPlaying && birdPos < spaceDimensions.y / 2.0) { + if (!startedPlaying && bird.position().y < spaceDimensions.y / 2.0) { isJumping = true; } // Apply jumps if (isJumping) { - birdVel = jumpVelocity; + bird.jump(); isJumping = false; } - // Apply gravity - birdPos += deltaTime * (birdVel + deltaTime * birdAcc / 2.0); - birdVel += deltaTime * birdAcc; + bird.update(deltaTime); // Move pipes forward @@ -167,13 +201,13 @@ function Game() { // Check lost - var hasLost = birdPos < 0.0 || birdPos > space.dimensions.y; + var hasLost = bird.position().y < 0.0 || bird.position().y > space.dimensions.y; if (!hasLost) { pipes.forEach(function(element) { - var deltaX = Math.abs(element.position - birdXPos); - if (deltaX < (birdDimensions + pipeWidth) / 2.0) { - var deltaY = birdPos - pipeLength; - if (deltaY < 0 || deltaY < birdDimensions / 2.0) { + var deltaX = Math.abs(element.position - bird.position().x); + if (deltaX < (bird.size() + pipeWidth) / 2.0) { + var deltaY = bird.position().y - pipeLength; + if (deltaY < 0 || deltaY < bird.size() / 2.0) { hasLost = true; } } @@ -182,8 +216,7 @@ function Game() { // Cleanup if (hasLost) { - birdPos = spaceDimensions.y / 2.0; - birdVel = 0.0; + bird.reset() startedPlaying = false; lastLost = gameTime; @@ -198,7 +231,7 @@ function Game() { } function draw() { //print("draw"); - Entities.editEntity(bird, { position: to3DPosition({ x: birdXPos, y: birdPos }) }); + bird.draw(); pipes.forEach(function(element) { Entities.editEntity(element.id, { position: to3DPosition({ x: element.position, y: 0.2 }) }); From dc1acd7a5bca4b1737669e58222b3e5b477b1410 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 16:40:53 -0800 Subject: [PATCH 214/292] Give pipes their own class --- examples/flappyBird.js | 165 +++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 63 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 93335ee969..a786b78947 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -61,10 +61,98 @@ function Bird(DEFAULT_X, DEFAULT_Y, to3DPosition) { } } -function Pipe() { +function Pipe(xPosition, height, to3DPosition) { + var velocity = 1.0; + var width = 0.05; + var color = { red: 0, green: 255, blue: 0 }; + this.position = function() { + return { x: xPosition, y: height / 2.0 }; + } + this.width = function() { + return width; + } + this.height = function() { + return height; + } + + var id = entityManager.add({ + type: "Box", + position: to3DPosition(this.position()), + dimensions: { x: width, y: height, z: width }, + color: color + }); + + this.update = function(deltaTime) { + xPosition -= deltaTime * velocity; + } + this.isColliding = function(bird) { + var deltaX = Math.abs(this.position().x - bird.position().x); + if (deltaX < (bird.size() + this.width()) / 2.0) { + var deltaY = bird.position().y - this.height(); + if (deltaY < 0 || deltaY < bird.size() / 2.0) { + return true; + } + } + + return false; + } + this.draw = function() { + Entities.editEntity(id, { position: to3DPosition(this.position()) }); + } + this.clear = function() { + entityManager.remove(id); + } } +function Pipes(newPipesPosition, to3DPosition) { + var lastPipe = 0; + var pipesInterval = 0.5; + + var pipes = new Array(); + + this.update = function(deltaTime, gameTime, startedPlaying) { + // Move pipes forward + pipes.forEach(function(element) { + element.update(deltaTime); + }); + // Delete pipes over the end + var count = 0; + while(count < pipes.length && pipes[count].position().x <= 0.0) { + pipes[count].clear(); + count++; + } + if (count > 0) { + pipes = pipes.splice(count); + } + // Make new pipes + if (startedPlaying && gameTime - lastPipe > pipesInterval) { + pipes.push(new Pipe(newPipesPosition, 0.4, to3DPosition)); + lastPipe = gameTime; + } + } + this.isColliding = function(bird) { + var isColliding = false; + + pipes.forEach(function(element) { + isColliding |= element.isColliding(bird); + }); + + return isColliding; + } + this.draw = function() { + // Clearing pipes + pipes.forEach(function(element) { + element.draw(); + }); + } + this.clear = function() { + pipes.forEach(function(element) { + element.clear(); + }); + pipes = new Array(); + } +} function Game() { // public methods @@ -95,8 +183,6 @@ function Game() { var spaceDistance = 1.5; var spaceYOffset = 0.6; - var jumpVelocity = 1.0; - // Private game state var that = this; var isRunning = false; @@ -111,15 +197,8 @@ function Game() { var space = null var board = null; - var bird = null; - - var pipes = new Array(); - var lastPipe = 0; - var pipesInterval = 0.5; - var pipesVelocity = 1.0; - var pipeWidth = 0.05; - var pipeLength = 0.4; + var pipes = null; // Game loop setup function idle(deltaTime) { @@ -146,6 +225,8 @@ function Game() { }); bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, to3DPosition); + + pipes = new Pipes(space.dimensions.x, to3DPosition); } function inputs() { //print("inputs"); @@ -172,70 +253,28 @@ function Game() { } bird.update(deltaTime); - - // Move pipes forward - pipes.forEach(function(element) { - element.position -= deltaTime * pipesVelocity; - }); - // Delete pipes over the end - var count = 0; - while(count < pipes.length && pipes[count].position <= 0.0) { - entityManager.remove(pipes[count].id); - count++; - } - if (count > 0) { - pipes = pipes.splice(count); - } - // Move pipes forward - if (startedPlaying && gameTime - lastPipe > pipesInterval) { - print("New pipe"); - var newPipe = entityManager.add({ - type: "Box", - position: to3DPosition({ x: space.dimensions.x, y: 0.2 }), - dimensions: { x: pipeWidth, y: pipeLength, z: pipeWidth }, - color: { red: 0, green: 255, blue: 0 } - }); - pipes.push({ id: newPipe, position: space.dimensions.x }); - lastPipe = gameTime; - } - + pipes.update(deltaTime, gameTime, startedPlaying); // Check lost - var hasLost = bird.position().y < 0.0 || bird.position().y > space.dimensions.y; - if (!hasLost) { - pipes.forEach(function(element) { - var deltaX = Math.abs(element.position - bird.position().x); - if (deltaX < (bird.size() + pipeWidth) / 2.0) { - var deltaY = bird.position().y - pipeLength; - if (deltaY < 0 || deltaY < bird.size() / 2.0) { - hasLost = true; - } - } - }); - } + var hasLost = bird.position().y < 0.0 || + bird.position().y > space.dimensions.y || + pipes.isColliding(bird); + // Cleanup if (hasLost) { - bird.reset() + print("Game Over!"); + bird.reset(); + pipes.clear(); + startedPlaying = false; lastLost = gameTime; - - - // Clearing pipes - print("Clearing pipes: " + pipes.length); - pipes.forEach(function(element) { - entityManager.remove(element.id); - }); - pipes = new Array(); } } function draw() { //print("draw"); bird.draw(); - - pipes.forEach(function(element) { - Entities.editEntity(element.id, { position: to3DPosition({ x: element.position, y: 0.2 }) }); - }); + pipes.draw(); } function cleanup() { print("cleanup"); From 46bb3c05a507202189b08dfa416c6be103e788f7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 14:17:02 +1300 Subject: [PATCH 215/292] Right justify leading control labels --- .../resources/qml/dialogs/preferences/ComboBoxPreference.qml | 3 ++- .../resources/qml/dialogs/preferences/SliderPreference.qml | 3 ++- .../resources/qml/dialogs/preferences/SpinBoxPreference.qml | 3 ++- interface/resources/qml/styles-uit/HifiConstants.qml | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index 042d172bd0..10e5f5febf 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -35,9 +35,10 @@ Preference { anchors { left: parent.left right: dataComboBox.left - rightMargin: hifi.dimensions.contentSpacing.x + rightMargin: hifi.dimensions.labelPadding verticalCenter: dataComboBox.verticalCenter } + horizontalAlignment: Text.AlignRight wrapMode: Text.Wrap } diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index 11bcc25716..92cab40133 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -33,9 +33,10 @@ Preference { anchors { left: parent.left right: slider.left - rightMargin: hifi.dimensions.contentSpacing.x + rightMargin: hifi.dimensions.labelPadding verticalCenter: slider.verticalCenter } + horizontalAlignment: Text.AlignRight wrapMode: Text.Wrap } diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index c77d0bd18b..aa9068bb00 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -32,9 +32,10 @@ Preference { anchors { left: parent.left right: spinner.left - rightMargin: hifi.dimensions.contentSpacing.x + rightMargin: hifi.dimensions.labelPadding verticalCenter: spinner.verticalCenter } + horizontalAlignment: Text.AlignRight wrapMode: Text.Wrap } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 5c50a4f6ae..e99fa9dc2a 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -98,6 +98,7 @@ Item { readonly property real borderWidth: largeScreen ? 2 : 1 readonly property vector2d contentMargin: Qt.vector2d(12, 24) readonly property vector2d contentSpacing: Qt.vector2d(8, 12) + readonly property real labelPadding: 40 readonly property real textPadding: 8 readonly property real sliderHandleSize: 18 readonly property real sliderGrooveHeight: 8 From 4729020df1e6faf8d76f1bf7c5fed6508e83db89 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 14:32:08 +1300 Subject: [PATCH 216/292] Change section expand/collapse icons --- interface/resources/qml/controls-uit/ContentSection.qml | 6 +++--- interface/resources/qml/styles-uit/HifiConstants.qml | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index 20137c28cb..46f8c22420 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -88,11 +88,11 @@ Column { anchors { verticalCenter: title.verticalCenter right: parent.right - rightMargin: -hifi.dimensions.contentMargin.x + rightMargin: -4 } y: -2 - size: hifi.fontSizes.carat - text: isCollapsed ? hifi.glyphs.caratR : hifi.glyphs.caratDn + size: hifi.fontSizes.disclosureButton + text: isCollapsed ? hifi.glyphs.disclosureButtonExpand : hifi.glyphs.disclosureButtonCollapse color: hifi.colors.lightGrayText visible: isCollapsible } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index e99fa9dc2a..e1dc77a695 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -127,6 +127,7 @@ Item { readonly property real menuItem: dimensions.largeScreen ? 15 : 11 readonly property real shortcutText: dimensions.largeScreen ? 13 : 9 readonly property real carat: dimensions.largeScreen ? 38 : 30 + readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15 } Item { @@ -138,6 +139,8 @@ Item { readonly property string close: "w" readonly property string closeInverted: "x" readonly property string closeSmall: "C" + readonly property string disclosureButtonCollapse: "M" + readonly property string disclosureButtonExpand: "L" readonly property string disclosureCollapse: "Z" readonly property string disclosureExpand: "B" readonly property string forward: "D" From 553300a7834f3ba4dec981149b4baccd821f4031 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 17:37:26 -0800 Subject: [PATCH 217/292] Added a pipe on the top, randomized the height --- examples/flappyBird.js | 53 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index a786b78947..70e117110b 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -61,24 +61,27 @@ function Bird(DEFAULT_X, DEFAULT_Y, to3DPosition) { } } -function Pipe(xPosition, height, to3DPosition) { - var velocity = 1.0; +function Pipe(xPosition, yPosition, height, gap, to3DPosition) { + var velocity = 0.6; var width = 0.05; var color = { red: 0, green: 255, blue: 0 }; this.position = function() { - return { x: xPosition, y: height / 2.0 }; - } - this.width = function() { - return width; - } - this.height = function() { - return height; + return xPosition; } - var id = entityManager.add({ + var upHeight = yPosition - (height + gap); + var upYPosition = height + gap + upHeight / 2.0; + + var idUp = entityManager.add({ type: "Box", - position: to3DPosition(this.position()), + position: to3DPosition({ x: xPosition, y: upYPosition }), + dimensions: { x: width, y: upHeight, z: width }, + color: color + }); + var idDown = entityManager.add({ + type: "Box", + position: to3DPosition({ x: xPosition, y: height / 2.0 }), dimensions: { x: width, y: height, z: width }, color: color }); @@ -87,10 +90,11 @@ function Pipe(xPosition, height, to3DPosition) { xPosition -= deltaTime * velocity; } this.isColliding = function(bird) { - var deltaX = Math.abs(this.position().x - bird.position().x); - if (deltaX < (bird.size() + this.width()) / 2.0) { - var deltaY = bird.position().y - this.height(); - if (deltaY < 0 || deltaY < bird.size() / 2.0) { + var deltaX = Math.abs(this.position() - bird.position().x); + if (deltaX < (bird.size() + width) / 2.0) { + var upDistance = (yPosition - upHeight) - (bird.position().y + bird.size()); + var downDistance = (bird.position().y - bird.size()) - height; + if (upDistance <= 0 || downDistance <= 0) { return true; } } @@ -98,16 +102,18 @@ function Pipe(xPosition, height, to3DPosition) { return false; } this.draw = function() { - Entities.editEntity(id, { position: to3DPosition(this.position()) }); + Entities.editEntity(idUp, { position: to3DPosition({ x: xPosition, y: upYPosition }) }); + Entities.editEntity(idDown, { position: to3DPosition({ x: xPosition, y: height / 2.0 }) }); } this.clear = function() { - entityManager.remove(id); + entityManager.remove(idUp); + entityManager.remove(idDown); } } -function Pipes(newPipesPosition, to3DPosition) { +function Pipes(newPipesPosition, newPipesHeight, to3DPosition) { var lastPipe = 0; - var pipesInterval = 0.5; + var pipesInterval = 1.0; var pipes = new Array(); @@ -118,7 +124,7 @@ function Pipes(newPipesPosition, to3DPosition) { }); // Delete pipes over the end var count = 0; - while(count < pipes.length && pipes[count].position().x <= 0.0) { + while(count < pipes.length && pipes[count].position() <= 0.0) { pipes[count].clear(); count++; } @@ -127,7 +133,10 @@ function Pipes(newPipesPosition, to3DPosition) { } // Make new pipes if (startedPlaying && gameTime - lastPipe > pipesInterval) { - pipes.push(new Pipe(newPipesPosition, 0.4, to3DPosition)); + var min = 0.1; + var max = 0.4; + var height = Math.random() * (max - min) + min; + pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.3, to3DPosition)); lastPipe = gameTime; } } @@ -226,7 +235,7 @@ function Game() { bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, to3DPosition); - pipes = new Pipes(space.dimensions.x, to3DPosition); + pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); } function inputs() { //print("inputs"); From 811ed91e02c698de027502fe4ef070571acfeae8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 18:02:57 -0800 Subject: [PATCH 218/292] Port to entity script --- examples/flappyBird.js | 730 ++++++++++++++++++++++------------------- 1 file changed, 393 insertions(+), 337 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 70e117110b..11bafef313 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -8,390 +8,446 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Constants -var OBJECTS_LIFETIME = 1; -var G = 4.0; +(function() { + // Constants + var TRIGGER_CONTROLS = [ + Controller.Standard.LT, + Controller.Standard.RT, + ]; -var entityManager = new EntityManager(); + var OBJECTS_LIFETIME = 1; + var G = 4.0; -Number.prototype.clamp = function(min, max) { - return Math.min(Math.max(this, min), max); -}; + var entityManager = new EntityManager(); -// Class definitions -function Bird(DEFAULT_X, DEFAULT_Y, to3DPosition) { - var DIMENSION = 0.05; - var JUMP_VELOCITY = 1.0; - var xPosition = DEFAULT_X; - var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; - var color = { red: 0, green: 0, blue: 255 }; - - var yPosition = DEFAULT_Y; - var yVelocity = 0.0; - var yAcceleration = -G; + Number.prototype.clamp = function(min, max) { + return Math.min(Math.max(this, min), max); + }; - this.position = function() { - return { x: xPosition, y: yPosition }; - } - this.size = function() { - return DIMENSION; + // Class definitions + function Bird(DEFAULT_X, DEFAULT_Y, to3DPosition) { + var DIMENSION = 0.05; + var JUMP_VELOCITY = 1.0; + var xPosition = DEFAULT_X; + var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; + var color = { red: 0, green: 0, blue: 255 }; + + var yPosition = DEFAULT_Y; + var yVelocity = 0.0; + var yAcceleration = -G; + + this.position = function() { + return { x: xPosition, y: yPosition }; + } + this.size = function() { + return DIMENSION; + } + + var id = entityManager.add({ + type: "Sphere", + position: to3DPosition(this.position()), + dimensions: dimensions, + color: color + }); + + + this.jump = function() { + yVelocity = JUMP_VELOCITY; + } + this.update = function(deltaTime) { + yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); + yVelocity += deltaTime * yAcceleration; + } + this.draw = function() { + Entities.editEntity(id, { position: to3DPosition(this.position()) }); + } + this.reset = function() { + yPosition = DEFAULT_Y; + yVelocity = 0.0; + } } - var id = entityManager.add({ - type: "Sphere", - position: to3DPosition(this.position()), - dimensions: dimensions, - color: color - }); + function Pipe(xPosition, yPosition, height, gap, to3DPosition) { + var velocity = 0.6; + var width = 0.05; + var color = { red: 0, green: 255, blue: 0 }; + this.position = function() { + return xPosition; + } - this.jump = function() { - yVelocity = JUMP_VELOCITY; - } - this.update = function(deltaTime) { - yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); - yVelocity += deltaTime * yAcceleration; - } - this.draw = function() { - Entities.editEntity(id, { position: to3DPosition(this.position()) }); - } - this.reset = function() { - yPosition = DEFAULT_Y; - yVelocity = 0.0; - } -} + var upHeight = yPosition - (height + gap); + var upYPosition = height + gap + upHeight / 2.0; -function Pipe(xPosition, yPosition, height, gap, to3DPosition) { - var velocity = 0.6; - var width = 0.05; - var color = { red: 0, green: 255, blue: 0 }; + var idUp = entityManager.add({ + type: "Box", + position: to3DPosition({ x: xPosition, y: upYPosition }), + dimensions: { x: width, y: upHeight, z: width }, + color: color + }); + var idDown = entityManager.add({ + type: "Box", + position: to3DPosition({ x: xPosition, y: height / 2.0 }), + dimensions: { x: width, y: height, z: width }, + color: color + }); - this.position = function() { - return xPosition; + this.update = function(deltaTime) { + xPosition -= deltaTime * velocity; + } + this.isColliding = function(bird) { + var deltaX = Math.abs(this.position() - bird.position().x); + if (deltaX < (bird.size() + width) / 2.0) { + var upDistance = (yPosition - upHeight) - (bird.position().y + bird.size()); + var downDistance = (bird.position().y - bird.size()) - height; + if (upDistance <= 0 || downDistance <= 0) { + return true; + } + } + + return false; + } + this.draw = function() { + Entities.editEntity(idUp, { position: to3DPosition({ x: xPosition, y: upYPosition }) }); + Entities.editEntity(idDown, { position: to3DPosition({ x: xPosition, y: height / 2.0 }) }); + } + this.clear = function() { + entityManager.remove(idUp); + entityManager.remove(idDown); + } } - var upHeight = yPosition - (height + gap); - var upYPosition = height + gap + upHeight / 2.0; + function Pipes(newPipesPosition, newPipesHeight, to3DPosition) { + var lastPipe = 0; + var pipesInterval = 1.0; - var idUp = entityManager.add({ - type: "Box", - position: to3DPosition({ x: xPosition, y: upYPosition }), - dimensions: { x: width, y: upHeight, z: width }, - color: color - }); - var idDown = entityManager.add({ - type: "Box", - position: to3DPosition({ x: xPosition, y: height / 2.0 }), - dimensions: { x: width, y: height, z: width }, - color: color - }); + var pipes = new Array(); - this.update = function(deltaTime) { - xPosition -= deltaTime * velocity; + this.update = function(deltaTime, gameTime, startedPlaying) { + // Move pipes forward + pipes.forEach(function(element) { + element.update(deltaTime); + }); + // Delete pipes over the end + var count = 0; + while(count < pipes.length && pipes[count].position() <= 0.0) { + pipes[count].clear(); + count++; + } + if (count > 0) { + pipes = pipes.splice(count); + } + // Make new pipes + if (startedPlaying && gameTime - lastPipe > pipesInterval) { + var min = 0.1; + var max = 0.4; + var height = Math.random() * (max - min) + min; + pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.3, to3DPosition)); + lastPipe = gameTime; + } + } + this.isColliding = function(bird) { + var isColliding = false; + + pipes.forEach(function(element) { + isColliding |= element.isColliding(bird); + }); + + return isColliding; + } + this.draw = function() { + // Clearing pipes + pipes.forEach(function(element) { + element.draw(); + }); + } + this.clear = function() { + pipes.forEach(function(element) { + element.clear(); + }); + pipes = new Array(); + } } - this.isColliding = function(bird) { - var deltaX = Math.abs(this.position() - bird.position().x); - if (deltaX < (bird.size() + width) / 2.0) { - var upDistance = (yPosition - upHeight) - (bird.position().y + bird.size()); - var downDistance = (bird.position().y - bird.size()) - height; - if (upDistance <= 0 || downDistance <= 0) { - return true; + + function Game() { + // public methods + this.start = function() { + if (!isRunning) { + isRunning = true; + setup(); + // Script.update.connect(idle); } } - return false; - } - this.draw = function() { - Entities.editEntity(idUp, { position: to3DPosition({ x: xPosition, y: upYPosition }) }); - Entities.editEntity(idDown, { position: to3DPosition({ x: xPosition, y: height / 2.0 }) }); - } - this.clear = function() { - entityManager.remove(idUp); - entityManager.remove(idDown); - } -} - -function Pipes(newPipesPosition, newPipesHeight, to3DPosition) { - var lastPipe = 0; - var pipesInterval = 1.0; - - var pipes = new Array(); - - this.update = function(deltaTime, gameTime, startedPlaying) { - // Move pipes forward - pipes.forEach(function(element) { - element.update(deltaTime); - }); - // Delete pipes over the end - var count = 0; - while(count < pipes.length && pipes[count].position() <= 0.0) { - pipes[count].clear(); - count++; + this.stop = function() { + if (isRunning) { + // Script.update.disconnect(idle); + cleanup(); + isRunning = false; + } } - if (count > 0) { - pipes = pipes.splice(count); - } - // Make new pipes - if (startedPlaying && gameTime - lastPipe > pipesInterval) { - var min = 0.1; - var max = 0.4; - var height = Math.random() * (max - min) + min; - pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.3, to3DPosition)); - lastPipe = gameTime; - } - } - this.isColliding = function(bird) { - var isColliding = false; - pipes.forEach(function(element) { - isColliding |= element.isColliding(bird); - }); - - return isColliding; - } - this.draw = function() { - // Clearing pipes - pipes.forEach(function(element) { - element.draw(); - }); - } - this.clear = function() { - pipes.forEach(function(element) { - element.clear(); - }); - pipes = new Array(); - } -} - -function Game() { - // public methods - this.start = function() { - if (!isRunning) { - isRunning = true; - setup(); - Script.update.connect(idle); + // Game loop setup + var timestamp = 0; + this.idle = function() { + var now = Date.now(); + var deltaTime = (now - timestamp) / 1000.0; + if (timestamp === 0) { + deltaTime = 0; + } + inputs(); + update(deltaTime); + draw(); + timestamp = now; } - } - - this.stop = function() { - if (isRunning) { - Script.update.disconnect(idle); - cleanup(); - isRunning = false; + // this.keyPressed = function(event) { + // if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) { + // isJumping = true; + // startedPlaying = true; + // } + // } + + // Constants + var spaceDimensions = { x: 1.5, y: 0.8, z: 0.01 }; + var spaceDistance = 1.5; + var spaceYOffset = 0.6; + + // Private game state + var that = this; + var isRunning = false; + var startedPlaying = false; + + var coolDown = 1; + var lastLost = -coolDown; + + var gameTime = 0; + + var isJumping = false; + + var space = null + var board = null; + var bird = null; + var pipes = null; + + function setup() { + print("setup"); + + space = { + position: getSpacePosition(), + orientation: getSpaceOrientation(), + dimensions: getSpaceDimensions() + } + + // board = entityManager.add({ + // type: "Box", + // position: space.position, + // rotation: space.orientation, + // dimensions: space.dimensions, + // color: { red: 100, green: 200, blue: 200 } + // }); + + bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, to3DPosition); + + pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); } - } - this.keyPressed = function(event) { - if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) { + function inputs(triggerValue) { isJumping = true; startedPlaying = true; } - } + function update(deltaTime) { + //print("update: " + deltaTime); - // Constants - var spaceDimensions = { x: 1.5, y: 0.8, z: 0.01 }; - var spaceDistance = 1.5; - var spaceYOffset = 0.6; + // Keep entities alive + gameTime += deltaTime; + entityManager.update(deltaTime); - // Private game state - var that = this; - var isRunning = false; - var startedPlaying = false; + if (!startedPlaying && (gameTime - lastLost) < coolDown) { + return; + } - var coolDown = 1; - var lastLost = -coolDown; + // Update Bird + if (!startedPlaying && bird.position().y < spaceDimensions.y / 2.0) { + isJumping = true; + } + // Apply jumps + if (isJumping) { + bird.jump(); + isJumping = false; + } + bird.update(deltaTime); - var gameTime = 0; + pipes.update(deltaTime, gameTime, startedPlaying); - var isJumping = false; + // Check lost + var hasLost = bird.position().y < 0.0 || + bird.position().y > space.dimensions.y || + pipes.isColliding(bird); - var space = null - var board = null; - var bird = null; - var pipes = null; - // Game loop setup - function idle(deltaTime) { - inputs(); - update(deltaTime); - draw(); - } + // Cleanup + if (hasLost) { + print("Game Over!"); + bird.reset(); + pipes.clear(); - function setup() { - print("setup"); - - space = { - position: getSpacePosition(), - orientation: getSpaceOrientation(), - dimensions: getSpaceDimensions() + startedPlaying = false; + lastLost = gameTime; + } + } + function draw() { + //print("draw"); + bird.draw(); + pipes.draw(); + } + function cleanup() { + print("cleanup"); + entityManager.removeAll(); } - board = entityManager.add({ - type: "Box", - position: space.position, - rotation: space.orientation, - dimensions: space.dimensions, - color: { red: 100, green: 200, blue: 200 } - }); - - bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, to3DPosition); - - pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); - } - function inputs() { - //print("inputs"); - } - function update(deltaTime) { - //print("update: " + deltaTime); - - // Keep entities alive - gameTime += deltaTime; - entityManager.update(deltaTime); - - if (!startedPlaying && (gameTime - lastLost) < coolDown) { - return; + // Private methods + function getSpacePosition() { + var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT); + var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward)); + return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP)); + } + function getSpaceOrientation() { + return MyAvatar.orientation; + } + function getSpaceDimensions() { + return spaceDimensions; } - // Update Bird - if (!startedPlaying && bird.position().y < spaceDimensions.y / 2.0) { - isJumping = true; + + + function project(point, plane) { + var v = Vec3.subtract(point, plane.origin); + var dist = Vec3.dot(v, plane.normal); + return Vec3.subtract(point, Vec3.multiply(dist, v)); } - // Apply jumps - if (isJumping) { - bird.jump(); - isJumping = false; - } - bird.update(deltaTime); - - pipes.update(deltaTime, gameTime, startedPlaying); - - // Check lost - var hasLost = bird.position().y < 0.0 || - bird.position().y > space.dimensions.y || - pipes.isColliding(bird); - - - // Cleanup - if (hasLost) { - print("Game Over!"); - bird.reset(); - pipes.clear(); - - startedPlaying = false; - lastLost = gameTime; - } - } - function draw() { - //print("draw"); - bird.draw(); - pipes.draw(); - } - function cleanup() { - print("cleanup"); - entityManager.removeAll(); - } - - // Private methods - function getSpacePosition() { - var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT); - var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward)); - return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP)); - } - function getSpaceOrientation() { - return MyAvatar.orientation; - } - function getSpaceDimensions() { - return spaceDimensions; - } - - - - function project(point, plane) { - var v = Vec3.subtract(point, plane.origin); - var dist = Vec3.dot(v, plane.normal); - return Vec3.subtract(point, Vec3.multiply(dist, v)); - } - function to3DPosition(position) { - var position2D = { - x: position.x - space.dimensions.x / 2.0, - y: position.y - space.dimensions.y / 2.0, - z: 0.0 - } - return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D)); - } - function to2DPosition(position) { - var position3D = project(position, { - origin: Vec3.subtract(space.position, { - x: space.dimensions.x / 2.0, - y: space.dimensions.y / 2.0, + function to3DPosition(position) { + var position2D = { + x: position.x - space.dimensions.x / 2.0, + y: position.y - space.dimensions.y / 2.0, z: 0.0 - }), - normal: Vec3.multiplyQbyV(space.orientation, Vec3.FRONT) - }); - - var position2D = { - x: position3D.x.clamp(0.0, space.dimensions.x), - y: position3D.y.clamp(0.0, space.dimensions.y) + } + return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D)); } - return position2D; + function to2DPosition(position) { + var position3D = project(position, { + origin: Vec3.subtract(space.position, { + x: space.dimensions.x / 2.0, + y: space.dimensions.y / 2.0, + z: 0.0 + }), + normal: Vec3.multiplyQbyV(space.orientation, Vec3.FRONT) + }); + + var position2D = { + x: position3D.x.clamp(0.0, space.dimensions.x), + y: position3D.y.clamp(0.0, space.dimensions.y) + } + return position2D; + } + } -} + function EntityManager() { + var entities = new Array(); + var lifetime = OBJECTS_LIFETIME; -function EntityManager() { - var entities = new Array(); - var lifetime = OBJECTS_LIFETIME; + this.setLifetime = function(newLifetime) { + lifetime = newLifetime; + this.update(); + } + this.add = function(properties) { + // Add to scene + properties.lifetime = lifetime; + var entityID = Entities.addEntity(properties); + // Add to array + entities.push({ id: entityID, properties: properties }); - this.setLifetime = function(newLifetime) { - lifetime = newLifetime; - this.update(); + return entityID; + } + this.update = function(deltaTime) { + entities.forEach(function(element) { + // Get entity's age + var properties = Entities.getEntityProperties(element.id, ["age"]); + // Update entity's lifetime + Entities.editEntity(element.id, { lifetime: properties.age + lifetime }); + }); + } + this.remove = function(entityID) { + // Remove from scene + Entities.deleteEntity(entityID); + + // Remove from array + entities = entities.filter(function(element) { + return element.id !== entityID; + }); + } + this.removeAll = function() { + // Remove all from scene + entities.forEach(function(element) { + Entities.deleteEntity(element.id); + }); + // Remove all from array + entities = new Array(); + } } - this.add = function(properties) { - // Add to scene - properties.lifetime = lifetime; - var entityID = Entities.addEntity(properties); - // Add to array - entities.push({ id: entityID, properties: properties }); - return entityID; - } - this.update = function(deltaTime) { - entities.forEach(function(element) { - // Get entity's age - var properties = Entities.getEntityProperties(element.id, ["age"]); - // Update entity's lifetime - Entities.editEntity(element.id, { lifetime: properties.age + lifetime }); - }); - } - this.remove = function(entityID) { - // Remove from scene - Entities.deleteEntity(entityID); + PartableGame = function() { + this.equipped = false; + this.triggerValue = 0.0; + this.hand = 0; + this.game = null; + }; - // Remove from array - entities = entities.filter(function(element) { - return element.id !== entityID; - }); - } - this.removeAll = function() { - // Remove all from scene - entities.forEach(function(element) { - Entities.deleteEntity(element.id); - }); - // Remove all from array - entities = new Array(); - } -} + PartableGame.prototype = { + preload: function(entityID) { + this.entityID = entityID; + }, + unload: function() { + }, + startEquip: function(id, params) { + this.equipped = true; + this.hand = params[0] == "left" ? 0 : 1; -// Script logic -function scriptStarting() { - var game = new Game(); + this.game = new Game(); + this.game.start(); + }, + releaseEquip: function(id, params) { + this.equipped = false; - Controller.keyPressEvent.connect(function(event) { - game.keyPressed(event); - }); - Script.scriptEnding.connect(function() { - game.stop(); - }); - game.start(); -} + this.game.stop(); + delete this.game; + }, + continueEquip: function(id, params) { + if (!this.equipped) { + return; + } + this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]); + + this.game.idle(); + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new PartableGame(); +}); + + +// // Script logic +// function scriptStarting() { +// var game = new Game(); + +// Controller.keyPressEvent.connect(function(event) { +// game.keyPressed(event); +// }); +// Script.scriptEnding.connect(function() { +// game.stop(); +// }); +// game.start(); +// } + +// scriptStarting(); -scriptStarting(); \ No newline at end of file From 48fe9b343ee180ca574b161930af13d14059a800 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 18:20:18 -0800 Subject: [PATCH 219/292] Couple trigger value fixes --- examples/flappyBird.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 11bafef313..2820d3afc7 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -189,13 +189,13 @@ // Game loop setup var timestamp = 0; - this.idle = function() { + this.idle = function(triggerValue) { var now = Date.now(); var deltaTime = (now - timestamp) / 1000.0; if (timestamp === 0) { deltaTime = 0; } - inputs(); + inputs(triggerValue); update(deltaTime); draw(); timestamp = now; @@ -251,8 +251,10 @@ pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); } function inputs(triggerValue) { - isJumping = true; - startedPlaying = true; + if (triggerValue > 0.5) { + isJumping = true; + startedPlaying = true; + } } function update(deltaTime) { //print("update: " + deltaTime); @@ -426,8 +428,7 @@ return; } this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]); - - this.game.idle(); + this.game.idle(this.triggerValue); }, }; From cf52aeeed296f3e8b8be0c124af525276decc328 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 20:40:25 -0800 Subject: [PATCH 220/292] Use correctly resized avatar model with fly animation --- examples/flappyBird.js | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 2820d3afc7..49dec4c32a 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -29,9 +29,10 @@ var DIMENSION = 0.05; var JUMP_VELOCITY = 1.0; var xPosition = DEFAULT_X; - var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; var color = { red: 0, green: 0, blue: 255 }; + var dimensionsSet = false; + var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; var yPosition = DEFAULT_Y; var yVelocity = 0.0; var yAcceleration = -G; @@ -44,7 +45,18 @@ } var id = entityManager.add({ - type: "Sphere", + type: "Model", + modelURL: MyAvatar.skeletonModelURL, + animation: { + url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx", + running: true, + fps: 30, + firstFrame: 1.0, + lastFrame: 80.0, + currentFrame: 1.0, + loop: true, + hold: true + }, position: to3DPosition(this.position()), dimensions: dimensions, color: color @@ -55,11 +67,26 @@ yVelocity = JUMP_VELOCITY; } this.update = function(deltaTime) { + if (!dimensionsSet) { + var properties = Entities.getEntityProperties(id, ["naturalDimensions"]); + var naturalDimensions = properties.naturalDimensions; + if (naturalDimensions.x != 1 || naturalDimensions.y != 1 || naturalDimensions.z != 1) { + var max = Math.max(naturalDimensions.x, Math.max(naturalDimensions.y, naturalDimensions.z)); + dimensions.x = naturalDimensions.x / max * dimensions.x; + dimensions.y = naturalDimensions.y / max * dimensions.y; + dimensions.z = naturalDimensions.z / max * dimensions.z; + dimensionsSet = true; + } + }; + yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); yVelocity += deltaTime * yAcceleration; } this.draw = function() { - Entities.editEntity(id, { position: to3DPosition(this.position()) }); + Entities.editEntity(id, { + position: to3DPosition(this.position()), + dimensions: dimensions + }); } this.reset = function() { yPosition = DEFAULT_Y; From a41f409e33bb3a0af94808f4d0b696ffad7cd8f0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 17:49:18 +1300 Subject: [PATCH 221/292] Defer dialog vertical spacing decisions to content items --- interface/resources/qml/controls-uit/ContentSection.qml | 2 +- interface/resources/qml/styles-uit/HifiConstants.qml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index 46f8c22420..1700b5939a 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -19,7 +19,7 @@ Column { property bool isCollapsible: false // Set at creation. property bool isCollapsed: false - spacing: hifi.dimensions.contentSpacing.y + spacing: 0 // Defer spacing decisions to individual controls. anchors { left: parent.left diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index e1dc77a695..108cf8a221 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -107,6 +107,8 @@ Item { readonly property real tableRowHeight: largeScreen ? 26 : 23 readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30) readonly property real modalDialogTitleHeight: 40 + readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor + readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight } Item { From 2d250e2f64e7d8668fc46e2b8e25120bb4ff971c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 17:51:14 +1300 Subject: [PATCH 222/292] Only the first checkbox in a group has vertical space before it --- .../preferences/CheckBoxPreference.qml | 19 +++++++++++++++++-- .../qml/dialogs/preferences/Preference.qml | 1 + .../qml/dialogs/preferences/Section.qml | 12 +++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index 5e6ce3db3c..f8f992735c 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -14,7 +14,7 @@ import "../../controls-uit" Preference { id: root - height: checkBox.implicitHeight + height: spacer.height + Math.max(hifi.dimensions.controlLineHeight, checkBox.implicitHeight) Component.onCompleted: { checkBox.checked = preference.value; @@ -26,9 +26,24 @@ Preference { preference.save(); } + Item { + id: spacer + anchors { + top: parent.top + left: parent.left + right: parent.right + } + height: isFirstCheckBox ? hifi.dimensions.controlInterlineHeight : 0 + } + CheckBox { id: checkBox - anchors.fill: parent + anchors { + top: spacer.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } text: root.label colorScheme: hifi.colorSchemes.dark } diff --git a/interface/resources/qml/dialogs/preferences/Preference.qml b/interface/resources/qml/dialogs/preferences/Preference.qml index 733e2c4ebe..1d72197382 100644 --- a/interface/resources/qml/dialogs/preferences/Preference.qml +++ b/interface/resources/qml/dialogs/preferences/Preference.qml @@ -16,6 +16,7 @@ Item { anchors { left: parent.left; right: parent.right } property var preference; property string label: preference ? preference.name : ""; + property bool isFirstCheckBox; Component.onCompleted: { if (preference) { preference.load(); diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index 81e9278903..e48612ca03 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -73,6 +73,7 @@ Preference { property var buttonBuilder: Component { ButtonPreference { } } property var comboBoxBuilder: Component { ComboBoxPreference { } } property var preferences: [] + property int checkBoxCount: 0 function buildPreferences() { var categoryPreferences = Preferences.preferencesByCategory[root.name]; @@ -89,40 +90,49 @@ Preference { var builder; switch (preference.type) { case Preference.Editable: + checkBoxCount = 0; builder = editableBuilder; break; case Preference.Browsable: + checkBoxCount = 0; builder = browsableBuilder; break; case Preference.Spinner: + checkBoxCount = 0; builder = spinnerBuilder; break; case Preference.Slider: + checkBoxCount = 0; builder = sliderBuilder; break; case Preference.Checkbox: + checkBoxCount++; + console.log("####### checkBoxCount = " + checkBoxCount); builder = checkboxBuilder; break; case Preference.Avatar: + checkBoxCount = 0; builder = avatarBuilder; break; case Preference.Button: + checkBoxCount = 0; builder = buttonBuilder; break; case Preference.ComboBox: + checkBoxCount = 0; builder = comboBoxBuilder; break; }; if (builder) { - preferences.push(builder.createObject(contentContainer, { preference: preference })); + preferences.push(builder.createObject(contentContainer, { preference: preference, isFirstCheckBox: (checkBoxCount === 1) })); } } } From fb675dbaf5a488e1016024315a4d0ad53b4bebfb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 18:49:13 +1300 Subject: [PATCH 223/292] Add vertical spacing above other settings fields --- .../resources/qml/controls-uit/TextField.qml | 2 +- .../dialogs/preferences/AvatarPreference.qml | 65 ++++++++++-------- .../preferences/BrowsablePreference.qml | 66 +++++++++++-------- .../dialogs/preferences/ButtonPreference.qml | 3 +- .../preferences/ComboBoxPreference.qml | 47 ++++++++----- .../preferences/EditablePreference.qml | 5 +- .../dialogs/preferences/SliderPreference.qml | 46 ++++++++----- .../dialogs/preferences/SpinBoxPreference.qml | 50 +++++++++----- 8 files changed, 175 insertions(+), 109 deletions(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index 42712e9d23..ff1bbe8eb6 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -21,7 +21,7 @@ TextField { property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property string label: "" - property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0) + property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0) placeholderText: textField.placeholderText diff --git a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml index 20029a1cd7..8f05ca4ffe 100644 --- a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml +++ b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml @@ -18,9 +18,8 @@ Preference { property alias text: dataTextField.text property alias buttonText: button.text property alias placeholderText: dataTextField.placeholderText - property real spacing: 0 property var browser; - height: Math.max(dataTextField.controlHeight, button.height) + spacing + height: control.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: { dataTextField.text = preference.value; @@ -52,34 +51,48 @@ Preference { preference.save(); } - TextField { - id: dataTextField - placeholderText: root.placeholderText - text: preference.value - label: root.label + Item { + id: control anchors { left: parent.left - right: button.left - rightMargin: hifi.dimensions.contentSpacing.x - bottomMargin: spacing + right: parent.right + bottom: parent.bottom } - colorScheme: hifi.colorSchemes.dark - } + height: Math.max(dataTextField.controlHeight, button.height) - Component { - id: avatarBrowserBuilder; - AvatarBrowser { } - } - - Button { - id: button - anchors { right: parent.right; verticalCenter: dataTextField.verticalCenter } - text: "Browse" - onClicked: { - root.browser = avatarBrowserBuilder.createObject(desktop); - root.browser.windowDestroyed.connect(function(){ - root.browser = null; - }) + TextField { + id: dataTextField + placeholderText: root.placeholderText + text: preference.value + label: root.label + anchors { + left: parent.left + right: button.left + rightMargin: hifi.dimensions.contentSpacing.x + bottom: parent.bottom + } + colorScheme: hifi.colorSchemes.dark } + + Component { + id: avatarBrowserBuilder; + AvatarBrowser { } + } + + Button { + id: button + text: "Browse" + anchors { + right: parent.right + verticalCenter: dataTextField.verticalCenter + } + onClicked: { + root.browser = avatarBrowserBuilder.createObject(desktop); + root.browser.windowDestroyed.connect(function(){ + root.browser = null; + }) + } + } + } } diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml index 9a4ae2fbf9..9a19889938 100644 --- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml @@ -17,8 +17,7 @@ Preference { id: root property alias text: dataTextField.text property alias placeholderText: dataTextField.placeholderText - property real spacing: 0 - height: Math.max(dataTextField.controlHeight, button.height) + spacing + height: control.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: { dataTextField.text = preference.value; @@ -29,36 +28,49 @@ Preference { preference.save(); } - TextField { - id: dataTextField - + Item { + id: control anchors { left: parent.left - right: button.left - rightMargin: hifi.dimensions.contentSpacing.x - bottomMargin: spacing + right: parent.right + bottom: parent.bottom + } + height: Math.max(dataTextField.controlHeight, button.height) + + TextField { + id: dataTextField + + anchors { + left: parent.left + right: button.left + rightMargin: hifi.dimensions.contentSpacing.x + bottom: parent.bottom + } + + label: root.label + placeholderText: root.placeholderText + colorScheme: hifi.colorSchemes.dark } - label: root.label - placeholderText: root.placeholderText - colorScheme: hifi.colorSchemes.dark - } + Component { + id: fileBrowserBuilder; + FileDialog { selectDirectory: true } + } - Component { - id: fileBrowserBuilder; - FileDialog { selectDirectory: true } - } - - Button { - id: button - anchors { right: parent.right; verticalCenter: dataTextField.verticalCenter } - text: preference.browseLabel - onClicked: { - var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); - browser.selectedFile.connect(function(fileUrl){ - console.log(fileUrl); - dataTextField.text = fileDialogHelper.urlToPath(fileUrl); - }); + Button { + id: button + text: preference.browseLabel + anchors { + right: parent.right + verticalCenter: dataTextField.verticalCenter + } + onClicked: { + var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); + browser.selectedFile.connect(function(fileUrl){ + console.log(fileUrl); + dataTextField.text = fileDialogHelper.urlToPath(fileUrl); + }); + } } } } diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index c7b5583bf3..06332bd1be 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -14,7 +14,7 @@ import "../../controls-uit" Preference { id: root - height: button.height + height: button.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: button.text = preference.name; @@ -24,5 +24,6 @@ Preference { id: button onClicked: preference.trigger() width: 180 + anchors.bottom: parent.bottom } } diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index 10e5f5febf..860cbcb5a8 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -17,7 +17,7 @@ import "../../styles-uit" Preference { id: root - height: dataComboBox.controlHeight + height: control.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: { dataComboBox.currentIndex = dataComboBox.comboBox.find(preference.value); @@ -25,28 +25,41 @@ Preference { function save() { preference.value = dataComboBox.currentText; - //preference.value = comboBox.currentText; preference.save(); } - HiFiControls.Label { - text: root.label + ":" - colorScheme: hifi.colorSchemes.dark + Item { + id: control anchors { left: parent.left - right: dataComboBox.left - rightMargin: hifi.dimensions.labelPadding - verticalCenter: dataComboBox.verticalCenter + right: parent.right + bottom: parent.bottom } - horizontalAlignment: Text.AlignRight - wrapMode: Text.Wrap - } + height: Math.max(labelText.height, dataComboBox.controlHeight) - HiFiControls.ComboBox { - id: dataComboBox - model: preference.items - width: 150 - anchors { right: parent.right } - colorScheme: hifi.colorSchemes.dark + HiFiControls.Label { + id: labelText + text: root.label + ":" + colorScheme: hifi.colorSchemes.dark + anchors { + left: parent.left + right: dataComboBox.left + rightMargin: hifi.dimensions.labelPadding + verticalCenter: parent.verticalCenter + } + horizontalAlignment: Text.AlignRight + wrapMode: Text.Wrap + } + + HiFiControls.ComboBox { + id: dataComboBox + model: preference.items + width: 150 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + colorScheme: hifi.colorSchemes.dark + } } } diff --git a/interface/resources/qml/dialogs/preferences/EditablePreference.qml b/interface/resources/qml/dialogs/preferences/EditablePreference.qml index 3b0f7802ea..8acf8e1f76 100644 --- a/interface/resources/qml/dialogs/preferences/EditablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/EditablePreference.qml @@ -15,8 +15,7 @@ import "../../controls-uit" Preference { id: root - property real spacing: 8 - height: dataTextField.controlHeight + spacing + height: dataTextField.controlHeight + hifi.dimensions.controlInterlineHeight Component.onCompleted: { dataTextField.text = preference.value; @@ -36,7 +35,7 @@ Preference { anchors { left: parent.left right: parent.right - bottomMargin: spacing + bottom: parent.bottom } } } diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index 92cab40133..e9013bc17a 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -16,7 +16,7 @@ import "../../controls-uit" Preference { id: root property alias slider: slider - height: slider.controlHeight + height: control.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: { slider.value = preference.value; @@ -27,24 +27,38 @@ Preference { preference.save(); } - Label { - text: root.label + ":" - colorScheme: hifi.colorSchemes.dark + Item { + id: control anchors { left: parent.left - right: slider.left - rightMargin: hifi.dimensions.labelPadding - verticalCenter: slider.verticalCenter + right: parent.right + bottom: parent.bottom } - horizontalAlignment: Text.AlignRight - wrapMode: Text.Wrap - } + height: Math.max(labelText.height, slider.height) - Slider { - id: slider - value: preference.value - width: 130 - anchors { right: parent.right } - colorScheme: hifi.colorSchemes.dark + Label { + id: labelText + text: root.label + ":" + colorScheme: hifi.colorSchemes.dark + anchors { + left: parent.left + right: slider.left + rightMargin: hifi.dimensions.labelPadding + verticalCenter: parent.verticalCenter + } + horizontalAlignment: Text.AlignRight + wrapMode: Text.Wrap + } + + Slider { + id: slider + value: preference.value + width: 130 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + colorScheme: hifi.colorSchemes.dark + } } } diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index aa9068bb00..e670cd37c4 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -15,7 +15,7 @@ import "../../controls-uit" Preference { id: root property alias spinner: spinner - height: spinner.controlHeight + height: control.height + hifi.dimensions.controlInterlineHeight Component.onCompleted: { spinner.value = preference.value; @@ -26,26 +26,40 @@ Preference { preference.save(); } - Label { - text: root.label + ":" - colorScheme: hifi.colorSchemes.dark + Item { + id: control anchors { left: parent.left - right: spinner.left - rightMargin: hifi.dimensions.labelPadding - verticalCenter: spinner.verticalCenter + right: parent.right + bottom: parent.bottom } - horizontalAlignment: Text.AlignRight - wrapMode: Text.Wrap - } + height: Math.max(spinnerLabel.height, spinner.controlHeight) - SpinBox { - id: spinner - decimals: preference.decimals - minimumValue: preference.min - maximumValue: preference.max - width: 100 - anchors { right: parent.right } - colorScheme: hifi.colorSchemes.dark + Label { + id: spinnerLabel + text: root.label + ":" + colorScheme: hifi.colorSchemes.dark + anchors { + left: parent.left + right: spinner.left + rightMargin: hifi.dimensions.labelPadding + verticalCenter: parent.verticalCenter + } + horizontalAlignment: Text.AlignRight + wrapMode: Text.Wrap + } + + SpinBox { + id: spinner + decimals: preference.decimals + minimumValue: preference.min + maximumValue: preference.max + width: 100 + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + colorScheme: hifi.colorSchemes.dark + } } } From 21b3f88deeb9c2feba7cb0a02d8e9b18b9700147 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 21:59:40 -0800 Subject: [PATCH 224/292] Scale up/Add avatar rotation/Cleanup --- examples/flappyBird.js | 76 +++++++++++------------------------------- 1 file changed, 19 insertions(+), 57 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 49dec4c32a..d9440a8fe9 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -15,18 +15,17 @@ Controller.Standard.RT, ]; - var OBJECTS_LIFETIME = 1; var G = 4.0; - var entityManager = new EntityManager(); - Number.prototype.clamp = function(min, max) { return Math.min(Math.max(this, min), max); }; + + var entityManager = new EntityManager(); // Class definitions - function Bird(DEFAULT_X, DEFAULT_Y, to3DPosition) { - var DIMENSION = 0.05; + function Bird(DEFAULT_X, DEFAULT_Y, rotation, to3DPosition) { + var DIMENSION = 0.15; var JUMP_VELOCITY = 1.0; var xPosition = DEFAULT_X; var color = { red: 0, green: 0, blue: 255 }; @@ -58,6 +57,7 @@ hold: true }, position: to3DPosition(this.position()), + rotation: rotation, dimensions: dimensions, color: color }); @@ -95,7 +95,7 @@ } function Pipe(xPosition, yPosition, height, gap, to3DPosition) { - var velocity = 0.6; + var velocity = 0.4; var width = 0.05; var color = { red: 0, green: 255, blue: 0 }; @@ -146,7 +146,7 @@ function Pipes(newPipesPosition, newPipesHeight, to3DPosition) { var lastPipe = 0; - var pipesInterval = 1.0; + var pipesInterval = 2.0; var pipes = new Array(); @@ -166,10 +166,10 @@ } // Make new pipes if (startedPlaying && gameTime - lastPipe > pipesInterval) { - var min = 0.1; - var max = 0.4; + var min = 0.4; + var max = 0.7; var height = Math.random() * (max - min) + min; - pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.3, to3DPosition)); + pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.5, to3DPosition)); lastPipe = gameTime; } } @@ -202,13 +202,11 @@ if (!isRunning) { isRunning = true; setup(); - // Script.update.connect(idle); } } this.stop = function() { if (isRunning) { - // Script.update.disconnect(idle); cleanup(); isRunning = false; } @@ -235,7 +233,7 @@ // } // Constants - var spaceDimensions = { x: 1.5, y: 0.8, z: 0.01 }; + var spaceDimensions = { x: 2.0, y: 1.5, z: 0.01 }; var spaceDistance = 1.5; var spaceYOffset = 0.6; @@ -250,6 +248,9 @@ var gameTime = 0; var isJumping = false; + var lastJumpValue = 0.0; + var lastTriggerValue = 0.0; + var TRIGGER_THRESHOLD = 0.9; var space = null var board = null; @@ -273,15 +274,16 @@ // color: { red: 100, green: 200, blue: 200 } // }); - bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, to3DPosition); - + var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); + bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); } function inputs(triggerValue) { - if (triggerValue > 0.5) { + if (triggerValue > TRIGGER_THRESHOLD && lastTriggerValue < TRIGGER_THRESHOLD) { isJumping = true; startedPlaying = true; } + lastTriggerValue = triggerValue; } function update(deltaTime) { //print("update: " + deltaTime); @@ -346,13 +348,6 @@ return spaceDimensions; } - - - function project(point, plane) { - var v = Vec3.subtract(point, plane.origin); - var dist = Vec3.dot(v, plane.normal); - return Vec3.subtract(point, Vec3.multiply(dist, v)); - } function to3DPosition(position) { var position2D = { x: position.x - space.dimensions.x / 2.0, @@ -361,26 +356,10 @@ } return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D)); } - function to2DPosition(position) { - var position3D = project(position, { - origin: Vec3.subtract(space.position, { - x: space.dimensions.x / 2.0, - y: space.dimensions.y / 2.0, - z: 0.0 - }), - normal: Vec3.multiplyQbyV(space.orientation, Vec3.FRONT) - }); - - var position2D = { - x: position3D.x.clamp(0.0, space.dimensions.x), - y: position3D.y.clamp(0.0, space.dimensions.y) - } - return position2D; - } - } function EntityManager() { + var OBJECTS_LIFETIME = 1; var entities = new Array(); var lifetime = OBJECTS_LIFETIME; @@ -462,20 +441,3 @@ // entity scripts always need to return a newly constructed object of our type return new PartableGame(); }); - - -// // Script logic -// function scriptStarting() { -// var game = new Game(); - -// Controller.keyPressEvent.connect(function(event) { -// game.keyPressed(event); -// }); -// Script.scriptEnding.connect(function() { -// game.stop(); -// }); -// game.start(); -// } - -// scriptStarting(); - From f88eef7549dd9de95391e31785257c4ba53d1a2c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 19:17:48 +1300 Subject: [PATCH 225/292] Update section headers --- .../qml/controls-uit/ContentSection.qml | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml index 1700b5939a..d51ab9cd1b 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -39,13 +39,22 @@ Column { Item { id: sectionName - height: (isCollapsible ? 4 : 3) * hifi.dimensions.contentSpacing.y anchors.left: parent.left anchors.right: parent.right + height: leadingSpace.height + topBar.height + heading.height + bottomBar.height Item { + id: leadingSpace + width: 1 + height: isFirst ? hifi.dimensions.contentSpacing.y : hifi.dimensions.controlInterlineHeight + anchors.top: parent.top + } + + Item { + id: topBar visible: !isFirst - anchors.top: heading.top + height: visible ? 2 : 0 + anchors.top: leadingSpace.bottom Rectangle { id: shadow @@ -69,15 +78,17 @@ Column { anchors { left: parent.left right: parent.right - top: parent.top - topMargin: hifi.dimensions.contentSpacing.y + top: topBar.bottom } - height: 3 * hifi.dimensions.contentSpacing.y + height: (isCollapsible ? 3 : 2) * hifi.dimensions.contentSpacing.y RalewayRegular { id: title - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter + anchors { + left: parent.left + top: parent.top + topMargin: hifi.dimensions.contentSpacing.y + } size: hifi.fontSizes.sectionName font.capitalization: Font.AllUppercase text: name @@ -104,9 +115,10 @@ Column { } LinearGradient { + id: bottomBar visible: isCollapsible width: frame.width - height: 4 + height: visible ? 4 : 0 x: -hifi.dimensions.contentMargin.x anchors.top: heading.bottom start: Qt.point(0, 0) From bef28859573d9a4319cc5c69d8cbe71183b5f643 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 22:25:30 -0800 Subject: [PATCH 226/292] Couple bounding box fixes --- examples/flappyBird.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index d9440a8fe9..d4de629e8d 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -39,8 +39,8 @@ this.position = function() { return { x: xPosition, y: yPosition }; } - this.size = function() { - return DIMENSION; + this.dimensions = function() { + return dimensions; } var id = entityManager.add({ @@ -77,7 +77,9 @@ dimensions.z = naturalDimensions.z / max * dimensions.z; dimensionsSet = true; } - }; + } else { + dimensions = Entities.getEntityProperties(id, ["dimensions"]).dimensions; + } yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); yVelocity += deltaTime * yAcceleration; @@ -124,9 +126,9 @@ } this.isColliding = function(bird) { var deltaX = Math.abs(this.position() - bird.position().x); - if (deltaX < (bird.size() + width) / 2.0) { - var upDistance = (yPosition - upHeight) - (bird.position().y + bird.size()); - var downDistance = (bird.position().y - bird.size()) - height; + if (deltaX < (bird.dimensions().z + width) / 2.0) { + var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y); + var downDistance = (bird.position().y - bird.dimensions().y) - height; if (upDistance <= 0 || downDistance <= 0) { return true; } From 1eb6fa425cdd116a9cf74225d799a1836de29977 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Mar 2016 20:09:50 +1300 Subject: [PATCH 227/292] Fix up Running Scripts dialog --- .../qml/controls-uit/VerticalSpacer.qml | 2 +- .../qml/hifi/dialogs/RunningScripts.qml | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/VerticalSpacer.qml b/interface/resources/qml/controls-uit/VerticalSpacer.qml index a3a0276f8f..6fc49605c0 100644 --- a/interface/resources/qml/controls-uit/VerticalSpacer.qml +++ b/interface/resources/qml/controls-uit/VerticalSpacer.qml @@ -14,5 +14,5 @@ import "../styles-uit" Item { width: 1 // Must be non-zero - height: hifi.dimensions.contentSpacing.y + height: hifi.dimensions.controlInterlineHeight } diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 9e356582cf..b156a95a02 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -24,7 +24,7 @@ Window { resizable: true destroyOnInvisible: true x: 40; y: 40 - implicitWidth: 384; implicitHeight: 640 + implicitWidth: 400; implicitHeight: 695 minSize: Qt.vector2d(200, 300) HifiConstants { id: hifi } @@ -91,6 +91,8 @@ Window { name: "Currently Running" isFirst: true + HifiControls.VerticalSpacer {} + Row { spacing: hifi.dimensions.contentSpacing.x @@ -107,6 +109,8 @@ Window { } } + HifiControls.VerticalSpacer {} + HifiControls.Table { tableModel: runningScriptsModel height: 185 @@ -116,13 +120,15 @@ Window { } HifiControls.VerticalSpacer { - height: 4 + height: 2 // Table view draws a little taller than it's height. } } HifiControls.ContentSection { name: "Load Scripts" + HifiControls.VerticalSpacer {} + Row { spacing: hifi.dimensions.contentSpacing.x anchors.right: parent.right @@ -165,6 +171,8 @@ Window { } } + HifiControls.VerticalSpacer {} + HifiControls.TextField { id: filterEdit anchors.left: parent.left @@ -176,6 +184,8 @@ Window { Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i") } + HifiControls.VerticalSpacer {} + HifiControls.Tree { id: treeView height: 155 @@ -185,6 +195,8 @@ Window { anchors.right: parent.right } + HifiControls.VerticalSpacer {} + HifiControls.TextField { id: selectedScript anchors.left: parent.left From d5d5eaaf9c5905ee71a178e966e1c5e68785dbf5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Mar 2016 23:42:27 -0800 Subject: [PATCH 228/292] Fix cooldown --- examples/flappyBird.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index d4de629e8d..041535caa5 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -281,7 +281,9 @@ pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); } function inputs(triggerValue) { - if (triggerValue > TRIGGER_THRESHOLD && lastTriggerValue < TRIGGER_THRESHOLD) { + if (triggerValue > TRIGGER_THRESHOLD && + lastTriggerValue < TRIGGER_THRESHOLD && + (gameTime - lastLost) > coolDown) { isJumping = true; startedPlaying = true; } From a752f55deb4b1ebb5f70466e59f4f2cc1620852f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Mar 2016 02:25:41 -0800 Subject: [PATCH 229/292] example of a rainy day/night zone --- examples/entityScripts/lighteningEntity.js | 339 +++++++++++++++++++++ examples/shaders/rainyDayNightSkybox.fs | 126 ++++++++ examples/zones/RainyDayNightZone.json | 27 ++ 3 files changed, 492 insertions(+) create mode 100644 examples/entityScripts/lighteningEntity.js create mode 100644 examples/shaders/rainyDayNightSkybox.fs create mode 100644 examples/zones/RainyDayNightZone.json diff --git a/examples/entityScripts/lighteningEntity.js b/examples/entityScripts/lighteningEntity.js new file mode 100644 index 0000000000..67cc6c8ea6 --- /dev/null +++ b/examples/entityScripts/lighteningEntity.js @@ -0,0 +1,339 @@ +// +// lighteningEntity.js +// examples/entityScripts +// +// Created by Brad Hefta-Gaub on 3/1/16. +// Copyright 2016 High Fidelity, Inc. +// +// This is an example of an entity script which will randomly create a flash of lightening and a thunder sound +// effect, as well as a background rain sound effect. It can be applied to any entity, although it works best +// on a zone entity. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ +(function () { + "use strict"; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Various configurable settings. + // + // You can change these values to change some of the various effects of the rain storm. + // These values can also be controlled by setting user properties on the entity that you've attached this script to. + // add a "lightening" section to a JSON encoded portion of the user data... for example: + // { + // "lightening": { + // "flashMax": 20, + // "flashMin": 0, + // "flashMaxRandomness": 10, + // "flashIntensityStepRandomeness": 2, + // "averageLighteningStrikeGap": 120, + // "extraRandomRangeLighteningStrikeGap": 10, + // "thunderURL": "atp:1336efe995398f5e0d46b37585785de8ba872fe9a9b718264db03748cd41c758.wav", + // "thunderVolume": 0.1, + // "rainURL": "atp:e0cc7438aca776636f6e6f731685781d9999b961c945e4e5760d937be5beecdd.wav", + // "rainVolume": 0.05 + // } + // // NOTE: you can have other user data here as well, so long as it's JSON encoded, it won't impact the lightening script + // } + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var MAX_FLASH_INTENSITY = 20; // this controls how bright the lightening effect appears + var MIN_FLASH_INTENSITY = 0; // this is probably best at 0, but it could be higher, which will make the lightening not fade completely to darkness before going away. + var MAX_FLASH_INTENSITY_RANDOMNESS = 10; // this will add some randomness to the max brightness of the lightening + var FLASH_INTENSITY_STEP_RANDOMNESS = 2; // as the lightening goes from min to max back to min, this will make it more random in it's brightness + var AVERAGE_LIGHTENING_STRIKE_GAP_IN_SECONDS = 120; // how long on average between lighting + var EXTRA_RANDOM_RANGE_LIGHTENING_STRIKE_GAP_IN_SECONDS = 10; // some randomness to the lightening gap + var THUNDER_SOUND_URL = "https://s3.amazonaws.com/hifi-public/brad/rainstorm/thunder-48k.wav"; // thunder sound effect, must be 48k 16bit PCM + var THUNDER_VOLUME = 1; // adjust the volume of the thunder sound effect + var RAIN_SOUND_URL = "https://s3.amazonaws.com/hifi-public/brad/rainstorm/rain.wav"; // the background rain, this will loop + var RAIN_VOLUME = 0.05; // adjust the volume of the rain sound effect. + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Various constants and variables we need access to in all scopes + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + var MSECS_PER_SECOND = 1000; // number of milliseconds in a second, a universal truth, don't change this. :) + + // This is a little trick for implementing entity scripts. Many of the entity callbacks will have the JavaScript + // "this" variable set, but if you connect to a signal like update, "this" won't correctly point to the instance + // of your entity script, and so we set "_this" and use it in cases we need to access "this". We need to define + // the variable in this scope so that it's not share among all entities. + + var _this; // this is important here... or else the _this will be globally scoped. + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Various helper functions... + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // Helper function for returning either a value, or the default value if the value is undefined. This is + // is handing in parsing JSON where you don't know if the values have been set or not. + function valueOrDefault(value, defaultValue) { + if (value !== undefined) { + return value; + } + return defaultValue; + } + + // return a random float between high and low + function randFloat(low, high) { + return low + Math.random() * (high - low); + } + + // the "constructor" for our class. pretty simple, it just sets our _this, so we can access it later. + function Lightening() { + _this = this; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // The class prototype + // + // This is the class definition/prototype for our class. Funtions declared here will be accessible + // via the instance of the entity + // + Lightening.prototype = { + + // preload() + // This is called by every viewer/interface instance that "sees" the entity you've attached this script to. + // If this is a zone entity, then it will surely be called whenever someone enters the zone. + preload: function (entityID) { + + // we always make a point of remember our entityID, so that we can access our entity later + _this.entityID = entityID; + + // set up some of our time related state + var now = Date.now(); + _this.lastUpdate = now; + _this.lastStrike = now; + + // some of our other state related items + _this.lighteningID = false; // this will be the entityID for any lightening that we create + _this.lighteningActive = false; // are we actively managing lightening + + // Get the entities userData property, to see if someone has overridden any of our default settings + var userDataText = Entities.getEntityProperties(entityID, ["userData"]).userData; + var userData = {}; + if (userDataText !== "") { + userData = JSON.parse(userDataText); + } + var lighteningUserData = valueOrDefault(userData.lightening, {}); + _this.flashIntensityStepRandomeness = valueOrDefault(lighteningUserData.flashIntensityStepRandomness, FLASH_INTENSITY_STEP_RANDOMNESS); + _this.flashMax = valueOrDefault(lighteningUserData.flashMax, MAX_FLASH_INTENSITY); + _this.flashMin = valueOrDefault(lighteningUserData.flashMin, MIN_FLASH_INTENSITY); + _this.flashMaxRandomness = valueOrDefault(lighteningUserData.flashMaxRandomness, MAX_FLASH_INTENSITY_RANDOMNESS); + _this.averageLighteningStrikeGap = valueOrDefault(lighteningUserData.averageLighteningStrikeGap, AVERAGE_LIGHTENING_STRIKE_GAP_IN_SECONDS); + _this.extraRandomRangeLighteningStrikeGap = valueOrDefault(lighteningUserData.extraRandomRangeLighteningStrikeGap, EXTRA_RANDOM_RANGE_LIGHTENING_STRIKE_GAP_IN_SECONDS); + + var thunderURL = valueOrDefault(lighteningUserData.thunderURL, THUNDER_SOUND_URL); + _this.thunderSound = SoundCache.getSound(thunderURL); // start downloading the thunder into the cache in case we need it later + _this.thunderVolume = valueOrDefault(lighteningUserData.thunderVolume, THUNDER_VOLUME); + + var rainURL = valueOrDefault(lighteningUserData.rainURL, RAIN_SOUND_URL); + _this.rainSound = SoundCache.getSound(rainURL); // start downloading the rain, we will be using it for sure + _this.rainVolume = valueOrDefault(lighteningUserData.rainVolume, RAIN_VOLUME); + _this.rainPlaying = false; + + Script.update.connect(_this.onUpdate); // connect our onUpdate to a regular update signal from the interface + }, + + // unload() + // This is called by every viewer/interface instance that "sees" the entity when you "stop knowing about" the + // entity. Usually this means the user has left then domain, or maybe the entity has been deleted. We need to + // clean up anything transient that we created here. In this case it means disconnecting from the update signal + // and stopping the rain sound if we started it. + unload: function ( /*entityID*/ ) { + Script.update.disconnect(_this.onUpdate); + if (_this.rainInjector !== undefined) { + _this.rainInjector.stop(); + } + }, + + // plays the rain sound effect. This is played locally, which means it doesn't provide spatialization, which + // we don't really want for the ambient sound effect of rain. Also, since it's playing locally, we don't send + // the stream to the audio mixer. Another subtle side effect of playing locally is that the sound isn't in sync + // for all users in the domain, but that's ok for a sound effect like rain which is more of a white noise like + // sound effect. + playLocalRain: function () { + var myPosition = Entities.getEntityProperties(_this.entityID, "position").position; + _this.rainInjector = Audio.playSound(_this.rainSound, { + position: myPosition, + volume: _this.rainVolume, + loop: true, + localOnly: true + }); + _this.rainPlaying = true; + }, + + // this handles a single "step" of the lightening flash effect. It assumes a light entity has already been created, + // and all it really does is change the intensity of the light based on the settings that are part of this entity's + // userData. + flashLightening: function (lighteningID) { + var lighteningProperties = Entities.getEntityProperties(lighteningID, ["userData", "intensity"]); + var lighteningParameters = JSON.parse(lighteningProperties.userData); + var currentIntensity = lighteningProperties.intensity; + var flashDirection = lighteningParameters.flashDirection; + var flashMax = lighteningParameters.flashMax; + var flashMin = lighteningParameters.flashMin; + var flashIntensityStepRandomeness = lighteningParameters.flashIntensityStepRandomeness; + var newIntensity = currentIntensity + flashDirection + randFloat(-flashIntensityStepRandomeness, flashIntensityStepRandomeness); + + if (flashDirection > 0) { + if (newIntensity >= flashMax) { + flashDirection = -1; // reverse flash + newIntensity = flashMax; + } + } else { + if (newIntensity <= flashMin) { + flashDirection = 1; // reverse flash + newIntensity = flashMin; + } + } + + // if we reached 0 intensity, then we're done with this strike... + if (newIntensity === 0) { + _this.lighteningActive = false; + Entities.deleteEntity(lighteningID); + } + + // FIXME - we probably don't need to re-edit the userData of the light... we're only + // changing direction, the rest are the same... we could just store direction in our + // own local variable state + var newLighteningParameters = JSON.stringify({ + flashDirection: flashDirection, + flashIntensityStepRandomeness: flashIntensityStepRandomeness, + flashMax: flashMax, + flashMin: flashMin + }); + + // this is what actually creates the effect, changing the intensity of the light + Entities.editEntity(lighteningID, {intensity: newIntensity, userData: newLighteningParameters}); + }, + + // findMyLightening() is designed to make the script more robust. Since we're an open editable platform + // it's possible that from the time that we started the lightening effect until "now" when we're attempting + // to change the light, some other client might have deleted our light. Before we proceed in editing + // the light, we check to see if it exists. + findMyLightening: function () { + if (_this.lighteningID !== false) { + var lighteningName = Entities.getEntityProperties(_this.lighteningID, "name").name; + if (lighteningName !== undefined) { + return _this.lighteningID; + } + } + return false; + }, + + // findOtherLightening() is designed to allow this script to work in a "multi-user" environment, which we + // must assume we are in. Since every user/viewer/client that connect to the domain and "sees" our entity + // is going to run this script, any of them could be in charge of flashing the lightening. So before we + // start to flash the lightening, we will first check to see if someone else already is. + // + // returns true if some other lightening exists... likely because some other viewer is flashing it + // returns false if no other lightening exists... + findOtherLightening: function () { + var myPosition = Entities.getEntityProperties(_this.entityID, "position").position; + + // find all entities near me... + var entities = Entities.findEntities(myPosition, 1000); + var checkEntityID; + var checkProperties; + var entity; + for (entity = 0; entity < entities.length; entity++) { + checkEntityID = entities[entity]; + checkProperties = Entities.getEntityProperties(checkEntityID, ["name", "type"]); + + // check to see if they are lightening + if (checkProperties.type === "Light" && checkProperties.name === "lightening for creator:" + _this.entityID) { + return true; + } + } + return false; + }, + + // createNewLightening() actually creates new lightening and plays the thunder sound + createNewLightening: function () { + var myPosition = Entities.getEntityProperties(_this.entityID, "position").position; + _this.lighteningID = Entities.addEntity({ + type: "Light", + name: "lightening for creator:" + _this.entityID, + userData: JSON.stringify({ + flashDirection: 1, + flashIntensityStepRandomeness: _this.flashIntensityStepRandomeness, + flashMax: _this.flashMax + randFloat(-_this.flashMaxRandomness, _this.flashMaxRandomness), + flashMin: _this.flashMin + }), + falloffRadius: 1000, + intensity: 0, + position: myPosition, + collisionless: true, + dimensions: {x: 1000, y: 1000, z: 1000}, + color: {red: 255, green: 255, blue: 255}, + lifetime: 10 // lightening only lasts 10 seconds.... + }); + + // play the thunder... + Audio.playSound(_this.thunderSound, { + position: myPosition, + volume: _this.thunderVolume + }); + + return _this.lighteningID; + }, + + // onUpdate() this will be called regularly, approximately every frame of the simulation. We will use + // it to determine if we need to do a lightening/thunder strike + onUpdate: function () { + var now = Date.now(); + + // check to see if rain is downloaded and not yet playing, if so start playing + if (!_this.rainPlaying && _this.rainSound.downloaded) { + _this.playLocalRain(); + } + + // NOTE: _this.lighteningActive will only be TRUE if we are the one who created + // the lightening and we are in charge of flashing it... + if (_this.lighteningActive) { + var lighteningID = _this.findMyLightening(); + // if for some reason our lightening is gone... then just return to non-active state + if (lighteningID === false) { + _this.lighteningActive = false; + _this.lighteningID = false; + } else { + // otherwise, flash our lightening... + _this.flashLightening(lighteningID); + } + } else { + // whether or not it's time for us to strike, we always keep an eye out for anyone else + // striking... and if we see someone else striking, we will reset our lastStrike time + if (_this.findOtherLightening()) { + _this.lastStrike = now; + } + + var sinceLastStrike = now - _this.lastStrike; + var nextRandomStrikeTime = _this.averageLighteningStrikeGap + + randFloat(-_this.extraRandomRangeLighteningStrikeGap, + _this.extraRandomRangeLighteningStrikeGap); + + if (sinceLastStrike > nextRandomStrikeTime * MSECS_PER_SECOND) { + + // so it's time for a strike... let's see if someone else has lightening... + // if no one else is flashing lightening... then we create it... + if (_this.findOtherLightening()) { + _this.lighteningActive = false; + _this.lighteningID = false; + } else { + _this.createNewLightening(); + _this.lighteningActive = true; + } + + _this.lastStrike = now; + } + } + } + }; + + return new Lightening(); +}); \ No newline at end of file diff --git a/examples/shaders/rainyDayNightSkybox.fs b/examples/shaders/rainyDayNightSkybox.fs new file mode 100644 index 0000000000..359bfb1653 --- /dev/null +++ b/examples/shaders/rainyDayNightSkybox.fs @@ -0,0 +1,126 @@ +// Created by inigo quilez - iq/2013 +// Turbulence and Day/Night cycle added by Michael Olson - OMGparticles/2015 +// rain effect adapted from Rainy London by David Hoskins. - https://www.shadertoy.com/view/XdSGDc +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. +#line 5 +const float PI = 3.14159; +uniform float rotationSpeed = 0.005; +uniform float gridLevel = 0.0; +uniform float constellationLevel = 0.0; +uniform float constellationBoundaryLevel = 0.0; + +// Axial tilt +const float axialTilt = 0.408407; +const vec2 atsc = vec2(sin(axialTilt), cos(axialTilt)); +const mat3 axialTiltMatrix = mat3( + vec3(atsc.y, -atsc.x, 0.0), + vec3(atsc.x, atsc.y, 0.0), + vec3(0.0, 0.0, 1.0)); + +vec2 directionToSpherical(in vec3 d) { + return vec2(atan(d.x, -d.z), asin(d.y)) * -1.0f; +} + +vec2 directionToUv(in vec3 d) { + vec2 uv = directionToSpherical(d); + uv /= PI; + uv.x /= 2.0; + uv += 0.5; + return uv; +} + +vec3 stars3(in vec3 d) { + //return rd; + vec3 dir = d * axialTiltMatrix; + + float theta = rotationSpeed * iGlobalTime * 4.0; + vec2 sc = vec2(sin(theta), cos(theta)); + dir = dir * mat3( vec3(sc.y, 0.0, sc.x), + vec3(0.0, 1.0, 0.0), + vec3(-sc.x, 0.0, sc.y)); + + vec2 uv = directionToUv(dir); + vec3 starColor = texture2D( iChannel0, uv).xyz; + starColor = pow(starColor, vec3(0.75)); + + if (gridLevel > 0.0) { + starColor += texture2D( iChannel1, uv).xyz * gridLevel; + } + return starColor; +} + +//const vec3 vNightColor = vec3(.15, 0.3, 0.6); +uniform vec3 uDayColor = vec3(0.9,0.7,0.7); +const vec3 vNightColor = vec3(1.0, 1.0, 1.0); +const vec3 vHorizonColor = vec3(0.6, 0.3, 0.4); +const vec3 vSunColor = vec3(1.0,0.8,0.6); +const vec3 vSunRimColor = vec3(1.0,0.66,0.33); + +vec4 render( in vec3 ro, in vec3 rd ) +{ + float fSunSpeed = (rotationSpeed * 10.0 * iGlobalTime) + PI / 2.0 * 3.0; + vec3 sundir = normalize( vec3(cos(fSunSpeed),sin(fSunSpeed),0.0) ); + sundir = sundir * axialTiltMatrix; + float sun = clamp( dot(sundir,rd), 0.0, 1.0 ); + + float fSunHeight = sundir.y; + + // below this height will be full night color + float fNightHeight = -0.8; + // above this height will be full day color + float fDayHeight = 0.3; + + float fHorizonLength = fDayHeight - fNightHeight; + float fInverseHL = 1.0 / fHorizonLength; + float fHalfHorizonLength = fHorizonLength / 2.0; + float fInverseHHL = 1.0 / fHalfHorizonLength; + float fMidPoint = fNightHeight + fHalfHorizonLength; + + float fNightContrib = clamp((fSunHeight - fMidPoint) * (-fInverseHHL), 0.0, 1.0); + float fHorizonContrib = -clamp(abs((fSunHeight - fMidPoint) * (-fInverseHHL)), 0.0, 1.0) + 1.0; + float fDayContrib = clamp((fSunHeight - fMidPoint) * ( fInverseHHL), 0.0, 1.0); + + // sky color + vec3 vSkyColor = vec3(0.0); + vSkyColor += mix(vec3(0.0), vNightColor, fNightContrib); // Night + vSkyColor += mix(vec3(0.0), vHorizonColor, fHorizonContrib); // Horizon + vSkyColor += mix(vec3(0.0), uDayColor, fDayContrib); // Day + vec3 col = vSkyColor; + + // atmosphere brighter near horizon + col -= clamp(rd.y, 0.0, 0.5); + + // draw sun + col += 0.4 * vSunRimColor * pow( sun, 4.0 ); + col += 1.0 * vSunColor * pow( sun, 2000.0 ); + + // stars + float fStarContrib = clamp((fSunHeight - fDayHeight) * (-fInverseHL), 0.0, 1.0); + + vec3 vStarDir = rd; + + col = mix(col, stars3(vStarDir), fStarContrib); + col += stars3(vStarDir) * fStarContrib; + + // Ten layers of rain sheets... + float rainBrightness = 0.15; + vec2 q = vec2(atan(rd.x, -rd.z), asin(rd.y)); + float dis = 1; + int sheets = 12; + for (int i = 0; i < sheets; i++) { + float f = pow(dis, .45) + 0.25; + vec2 st = f * (q * vec2(2.0, .05) + vec2(-iGlobalTime*.01 + q.y * .05, iGlobalTime * 0.12)); + f = texture2D(iChannel2, st * .5, -59.0).x; + f += texture2D(iChannel2, st*.284, -99.0).y; + f = clamp(pow(abs(f)*.5, 29.0) * 140.0, 0.00, q.y*.4+.05); + vec3 bri = vec3(rainBrightness); + col += bri*f; + dis += 3.5; + } + + return vec4( col, 1.0 ); +} + +vec3 getSkyboxColor() { + return render( vec3(0.0), normalize(_normal) ).rgb; +} diff --git a/examples/zones/RainyDayNightZone.json b/examples/zones/RainyDayNightZone.json new file mode 100644 index 0000000000..dc69ca22ac --- /dev/null +++ b/examples/zones/RainyDayNightZone.json @@ -0,0 +1,27 @@ +{ + "Entities": [ + { + "backgroundMode": "skybox", + "dimensions": { + "x": 30000, + "y": 30000, + "z": 30000 + }, + "name": "Rainy Day/Night Cycle", + "rotation": { + "w": 1, + "x": 0, + "y": 0, + "z": 0 + }, + "script": "https://s3.amazonaws.com/hifi-public/brad/rainstorm/lighteningEntity.js", + "shapeType": "box", + "skybox": { + "url": "https://hifi-public.s3.amazonaws.com/images/SkyboxTextures/CloudyDay1.jpg" + }, + "type": "Zone", + "userData":"{\n\"ProceduralEntity\":{\n\"version\":2,\n\"shaderUrl\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/rainyDayNightSkybox.fs\",\n\"channels\":[\n\"https://hifi-public.s3.amazonaws.com/austin/assets/images/skybox/starmap_8k.jpg\",\n\"https://hifi-public.s3.amazonaws.com/austin/assets/images/skybox/celestial_grid.jpg\",\n\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/noise.jpg\",\n\"https://s3.amazonaws.com/hifi-public/brad/noise.jpg\"\n],\n\"uniforms\":{\n\"rotationSpeed\":0.001,\n\"uDayColor\":[0.4,0.3,0.3],\n\"constellationLevel\":0.0,\n\"constellationBoundaryLevel\":0.00,\n\"gridLevel\":0.0\n}\n},\n\"lightening\":{\n\"flashMax\":20,\n\"flashMin\":0,\n\"flashIntensityStepRandomeness\":2,\n\"flashMaxRandomness\":10,\n\"averageLighteningStrikeGap\":120,\n\"extraRandomRangeLighteningStrikeGap\":5,\n\"thunderURL\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/thunder-48k.wav\",\n\"thunderVolume\":0.1,\n\"rainURL\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/rain.wav\",\n\"rainVolume\":0.05\n}\n}" + } + ], + "Version": 57 +} From f5822223898813e4ffcbbd045f91a44413b6e77a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Mar 2016 03:24:12 -0800 Subject: [PATCH 230/292] Couple additional features --- examples/flappyBird.js | 43 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 041535caa5..a9e901a9f8 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -58,10 +58,20 @@ }, position: to3DPosition(this.position()), rotation: rotation, - dimensions: dimensions, - color: color + dimensions: dimensions }); + this.changeModel = function(modelURL) { + dimensionsSet = false; + dimensions = { x: 0.10, y: 0.10, z: 0.01 }; + + Entities.editEntity(id, { + modelURL: modelURL, + rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, -90, 0)), + dimensions: dimensions, + animation: {running: false} + }); + } this.jump = function() { yVelocity = JUMP_VELOCITY; @@ -98,7 +108,7 @@ function Pipe(xPosition, yPosition, height, gap, to3DPosition) { var velocity = 0.4; - var width = 0.05; + var width = 0.1; var color = { red: 0, green: 255, blue: 0 }; this.position = function() { @@ -109,13 +119,16 @@ var upYPosition = height + gap + upHeight / 2.0; var idUp = entityManager.add({ - type: "Box", + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", + rotation: Quat.fromPitchYawRollDegrees(180, 0, 0), position: to3DPosition({ x: xPosition, y: upYPosition }), dimensions: { x: width, y: upHeight, z: width }, color: color }); var idDown = entityManager.add({ - type: "Box", + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", position: to3DPosition({ x: xPosition, y: height / 2.0 }), dimensions: { x: width, y: height, z: width }, color: color @@ -259,6 +272,22 @@ var bird = null; var pipes = null; + var directions = ["UP", "DOWN", "LEFT", "RIGHT"]; + var sequence = [directions[0], directions[0], directions[1], directions[1], directions[2], directions[3], directions[2], directions[3], "b", "a"]; + var current = 0; + function keyPress(event) { + if (event.text === sequence[current]) { + ++current; + } else { + current = 0; + } + if (current === sequence.length) { + print("KONAMI CODE!!!"); + bird.changeModel("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/mario.fbx"); + current = 0; + } + } + function setup() { print("setup"); @@ -279,6 +308,8 @@ var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); + + Controller.keyPressEvent.connect(keyPress); } function inputs(triggerValue) { if (triggerValue > TRIGGER_THRESHOLD && @@ -337,6 +368,8 @@ function cleanup() { print("cleanup"); entityManager.removeAll(); + + Controller.keyPressEvent.disconnect(keyPress); } // Private methods From 442bd22f4641be47dc97eafd4c9abc442dcc14ff Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Mar 2016 09:56:11 -0800 Subject: [PATCH 231/292] New sounds + coins!!! --- examples/flappyBird.js | 109 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index a9e901a9f8..b13f93b727 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -36,6 +36,9 @@ var yVelocity = 0.0; var yAcceleration = -G; + var airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Air Swipe 05.wav"); + var injector = null; + this.position = function() { return { x: xPosition, y: yPosition }; } @@ -54,7 +57,7 @@ lastFrame: 80.0, currentFrame: 1.0, loop: true, - hold: true + hold: false }, position: to3DPosition(this.position()), rotation: rotation, @@ -71,10 +74,19 @@ dimensions: dimensions, animation: {running: false} }); + + airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/8bit Jump 03.wav"); + injector = null; } this.jump = function() { yVelocity = JUMP_VELOCITY; + + if (airSwipeSound.downloaded && !injector) { + injector = Audio.playSound(airSwipeSound, { position: to3DPosition(this.position()), volume: 0.05 }); + } else if (injector) { + injector.restart(); + } } this.update = function(deltaTime) { if (!dimensionsSet) { @@ -86,6 +98,10 @@ dimensions.y = naturalDimensions.y / max * dimensions.y; dimensions.z = naturalDimensions.z / max * dimensions.z; dimensionsSet = true; + + Entities.editEntity(id, { + dimensions: dimensions + }); } } else { dimensions = Entities.getEntityProperties(id, ["dimensions"]).dimensions; @@ -96,8 +112,7 @@ } this.draw = function() { Entities.editEntity(id, { - position: to3DPosition(this.position()), - dimensions: dimensions + position: to3DPosition(this.position()) }); } this.reset = function() { @@ -106,10 +121,47 @@ } } + function Coin(xPosition, yPosition, to3DPosition) { + var velocity = 0.4; + + this.position = function() { + return xPosition; + } + + var id = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/coin.fbx", + angularVelocity: { x: 0, y: 20, z: 0 }, + position: to3DPosition({ x: xPosition, y: yPosition }), + dimensions: { x: 0.0625, y: 0.0625, z: 0.0088 } + }); + + this.update = function(deltaTime) { + xPosition -= deltaTime * velocity; + } + this.isColliding = function(bird) { + var deltaX = Math.abs(this.position() - bird.position().x); + if (deltaX < (bird.dimensions().z + width) / 2.0) { + var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y); + var downDistance = (bird.position().y - bird.dimensions().y) - height; + if (upDistance <= 0 || downDistance <= 0) { + return true; + } + } + + return false; + } + this.draw = function() { + Entities.editEntity(id, { position: to3DPosition({ x: xPosition, y: yPosition }) }); + } + this.clear = function() { + entityManager.remove(id); + } + } + function Pipe(xPosition, yPosition, height, gap, to3DPosition) { var velocity = 0.4; var width = 0.1; - var color = { red: 0, green: 255, blue: 0 }; this.position = function() { return xPosition; @@ -123,15 +175,13 @@ modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", rotation: Quat.fromPitchYawRollDegrees(180, 0, 0), position: to3DPosition({ x: xPosition, y: upYPosition }), - dimensions: { x: width, y: upHeight, z: width }, - color: color + dimensions: { x: width, y: upHeight, z: width } }); var idDown = entityManager.add({ type: "Model", modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", position: to3DPosition({ x: xPosition, y: height / 2.0 }), - dimensions: { x: width, y: height, z: width }, - color: color + dimensions: { x: width, y: height, z: width } }); this.update = function(deltaTime) { @@ -164,12 +214,17 @@ var pipesInterval = 2.0; var pipes = new Array(); + var coins = new Array(); this.update = function(deltaTime, gameTime, startedPlaying) { // Move pipes forward pipes.forEach(function(element) { element.update(deltaTime); }); + // Move coins forward + coins.forEach(function(element) { + element.update(deltaTime); + }); // Delete pipes over the end var count = 0; while(count < pipes.length && pipes[count].position() <= 0.0) { @@ -179,12 +234,22 @@ if (count > 0) { pipes = pipes.splice(count); } - // Make new pipes + // Delete coins over the end + count = 0; + while(count < coins.length && coins[count].position() <= 0.0) { + coins[count].clear(); + count++; + } + if (count > 0) { + coins = coins.splice(count); + } + // Make new pipes and coins if (startedPlaying && gameTime - lastPipe > pipesInterval) { var min = 0.4; var max = 0.7; var height = Math.random() * (max - min) + min; pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.5, to3DPosition)); + coins.push(new Coin(newPipesPosition, height + 0.5 / 2.0, to3DPosition)); lastPipe = gameTime; } } @@ -198,16 +263,27 @@ return isColliding; } this.draw = function() { - // Clearing pipes + // Drawing pipes pipes.forEach(function(element) { element.draw(); }); + // Drawing coins + coins.forEach(function(element) { + element.draw(); + }); } this.clear = function() { + // Clearing pipes pipes.forEach(function(element) { element.clear(); }); pipes = new Array(); + + // Clearing coins + coins.forEach(function(element) { + element.clear(); + }); + coins = new Array(); } } @@ -257,7 +333,7 @@ var isRunning = false; var startedPlaying = false; - var coolDown = 1; + var coolDown = 1.5; var lastLost = -coolDown; var gameTime = 0; @@ -272,6 +348,9 @@ var bird = null; var pipes = null; + var gameOverSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Game Over.wav"); + var injector = null; + var directions = ["UP", "DOWN", "LEFT", "RIGHT"]; var sequence = [directions[0], directions[0], directions[1], directions[1], directions[2], directions[3], directions[2], directions[3], "b", "a"]; var current = 0; @@ -353,6 +432,14 @@ // Cleanup if (hasLost) { print("Game Over!"); + + if (gameOverSound.downloaded && !injector) { + injector = Audio.playSound(gameOverSound, { position: space.position, volume: 0.4 }); + } else if (injector) { + injector.restart(); + } + + bird.reset(); pipes.clear(); From 17f0688db50eff1b09324c4899176f1db14da93c Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 3 Mar 2016 19:18:47 +0100 Subject: [PATCH 232/292] removed stray traybar icon --- interface/src/MainWindow.cpp | 1 - interface/src/MainWindow.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/interface/src/MainWindow.cpp b/interface/src/MainWindow.cpp index 34e1638e94..16aedc4bb7 100644 --- a/interface/src/MainWindow.cpp +++ b/interface/src/MainWindow.cpp @@ -31,7 +31,6 @@ MainWindow::MainWindow(QWidget* parent) : _windowState("WindowState", 0) { setAcceptDrops(true); - _trayIcon.show(); } void MainWindow::restoreGeometry() { diff --git a/interface/src/MainWindow.h b/interface/src/MainWindow.h index 6a401cf2b7..eb262e0f97 100644 --- a/interface/src/MainWindow.h +++ b/interface/src/MainWindow.h @@ -13,7 +13,6 @@ #define __hifi__MainWindow__ #include -#include #include @@ -43,7 +42,6 @@ protected: private: Setting::Handle _windowGeometry; Setting::Handle _windowState; - QSystemTrayIcon _trayIcon; }; #endif /* defined(__hifi__MainWindow__) */ From d1f7cf6387409bab398458ba0c7cef0cfbff3239 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Mar 2016 10:51:37 -0800 Subject: [PATCH 233/292] Added freeze on loss and points architecture --- examples/flappyBird.js | 72 +++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index b13f93b727..82f3c89086 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -123,30 +123,29 @@ function Coin(xPosition, yPosition, to3DPosition) { var velocity = 0.4; + var dimensions = { x: 0.0625, y: 0.0625, z: 0.0088 }; this.position = function() { - return xPosition; + return { x: xPosition, y: yPosition }; } var id = entityManager.add({ type: "Model", modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/coin.fbx", angularVelocity: { x: 0, y: 20, z: 0 }, - position: to3DPosition({ x: xPosition, y: yPosition }), - dimensions: { x: 0.0625, y: 0.0625, z: 0.0088 } + position: to3DPosition(this.position()), + dimensions:dimensions }); this.update = function(deltaTime) { xPosition -= deltaTime * velocity; } this.isColliding = function(bird) { - var deltaX = Math.abs(this.position() - bird.position().x); - if (deltaX < (bird.dimensions().z + width) / 2.0) { - var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y); - var downDistance = (bird.position().y - bird.dimensions().y) - height; - if (upDistance <= 0 || downDistance <= 0) { - return true; - } + var deltaX = Math.abs(this.position().x - bird.position().x); + var deltaY = Math.abs(this.position().Y - bird.position().Y); + if (deltaX < (bird.dimensions().x + dimensions.x) / 2.0 && + deltaX < (bird.dimensions().y + dimensions.y) / 2.0) { + return true; } return false; @@ -209,13 +208,16 @@ } } - function Pipes(newPipesPosition, newPipesHeight, to3DPosition) { + function Pipes(newPipesPosition, newPipesHeight, to3DPosition, moveScore) { var lastPipe = 0; var pipesInterval = 2.0; var pipes = new Array(); var coins = new Array(); + var coinsSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Coin.wav"); + var injector = null; + this.update = function(deltaTime, gameTime, startedPlaying) { // Move pipes forward pipes.forEach(function(element) { @@ -254,6 +256,27 @@ } } this.isColliding = function(bird) { + // Check coin collection + var collected = -1; + coins.forEach(function(element, index) { + if (element.isColliding(bird)) { + element.clear(); + collected = index; + moveScore(10); + + if (coinsSound.downloaded && !injector) { + injector = Audio.playSound(coinsSound, { position: to3DPosition({ x: newPipesPosition, y: newPipesHeight }), volume: 0.1 }); + } else if (injector) { + injector.restart(); + } + } + }); + if (collected > -1) { + coins.splice(collected, 1); + } + + + // Check collisions var isColliding = false; pipes.forEach(function(element) { @@ -311,6 +334,8 @@ if (timestamp === 0) { deltaTime = 0; } + gameTime += deltaTime; + inputs(triggerValue); update(deltaTime); draw(); @@ -367,6 +392,13 @@ } } + var isBoardReset = true; + + var score = 0; + function moveScore(delta) { + score += delta; + } + function setup() { print("setup"); @@ -386,11 +418,19 @@ var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); - pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition); + pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition, moveScore); Controller.keyPressEvent.connect(keyPress); } function inputs(triggerValue) { + if (!startedPlaying && !isBoardReset && (gameTime - lastLost) > coolDown) { + score = 0; + bird.reset(); + pipes.clear(); + + isBoardReset = true; + } + if (triggerValue > TRIGGER_THRESHOLD && lastTriggerValue < TRIGGER_THRESHOLD && (gameTime - lastLost) > coolDown) { @@ -403,10 +443,9 @@ //print("update: " + deltaTime); // Keep entities alive - gameTime += deltaTime; entityManager.update(deltaTime); - if (!startedPlaying && (gameTime - lastLost) < coolDown) { + if (!startedPlaying && (gameTime - lastLost) < coolDown && !isBoardReset) { return; } @@ -439,10 +478,7 @@ injector.restart(); } - - bird.reset(); - pipes.clear(); - + isBoardReset = false; startedPlaying = false; lastLost = gameTime; } From b00ff7a81cc040c4d2fc4a337b2b53c553ef52ba Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Mar 2016 12:19:01 -0800 Subject: [PATCH 234/292] Display score and save high scores --- examples/flappyBird.js | 141 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 7 deletions(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 82f3c89086..9df1c9a89e 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -189,8 +189,9 @@ this.isColliding = function(bird) { var deltaX = Math.abs(this.position() - bird.position().x); if (deltaX < (bird.dimensions().z + width) / 2.0) { - var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y); - var downDistance = (bird.position().y - bird.dimensions().y) - height; + var factor = 0.8; + var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y * factor); + var downDistance = (bird.position().y - bird.dimensions().y * factor) - height; if (upDistance <= 0 || downDistance <= 0) { return true; } @@ -310,7 +311,109 @@ } } - function Game() { + + function Score(space, bestScore) { + var score = 0; + var highScore = bestScore; + + var topOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.2, z: -0.2 }); + var topLeft = Vec3.sum(space.position, topOffset); + var bottomOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.0, z: -0.2 }); + var bottomLeft = Vec3.sum(space.position, bottomOffset); + + function numberUrl(number) { + return "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/" + number + ".fbx" + } + function digitPosition(digit) { + return Vec3.multiplyQbyV(space.orientation, { x: 0.3778 + digit * 0.0760, y: 0.0, z: 0.0 }); + } + this.score = function() { + return score; + } + this.highScore = function() { + return highScore; + } + + var bestId = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/best.fbx", + position: topLeft, + rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), + dimensions: { x: 0.2781, y: 0.0063, z: 0.1037 } + }); + var best0 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(0)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var best1 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(1)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var best2 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(2)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + + var scoreId = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/score.fbx", + position: bottomLeft, + rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), + dimensions: { x: 0.3678, y: 0.0063, z: 0.1037 } + }); + var score0 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(0)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var score1 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(1)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var score2 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(2)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + + this.moveScore = function(delta) { + score += delta; + if (score > highScore) { + highScore = score; + } + } + this.resetScore = function() { + score = 0; + } + + this.draw = function() { + Entities.editEntity(best0, { modelURL: numberUrl(Math.floor((highScore / 100) % 10)) }); + Entities.editEntity(best1, { modelURL: numberUrl(Math.floor((highScore / 10) % 10)) }); + Entities.editEntity(best2, { modelURL: numberUrl(Math.floor((highScore / 1) % 10)) }); + + Entities.editEntity(score0, { modelURL: numberUrl(Math.floor((score / 100) % 10)) }); + Entities.editEntity(score1, { modelURL: numberUrl(Math.floor((score / 10) % 10)) }); + Entities.editEntity(score2, { modelURL: numberUrl(Math.floor((score / 1) % 10)) }); + } + } + + function Game(bestScore) { // public methods this.start = function() { if (!isRunning) { @@ -372,6 +475,7 @@ var board = null; var bird = null; var pipes = null; + var score = null; var gameOverSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Game Over.wav"); var injector = null; @@ -394,9 +498,15 @@ var isBoardReset = true; - var score = 0; function moveScore(delta) { - score += delta; + score.moveScore(delta); + } + + this.score = function() { + return score.score(); + } + this.highScore = function() { + return score.highScore(); } function setup() { @@ -419,12 +529,13 @@ var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition, moveScore); + score = new Score(space, bestScore); Controller.keyPressEvent.connect(keyPress); } function inputs(triggerValue) { if (!startedPlaying && !isBoardReset && (gameTime - lastLost) > coolDown) { - score = 0; + score.resetScore(); bird.reset(); pipes.clear(); @@ -487,6 +598,7 @@ //print("draw"); bird.draw(); pipes.draw(); + score.draw(); } function cleanup() { print("cleanup"); @@ -564,6 +676,7 @@ } PartableGame = function() { + this.entityID = null; this.equipped = false; this.triggerValue = 0.0; this.hand = 0; @@ -580,12 +693,26 @@ this.equipped = true; this.hand = params[0] == "left" ? 0 : 1; - this.game = new Game(); + + var bestScore = 0; + var properties = Entities.getEntityProperties(this.entityID, ["userData"]); + var userData = JSON.parse(properties.userData); + if (userData.highScore) { + bestScore = userData.highScore; + } + + this.game = new Game(bestScore); this.game.start(); }, releaseEquip: function(id, params) { this.equipped = false; + var properties = Entities.getEntityProperties(this.entityID, ["userData"]); + var userData = JSON.parse(properties.userData); + userData.highScore = this.game.highScore(); + properties.userData = JSON.stringify(userData); + Entities.editEntity(this.entityID, properties); + this.game.stop(); delete this.game; }, From 10d55666f2af067a127729d566482ee7311993c2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Mar 2016 12:23:50 -0800 Subject: [PATCH 235/292] Changed coin value --- examples/flappyBird.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flappyBird.js b/examples/flappyBird.js index 9df1c9a89e..11c8a82d52 100644 --- a/examples/flappyBird.js +++ b/examples/flappyBird.js @@ -263,7 +263,7 @@ if (element.isColliding(bird)) { element.clear(); collected = index; - moveScore(10); + moveScore(1); if (coinsSound.downloaded && !injector) { injector = Audio.playSound(coinsSound, { position: to3DPosition({ x: newPipesPosition, y: newPipesHeight }), volume: 0.1 }); From 0364703f86817a5e8249893f55a4d01a500bf44e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Mar 2016 17:29:11 -0800 Subject: [PATCH 236/292] Move script to toybox --- examples/{flappyBird.js => toybox/flappyAvatars.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{flappyBird.js => toybox/flappyAvatars.js} (100%) diff --git a/examples/flappyBird.js b/examples/toybox/flappyAvatars.js similarity index 100% rename from examples/flappyBird.js rename to examples/toybox/flappyAvatars.js From 3750d5d780f87f6889ff27ab7235e84c54ea9b54 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Mar 2016 17:57:34 -0800 Subject: [PATCH 237/292] manually install OpenSSL DLLs for Qt --- cmake/macros/InstallBesideConsole.cmake | 5 +++ .../macros/ManuallyInstallOpenSSLForQt.cmake | 34 +++++++++++++++++++ cmake/modules/FindOpenSSL.cmake | 5 +++ interface/CMakeLists.txt | 4 +++ 4 files changed, 48 insertions(+) create mode 100644 cmake/macros/ManuallyInstallOpenSSLForQt.cmake diff --git a/cmake/macros/InstallBesideConsole.cmake b/cmake/macros/InstallBesideConsole.cmake index ab3fa5dee4..318a7a3ffe 100644 --- a/cmake/macros/InstallBesideConsole.cmake +++ b/cmake/macros/InstallBesideConsole.cmake @@ -64,5 +64,10 @@ macro(install_beside_console) ) endif() + # set variables used by manual ssleay library copy + set(TARGET_INSTALL_DIR ${COMPONENT_INSTALL_DIR}) + set(TARGET_INSTALL_COMPONENT ${SERVER_COMPONENT}) + manually_install_openssl_for_qt() + endif () endmacro() diff --git a/cmake/macros/ManuallyInstallOpenSSLForQt.cmake b/cmake/macros/ManuallyInstallOpenSSLForQt.cmake new file mode 100644 index 0000000000..ea91bbb83b --- /dev/null +++ b/cmake/macros/ManuallyInstallOpenSSLForQt.cmake @@ -0,0 +1,34 @@ +# +# ManuallyInstallOpenSSLforQt.cmake +# +# Created by Stephen Birarda on 1/15/16. +# 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 +# + +macro(manually_install_openssl_for_qt) + + # Qt dynamically links OpenSSL if it can find it on the user's machine + # We want to avoid it being found somewhere random and have it not being a compatible version + # So even though we don't need the dynamic version of OpenSSL for our direct-use purposes + # we use this macro to include the two SSL DLLs with the targets using QtNetwork + if (WIN32) + # we have to call find_package(OpenSSL) here even though this target may not directly need it + find_package(OpenSSL REQUIRED) + + install( + FILES "${OPENSSL_DLL_PATH}/ssleay32.dll" + DESTINATION ${TARGET_INSTALL_DIR} + COMPONENT ${TARGET_INSTALL_COMPONENT} + ) + + install( + FILES "${OPENSSL_DLL_PATH}/libeay32.dll" + DESTINATION ${TARGET_INSTALL_DIR} + COMPONENT ${TARGET_INSTALL_COMPONENT} + ) + endif() + +endmacro() diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 7317516da7..69b6c367ca 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -107,6 +107,8 @@ if (WIN32 AND NOT CYGWIN) select_library_configurations(SSL_EAY) set(OPENSSL_LIBRARIES ${SSL_EAY_LIBRARY} ${LIB_EAY_LIBRARY}) + + find_path(OPENSSL_DLL_PATH NAMES ssleay32.dll PATH_SUFFIXES "bin" ${_OPENSSL_ROOT_HINTS_AND_PATHS}) endif() else() @@ -198,6 +200,9 @@ endif () include(FindPackageHandleStandardArgs) set(OPENSSL_REQUIREMENTS OPENSSL_LIBRARIES OPENSSL_INCLUDE_DIR) +if (WIN32) + list(APPEND OPENSSL_REQUIREMENTS OPENSSL_DLL_PATH) +endif () if (OPENSSL_VERSION) find_package_handle_standard_args(OpenSSL diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 35fbec76c8..bc4a53c797 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -266,5 +266,9 @@ add_bugsplat() if (WIN32) set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") + set(TARGET_INSTALL_DIR ${INTERFACE_INSTALL_DIR}) + set(TARGET_INSTALL_COMPONENT ${CLIENT_COMPONENT}) + manually_install_openssl_for_qt() + package_libraries_for_deployment() endif() From f62a3ed8f6a94733c1f843473bbed0c5c88be111 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Mar 2016 10:46:30 -0800 Subject: [PATCH 238/292] Remove tabs --- examples/toybox/flappyAvatars.js | 1298 +++++++++++++++--------------- 1 file changed, 649 insertions(+), 649 deletions(-) diff --git a/examples/toybox/flappyAvatars.js b/examples/toybox/flappyAvatars.js index 11c8a82d52..4c54187916 100644 --- a/examples/toybox/flappyAvatars.js +++ b/examples/toybox/flappyAvatars.js @@ -9,671 +9,671 @@ // (function() { - // Constants + // Constants var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT, ]; - var G = 4.0; + var G = 4.0; - Number.prototype.clamp = function(min, max) { - return Math.min(Math.max(this, min), max); - }; - - var entityManager = new EntityManager(); + Number.prototype.clamp = function(min, max) { + return Math.min(Math.max(this, min), max); + }; + + var entityManager = new EntityManager(); - // Class definitions - function Bird(DEFAULT_X, DEFAULT_Y, rotation, to3DPosition) { - var DIMENSION = 0.15; - var JUMP_VELOCITY = 1.0; - var xPosition = DEFAULT_X; - var color = { red: 0, green: 0, blue: 255 }; - - var dimensionsSet = false; - var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; - var yPosition = DEFAULT_Y; - var yVelocity = 0.0; - var yAcceleration = -G; + // Class definitions + function Bird(DEFAULT_X, DEFAULT_Y, rotation, to3DPosition) { + var DIMENSION = 0.15; + var JUMP_VELOCITY = 1.0; + var xPosition = DEFAULT_X; + var color = { red: 0, green: 0, blue: 255 }; + + var dimensionsSet = false; + var dimensions = { x: DIMENSION, y: DIMENSION, z: DIMENSION }; + var yPosition = DEFAULT_Y; + var yVelocity = 0.0; + var yAcceleration = -G; - var airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Air Swipe 05.wav"); - var injector = null; + var airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Air Swipe 05.wav"); + var injector = null; - this.position = function() { - return { x: xPosition, y: yPosition }; - } - this.dimensions = function() { - return dimensions; - } + this.position = function() { + return { x: xPosition, y: yPosition }; + } + this.dimensions = function() { + return dimensions; + } - var id = entityManager.add({ - type: "Model", - modelURL: MyAvatar.skeletonModelURL, - animation: { - url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx", - running: true, - fps: 30, - firstFrame: 1.0, - lastFrame: 80.0, - currentFrame: 1.0, - loop: true, - hold: false - }, - position: to3DPosition(this.position()), - rotation: rotation, - dimensions: dimensions - }); + var id = entityManager.add({ + type: "Model", + modelURL: MyAvatar.skeletonModelURL, + animation: { + url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx", + running: true, + fps: 30, + firstFrame: 1.0, + lastFrame: 80.0, + currentFrame: 1.0, + loop: true, + hold: false + }, + position: to3DPosition(this.position()), + rotation: rotation, + dimensions: dimensions + }); - this.changeModel = function(modelURL) { - dimensionsSet = false; - dimensions = { x: 0.10, y: 0.10, z: 0.01 }; + this.changeModel = function(modelURL) { + dimensionsSet = false; + dimensions = { x: 0.10, y: 0.10, z: 0.01 }; - Entities.editEntity(id, { - modelURL: modelURL, - rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, -90, 0)), - dimensions: dimensions, - animation: {running: false} - }); + Entities.editEntity(id, { + modelURL: modelURL, + rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, -90, 0)), + dimensions: dimensions, + animation: {running: false} + }); - airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/8bit Jump 03.wav"); - injector = null; - } + airSwipeSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/8bit Jump 03.wav"); + injector = null; + } - this.jump = function() { - yVelocity = JUMP_VELOCITY; + this.jump = function() { + yVelocity = JUMP_VELOCITY; if (airSwipeSound.downloaded && !injector) { injector = Audio.playSound(airSwipeSound, { position: to3DPosition(this.position()), volume: 0.05 }); } else if (injector) { - injector.restart(); + injector.restart(); } - } - this.update = function(deltaTime) { - if (!dimensionsSet) { - var properties = Entities.getEntityProperties(id, ["naturalDimensions"]); - var naturalDimensions = properties.naturalDimensions; - if (naturalDimensions.x != 1 || naturalDimensions.y != 1 || naturalDimensions.z != 1) { - var max = Math.max(naturalDimensions.x, Math.max(naturalDimensions.y, naturalDimensions.z)); - dimensions.x = naturalDimensions.x / max * dimensions.x; - dimensions.y = naturalDimensions.y / max * dimensions.y; - dimensions.z = naturalDimensions.z / max * dimensions.z; - dimensionsSet = true; - - Entities.editEntity(id, { - dimensions: dimensions - }); - } - } else { - dimensions = Entities.getEntityProperties(id, ["dimensions"]).dimensions; - } - - yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); - yVelocity += deltaTime * yAcceleration; - } - this.draw = function() { - Entities.editEntity(id, { - position: to3DPosition(this.position()) - }); - } - this.reset = function() { - yPosition = DEFAULT_Y; - yVelocity = 0.0; - } - } - - function Coin(xPosition, yPosition, to3DPosition) { - var velocity = 0.4; - var dimensions = { x: 0.0625, y: 0.0625, z: 0.0088 }; - - this.position = function() { - return { x: xPosition, y: yPosition }; - } - - var id = entityManager.add({ - type: "Model", - modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/coin.fbx", - angularVelocity: { x: 0, y: 20, z: 0 }, - position: to3DPosition(this.position()), - dimensions:dimensions - }); - - this.update = function(deltaTime) { - xPosition -= deltaTime * velocity; - } - this.isColliding = function(bird) { - var deltaX = Math.abs(this.position().x - bird.position().x); - var deltaY = Math.abs(this.position().Y - bird.position().Y); - if (deltaX < (bird.dimensions().x + dimensions.x) / 2.0 && - deltaX < (bird.dimensions().y + dimensions.y) / 2.0) { - return true; - } - - return false; - } - this.draw = function() { - Entities.editEntity(id, { position: to3DPosition({ x: xPosition, y: yPosition }) }); - } - this.clear = function() { - entityManager.remove(id); - } - } - - function Pipe(xPosition, yPosition, height, gap, to3DPosition) { - var velocity = 0.4; - var width = 0.1; - - this.position = function() { - return xPosition; - } - - var upHeight = yPosition - (height + gap); - var upYPosition = height + gap + upHeight / 2.0; - - var idUp = entityManager.add({ - type: "Model", - modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", - rotation: Quat.fromPitchYawRollDegrees(180, 0, 0), - position: to3DPosition({ x: xPosition, y: upYPosition }), - dimensions: { x: width, y: upHeight, z: width } - }); - var idDown = entityManager.add({ - type: "Model", - modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", - position: to3DPosition({ x: xPosition, y: height / 2.0 }), - dimensions: { x: width, y: height, z: width } - }); - - this.update = function(deltaTime) { - xPosition -= deltaTime * velocity; - } - this.isColliding = function(bird) { - var deltaX = Math.abs(this.position() - bird.position().x); - if (deltaX < (bird.dimensions().z + width) / 2.0) { - var factor = 0.8; - var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y * factor); - var downDistance = (bird.position().y - bird.dimensions().y * factor) - height; - if (upDistance <= 0 || downDistance <= 0) { - return true; - } - } - - return false; - } - this.draw = function() { - Entities.editEntity(idUp, { position: to3DPosition({ x: xPosition, y: upYPosition }) }); - Entities.editEntity(idDown, { position: to3DPosition({ x: xPosition, y: height / 2.0 }) }); - } - this.clear = function() { - entityManager.remove(idUp); - entityManager.remove(idDown); - } - } - - function Pipes(newPipesPosition, newPipesHeight, to3DPosition, moveScore) { - var lastPipe = 0; - var pipesInterval = 2.0; - - var pipes = new Array(); - var coins = new Array(); - - var coinsSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Coin.wav"); - var injector = null; - - this.update = function(deltaTime, gameTime, startedPlaying) { - // Move pipes forward - pipes.forEach(function(element) { - element.update(deltaTime); - }); - // Move coins forward - coins.forEach(function(element) { - element.update(deltaTime); - }); - // Delete pipes over the end - var count = 0; - while(count < pipes.length && pipes[count].position() <= 0.0) { - pipes[count].clear(); - count++; - } - if (count > 0) { - pipes = pipes.splice(count); - } - // Delete coins over the end - count = 0; - while(count < coins.length && coins[count].position() <= 0.0) { - coins[count].clear(); - count++; - } - if (count > 0) { - coins = coins.splice(count); - } - // Make new pipes and coins - if (startedPlaying && gameTime - lastPipe > pipesInterval) { - var min = 0.4; - var max = 0.7; - var height = Math.random() * (max - min) + min; - pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.5, to3DPosition)); - coins.push(new Coin(newPipesPosition, height + 0.5 / 2.0, to3DPosition)); - lastPipe = gameTime; - } - } - this.isColliding = function(bird) { - // Check coin collection - var collected = -1; - coins.forEach(function(element, index) { - if (element.isColliding(bird)) { - element.clear(); - collected = index; - moveScore(1); - - if (coinsSound.downloaded && !injector) { - injector = Audio.playSound(coinsSound, { position: to3DPosition({ x: newPipesPosition, y: newPipesHeight }), volume: 0.1 }); - } else if (injector) { - injector.restart(); - } - } - }); - if (collected > -1) { - coins.splice(collected, 1); - } - - - // Check collisions - var isColliding = false; - - pipes.forEach(function(element) { - isColliding |= element.isColliding(bird); - }); - - return isColliding; - } - this.draw = function() { - // Drawing pipes - pipes.forEach(function(element) { - element.draw(); - }); - // Drawing coins - coins.forEach(function(element) { - element.draw(); - }); - } - this.clear = function() { - // Clearing pipes - pipes.forEach(function(element) { - element.clear(); - }); - pipes = new Array(); - - // Clearing coins - coins.forEach(function(element) { - element.clear(); - }); - coins = new Array(); - } - } - - - function Score(space, bestScore) { - var score = 0; - var highScore = bestScore; - - var topOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.2, z: -0.2 }); - var topLeft = Vec3.sum(space.position, topOffset); - var bottomOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.0, z: -0.2 }); - var bottomLeft = Vec3.sum(space.position, bottomOffset); - - function numberUrl(number) { - return "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/" + number + ".fbx" - } - function digitPosition(digit) { - return Vec3.multiplyQbyV(space.orientation, { x: 0.3778 + digit * 0.0760, y: 0.0, z: 0.0 }); - } - this.score = function() { - return score; - } - this.highScore = function() { - return highScore; - } - - var bestId = entityManager.add({ - type: "Model", - modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/best.fbx", - position: topLeft, - rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), - dimensions: { x: 0.2781, y: 0.0063, z: 0.1037 } - }); - var best0 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(topLeft, digitPosition(0)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var best1 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(topLeft, digitPosition(1)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var best2 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(topLeft, digitPosition(2)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - - var scoreId = entityManager.add({ - type: "Model", - modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/score.fbx", - position: bottomLeft, - rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), - dimensions: { x: 0.3678, y: 0.0063, z: 0.1037 } - }); - var score0 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(bottomLeft, digitPosition(0)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var score1 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(bottomLeft, digitPosition(1)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var score2 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(bottomLeft, digitPosition(2)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - - this.moveScore = function(delta) { - score += delta; - if (score > highScore) { - highScore = score; - } - } - this.resetScore = function() { - score = 0; - } - - this.draw = function() { - Entities.editEntity(best0, { modelURL: numberUrl(Math.floor((highScore / 100) % 10)) }); - Entities.editEntity(best1, { modelURL: numberUrl(Math.floor((highScore / 10) % 10)) }); - Entities.editEntity(best2, { modelURL: numberUrl(Math.floor((highScore / 1) % 10)) }); - - Entities.editEntity(score0, { modelURL: numberUrl(Math.floor((score / 100) % 10)) }); - Entities.editEntity(score1, { modelURL: numberUrl(Math.floor((score / 10) % 10)) }); - Entities.editEntity(score2, { modelURL: numberUrl(Math.floor((score / 1) % 10)) }); - } - } - - function Game(bestScore) { - // public methods - this.start = function() { - if (!isRunning) { - isRunning = true; - setup(); - } - } - - this.stop = function() { - if (isRunning) { - cleanup(); - isRunning = false; - } - } - - // Game loop setup - var timestamp = 0; - this.idle = function(triggerValue) { - var now = Date.now(); - var deltaTime = (now - timestamp) / 1000.0; - if (timestamp === 0) { - deltaTime = 0; - } - gameTime += deltaTime; - - inputs(triggerValue); - update(deltaTime); - draw(); - timestamp = now; - } - // this.keyPressed = function(event) { - // if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) { - // isJumping = true; - // startedPlaying = true; - // } - // } - - // Constants - var spaceDimensions = { x: 2.0, y: 1.5, z: 0.01 }; - var spaceDistance = 1.5; - var spaceYOffset = 0.6; - - // Private game state - var that = this; - var isRunning = false; - var startedPlaying = false; - - var coolDown = 1.5; - var lastLost = -coolDown; - - var gameTime = 0; - - var isJumping = false; - var lastJumpValue = 0.0; - var lastTriggerValue = 0.0; - var TRIGGER_THRESHOLD = 0.9; - - var space = null - var board = null; - var bird = null; - var pipes = null; - var score = null; - - var gameOverSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Game Over.wav"); - var injector = null; - - var directions = ["UP", "DOWN", "LEFT", "RIGHT"]; - var sequence = [directions[0], directions[0], directions[1], directions[1], directions[2], directions[3], directions[2], directions[3], "b", "a"]; - var current = 0; - function keyPress(event) { - if (event.text === sequence[current]) { - ++current; - } else { - current = 0; - } - if (current === sequence.length) { - print("KONAMI CODE!!!"); - bird.changeModel("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/mario.fbx"); - current = 0; - } - } - - var isBoardReset = true; - - function moveScore(delta) { - score.moveScore(delta); - } - - this.score = function() { - return score.score(); - } - this.highScore = function() { - return score.highScore(); - } - - function setup() { - print("setup"); - - space = { - position: getSpacePosition(), - orientation: getSpaceOrientation(), - dimensions: getSpaceDimensions() - } - - // board = entityManager.add({ - // type: "Box", - // position: space.position, - // rotation: space.orientation, - // dimensions: space.dimensions, - // color: { red: 100, green: 200, blue: 200 } - // }); - - var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); - bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); - pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition, moveScore); - score = new Score(space, bestScore); - - Controller.keyPressEvent.connect(keyPress); - } - function inputs(triggerValue) { - if (!startedPlaying && !isBoardReset && (gameTime - lastLost) > coolDown) { - score.resetScore(); - bird.reset(); - pipes.clear(); - - isBoardReset = true; - } - - if (triggerValue > TRIGGER_THRESHOLD && - lastTriggerValue < TRIGGER_THRESHOLD && - (gameTime - lastLost) > coolDown) { - isJumping = true; - startedPlaying = true; - } - lastTriggerValue = triggerValue; - } - function update(deltaTime) { - //print("update: " + deltaTime); - - // Keep entities alive - entityManager.update(deltaTime); - - if (!startedPlaying && (gameTime - lastLost) < coolDown && !isBoardReset) { - return; - } - - // Update Bird - if (!startedPlaying && bird.position().y < spaceDimensions.y / 2.0) { - isJumping = true; - } - // Apply jumps - if (isJumping) { - bird.jump(); - isJumping = false; - } - bird.update(deltaTime); - - pipes.update(deltaTime, gameTime, startedPlaying); - - // Check lost - var hasLost = bird.position().y < 0.0 || - bird.position().y > space.dimensions.y || - pipes.isColliding(bird); - - - // Cleanup - if (hasLost) { - print("Game Over!"); - - if (gameOverSound.downloaded && !injector) { - injector = Audio.playSound(gameOverSound, { position: space.position, volume: 0.4 }); - } else if (injector) { - injector.restart(); - } - - isBoardReset = false; - startedPlaying = false; - lastLost = gameTime; - } - } - function draw() { - //print("draw"); - bird.draw(); - pipes.draw(); - score.draw(); - } - function cleanup() { - print("cleanup"); - entityManager.removeAll(); - - Controller.keyPressEvent.disconnect(keyPress); - } - - // Private methods - function getSpacePosition() { - var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT); - var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward)); - return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP)); - } - function getSpaceOrientation() { - return MyAvatar.orientation; - } - function getSpaceDimensions() { - return spaceDimensions; - } - - function to3DPosition(position) { - var position2D = { - x: position.x - space.dimensions.x / 2.0, - y: position.y - space.dimensions.y / 2.0, - z: 0.0 - } - return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D)); - } - } - - function EntityManager() { - var OBJECTS_LIFETIME = 1; - var entities = new Array(); - var lifetime = OBJECTS_LIFETIME; - - this.setLifetime = function(newLifetime) { - lifetime = newLifetime; - this.update(); - } - this.add = function(properties) { - // Add to scene - properties.lifetime = lifetime; - var entityID = Entities.addEntity(properties); - // Add to array - entities.push({ id: entityID, properties: properties }); - - return entityID; - } - this.update = function(deltaTime) { - entities.forEach(function(element) { - // Get entity's age - var properties = Entities.getEntityProperties(element.id, ["age"]); - // Update entity's lifetime - Entities.editEntity(element.id, { lifetime: properties.age + lifetime }); - }); - } - this.remove = function(entityID) { - // Remove from scene - Entities.deleteEntity(entityID); - - // Remove from array - entities = entities.filter(function(element) { - return element.id !== entityID; - }); - } - this.removeAll = function() { - // Remove all from scene - entities.forEach(function(element) { - Entities.deleteEntity(element.id); - }); - // Remove all from array - entities = new Array(); - } - } + } + this.update = function(deltaTime) { + if (!dimensionsSet) { + var properties = Entities.getEntityProperties(id, ["naturalDimensions"]); + var naturalDimensions = properties.naturalDimensions; + if (naturalDimensions.x != 1 || naturalDimensions.y != 1 || naturalDimensions.z != 1) { + var max = Math.max(naturalDimensions.x, Math.max(naturalDimensions.y, naturalDimensions.z)); + dimensions.x = naturalDimensions.x / max * dimensions.x; + dimensions.y = naturalDimensions.y / max * dimensions.y; + dimensions.z = naturalDimensions.z / max * dimensions.z; + dimensionsSet = true; + + Entities.editEntity(id, { + dimensions: dimensions + }); + } + } else { + dimensions = Entities.getEntityProperties(id, ["dimensions"]).dimensions; + } + + yPosition += deltaTime * (yVelocity + deltaTime * yAcceleration / 2.0); + yVelocity += deltaTime * yAcceleration; + } + this.draw = function() { + Entities.editEntity(id, { + position: to3DPosition(this.position()) + }); + } + this.reset = function() { + yPosition = DEFAULT_Y; + yVelocity = 0.0; + } + } + + function Coin(xPosition, yPosition, to3DPosition) { + var velocity = 0.4; + var dimensions = { x: 0.0625, y: 0.0625, z: 0.0088 }; + + this.position = function() { + return { x: xPosition, y: yPosition }; + } + + var id = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/coin.fbx", + angularVelocity: { x: 0, y: 20, z: 0 }, + position: to3DPosition(this.position()), + dimensions:dimensions + }); + + this.update = function(deltaTime) { + xPosition -= deltaTime * velocity; + } + this.isColliding = function(bird) { + var deltaX = Math.abs(this.position().x - bird.position().x); + var deltaY = Math.abs(this.position().Y - bird.position().Y); + if (deltaX < (bird.dimensions().x + dimensions.x) / 2.0 && + deltaX < (bird.dimensions().y + dimensions.y) / 2.0) { + return true; + } + + return false; + } + this.draw = function() { + Entities.editEntity(id, { position: to3DPosition({ x: xPosition, y: yPosition }) }); + } + this.clear = function() { + entityManager.remove(id); + } + } + + function Pipe(xPosition, yPosition, height, gap, to3DPosition) { + var velocity = 0.4; + var width = 0.1; + + this.position = function() { + return xPosition; + } + + var upHeight = yPosition - (height + gap); + var upYPosition = height + gap + upHeight / 2.0; + + var idUp = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", + rotation: Quat.fromPitchYawRollDegrees(180, 0, 0), + position: to3DPosition({ x: xPosition, y: upYPosition }), + dimensions: { x: width, y: upHeight, z: width } + }); + var idDown = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/greenPipe.fbx", + position: to3DPosition({ x: xPosition, y: height / 2.0 }), + dimensions: { x: width, y: height, z: width } + }); + + this.update = function(deltaTime) { + xPosition -= deltaTime * velocity; + } + this.isColliding = function(bird) { + var deltaX = Math.abs(this.position() - bird.position().x); + if (deltaX < (bird.dimensions().z + width) / 2.0) { + var factor = 0.8; + var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y * factor); + var downDistance = (bird.position().y - bird.dimensions().y * factor) - height; + if (upDistance <= 0 || downDistance <= 0) { + return true; + } + } + + return false; + } + this.draw = function() { + Entities.editEntity(idUp, { position: to3DPosition({ x: xPosition, y: upYPosition }) }); + Entities.editEntity(idDown, { position: to3DPosition({ x: xPosition, y: height / 2.0 }) }); + } + this.clear = function() { + entityManager.remove(idUp); + entityManager.remove(idDown); + } + } + + function Pipes(newPipesPosition, newPipesHeight, to3DPosition, moveScore) { + var lastPipe = 0; + var pipesInterval = 2.0; + + var pipes = new Array(); + var coins = new Array(); + + var coinsSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Coin.wav"); + var injector = null; + + this.update = function(deltaTime, gameTime, startedPlaying) { + // Move pipes forward + pipes.forEach(function(element) { + element.update(deltaTime); + }); + // Move coins forward + coins.forEach(function(element) { + element.update(deltaTime); + }); + // Delete pipes over the end + var count = 0; + while(count < pipes.length && pipes[count].position() <= 0.0) { + pipes[count].clear(); + count++; + } + if (count > 0) { + pipes = pipes.splice(count); + } + // Delete coins over the end + count = 0; + while(count < coins.length && coins[count].position() <= 0.0) { + coins[count].clear(); + count++; + } + if (count > 0) { + coins = coins.splice(count); + } + // Make new pipes and coins + if (startedPlaying && gameTime - lastPipe > pipesInterval) { + var min = 0.4; + var max = 0.7; + var height = Math.random() * (max - min) + min; + pipes.push(new Pipe(newPipesPosition, newPipesHeight, height, 0.5, to3DPosition)); + coins.push(new Coin(newPipesPosition, height + 0.5 / 2.0, to3DPosition)); + lastPipe = gameTime; + } + } + this.isColliding = function(bird) { + // Check coin collection + var collected = -1; + coins.forEach(function(element, index) { + if (element.isColliding(bird)) { + element.clear(); + collected = index; + moveScore(1); + + if (coinsSound.downloaded && !injector) { + injector = Audio.playSound(coinsSound, { position: to3DPosition({ x: newPipesPosition, y: newPipesHeight }), volume: 0.1 }); + } else if (injector) { + injector.restart(); + } + } + }); + if (collected > -1) { + coins.splice(collected, 1); + } + + + // Check collisions + var isColliding = false; + + pipes.forEach(function(element) { + isColliding |= element.isColliding(bird); + }); + + return isColliding; + } + this.draw = function() { + // Drawing pipes + pipes.forEach(function(element) { + element.draw(); + }); + // Drawing coins + coins.forEach(function(element) { + element.draw(); + }); + } + this.clear = function() { + // Clearing pipes + pipes.forEach(function(element) { + element.clear(); + }); + pipes = new Array(); + + // Clearing coins + coins.forEach(function(element) { + element.clear(); + }); + coins = new Array(); + } + } + + + function Score(space, bestScore) { + var score = 0; + var highScore = bestScore; + + var topOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.2, z: -0.2 }); + var topLeft = Vec3.sum(space.position, topOffset); + var bottomOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.0, z: -0.2 }); + var bottomLeft = Vec3.sum(space.position, bottomOffset); + + function numberUrl(number) { + return "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/" + number + ".fbx" + } + function digitPosition(digit) { + return Vec3.multiplyQbyV(space.orientation, { x: 0.3778 + digit * 0.0760, y: 0.0, z: 0.0 }); + } + this.score = function() { + return score; + } + this.highScore = function() { + return highScore; + } + + var bestId = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/best.fbx", + position: topLeft, + rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), + dimensions: { x: 0.2781, y: 0.0063, z: 0.1037 } + }); + var best0 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(0)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var best1 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(1)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var best2 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(2)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + + var scoreId = entityManager.add({ + type: "Model", + modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/score.fbx", + position: bottomLeft, + rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), + dimensions: { x: 0.3678, y: 0.0063, z: 0.1037 } + }); + var score0 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(0)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var score1 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(1)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + var score2 = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(2)), + rotation: space.orientation, + dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } + }); + + this.moveScore = function(delta) { + score += delta; + if (score > highScore) { + highScore = score; + } + } + this.resetScore = function() { + score = 0; + } + + this.draw = function() { + Entities.editEntity(best0, { modelURL: numberUrl(Math.floor((highScore / 100) % 10)) }); + Entities.editEntity(best1, { modelURL: numberUrl(Math.floor((highScore / 10) % 10)) }); + Entities.editEntity(best2, { modelURL: numberUrl(Math.floor((highScore / 1) % 10)) }); + + Entities.editEntity(score0, { modelURL: numberUrl(Math.floor((score / 100) % 10)) }); + Entities.editEntity(score1, { modelURL: numberUrl(Math.floor((score / 10) % 10)) }); + Entities.editEntity(score2, { modelURL: numberUrl(Math.floor((score / 1) % 10)) }); + } + } + + function Game(bestScore) { + // public methods + this.start = function() { + if (!isRunning) { + isRunning = true; + setup(); + } + } + + this.stop = function() { + if (isRunning) { + cleanup(); + isRunning = false; + } + } + + // Game loop setup + var timestamp = 0; + this.idle = function(triggerValue) { + var now = Date.now(); + var deltaTime = (now - timestamp) / 1000.0; + if (timestamp === 0) { + deltaTime = 0; + } + gameTime += deltaTime; + + inputs(triggerValue); + update(deltaTime); + draw(); + timestamp = now; + } + // this.keyPressed = function(event) { + // if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) { + // isJumping = true; + // startedPlaying = true; + // } + // } + + // Constants + var spaceDimensions = { x: 2.0, y: 1.5, z: 0.01 }; + var spaceDistance = 1.5; + var spaceYOffset = 0.6; + + // Private game state + var that = this; + var isRunning = false; + var startedPlaying = false; + + var coolDown = 1.5; + var lastLost = -coolDown; + + var gameTime = 0; + + var isJumping = false; + var lastJumpValue = 0.0; + var lastTriggerValue = 0.0; + var TRIGGER_THRESHOLD = 0.9; + + var space = null + var board = null; + var bird = null; + var pipes = null; + var score = null; + + var gameOverSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/Game Over.wav"); + var injector = null; + + var directions = ["UP", "DOWN", "LEFT", "RIGHT"]; + var sequence = [directions[0], directions[0], directions[1], directions[1], directions[2], directions[3], directions[2], directions[3], "b", "a"]; + var current = 0; + function keyPress(event) { + if (event.text === sequence[current]) { + ++current; + } else { + current = 0; + } + if (current === sequence.length) { + print("KONAMI CODE!!!"); + bird.changeModel("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/mario.fbx"); + current = 0; + } + } + + var isBoardReset = true; + + function moveScore(delta) { + score.moveScore(delta); + } + + this.score = function() { + return score.score(); + } + this.highScore = function() { + return score.highScore(); + } + + function setup() { + print("setup"); + + space = { + position: getSpacePosition(), + orientation: getSpaceOrientation(), + dimensions: getSpaceDimensions() + } + + // board = entityManager.add({ + // type: "Box", + // position: space.position, + // rotation: space.orientation, + // dimensions: space.dimensions, + // color: { red: 100, green: 200, blue: 200 } + // }); + + var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); + bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); + pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition, moveScore); + score = new Score(space, bestScore); + + Controller.keyPressEvent.connect(keyPress); + } + function inputs(triggerValue) { + if (!startedPlaying && !isBoardReset && (gameTime - lastLost) > coolDown) { + score.resetScore(); + bird.reset(); + pipes.clear(); + + isBoardReset = true; + } + + if (triggerValue > TRIGGER_THRESHOLD && + lastTriggerValue < TRIGGER_THRESHOLD && + (gameTime - lastLost) > coolDown) { + isJumping = true; + startedPlaying = true; + } + lastTriggerValue = triggerValue; + } + function update(deltaTime) { + //print("update: " + deltaTime); + + // Keep entities alive + entityManager.update(deltaTime); + + if (!startedPlaying && (gameTime - lastLost) < coolDown && !isBoardReset) { + return; + } + + // Update Bird + if (!startedPlaying && bird.position().y < spaceDimensions.y / 2.0) { + isJumping = true; + } + // Apply jumps + if (isJumping) { + bird.jump(); + isJumping = false; + } + bird.update(deltaTime); + + pipes.update(deltaTime, gameTime, startedPlaying); + + // Check lost + var hasLost = bird.position().y < 0.0 || + bird.position().y > space.dimensions.y || + pipes.isColliding(bird); + + + // Cleanup + if (hasLost) { + print("Game Over!"); + + if (gameOverSound.downloaded && !injector) { + injector = Audio.playSound(gameOverSound, { position: space.position, volume: 0.4 }); + } else if (injector) { + injector.restart(); + } + + isBoardReset = false; + startedPlaying = false; + lastLost = gameTime; + } + } + function draw() { + //print("draw"); + bird.draw(); + pipes.draw(); + score.draw(); + } + function cleanup() { + print("cleanup"); + entityManager.removeAll(); + + Controller.keyPressEvent.disconnect(keyPress); + } + + // Private methods + function getSpacePosition() { + var forward = Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.FRONT); + var spacePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(spaceDistance, forward)); + return Vec3.sum(spacePosition, Vec3.multiply(spaceYOffset, Vec3.UP)); + } + function getSpaceOrientation() { + return MyAvatar.orientation; + } + function getSpaceDimensions() { + return spaceDimensions; + } + + function to3DPosition(position) { + var position2D = { + x: position.x - space.dimensions.x / 2.0, + y: position.y - space.dimensions.y / 2.0, + z: 0.0 + } + return Vec3.sum(space.position, Vec3.multiplyQbyV(space.orientation, position2D)); + } + } + + function EntityManager() { + var OBJECTS_LIFETIME = 1; + var entities = new Array(); + var lifetime = OBJECTS_LIFETIME; + + this.setLifetime = function(newLifetime) { + lifetime = newLifetime; + this.update(); + } + this.add = function(properties) { + // Add to scene + properties.lifetime = lifetime; + var entityID = Entities.addEntity(properties); + // Add to array + entities.push({ id: entityID, properties: properties }); + + return entityID; + } + this.update = function(deltaTime) { + entities.forEach(function(element) { + // Get entity's age + var properties = Entities.getEntityProperties(element.id, ["age"]); + // Update entity's lifetime + Entities.editEntity(element.id, { lifetime: properties.age + lifetime }); + }); + } + this.remove = function(entityID) { + // Remove from scene + Entities.deleteEntity(entityID); + + // Remove from array + entities = entities.filter(function(element) { + return element.id !== entityID; + }); + } + this.removeAll = function() { + // Remove all from scene + entities.forEach(function(element) { + Entities.deleteEntity(element.id); + }); + // Remove all from array + entities = new Array(); + } + } PartableGame = function() { this.entityID = null; @@ -694,11 +694,11 @@ this.hand = params[0] == "left" ? 0 : 1; - var bestScore = 0; + var bestScore = 0; var properties = Entities.getEntityProperties(this.entityID, ["userData"]); var userData = JSON.parse(properties.userData); if (userData.highScore) { - bestScore = userData.highScore; + bestScore = userData.highScore; } this.game = new Game(bestScore); @@ -721,7 +721,7 @@ return; } this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]); - this.game.idle(this.triggerValue); + this.game.idle(this.triggerValue); }, }; From c06d76f7f06fe05213f138fd3532d7bdba89101f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Mar 2016 10:56:29 -0800 Subject: [PATCH 239/292] remove twist constraints on hands also tighten swing limit on shoulder --- .../animation/src/AnimInverseKinematics.cpp | 8 +- .../animation/src/SwingTwistConstraint.cpp | 79 ++++++++++--------- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 48ad9b852d..6a29ad61ac 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -627,6 +627,9 @@ void AnimInverseKinematics::initConstraints() { } else if (0 == baseName.compare("Hand", Qt::CaseSensitive)) { SwingTwistConstraint* stConstraint = new SwingTwistConstraint(); stConstraint->setReferenceRotation(_defaultRelativePoses[i].rot); + stConstraint->setTwistLimits(0.0f, 0.0f); // max == min, disables twist limits + + /* KEEP THIS CODE for future experimentation -- twist limits for hands const float MAX_HAND_TWIST = 3.0f * PI / 5.0f; const float MIN_HAND_TWIST = -PI / 2.0f; if (isLeft) { @@ -634,8 +637,9 @@ void AnimInverseKinematics::initConstraints() { } else { stConstraint->setTwistLimits(MIN_HAND_TWIST, MAX_HAND_TWIST); } + */ - /* KEEP THIS CODE for future experimentation + /* KEEP THIS CODE for future experimentation -- non-symmetrical swing limits for wrist * a more complicated wrist with asymmetric cone // these directions are approximate swing limits in parent-frame // NOTE: they don't need to be normalized @@ -670,7 +674,7 @@ void AnimInverseKinematics::initConstraints() { stConstraint->setTwistLimits(-MAX_SHOULDER_TWIST, MAX_SHOULDER_TWIST); std::vector minDots; - const float MAX_SHOULDER_SWING = PI / 6.0f; + const float MAX_SHOULDER_SWING = PI / 20.0f; minDots.push_back(cosf(MAX_SHOULDER_SWING)); stConstraint->setSwingLimits(minDots); diff --git a/libraries/animation/src/SwingTwistConstraint.cpp b/libraries/animation/src/SwingTwistConstraint.cpp index 7386fb2bcd..3bf661612e 100644 --- a/libraries/animation/src/SwingTwistConstraint.cpp +++ b/libraries/animation/src/SwingTwistConstraint.cpp @@ -182,49 +182,52 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { glm::vec3 twistedX = twistRotation * xAxis; twistAngle *= copysignf(1.0f, glm::dot(glm::cross(xAxis, twistedX), yAxis)); - // adjust measured twistAngle according to clamping history - switch (_lastTwistBoundary) { - case LAST_CLAMP_LOW_BOUNDARY: - // clamp to min - if (twistAngle > _maxTwist) { - twistAngle -= TWO_PI; - } - break; - case LAST_CLAMP_HIGH_BOUNDARY: - // clamp to max - if (twistAngle < _minTwist) { - twistAngle += TWO_PI; - } - break; - default: // LAST_CLAMP_NO_BOUNDARY - // clamp to nearest boundary - float midBoundary = 0.5f * (_maxTwist + _minTwist + TWO_PI); - if (twistAngle > midBoundary) { - // lower boundary is closer --> phase down one cycle - twistAngle -= TWO_PI; - } else if (twistAngle < midBoundary - TWO_PI) { - // higher boundary is closer --> phase up one cycle - twistAngle += TWO_PI; - } - break; - } + bool somethingClamped = false; + if (_minTwist != _maxTwist) { + // adjust measured twistAngle according to clamping history + switch (_lastTwistBoundary) { + case LAST_CLAMP_LOW_BOUNDARY: + // clamp to min + if (twistAngle > _maxTwist) { + twistAngle -= TWO_PI; + } + break; + case LAST_CLAMP_HIGH_BOUNDARY: + // clamp to max + if (twistAngle < _minTwist) { + twistAngle += TWO_PI; + } + break; + default: // LAST_CLAMP_NO_BOUNDARY + // clamp to nearest boundary + float midBoundary = 0.5f * (_maxTwist + _minTwist + TWO_PI); + if (twistAngle > midBoundary) { + // lower boundary is closer --> phase down one cycle + twistAngle -= TWO_PI; + } else if (twistAngle < midBoundary - TWO_PI) { + // higher boundary is closer --> phase up one cycle + twistAngle += TWO_PI; + } + break; + } - // clamp twistAngle - float clampedTwistAngle = glm::clamp(twistAngle, _minTwist, _maxTwist); - bool twistWasClamped = (twistAngle != clampedTwistAngle); + // clamp twistAngle + float clampedTwistAngle = glm::clamp(twistAngle, _minTwist, _maxTwist); + somethingClamped = (twistAngle != clampedTwistAngle); - // remember twist's clamp boundary history - if (twistWasClamped) { - _lastTwistBoundary = (twistAngle > clampedTwistAngle) ? LAST_CLAMP_HIGH_BOUNDARY : LAST_CLAMP_LOW_BOUNDARY; - } else { - _lastTwistBoundary = LAST_CLAMP_NO_BOUNDARY; + // remember twist's clamp boundary history + if (somethingClamped) { + _lastTwistBoundary = (twistAngle > clampedTwistAngle) ? LAST_CLAMP_HIGH_BOUNDARY : LAST_CLAMP_LOW_BOUNDARY; + twistAngle = clampedTwistAngle; + } else { + _lastTwistBoundary = LAST_CLAMP_NO_BOUNDARY; + } } // clamp the swing // The swingAxis is always perpendicular to the reference axis (yAxis in the constraint's frame). glm::vec3 swungY = swingRotation * yAxis; glm::vec3 swingAxis = glm::cross(yAxis, swungY); - bool swingWasClamped = false; float axisLength = glm::length(swingAxis); if (axisLength > EPSILON) { // The limit of swing is a function of "theta" which can be computed from the swingAxis @@ -236,13 +239,13 @@ bool SwingTwistConstraint::apply(glm::quat& rotation) const { // use it to supply a new rotation. swingAxis /= axisLength; swingRotation = glm::angleAxis(acosf(minDot), swingAxis); - swingWasClamped = true; + somethingClamped = true; } } - if (swingWasClamped || twistWasClamped) { + if (somethingClamped) { // update the rotation - twistRotation = glm::angleAxis(clampedTwistAngle, yAxis); + twistRotation = glm::angleAxis(twistAngle, yAxis); rotation = swingRotation * twistRotation * _referenceRotation; return true; } From 9bf4a30a232b9008c741effe53263789101bd3f5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Mar 2016 10:57:06 -0800 Subject: [PATCH 240/292] fix typo in example script --- examples/tests/particleOrientationTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tests/particleOrientationTest.js b/examples/tests/particleOrientationTest.js index 7fe670f4b7..97915c79e3 100644 --- a/examples/tests/particleOrientationTest.js +++ b/examples/tests/particleOrientationTest.js @@ -46,7 +46,7 @@ function emitter(jointName) { x:0, y: 0, z: 0, - w: Math.PI + w: 1 }, emitRadiusStart: 0, polarStart: 0, @@ -84,7 +84,7 @@ function emitter(jointName) { alpha: 1, alphaSpread: 0, alphaStart: 1, - alphaFinish: 1 + alphaFinish: 1 }); return newEmitter; } From dc456cbdbebbabf7c1518cc8e79db0aed3d720e7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 4 Mar 2016 11:15:11 -0800 Subject: [PATCH 241/292] MyAvatar: dropped vertical recenter limit. --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ed5d2b0430..92a449f1dc 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1956,7 +1956,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float CYLINDER_TOP = 0.1f; - const float CYLINDER_BOTTOM = -1.0f; + const float CYLINDER_BOTTOM = -1.5f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); From e01524abbe4c6657341ee78c1037edce20c28196 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Fri, 4 Mar 2016 11:24:35 -0800 Subject: [PATCH 242/292] fix for clicking --- examples/controllers/handControllerMouse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerMouse.js b/examples/controllers/handControllerMouse.js index d353afab5e..8807fb9794 100644 --- a/examples/controllers/handControllerMouse.js +++ b/examples/controllers/handControllerMouse.js @@ -35,7 +35,7 @@ function moveReticleAbsolute(x, y) { var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); -if (Controller.Hardware.hydra !== undefined) { +if (Controller.Hardware.Hydra !== undefined) { mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); } From 2f89253dc16134e7dc1f77d477bf24441f3f740b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 24 Feb 2016 18:38:11 -0800 Subject: [PATCH 243/292] Make Overlays usable from QML --- interface/src/ui/overlays/Base3DOverlay.cpp | 91 ++++------ interface/src/ui/overlays/Base3DOverlay.h | 4 +- .../src/ui/overlays/Billboard3DOverlay.cpp | 10 +- .../src/ui/overlays/Billboard3DOverlay.h | 4 +- interface/src/ui/overlays/Billboardable.cpp | 10 +- interface/src/ui/overlays/Billboardable.h | 8 +- interface/src/ui/overlays/Circle3DOverlay.cpp | 71 ++++---- interface/src/ui/overlays/Circle3DOverlay.h | 4 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 10 +- interface/src/ui/overlays/Cube3DOverlay.h | 4 +- interface/src/ui/overlays/Grid3DOverlay.cpp | 19 +-- interface/src/ui/overlays/Grid3DOverlay.h | 4 +- interface/src/ui/overlays/Image3DOverlay.cpp | 39 +++-- interface/src/ui/overlays/Image3DOverlay.h | 4 +- interface/src/ui/overlays/Line3DOverlay.cpp | 39 ++--- interface/src/ui/overlays/Line3DOverlay.h | 4 +- interface/src/ui/overlays/ModelOverlay.cpp | 22 +-- interface/src/ui/overlays/ModelOverlay.h | 6 +- interface/src/ui/overlays/Overlay.cpp | 62 ++++--- interface/src/ui/overlays/Overlay.h | 10 +- interface/src/ui/overlays/Overlay2D.cpp | 35 ++-- interface/src/ui/overlays/Overlay2D.h | 4 +- interface/src/ui/overlays/OverlayPanel.cpp | 90 ++++------ interface/src/ui/overlays/OverlayPanel.h | 9 +- interface/src/ui/overlays/Overlays.cpp | 74 ++++---- interface/src/ui/overlays/Overlays.h | 10 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 - interface/src/ui/overlays/PanelAttachable.cpp | 59 +++---- interface/src/ui/overlays/PanelAttachable.h | 4 +- interface/src/ui/overlays/Planar3DOverlay.cpp | 44 +---- interface/src/ui/overlays/Planar3DOverlay.h | 4 +- interface/src/ui/overlays/QmlOverlay.cpp | 4 +- interface/src/ui/overlays/QmlOverlay.h | 2 +- .../src/ui/overlays/Rectangle3DOverlay.cpp | 2 +- .../src/ui/overlays/Rectangle3DOverlay.h | 2 +- interface/src/ui/overlays/Text3DOverlay.cpp | 51 +++--- interface/src/ui/overlays/Text3DOverlay.h | 4 +- interface/src/ui/overlays/Volume3DOverlay.cpp | 54 +----- interface/src/ui/overlays/Volume3DOverlay.h | 4 +- interface/src/ui/overlays/Web3DOverlay.cpp | 21 ++- interface/src/ui/overlays/Web3DOverlay.h | 4 +- libraries/shared/src/RegisteredMetaTypes.cpp | 159 +++++++++++++++++- libraries/shared/src/RegisteredMetaTypes.h | 23 +++ 43 files changed, 540 insertions(+), 550 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index e648a22650..0cba089256 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -11,8 +11,6 @@ #include "Base3DOverlay.h" -#include - #include #include @@ -41,103 +39,78 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) : { } -void Base3DOverlay::setProperties(const QScriptValue& properties) { +void Base3DOverlay::setProperties(const QVariantMap& properties) { Overlay::setProperties(properties); - QScriptValue drawInFront = properties.property("drawInFront"); + auto drawInFront = properties["drawInFront"]; if (drawInFront.isValid()) { - bool value = drawInFront.toVariant().toBool(); + bool value = drawInFront.toBool(); setDrawInFront(value); } - QScriptValue position = properties.property("position"); + auto position = properties["position"]; // if "position" property was not there, check to see if they included aliases: point, p1 if (!position.isValid()) { - position = properties.property("p1"); + position = properties["p1"]; if (!position.isValid()) { - position = properties.property("point"); + position = properties["point"]; } } - if (position.isValid()) { - QScriptValue x = position.property("x"); - QScriptValue y = position.property("y"); - QScriptValue z = position.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newPosition; - newPosition.x = x.toVariant().toFloat(); - newPosition.y = y.toVariant().toFloat(); - newPosition.z = z.toVariant().toFloat(); - setPosition(newPosition); - } + setPosition(vec3FromVariant(position)); } - if (properties.property("lineWidth").isValid()) { - setLineWidth(properties.property("lineWidth").toVariant().toFloat()); + if (properties["lineWidth"].isValid()) { + setLineWidth(properties["lineWidth"].toFloat()); } - QScriptValue rotation = properties.property("rotation"); + auto rotation = properties["rotation"]; if (rotation.isValid()) { - glm::quat newRotation; - - // size, scale, dimensions is special, it might just be a single scalar, or it might be a vector, check that here - QScriptValue x = rotation.property("x"); - QScriptValue y = rotation.property("y"); - QScriptValue z = rotation.property("z"); - QScriptValue w = rotation.property("w"); - - - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { - newRotation.x = x.toVariant().toFloat(); - newRotation.y = y.toVariant().toFloat(); - newRotation.z = z.toVariant().toFloat(); - newRotation.w = w.toVariant().toFloat(); - setRotation(newRotation); - } + setRotation(quatFromVariant(rotation)); } - if (properties.property("isSolid").isValid()) { - setIsSolid(properties.property("isSolid").toVariant().toBool()); + if (properties["isSolid"].isValid()) { + setIsSolid(properties["isSolid"].toBool()); } - if (properties.property("isFilled").isValid()) { - setIsSolid(properties.property("isSolid").toVariant().toBool()); + if (properties["isFilled"].isValid()) { + setIsSolid(properties["isSolid"].toBool()); } - if (properties.property("isWire").isValid()) { - setIsSolid(!properties.property("isWire").toVariant().toBool()); + if (properties["isWire"].isValid()) { + setIsSolid(!properties["isWire"].toBool()); } - if (properties.property("solid").isValid()) { - setIsSolid(properties.property("solid").toVariant().toBool()); + if (properties["solid"].isValid()) { + setIsSolid(properties["solid"].toBool()); } - if (properties.property("filled").isValid()) { - setIsSolid(properties.property("filled").toVariant().toBool()); + if (properties["filled"].isValid()) { + setIsSolid(properties["filled"].toBool()); } - if (properties.property("wire").isValid()) { - setIsSolid(!properties.property("wire").toVariant().toBool()); + if (properties["wire"].isValid()) { + setIsSolid(!properties["wire"].toBool()); } - if (properties.property("isDashedLine").isValid()) { - setIsDashedLine(properties.property("isDashedLine").toVariant().toBool()); + if (properties["isDashedLine"].isValid()) { + setIsDashedLine(properties["isDashedLine"].toBool()); } - if (properties.property("dashed").isValid()) { - setIsDashedLine(properties.property("dashed").toVariant().toBool()); + if (properties["dashed"].isValid()) { + setIsDashedLine(properties["dashed"].toBool()); } - if (properties.property("ignoreRayIntersection").isValid()) { - setIgnoreRayIntersection(properties.property("ignoreRayIntersection").toVariant().toBool()); + if (properties["ignoreRayIntersection"].isValid()) { + setIgnoreRayIntersection(properties["ignoreRayIntersection"].toBool()); } } -QScriptValue Base3DOverlay::getProperty(const QString& property) { +QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "position" || property == "start" || property == "p1" || property == "point") { - return vec3toScriptValue(_scriptEngine, getPosition()); + return vec3toVariant(getPosition()); } if (property == "lineWidth") { return _lineWidth; } if (property == "rotation") { - return quatToScriptValue(_scriptEngine, getRotation()); + return quatToVariant(getRotation()); } if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") { return _isSolid; diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 791d08109f..c001d39f69 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -52,8 +52,8 @@ public: virtual AABox getBounds() const = 0; - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal); diff --git a/interface/src/ui/overlays/Billboard3DOverlay.cpp b/interface/src/ui/overlays/Billboard3DOverlay.cpp index 908676e0eb..182e7da978 100644 --- a/interface/src/ui/overlays/Billboard3DOverlay.cpp +++ b/interface/src/ui/overlays/Billboard3DOverlay.cpp @@ -18,19 +18,19 @@ Billboard3DOverlay::Billboard3DOverlay(const Billboard3DOverlay* billboard3DOver { } -void Billboard3DOverlay::setProperties(const QScriptValue &properties) { +void Billboard3DOverlay::setProperties(const QVariantMap& properties) { Planar3DOverlay::setProperties(properties); PanelAttachable::setProperties(properties); Billboardable::setProperties(properties); } -QScriptValue Billboard3DOverlay::getProperty(const QString &property) { - QScriptValue value; - value = Billboardable::getProperty(_scriptEngine, property); +QVariant Billboard3DOverlay::getProperty(const QString &property) { + QVariant value; + value = Billboardable::getProperty(property); if (value.isValid()) { return value; } - value = PanelAttachable::getProperty(_scriptEngine, property); + value = PanelAttachable::getProperty(property); if (value.isValid()) { return value; } diff --git a/interface/src/ui/overlays/Billboard3DOverlay.h b/interface/src/ui/overlays/Billboard3DOverlay.h index 2f5af1068f..1d4d60bf5b 100644 --- a/interface/src/ui/overlays/Billboard3DOverlay.h +++ b/interface/src/ui/overlays/Billboard3DOverlay.h @@ -23,8 +23,8 @@ public: Billboard3DOverlay() {} Billboard3DOverlay(const Billboard3DOverlay* billboard3DOverlay); - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; protected: virtual void applyTransformTo(Transform& transform, bool force = false); diff --git a/interface/src/ui/overlays/Billboardable.cpp b/interface/src/ui/overlays/Billboardable.cpp index 997cf27609..a6226a46b0 100644 --- a/interface/src/ui/overlays/Billboardable.cpp +++ b/interface/src/ui/overlays/Billboardable.cpp @@ -14,18 +14,18 @@ #include #include -void Billboardable::setProperties(const QScriptValue &properties) { - QScriptValue isFacingAvatar = properties.property("isFacingAvatar"); +void Billboardable::setProperties(const QVariantMap& properties) { + auto isFacingAvatar = properties["isFacingAvatar"]; if (isFacingAvatar.isValid()) { - setIsFacingAvatar(isFacingAvatar.toVariant().toBool()); + setIsFacingAvatar(isFacingAvatar.toBool()); } } -QScriptValue Billboardable::getProperty(QScriptEngine* scriptEngine, const QString &property) { +QVariant Billboardable::getProperty(const QString &property) { if (property == "isFacingAvatar") { return isFacingAvatar(); } - return QScriptValue(); + return QVariant(); } void Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offsetRotation) { diff --git a/interface/src/ui/overlays/Billboardable.h b/interface/src/ui/overlays/Billboardable.h index 82387ad703..e2d29a2769 100644 --- a/interface/src/ui/overlays/Billboardable.h +++ b/interface/src/ui/overlays/Billboardable.h @@ -12,11 +12,9 @@ #ifndef hifi_Billboardable_h #define hifi_Billboardable_h -#include - #include +#include -class QScriptEngine; class QString; class Transform; @@ -26,8 +24,8 @@ public: void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; } protected: - void setProperties(const QScriptValue& properties); - QScriptValue getProperty(QScriptEngine* scriptEngine, const QString& property); + void setProperties(const QVariantMap& properties); + QVariant getProperty(const QString& property); void pointTransformAtCamera(Transform& transform, glm::quat offsetRotation = {1, 0, 0, 0}); diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index a3ecbe7137..8fb3a36919 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -286,83 +286,76 @@ const render::ShapeKey Circle3DOverlay::getShapeKey() { return builder.build(); } -void Circle3DOverlay::setProperties(const QScriptValue &properties) { +void Circle3DOverlay::setProperties(const QVariantMap& properties) { Planar3DOverlay::setProperties(properties); - QScriptValue startAt = properties.property("startAt"); + QVariant startAt = properties["startAt"]; if (startAt.isValid()) { - setStartAt(startAt.toVariant().toFloat()); + setStartAt(startAt.toFloat()); } - QScriptValue endAt = properties.property("endAt"); + QVariant endAt = properties["endAt"]; if (endAt.isValid()) { - setEndAt(endAt.toVariant().toFloat()); + setEndAt(endAt.toFloat()); } - QScriptValue outerRadius = properties.property("radius"); + QVariant outerRadius = properties["radius"]; if (!outerRadius.isValid()) { - outerRadius = properties.property("outerRadius"); + outerRadius = properties["outerRadius"]; } if (outerRadius.isValid()) { - setOuterRadius(outerRadius.toVariant().toFloat()); + setOuterRadius(outerRadius.toFloat()); } - QScriptValue innerRadius = properties.property("innerRadius"); + QVariant innerRadius = properties["innerRadius"]; if (innerRadius.isValid()) { - setInnerRadius(innerRadius.toVariant().toFloat()); + setInnerRadius(innerRadius.toFloat()); } - QScriptValue hasTickMarks = properties.property("hasTickMarks"); + QVariant hasTickMarks = properties["hasTickMarks"]; if (hasTickMarks.isValid()) { - setHasTickMarks(hasTickMarks.toVariant().toBool()); + setHasTickMarks(hasTickMarks.toBool()); } - QScriptValue majorTickMarksAngle = properties.property("majorTickMarksAngle"); + QVariant majorTickMarksAngle = properties["majorTickMarksAngle"]; if (majorTickMarksAngle.isValid()) { - setMajorTickMarksAngle(majorTickMarksAngle.toVariant().toFloat()); + setMajorTickMarksAngle(majorTickMarksAngle.toFloat()); } - QScriptValue minorTickMarksAngle = properties.property("minorTickMarksAngle"); + QVariant minorTickMarksAngle = properties["minorTickMarksAngle"]; if (minorTickMarksAngle.isValid()) { - setMinorTickMarksAngle(minorTickMarksAngle.toVariant().toFloat()); + setMinorTickMarksAngle(minorTickMarksAngle.toFloat()); } - QScriptValue majorTickMarksLength = properties.property("majorTickMarksLength"); + QVariant majorTickMarksLength = properties["majorTickMarksLength"]; if (majorTickMarksLength.isValid()) { - setMajorTickMarksLength(majorTickMarksLength.toVariant().toFloat()); + setMajorTickMarksLength(majorTickMarksLength.toFloat()); } - QScriptValue minorTickMarksLength = properties.property("minorTickMarksLength"); + QVariant minorTickMarksLength = properties["minorTickMarksLength"]; if (minorTickMarksLength.isValid()) { - setMinorTickMarksLength(minorTickMarksLength.toVariant().toFloat()); + setMinorTickMarksLength(minorTickMarksLength.toFloat()); } - QScriptValue majorTickMarksColor = properties.property("majorTickMarksColor"); + bool valid; + auto majorTickMarksColor = properties["majorTickMarksColor"]; if (majorTickMarksColor.isValid()) { - QScriptValue red = majorTickMarksColor.property("red"); - QScriptValue green = majorTickMarksColor.property("green"); - QScriptValue blue = majorTickMarksColor.property("blue"); - if (red.isValid() && green.isValid() && blue.isValid()) { - _majorTickMarksColor.red = red.toVariant().toInt(); - _majorTickMarksColor.green = green.toVariant().toInt(); - _majorTickMarksColor.blue = blue.toVariant().toInt(); + auto color = xColorFromVariant(majorTickMarksColor, valid); + if (valid) { + _majorTickMarksColor = color; } } - QScriptValue minorTickMarksColor = properties.property("minorTickMarksColor"); + auto minorTickMarksColor = properties["minorTickMarksColor"]; if (minorTickMarksColor.isValid()) { - QScriptValue red = minorTickMarksColor.property("red"); - QScriptValue green = minorTickMarksColor.property("green"); - QScriptValue blue = minorTickMarksColor.property("blue"); - if (red.isValid() && green.isValid() && blue.isValid()) { - _minorTickMarksColor.red = red.toVariant().toInt(); - _minorTickMarksColor.green = green.toVariant().toInt(); - _minorTickMarksColor.blue = blue.toVariant().toInt(); + auto color = xColorFromVariant(majorTickMarksColor, valid); + if (valid) { + _minorTickMarksColor = color; } } } -QScriptValue Circle3DOverlay::getProperty(const QString& property) { +QVariant Circle3DOverlay::getProperty(const QString& property) { if (property == "startAt") { return _startAt; } @@ -394,10 +387,10 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { return _minorTickMarksLength; } if (property == "majorTickMarksColor") { - return xColorToScriptValue(_scriptEngine, _majorTickMarksColor); + return xColorToVariant(_majorTickMarksColor); } if (property == "minorTickMarksColor") { - return xColorToScriptValue(_scriptEngine, _minorTickMarksColor); + return xColorToVariant(_minorTickMarksColor); } return Planar3DOverlay::getProperty(property); diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index 7050da3368..f0bc49c313 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -26,8 +26,8 @@ public: virtual void render(RenderArgs* args); virtual const render::ShapeKey getShapeKey() override; - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; float getStartAt() const { return _startAt; } float getEndAt() const { return _endAt; } diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index 8ba29bd336..38650f9fda 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -11,8 +11,6 @@ // include this before QGLWidget, which includes an earlier version of OpenGL #include "Cube3DOverlay.h" -#include - #include #include #include @@ -110,18 +108,18 @@ Cube3DOverlay* Cube3DOverlay::createClone() const { return new Cube3DOverlay(this); } -void Cube3DOverlay::setProperties(const QScriptValue& properties) { +void Cube3DOverlay::setProperties(const QVariantMap& properties) { Volume3DOverlay::setProperties(properties); - QScriptValue borderSize = properties.property("borderSize"); + auto borderSize = properties["borderSize"]; if (borderSize.isValid()) { - float value = borderSize.toVariant().toFloat(); + float value = borderSize.toFloat(); setBorderSize(value); } } -QScriptValue Cube3DOverlay::getProperty(const QString& property) { +QVariant Cube3DOverlay::getProperty(const QString& property) { if (property == "borderSize") { return _borderSize; } diff --git a/interface/src/ui/overlays/Cube3DOverlay.h b/interface/src/ui/overlays/Cube3DOverlay.h index 30b6646362..93ea46db4d 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.h +++ b/interface/src/ui/overlays/Cube3DOverlay.h @@ -32,8 +32,8 @@ public: void setBorderSize(float value) { _borderSize = value; } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; private: float _borderSize; diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index 817e71a4da..39106ad61e 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -11,10 +11,7 @@ #include "Grid3DOverlay.h" -#include - #include - #include #include #include @@ -92,24 +89,24 @@ const render::ShapeKey Grid3DOverlay::getShapeKey() { return render::ShapeKey::Builder().withOwnPipeline(); } -void Grid3DOverlay::setProperties(const QScriptValue& properties) { +void Grid3DOverlay::setProperties(const QVariantMap& properties) { Planar3DOverlay::setProperties(properties); - if (properties.property("followCamera").isValid()) { - _followCamera = properties.property("followCamera").toVariant().toBool(); + if (properties["followCamera"].isValid()) { + _followCamera = properties["followCamera"].toBool(); } - if (properties.property("majorGridEvery").isValid()) { - _majorGridEvery = properties.property("majorGridEvery").toVariant().toInt(); + if (properties["majorGridEvery"].isValid()) { + _majorGridEvery = properties["majorGridEvery"].toInt(); } - if (properties.property("minorGridEvery").isValid()) { - _minorGridEvery = properties.property("minorGridEvery").toVariant().toFloat(); + if (properties["minorGridEvery"].isValid()) { + _minorGridEvery = properties["minorGridEvery"].toFloat(); } updateGrid(); } -QScriptValue Grid3DOverlay::getProperty(const QString& property) { +QVariant Grid3DOverlay::getProperty(const QString& property) { if (property == "followCamera") { return _followCamera; } diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h index 3614a13000..aa372436de 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.h +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -28,8 +28,8 @@ public: virtual void render(RenderArgs* args); virtual const render::ShapeKey getShapeKey() override; - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual Grid3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 66f7143e83..fe2fc5ddcd 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -12,8 +12,6 @@ #include "Image3DOverlay.h" -#include - #include #include #include @@ -114,41 +112,42 @@ const render::ShapeKey Image3DOverlay::getShapeKey() { return builder.build(); } -void Image3DOverlay::setProperties(const QScriptValue &properties) { +void Image3DOverlay::setProperties(const QVariantMap& properties) { Billboard3DOverlay::setProperties(properties); - QScriptValue urlValue = properties.property("url"); + auto urlValue = properties["url"]; if (urlValue.isValid()) { - QString newURL = urlValue.toVariant().toString(); + QString newURL = urlValue.toString(); if (newURL != _url) { setURL(newURL); } } - QScriptValue subImageBounds = properties.property("subImage"); - if (subImageBounds.isValid()) { - if (subImageBounds.isNull()) { + auto subImageBoundsVar = properties["subImage"]; + if (subImageBoundsVar.isValid()) { + if (subImageBoundsVar.isNull()) { _fromImage = QRect(); } else { QRect oldSubImageRect = _fromImage; QRect subImageRect = _fromImage; - if (subImageBounds.property("x").isValid()) { - subImageRect.setX(subImageBounds.property("x").toVariant().toInt()); + auto subImageBounds = subImageBoundsVar.toMap(); + if (subImageBounds["x"].isValid()) { + subImageRect.setX(subImageBounds["x"].toInt()); } else { subImageRect.setX(oldSubImageRect.x()); } - if (subImageBounds.property("y").isValid()) { - subImageRect.setY(subImageBounds.property("y").toVariant().toInt()); + if (subImageBounds["y"].isValid()) { + subImageRect.setY(subImageBounds["y"].toInt()); } else { subImageRect.setY(oldSubImageRect.y()); } - if (subImageBounds.property("width").isValid()) { - subImageRect.setWidth(subImageBounds.property("width").toVariant().toInt()); + if (subImageBounds["width"].isValid()) { + subImageRect.setWidth(subImageBounds["width"].toInt()); } else { subImageRect.setWidth(oldSubImageRect.width()); } - if (subImageBounds.property("height").isValid()) { - subImageRect.setHeight(subImageBounds.property("height").toVariant().toInt()); + if (subImageBounds["height"].isValid()) { + subImageRect.setHeight(subImageBounds["height"].toInt()); } else { subImageRect.setHeight(oldSubImageRect.height()); } @@ -156,21 +155,21 @@ void Image3DOverlay::setProperties(const QScriptValue &properties) { } } - QScriptValue emissiveValue = properties.property("emissive"); + auto emissiveValue = properties["emissive"]; if (emissiveValue.isValid()) { _emissive = emissiveValue.toBool(); } } -QScriptValue Image3DOverlay::getProperty(const QString& property) { +QVariant Image3DOverlay::getProperty(const QString& property) { if (property == "url") { return _url; } if (property == "subImage") { - return qRectToScriptValue(_scriptEngine, _fromImage); + return _fromImage; } if (property == "offsetPosition") { - return vec3toScriptValue(_scriptEngine, getOffsetPosition()); + return vec3toVariant(getOffsetPosition()); } if (property == "emissive") { return _emissive; diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index 0b0b245872..2bdc58709a 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -37,8 +37,8 @@ public: void setURL(const QString& url); void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal); diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 8a9ba98eeb..3971e91211 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -71,49 +71,34 @@ const render::ShapeKey Line3DOverlay::getShapeKey() { return builder.build(); } -void Line3DOverlay::setProperties(const QScriptValue& properties) { +void Line3DOverlay::setProperties(const QVariantMap& properties) { Base3DOverlay::setProperties(properties); - QScriptValue start = properties.property("start"); + auto start = properties["start"]; // if "start" property was not there, check to see if they included aliases: startPoint if (!start.isValid()) { - start = properties.property("startPoint"); + start = properties["startPoint"]; } if (start.isValid()) { - QScriptValue x = start.property("x"); - QScriptValue y = start.property("y"); - QScriptValue z = start.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newStart; - newStart.x = x.toVariant().toFloat(); - newStart.y = y.toVariant().toFloat(); - newStart.z = z.toVariant().toFloat(); - setStart(newStart); - } + setStart(vec3FromVariant(start)); } - QScriptValue end = properties.property("end"); + auto end = properties["end"]; // if "end" property was not there, check to see if they included aliases: endPoint if (!end.isValid()) { - end = properties.property("endPoint"); + end = properties["endPoint"]; } if (end.isValid()) { - QScriptValue x = end.property("x"); - QScriptValue y = end.property("y"); - QScriptValue z = end.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newEnd; - newEnd.x = x.toVariant().toFloat(); - newEnd.y = y.toVariant().toFloat(); - newEnd.z = z.toVariant().toFloat(); - setEnd(newEnd); - } + setEnd(vec3FromVariant(end)); } } -QScriptValue Line3DOverlay::getProperty(const QString& property) { +QVariant Line3DOverlay::getProperty(const QString& property) { + if (property == "start" || property == "startPoint" || property == "p1") { + return vec3toVariant(_start); + } if (property == "end" || property == "endPoint" || property == "p2") { - return vec3toScriptValue(_scriptEngine, _end); + return vec3toVariant(_end); } return Base3DOverlay::getProperty(property); diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index b40ff78231..8ff38859a2 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -35,8 +35,8 @@ public: void setStart(const glm::vec3& start) { _start = start; } void setEnd(const glm::vec3& end) { _end = end; } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual Line3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index a06a9b0605..010698800b 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -84,7 +84,7 @@ void ModelOverlay::render(RenderArgs* args) { } } -void ModelOverlay::setProperties(const QScriptValue &properties) { +void ModelOverlay::setProperties(const QVariantMap& properties) { auto position = getPosition(); auto rotation = getRotation(); auto scale = getDimensions(); @@ -105,16 +105,16 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { } } - QScriptValue urlValue = properties.property("url"); - if (urlValue.isValid() && urlValue.isString()) { + auto urlValue = properties["url"]; + if (urlValue.isValid() && urlValue.canConvert()) { _url = urlValue.toString(); _updateModel = true; _isLoaded = false; } - QScriptValue texturesValue = properties.property("textures"); - if (texturesValue.isValid() && texturesValue.toVariant().canConvert(QVariant::Map)) { - QVariantMap textureMap = texturesValue.toVariant().toMap(); + auto texturesValue = properties["textures"]; + if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) { + QVariantMap textureMap = texturesValue.toMap(); foreach(const QString& key, textureMap.keys()) { QUrl newTextureURL = textureMap[key].toUrl(); @@ -129,22 +129,22 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { } } -QScriptValue ModelOverlay::getProperty(const QString& property) { +QVariant ModelOverlay::getProperty(const QString& property) { if (property == "url") { return _url.toString(); } if (property == "dimensions" || property == "scale" || property == "size") { - return vec3toScriptValue(_scriptEngine, _model.getScaleToFitDimensions()); + return vec3toVariant(_model.getScaleToFitDimensions()); } if (property == "textures") { if (_modelTextures.size() > 0) { - QScriptValue textures = _scriptEngine->newObject(); + QVariantMap textures; foreach(const QString& key, _modelTextures.keys()) { - textures.setProperty(key, _modelTextures[key].toString()); + textures[key] = _modelTextures[key].toString(); } return textures; } else { - return QScriptValue(); + return QVariant(); } } diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 5d09ea75a0..0b67f7ed37 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -27,9 +27,9 @@ public: virtual void update(float deltatime); virtual void render(RenderArgs* args); - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal); virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo); diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 64b5e2aedf..a53daf7d14 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -52,70 +52,68 @@ Overlay::Overlay(const Overlay* overlay) : _colorPulse(overlay->_colorPulse), _color(overlay->_color), _visible(overlay->_visible), - _anchor(overlay->_anchor), - _scriptEngine(NULL) + _anchor(overlay->_anchor) { } -void Overlay::init(QScriptEngine* scriptEngine) { - _scriptEngine = scriptEngine; -} - Overlay::~Overlay() { } -void Overlay::setProperties(const QScriptValue& properties) { - QScriptValue color = properties.property("color"); - xColorFromScriptValue(properties.property("color"), _color); +void Overlay::setProperties(const QVariantMap& properties) { + bool valid; + auto color = xColorFromVariant(properties["color"], valid); + if (valid) { + _color = color; + } - if (properties.property("alpha").isValid()) { - setAlpha(properties.property("alpha").toVariant().toFloat()); + if (properties["alpha"].isValid()) { + setAlpha(properties["alpha"].toFloat()); } - if (properties.property("glowLevel").isValid()) { - setGlowLevel(properties.property("glowLevel").toVariant().toFloat()); + if (properties["glowLevel"].isValid()) { + setGlowLevel(properties["glowLevel"].toFloat()); } - if (properties.property("pulseMax").isValid()) { - setPulseMax(properties.property("pulseMax").toVariant().toFloat()); + if (properties["pulseMax"].isValid()) { + setPulseMax(properties["pulseMax"].toFloat()); } - if (properties.property("pulseMin").isValid()) { - setPulseMin(properties.property("pulseMin").toVariant().toFloat()); + if (properties["pulseMin"].isValid()) { + setPulseMin(properties["pulseMin"].toFloat()); } - if (properties.property("pulsePeriod").isValid()) { - setPulsePeriod(properties.property("pulsePeriod").toVariant().toFloat()); + if (properties["pulsePeriod"].isValid()) { + setPulsePeriod(properties["pulsePeriod"].toFloat()); } - if (properties.property("glowLevelPulse").isValid()) { - setGlowLevelPulse(properties.property("glowLevelPulse").toVariant().toFloat()); + if (properties["glowLevelPulse"].isValid()) { + setGlowLevelPulse(properties["glowLevelPulse"].toFloat()); } - if (properties.property("alphaPulse").isValid()) { - setAlphaPulse(properties.property("alphaPulse").toVariant().toFloat()); + if (properties["alphaPulse"].isValid()) { + setAlphaPulse(properties["alphaPulse"].toFloat()); } - if (properties.property("colorPulse").isValid()) { - setColorPulse(properties.property("colorPulse").toVariant().toFloat()); + if (properties["colorPulse"].isValid()) { + setColorPulse(properties["colorPulse"].toFloat()); } - if (properties.property("visible").isValid()) { - bool visible = properties.property("visible").toVariant().toBool(); + if (properties["visible"].isValid()) { + bool visible = properties["visible"].toBool(); setVisible(visible); } - if (properties.property("anchor").isValid()) { - QString property = properties.property("anchor").toVariant().toString(); + if (properties["anchor"].isValid()) { + QString property = properties["anchor"].toString(); if (property == "MyAvatar") { setAnchor(MY_AVATAR); } } } -QScriptValue Overlay::getProperty(const QString& property) { +QVariant Overlay::getProperty(const QString& property) { if (property == "color") { - return xColorToScriptValue(_scriptEngine, _color); + return xColorToVariant(_color); } if (property == "alpha") { return _alpha; @@ -148,7 +146,7 @@ QScriptValue Overlay::getProperty(const QString& property) { return _anchor == MY_AVATAR ? "MyAvatar" : ""; } - return QScriptValue(); + return QVariant(); } xColor Overlay::getColor() { diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 84e9c1bb59..a2cf7a30f2 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -15,9 +15,6 @@ #include // for xColor #include -class QScriptEngine; -class QScriptValue; - class Overlay : public QObject { Q_OBJECT @@ -34,7 +31,6 @@ public: Overlay(); Overlay(const Overlay* overlay); ~Overlay(); - void init(QScriptEngine* scriptEngine); virtual void update(float deltatime) {} virtual void render(RenderArgs* args) = 0; @@ -82,9 +78,9 @@ public: void setColorPulse(float value) { _colorPulse = value; } void setAlphaPulse(float value) { _alphaPulse = value; } - virtual void setProperties(const QScriptValue& properties); + virtual void setProperties(const QVariantMap& properties); virtual Overlay* createClone() const = 0; - virtual QScriptValue getProperty(const QString& property); + virtual QVariant getProperty(const QString& property); render::ItemID getRenderItemID() const { return _renderItemID; } void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; } @@ -112,8 +108,6 @@ protected: xColor _color; bool _visible; // should the overlay be drawn at all Anchor _anchor; - - QScriptEngine* _scriptEngine; }; namespace render { diff --git a/interface/src/ui/overlays/Overlay2D.cpp b/interface/src/ui/overlays/Overlay2D.cpp index e37e70700c..d5f88a84d7 100644 --- a/interface/src/ui/overlays/Overlay2D.cpp +++ b/interface/src/ui/overlays/Overlay2D.cpp @@ -23,49 +23,44 @@ AABox Overlay2D::getBounds() const { glm::vec3(_bounds.width(), _bounds.height(), 0.01f)); } -void Overlay2D::setProperties(const QScriptValue& properties) { +void Overlay2D::setProperties(const QVariantMap& properties) { Overlay::setProperties(properties); - QScriptValue bounds = properties.property("bounds"); + auto bounds = properties["bounds"]; if (bounds.isValid()) { - QRect boundsRect; - boundsRect.setX(bounds.property("x").toVariant().toInt()); - boundsRect.setY(bounds.property("y").toVariant().toInt()); - boundsRect.setWidth(bounds.property("width").toVariant().toInt()); - boundsRect.setHeight(bounds.property("height").toVariant().toInt()); - setBounds(boundsRect); + bool valid; + auto rect = qRectFromVariant(bounds, valid); + setBounds(rect); } else { QRect oldBounds = _bounds; QRect newBounds = oldBounds; - - if (properties.property("x").isValid()) { - newBounds.setX(properties.property("x").toVariant().toInt()); + if (properties["x"].isValid()) { + newBounds.setX(properties["x"].toInt()); } else { newBounds.setX(oldBounds.x()); } - if (properties.property("y").isValid()) { - newBounds.setY(properties.property("y").toVariant().toInt()); + if (properties["y"].isValid()) { + newBounds.setY(properties["y"].toInt()); } else { newBounds.setY(oldBounds.y()); } - if (properties.property("width").isValid()) { - newBounds.setWidth(properties.property("width").toVariant().toInt()); + if (properties["width"].isValid()) { + newBounds.setWidth(properties["width"].toInt()); } else { newBounds.setWidth(oldBounds.width()); } - if (properties.property("height").isValid()) { - newBounds.setHeight(properties.property("height").toVariant().toInt()); + if (properties["height"].isValid()) { + newBounds.setHeight(properties["height"].toInt()); } else { newBounds.setHeight(oldBounds.height()); } setBounds(newBounds); - //qDebug() << "set bounds to " << getBounds(); } } -QScriptValue Overlay2D::getProperty(const QString& property) { +QVariant Overlay2D::getProperty(const QString& property) { if (property == "bounds") { - return qRectToScriptValue(_scriptEngine, _bounds); + return qRectToVariant(_bounds); } if (property == "x") { return _bounds.x(); diff --git a/interface/src/ui/overlays/Overlay2D.h b/interface/src/ui/overlays/Overlay2D.h index 382105c047..3fd11f79f0 100644 --- a/interface/src/ui/overlays/Overlay2D.h +++ b/interface/src/ui/overlays/Overlay2D.h @@ -40,8 +40,8 @@ public: void setHeight(int height) { _bounds.setHeight(height); } void setBounds(const QRect& bounds) { _bounds = bounds; } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; protected: QRect _bounds; // where on the screen to draw diff --git a/interface/src/ui/overlays/OverlayPanel.cpp b/interface/src/ui/overlays/OverlayPanel.cpp index 7db2c6f8a2..cb57c6ec6b 100644 --- a/interface/src/ui/overlays/OverlayPanel.cpp +++ b/interface/src/ui/overlays/OverlayPanel.cpp @@ -26,26 +26,27 @@ PropertyBinding::PropertyBinding(QString avatar, QUuid entity) : { } -QScriptValue propertyBindingToScriptValue(QScriptEngine* engine, const PropertyBinding& value) { - QScriptValue obj = engine->newObject(); +QVariant propertyBindingToVariant(const PropertyBinding& value) { + QVariantMap obj; if (value.avatar == "MyAvatar") { - obj.setProperty("avatar", "MyAvatar"); + obj["avatar"] = "MyAvatar"; } else if (!value.entity.isNull()) { - obj.setProperty("entity", engine->newVariant(value.entity)); + obj["entity"] = value.entity; } return obj; } -void propertyBindingFromScriptValue(const QScriptValue& object, PropertyBinding& value) { - QScriptValue avatar = object.property("avatar"); - QScriptValue entity = object.property("entity"); +void propertyBindingFromVariant(const QVariant& objectVar, PropertyBinding& value) { + auto object = objectVar.toMap(); + auto avatar = object["avatar"]; + auto entity = object["entity"]; if (avatar.isValid() && !avatar.isNull()) { - value.avatar = avatar.toVariant().toString(); + value.avatar = avatar.toString(); } else if (entity.isValid() && !entity.isNull()) { - value.entity = entity.toVariant().toUuid(); + value.entity = entity.toUuid(); } } @@ -62,103 +63,82 @@ void OverlayPanel::removeChild(unsigned int childId) { } } -QScriptValue OverlayPanel::getProperty(const QString &property) { +QVariant OverlayPanel::getProperty(const QString &property) { if (property == "anchorPosition") { - return vec3toScriptValue(_scriptEngine, getAnchorPosition()); + return vec3toVariant(getAnchorPosition()); } if (property == "anchorPositionBinding") { - return propertyBindingToScriptValue(_scriptEngine, - PropertyBinding(_anchorPositionBindMyAvatar ? + return propertyBindingToVariant(PropertyBinding(_anchorPositionBindMyAvatar ? "MyAvatar" : "", _anchorPositionBindEntity)); } if (property == "anchorRotation") { - return quatToScriptValue(_scriptEngine, getAnchorRotation()); + return quatToVariant(getAnchorRotation()); } if (property == "anchorRotationBinding") { - return propertyBindingToScriptValue(_scriptEngine, - PropertyBinding(_anchorRotationBindMyAvatar ? + return propertyBindingToVariant(PropertyBinding(_anchorRotationBindMyAvatar ? "MyAvatar" : "", _anchorRotationBindEntity)); } if (property == "anchorScale") { - return vec3toScriptValue(_scriptEngine, getAnchorScale()); + return vec3toVariant(getAnchorScale()); } if (property == "visible") { return getVisible(); } if (property == "children") { - QScriptValue array = _scriptEngine->newArray(_children.length()); + QVariantList array; for (int i = 0; i < _children.length(); i++) { - array.setProperty(i, _children[i]); + array.append(_children[i]); } return array; } - QScriptValue value = Billboardable::getProperty(_scriptEngine, property); + auto value = Billboardable::getProperty(property); if (value.isValid()) { return value; } - return PanelAttachable::getProperty(_scriptEngine, property); + return PanelAttachable::getProperty(property); } -void OverlayPanel::setProperties(const QScriptValue &properties) { +void OverlayPanel::setProperties(const QVariantMap& properties) { PanelAttachable::setProperties(properties); Billboardable::setProperties(properties); - QScriptValue anchorPosition = properties.property("anchorPosition"); - if (anchorPosition.isValid() && - anchorPosition.property("x").isValid() && - anchorPosition.property("y").isValid() && - anchorPosition.property("z").isValid()) { - glm::vec3 newPosition; - vec3FromScriptValue(anchorPosition, newPosition); - setAnchorPosition(newPosition); + auto anchorPosition = properties["anchorPosition"]; + if (anchorPosition.isValid()) { + setAnchorPosition(vec3FromVariant(anchorPosition)); } - QScriptValue anchorPositionBinding = properties.property("anchorPositionBinding"); + auto anchorPositionBinding = properties["anchorPositionBinding"]; if (anchorPositionBinding.isValid()) { PropertyBinding binding = {}; - propertyBindingFromScriptValue(anchorPositionBinding, binding); + propertyBindingFromVariant(anchorPositionBinding, binding); _anchorPositionBindMyAvatar = binding.avatar == "MyAvatar"; _anchorPositionBindEntity = binding.entity; } - QScriptValue anchorRotation = properties.property("anchorRotation"); - if (anchorRotation.isValid() && - anchorRotation.property("x").isValid() && - anchorRotation.property("y").isValid() && - anchorRotation.property("z").isValid() && - anchorRotation.property("w").isValid()) { - glm::quat newRotation; - quatFromScriptValue(anchorRotation, newRotation); - setAnchorRotation(newRotation); + auto anchorRotation = properties["anchorRotation"]; + if (anchorRotation.isValid()) { + setAnchorRotation(quatFromVariant(anchorRotation)); } - QScriptValue anchorRotationBinding = properties.property("anchorRotationBinding"); + auto anchorRotationBinding = properties["anchorRotationBinding"]; if (anchorRotationBinding.isValid()) { PropertyBinding binding = {}; - propertyBindingFromScriptValue(anchorPositionBinding, binding); + propertyBindingFromVariant(anchorPositionBinding, binding); _anchorRotationBindMyAvatar = binding.avatar == "MyAvatar"; _anchorRotationBindEntity = binding.entity; } - QScriptValue anchorScale = properties.property("anchorScale"); + auto anchorScale = properties["anchorScale"]; if (anchorScale.isValid()) { - if (anchorScale.property("x").isValid() && - anchorScale.property("y").isValid() && - anchorScale.property("z").isValid()) { - glm::vec3 newScale; - vec3FromScriptValue(anchorScale, newScale); - setAnchorScale(newScale); - } else { - setAnchorScale(anchorScale.toVariant().toFloat()); - } + setAnchorScale(vec3FromVariant(anchorScale)); } - QScriptValue visible = properties.property("visible"); + auto visible = properties["visible"]; if (visible.isValid()) { - setVisible(visible.toVariant().toBool()); + setVisible(visible.toBool()); } } diff --git a/interface/src/ui/overlays/OverlayPanel.h b/interface/src/ui/overlays/OverlayPanel.h index 221763fe87..df553883f1 100644 --- a/interface/src/ui/overlays/OverlayPanel.h +++ b/interface/src/ui/overlays/OverlayPanel.h @@ -16,7 +16,6 @@ #include #include -#include #include #include "PanelAttachable.h" @@ -30,8 +29,8 @@ public: QUuid entity; }; -QScriptValue propertyBindingToScriptValue(QScriptEngine* engine, const PropertyBinding& value); -void propertyBindingFromScriptValue(const QScriptValue& object, PropertyBinding& value); +QVariant propertyBindingToVariant(const PropertyBinding& value); +void propertyBindingFromVariant(const QVariant& object, PropertyBinding& value); class OverlayPanel : public QObject, public PanelAttachable, public Billboardable { @@ -60,8 +59,8 @@ public: void removeChild(unsigned int childId); unsigned int popLastChild() { return _children.takeLast(); } - QScriptValue getProperty(const QString& property); - void setProperties(const QScriptValue& properties); + void setProperties(const QVariantMap& properties); + QVariant getProperty(const QString& property); virtual void applyTransformTo(Transform& transform, bool force = false); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 2bc1286419..95c4368448 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -153,7 +153,7 @@ Overlay::Pointer Overlays::getOverlay(unsigned int id) const { return nullptr; } -unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) { +unsigned int Overlays::addOverlay(const QString& type, const QVariant& properties) { Overlay::Pointer thisOverlay = nullptr; if (type == ImageOverlay::TYPE) { @@ -187,15 +187,13 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope } if (thisOverlay) { - thisOverlay->setProperties(properties); + thisOverlay->setProperties(properties.toMap()); return addOverlay(thisOverlay); } return 0; } unsigned int Overlays::addOverlay(Overlay::Pointer overlay) { - overlay->init(_scriptEngine); - QWriteLocker lock(&_lock); unsigned int thisID = _nextOverlayID; _nextOverlayID++; @@ -228,7 +226,7 @@ unsigned int Overlays::cloneOverlay(unsigned int id) { return 0; // Not found } -bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { +bool Overlays::editOverlay(unsigned int id, const QVariant& properties) { QWriteLocker lock(&_lock); Overlay::Pointer thisOverlay = getOverlay(id); @@ -236,7 +234,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { if (thisOverlay->is3D()) { render::ItemKey oldItemKey = render::payloadGetKey(thisOverlay); - thisOverlay->setProperties(properties); + thisOverlay->setProperties(properties.toMap()); render::ItemKey itemKey = render::payloadGetKey(thisOverlay); if (itemKey != oldItemKey) { @@ -249,7 +247,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { } } } else { - thisOverlay->setProperties(properties); + thisOverlay->setProperties(properties.toMap()); } return true; @@ -380,36 +378,21 @@ OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& prop return result; } -OverlayPropertyResult::OverlayPropertyResult() : - value(QScriptValue()) -{ +OverlayPropertyResult::OverlayPropertyResult() { } -QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& result) -{ - if (!result.value.isValid()) { +QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value) { + if (!value.value.isValid()) { return QScriptValue::UndefinedValue; } - - QScriptValue object = engine->newObject(); - if (result.value.isObject()) { - QScriptValueIterator it(result.value); - while (it.hasNext()) { - it.next(); - object.setProperty(it.name(), QScriptValue(it.value().toString())); - } - - } else { - object = result.value; - } - return object; + return engine->newVariant(value.value); } -void OverlayPropertyResultFromScriptValue(const QScriptValue& value, OverlayPropertyResult& result) -{ - result.value = value; +void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value) { + value.value = object.toVariant(); } + RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) { float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; @@ -456,7 +439,7 @@ RayToOverlayIntersectionResult::RayToOverlayIntersectionResult() : } QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) { - QScriptValue obj = engine->newObject(); + auto obj = engine->newObject(); obj.setProperty("intersects", value.intersects); obj.setProperty("overlayID", value.overlayID); obj.setProperty("distance", value.distance); @@ -488,18 +471,19 @@ QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, break; } obj.setProperty("face", faceName); - QScriptValue intersection = vec3toScriptValue(engine, value.intersection); + auto intersection = vec3toScriptValue(engine, value.intersection); obj.setProperty("intersection", intersection); obj.setProperty("extraInfo", value.extraInfo); return obj; } -void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value) { - value.intersects = object.property("intersects").toVariant().toBool(); - value.overlayID = object.property("overlayID").toVariant().toInt(); - value.distance = object.property("distance").toVariant().toFloat(); +void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar, RayToOverlayIntersectionResult& value) { + QVariantMap object = objectVar.toVariant().toMap(); + value.intersects = object["intersects"].toBool(); + value.overlayID = object["overlayID"].toInt(); + value.distance = object["distance"].toFloat(); - QString faceName = object.property("face").toVariant().toString(); + QString faceName = object["face"].toString(); if (faceName == "MIN_X_FACE") { value.face = MIN_X_FACE; } else if (faceName == "MAX_X_FACE") { @@ -515,11 +499,15 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R } else { value.face = UNKNOWN_FACE; }; - QScriptValue intersection = object.property("intersection"); + auto intersection = object["intersection"]; if (intersection.isValid()) { - vec3FromScriptValue(intersection, value.intersection); + bool valid; + auto newIntersection = vec3FromVariant(intersection, valid); + if (valid) { + value.intersection = newIntersection; + } } - value.extraInfo = object.property("extraInfo").toVariant().toString(); + value.extraInfo = object["extraInfo"].toString(); } bool Overlays::isLoaded(unsigned int id) { @@ -556,16 +544,16 @@ unsigned int Overlays::addPanel(OverlayPanel::Pointer panel) { return thisID; } -unsigned int Overlays::addPanel(const QScriptValue& properties) { +unsigned int Overlays::addPanel(const QVariant& properties) { OverlayPanel::Pointer panel = std::make_shared(); panel->init(_scriptEngine); - panel->setProperties(properties); + panel->setProperties(properties.toMap()); return addPanel(panel); } -void Overlays::editPanel(unsigned int panelId, const QScriptValue& properties) { +void Overlays::editPanel(unsigned int panelId, const QVariant& properties) { if (_panels.contains(panelId)) { - _panels[panelId]->setProperties(properties); + _panels[panelId]->setProperties(properties.toMap()); } } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 7bf6ce94eb..25ba00fdf0 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -31,7 +31,7 @@ class PickRay; class OverlayPropertyResult { public: OverlayPropertyResult(); - QScriptValue value; + QVariant value; }; Q_DECLARE_METATYPE(OverlayPropertyResult); @@ -75,7 +75,7 @@ public: public slots: /// adds an overlay with the specific properties - unsigned int addOverlay(const QString& type, const QScriptValue& properties); + unsigned int addOverlay(const QString& type, const QVariant& properties); /// adds an overlay that's already been created unsigned int addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } @@ -86,7 +86,7 @@ public slots: /// edits an overlay updating only the included properties, will return the identified OverlayID in case of /// successful edit, if the input id is for an unknown overlay this function will have no effect - bool editOverlay(unsigned int id, const QScriptValue& properties); + bool editOverlay(unsigned int id, const QVariant& properties); /// deletes a particle void deleteOverlay(unsigned int id); @@ -122,10 +122,10 @@ public slots: unsigned int addPanel(OverlayPanel::Pointer panel); /// creates and adds a panel based on a set of properties - unsigned int addPanel(const QScriptValue& properties); + unsigned int addPanel(const QVariant& properties); /// edit the properties of a panel - void editPanel(unsigned int panelId, const QScriptValue& properties); + void editPanel(unsigned int panelId, const QVariant& properties); /// get a property of a panel OverlayPropertyResult getPanelProperty(unsigned int panelId, const QString& property); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 175d6fa408..174873a5c7 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -8,8 +8,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include #include diff --git a/interface/src/ui/overlays/PanelAttachable.cpp b/interface/src/ui/overlays/PanelAttachable.cpp index da3a37db45..7f1c4e2e50 100644 --- a/interface/src/ui/overlays/PanelAttachable.cpp +++ b/interface/src/ui/overlays/PanelAttachable.cpp @@ -23,53 +23,38 @@ bool PanelAttachable::getParentVisible() const { } } -QScriptValue PanelAttachable::getProperty(QScriptEngine* scriptEngine, const QString &property) { +QVariant PanelAttachable::getProperty(const QString& property) { if (property == "offsetPosition") { - return vec3toScriptValue(scriptEngine, getOffsetPosition()); + return vec3toVariant(getOffsetPosition()); } if (property == "offsetRotation") { - return quatToScriptValue(scriptEngine, getOffsetRotation()); + return quatToVariant(getOffsetRotation()); } if (property == "offsetScale") { - return vec3toScriptValue(scriptEngine, getOffsetScale()); + return vec3toVariant(getOffsetScale()); } - return QScriptValue(); + return QVariant(); } -void PanelAttachable::setProperties(const QScriptValue &properties) { - QScriptValue offsetPosition = properties.property("offsetPosition"); - if (offsetPosition.isValid() && - offsetPosition.property("x").isValid() && - offsetPosition.property("y").isValid() && - offsetPosition.property("z").isValid()) { - glm::vec3 newPosition; - vec3FromScriptValue(offsetPosition, newPosition); - setOffsetPosition(newPosition); - } - - QScriptValue offsetRotation = properties.property("offsetRotation"); - if (offsetRotation.isValid() && - offsetRotation.property("x").isValid() && - offsetRotation.property("y").isValid() && - offsetRotation.property("z").isValid() && - offsetRotation.property("w").isValid()) { - glm::quat newRotation; - quatFromScriptValue(offsetRotation, newRotation); - setOffsetRotation(newRotation); - } - - QScriptValue offsetScale = properties.property("offsetScale"); - if (offsetScale.isValid()) { - if (offsetScale.property("x").isValid() && - offsetScale.property("y").isValid() && - offsetScale.property("z").isValid()) { - glm::vec3 newScale; - vec3FromScriptValue(offsetScale, newScale); - setOffsetScale(newScale); - } else { - setOffsetScale(offsetScale.toVariant().toFloat()); +void PanelAttachable::setProperties(const QVariantMap& properties) { + auto offsetPosition = properties["offsetPosition"]; + bool valid; + if (offsetPosition.isValid()) { + glm::vec3 newPosition = vec3FromVariant(offsetPosition, valid); + if (valid) { + setOffsetPosition(newPosition); } } + + auto offsetRotation = properties["offsetRotation"]; + if (offsetRotation.isValid()) { + setOffsetRotation(quatFromVariant(offsetRotation)); + } + + auto offsetScale = properties["offsetScale"]; + if (offsetScale.isValid()) { + setOffsetScale(vec3FromVariant(offsetScale)); + } } void PanelAttachable::applyTransformTo(Transform& transform, bool force) { diff --git a/interface/src/ui/overlays/PanelAttachable.h b/interface/src/ui/overlays/PanelAttachable.h index f4e982f8e9..270addbfcf 100644 --- a/interface/src/ui/overlays/PanelAttachable.h +++ b/interface/src/ui/overlays/PanelAttachable.h @@ -57,8 +57,8 @@ public: void setOffsetScale(const glm::vec3& scale) { _offset.setScale(scale); } protected: - QScriptValue getProperty(QScriptEngine* scriptEngine, const QString& property); - void setProperties(const QScriptValue& properties); + void setProperties(const QVariantMap& properties); + QVariant getProperty(const QString& property); /// set position, rotation and scale on transform based on offsets, and parent panel offsets /// if force is false, only apply transform if it hasn't been applied in the last .1 seconds diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index b04316b3ee..c580464e16 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -35,57 +35,27 @@ AABox Planar3DOverlay::getBounds() const { return AABox(extents); } -void Planar3DOverlay::setProperties(const QScriptValue& properties) { +void Planar3DOverlay::setProperties(const QVariantMap& properties) { Base3DOverlay::setProperties(properties); - QScriptValue dimensions = properties.property("dimensions"); + auto dimensions = properties["dimensions"]; // if "dimensions" property was not there, check to see if they included aliases: scale if (!dimensions.isValid()) { - dimensions = properties.property("scale"); + dimensions = properties["scale"]; if (!dimensions.isValid()) { - dimensions = properties.property("size"); + dimensions = properties["size"]; } } if (dimensions.isValid()) { - bool validDimensions = false; - glm::vec2 newDimensions; - - QScriptValue x = dimensions.property("x"); - QScriptValue y = dimensions.property("y"); - - if (x.isValid() && y.isValid()) { - newDimensions.x = x.toVariant().toFloat(); - newDimensions.y = y.toVariant().toFloat(); - validDimensions = true; - } else { - QScriptValue width = dimensions.property("width"); - QScriptValue height = dimensions.property("height"); - if (width.isValid() && height.isValid()) { - newDimensions.x = width.toVariant().toFloat(); - newDimensions.y = height.toVariant().toFloat(); - validDimensions = true; - } - } - - // size, scale, dimensions is special, it might just be a single scalar, check that here - if (!validDimensions && dimensions.isNumber()) { - float size = dimensions.toVariant().toFloat(); - newDimensions.x = size; - newDimensions.y = size; - validDimensions = true; - } - - if (validDimensions) { - setDimensions(newDimensions); - } + setDimensions(vec2FromVariant(dimensions)); } } -QScriptValue Planar3DOverlay::getProperty(const QString& property) { +QVariant Planar3DOverlay::getProperty(const QString& property) { if (property == "dimensions" || property == "scale" || property == "size") { - return vec2toScriptValue(_scriptEngine, getDimensions()); + return vec2toVariant(getDimensions()); } return Base3DOverlay::getProperty(property); diff --git a/interface/src/ui/overlays/Planar3DOverlay.h b/interface/src/ui/overlays/Planar3DOverlay.h index 0542a8b491..ef391e61e4 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.h +++ b/interface/src/ui/overlays/Planar3DOverlay.h @@ -26,8 +26,8 @@ public: void setDimensions(float value) { _dimensions = glm::vec2(value); } void setDimensions(const glm::vec2& value) { _dimensions = value; } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal); diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp index 7675489258..27d03b5e09 100644 --- a/interface/src/ui/overlays/QmlOverlay.cpp +++ b/interface/src/ui/overlays/QmlOverlay.cpp @@ -57,7 +57,7 @@ QmlOverlay::~QmlOverlay() { } } -void QmlOverlay::setProperties(const QScriptValue& properties) { +void QmlOverlay::setProperties(const QVariantMap& properties) { Overlay2D::setProperties(properties); auto bounds = _bounds; std::weak_ptr weakQmlElement; @@ -71,7 +71,7 @@ void QmlOverlay::setProperties(const QScriptValue& properties) { _qmlElement->setHeight(bounds.height()); } }); - QMetaObject::invokeMethod(_qmlElement.get(), "updatePropertiesFromScript", Q_ARG(QVariant, properties.toVariant())); + QMetaObject::invokeMethod(_qmlElement.get(), "updatePropertiesFromScript", Q_ARG(QVariant, properties)); } void QmlOverlay::render(RenderArgs* args) { diff --git a/interface/src/ui/overlays/QmlOverlay.h b/interface/src/ui/overlays/QmlOverlay.h index a75783da1f..736d3884b5 100644 --- a/interface/src/ui/overlays/QmlOverlay.h +++ b/interface/src/ui/overlays/QmlOverlay.h @@ -28,7 +28,7 @@ public: // Cannot fetch properties from QML based overlays due to race conditions bool supportsGetProperty() const override { return false; } - void setProperties(const QScriptValue& properties) override; + void setProperties(const QVariantMap& properties) override; void render(RenderArgs* args) override; private: diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.cpp b/interface/src/ui/overlays/Rectangle3DOverlay.cpp index cee924c44c..5a541fd58a 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.cpp +++ b/interface/src/ui/overlays/Rectangle3DOverlay.cpp @@ -96,7 +96,7 @@ const render::ShapeKey Rectangle3DOverlay::getShapeKey() { return builder.build(); } -void Rectangle3DOverlay::setProperties(const QScriptValue &properties) { +void Rectangle3DOverlay::setProperties(const QVariantMap& properties) { Planar3DOverlay::setProperties(properties); } diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.h b/interface/src/ui/overlays/Rectangle3DOverlay.h index cde4ad2f53..31ccac45a3 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.h +++ b/interface/src/ui/overlays/Rectangle3DOverlay.h @@ -25,7 +25,7 @@ public: ~Rectangle3DOverlay(); virtual void render(RenderArgs* args); virtual const render::ShapeKey getShapeKey() override; - virtual void setProperties(const QScriptValue& properties); + void setProperties(const QVariantMap& properties) override; virtual Rectangle3DOverlay* createClone() const; private: diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 60cf6bcd4d..9fa8f6556b 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -121,57 +121,54 @@ const render::ShapeKey Text3DOverlay::getShapeKey() { return builder.build(); } -void Text3DOverlay::setProperties(const QScriptValue& properties) { +void Text3DOverlay::setProperties(const QVariantMap& properties) { Billboard3DOverlay::setProperties(properties); - QScriptValue text = properties.property("text"); + auto text = properties["text"]; if (text.isValid()) { - setText(text.toVariant().toString()); + setText(text.toString()); } - QScriptValue textAlpha = properties.property("textAlpha"); + auto textAlpha = properties["textAlpha"]; if (textAlpha.isValid()) { - setTextAlpha(textAlpha.toVariant().toFloat()); + setTextAlpha(textAlpha.toFloat()); } - QScriptValue backgroundColor = properties.property("backgroundColor"); + bool valid; + auto backgroundColor = properties["backgroundColor"]; if (backgroundColor.isValid()) { - QScriptValue red = backgroundColor.property("red"); - QScriptValue green = backgroundColor.property("green"); - QScriptValue blue = backgroundColor.property("blue"); - if (red.isValid() && green.isValid() && blue.isValid()) { - _backgroundColor.red = red.toVariant().toInt(); - _backgroundColor.green = green.toVariant().toInt(); - _backgroundColor.blue = blue.toVariant().toInt(); + auto color = xColorFromVariant(backgroundColor, valid); + if (valid) { + _backgroundColor = color; } } - if (properties.property("backgroundAlpha").isValid()) { - setAlpha(properties.property("backgroundAlpha").toVariant().toFloat()); + if (properties["backgroundAlpha"].isValid()) { + setAlpha(properties["backgroundAlpha"].toFloat()); } - if (properties.property("lineHeight").isValid()) { - setLineHeight(properties.property("lineHeight").toVariant().toFloat()); + if (properties["lineHeight"].isValid()) { + setLineHeight(properties["lineHeight"].toFloat()); } - if (properties.property("leftMargin").isValid()) { - setLeftMargin(properties.property("leftMargin").toVariant().toFloat()); + if (properties["leftMargin"].isValid()) { + setLeftMargin(properties["leftMargin"].toFloat()); } - if (properties.property("topMargin").isValid()) { - setTopMargin(properties.property("topMargin").toVariant().toFloat()); + if (properties["topMargin"].isValid()) { + setTopMargin(properties["topMargin"].toFloat()); } - if (properties.property("rightMargin").isValid()) { - setRightMargin(properties.property("rightMargin").toVariant().toFloat()); + if (properties["rightMargin"].isValid()) { + setRightMargin(properties["rightMargin"].toFloat()); } - if (properties.property("bottomMargin").isValid()) { - setBottomMargin(properties.property("bottomMargin").toVariant().toFloat()); + if (properties["bottomMargin"].isValid()) { + setBottomMargin(properties["bottomMargin"].toFloat()); } } -QScriptValue Text3DOverlay::getProperty(const QString& property) { +QVariant Text3DOverlay::getProperty(const QString& property) { if (property == "text") { return _text; } @@ -179,7 +176,7 @@ QScriptValue Text3DOverlay::getProperty(const QString& property) { return _textAlpha; } if (property == "backgroundColor") { - return xColorToScriptValue(_scriptEngine, _backgroundColor); + return xColorToVariant(_backgroundColor); } if (property == "backgroundAlpha") { return Billboard3DOverlay::getProperty("alpha"); diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index e9635947b6..181e9d526c 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -53,8 +53,8 @@ public: void setRightMargin(float margin) { _rightMargin = margin; } void setBottomMargin(float margin) { _bottomMargin = margin; } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; QSizeF textSize(const QString& test) const; // Meters diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index 687f1f6286..c8078d35c6 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -26,67 +26,27 @@ AABox Volume3DOverlay::getBounds() const { return AABox(extents); } -void Volume3DOverlay::setProperties(const QScriptValue& properties) { +void Volume3DOverlay::setProperties(const QVariantMap& properties) { Base3DOverlay::setProperties(properties); - QScriptValue dimensions = properties.property("dimensions"); + auto dimensions = properties["dimensions"]; // if "dimensions" property was not there, check to see if they included aliases: scale if (!dimensions.isValid()) { - dimensions = properties.property("scale"); + dimensions = properties["scale"]; if (!dimensions.isValid()) { - dimensions = properties.property("size"); + dimensions = properties["size"]; } } if (dimensions.isValid()) { - bool validDimensions = false; - glm::vec3 newDimensions; - - QScriptValue x = dimensions.property("x"); - QScriptValue y = dimensions.property("y"); - QScriptValue z = dimensions.property("z"); - - - if (x.isValid() && x.isNumber() && - y.isValid() && y.isNumber() && - z.isValid() && z.isNumber()) { - newDimensions.x = x.toNumber(); - newDimensions.y = y.toNumber(); - newDimensions.z = z.toNumber(); - validDimensions = true; - } else { - QScriptValue width = dimensions.property("width"); - QScriptValue height = dimensions.property("height"); - QScriptValue depth = dimensions.property("depth"); - if (width.isValid() && width.isNumber() && - height.isValid() && height.isNumber() && - depth.isValid() && depth.isNumber()) { - newDimensions.x = width.toNumber(); - newDimensions.y = height.toNumber(); - newDimensions.z = depth.toNumber(); - validDimensions = true; - } - } - - // size, scale, dimensions is special, it might just be a single scalar, check that here - if (!validDimensions && dimensions.isNumber()) { - float size = dimensions.toNumber(); - newDimensions.x = size; - newDimensions.y = size; - newDimensions.z = size; - validDimensions = true; - } - - if (validDimensions) { - setDimensions(newDimensions); - } + setDimensions(vec3FromVariant(dimensions)); } } -QScriptValue Volume3DOverlay::getProperty(const QString& property) { +QVariant Volume3DOverlay::getProperty(const QString& property) { if (property == "dimensions" || property == "scale" || property == "size") { - return vec3toScriptValue(_scriptEngine, getDimensions()); + return vec3toVariant(getDimensions()); } return Base3DOverlay::getProperty(property); diff --git a/interface/src/ui/overlays/Volume3DOverlay.h b/interface/src/ui/overlays/Volume3DOverlay.h index 5756b6549a..42b3d439d6 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.h +++ b/interface/src/ui/overlays/Volume3DOverlay.h @@ -26,8 +26,8 @@ public: void setDimensions(float value) { _localBoundingBox.setBox(glm::vec3(-value / 2.0f), value); } void setDimensions(const glm::vec3& value) { _localBoundingBox.setBox(-value / 2.0f, value); } - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 7ceff81dd2..f5baecd96a 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -12,7 +12,6 @@ #include "Web3DOverlay.h" -#include #include #include @@ -113,30 +112,34 @@ const render::ShapeKey Web3DOverlay::getShapeKey() { return builder.build(); } -void Web3DOverlay::setProperties(const QScriptValue &properties) { +void Web3DOverlay::setProperties(const QVariantMap& properties) { Billboard3DOverlay::setProperties(properties); - QScriptValue urlValue = properties.property("url"); + auto urlValue = properties["url"]; if (urlValue.isValid()) { - QString newURL = urlValue.toVariant().toString(); + QString newURL = urlValue.toString(); if (newURL != _url) { setURL(newURL); } } - QScriptValue resolution = properties.property("resolution"); + auto resolution = properties["resolution"]; if (resolution.isValid()) { - vec2FromScriptValue(resolution, _resolution); + bool valid; + auto res = vec2FromVariant(resolution, valid); + if (valid) { + _resolution = res; + } } - QScriptValue dpi = properties.property("dpi"); + auto dpi = properties["dpi"]; if (dpi.isValid()) { - _dpi = dpi.toVariant().toFloat(); + _dpi = dpi.toFloat(); } } -QScriptValue Web3DOverlay::getProperty(const QString& property) { +QVariant Web3DOverlay::getProperty(const QString& property) { if (property == "url") { return _url; } diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h index b1715dff46..062cff61d6 100644 --- a/interface/src/ui/overlays/Web3DOverlay.h +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -32,8 +32,8 @@ public: // setters void setURL(const QString& url); - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); + void setProperties(const QVariantMap& properties) override; + QVariant getProperty(const QString& property) override; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index a1aae35063..94d9b0ae26 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,19 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { vec3.z = object.property("z").toVariant().toFloat(); } +QVariant vec3toVariant(const glm::vec3 &vec3) { + if (vec3.x != vec3.x || vec3.y != vec3.y || vec3.z != vec3.z) { + // if vec3 contains a NaN don't try to convert it + return QVariant(); + } + QVariantMap result; + result["x"] = vec3.x; + result["y"] = vec3.y; + result["z"] = vec3.z; + return result; +} + + QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector) { QScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { @@ -94,6 +108,7 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVectornewObject(); if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { @@ -195,6 +209,19 @@ glm::quat quatFromVariant(const QVariant &object) { return quatFromVariant(object, valid); } +QVariant quatToVariant(const glm::quat &quat) { + if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z) { + // if vec3 contains a NaN don't try to convert it + return QVariant(); + } + QVariantMap result; + result["x"] = quat.x; + result["y"] = quat.y; + result["z"] = quat.z; + result["w"] = quat.w; + return result; +} + QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector& vector) { QScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { @@ -333,6 +360,51 @@ void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2) { vec2.y = object.property("y").toVariant().toFloat(); } +QVariant vec2toVariant(const glm::vec2 &vec2) { + if (vec2.x != vec2.x || vec2.y != vec2.y) { + // if vec2 contains a NaN don't try to convert it + return QVariant(); + } + QVariantMap result; + result["x"] = vec2.x; + result["y"] = vec2.y; + return result; +} + +glm::vec2 vec2FromVariant(const QVariant &object, bool& isValid) { + isValid = false; + glm::vec2 result; + if (object.canConvert()) { + result = glm::vec2(object.toFloat()); + } else if (object.canConvert()) { + auto qvec2 = qvariant_cast(object); + result.x = qvec2.x(); + result.y = qvec2.y(); + } else { + auto map = object.toMap(); + auto x = map["x"]; + if (!x.isValid()) { + x = map["width"]; + } + auto y = map["y"]; + if (!y.isValid()) { + y = map["height"]; + } + if (x.isValid() && y.isValid()) { + result.x = x.toFloat(&isValid); + if (isValid) { + result.y = y.toFloat(&isValid); + } + } + } + return result; +} + +glm::vec2 vec2FromVariant(const QVariant &object) { + bool valid; + return vec2FromVariant(object, valid); +} + QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect) { QScriptValue obj = engine->newObject(); obj.setProperty("x", rect.x()); @@ -357,6 +429,38 @@ QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) { return obj; } +QVariant qRectToVariant(const QRect& rect) { + QVariantMap obj; + obj["x"] = rect.x(); + obj["y"] = rect.y(); + obj["width"] = rect.width(); + obj["height"] = rect.height(); + return obj; +} + +QRect qRectFromVariant(const QVariant& objectVar, bool& valid) { + QVariantMap object = objectVar.toMap(); + QRect rect; + valid = false; + rect.setX(object["x"].toInt(&valid)); + if (valid) { + rect.setY(object["y"].toInt(&valid)); + } + if (valid) { + rect.setWidth(object["width"].toInt(&valid)); + } + if (valid) { + rect.setHeight(object["height"].toInt(&valid)); + } + return rect; +} + +QRect qRectFromVariant(const QVariant& object) { + bool valid; + return qRectFromVariant(object, valid); +} + + void xColorFromScriptValue(const QScriptValue &object, xColor& color) { if (!object.isValid()) { return; @@ -377,6 +481,59 @@ void xColorFromScriptValue(const QScriptValue &object, xColor& color) { } } + +QVariant xColorToVariant(const xColor& color) { + QVariantMap obj; + obj["red"] = color.red; + obj["green"] = color.green; + obj["blue"] = color.blue; + return obj; +} + +xColor xColorFromVariant(const QVariant &object, bool& isValid) { + isValid = false; + xColor color { 0, 0, 0 }; + if (!object.isValid()) { + return color; + } + if (object.canConvert()) { + isValid = true; + color.red = color.green = color.blue = (uint8_t)object.toInt(); + } else if (object.canConvert()) { + QColor qcolor(object.toString()); + if (qcolor.isValid()) { + isValid = true; + color.red = (uint8_t)qcolor.red(); + color.blue = (uint8_t)qcolor.blue(); + color.green = (uint8_t)qcolor.green(); + } + } else if (object.canConvert()) { + QColor qcolor = qvariant_cast(object); + if (qcolor.isValid()) { + isValid = true; + color.red = (uint8_t)qcolor.red(); + color.blue = (uint8_t)qcolor.blue(); + color.green = (uint8_t)qcolor.green(); + } + } else { + QVariantMap map = object.toMap(); + color.red = map["red"].toInt(&isValid); + if (isValid) { + color.green = map["green"].toInt(&isValid); + } + if (isValid) { + color.blue = map["blue"].toInt(&isValid); + } + } + return color; +} + +xColor xColorFromVariant(const QVariant &object) { + bool valid; + return xColorFromVariant(object, valid); +} + + QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color) { QScriptValue object = engine->newObject(); object.setProperty("red", color.red()); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 2bec5b025e..0a3e94a5b6 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -35,48 +35,71 @@ Q_DECLARE_METATYPE(AACube) void registerMetaTypes(QScriptEngine* engine); +// Vec4 QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4); void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4); +// Vec3 QScriptValue vec3toScriptValue(QScriptEngine* engine, const glm::vec3 &vec3); void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3); +QVariant vec3toVariant(const glm::vec3 &vec3); glm::vec3 vec3FromVariant(const QVariant &object, bool& valid); glm::vec3 vec3FromVariant(const QVariant &object); +// Vec2 QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2); void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2); +QVariant vec2toVariant(const glm::vec2 &vec2); +glm::vec2 vec2FromVariant(const QVariant &object, bool& valid); +glm::vec2 vec2FromVariant(const QVariant &object); + +// Quaternions QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat); void quatFromScriptValue(const QScriptValue &object, glm::quat& quat); +QVariant quatToVariant(const glm::quat& quat); glm::quat quatFromVariant(const QVariant &object, bool& isValid); glm::quat quatFromVariant(const QVariant &object); +// Rect QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect); void qRectFromScriptValue(const QScriptValue& object, QRect& rect); +QVariant qRectToVariant(const QRect& rect); +QRect qRectFromVariant(const QVariant& object, bool& isValid); + +// xColor QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color); void xColorFromScriptValue(const QScriptValue &object, xColor& color); +QVariant xColorToVariant(const xColor& color); +xColor xColorFromVariant(const QVariant &object, bool& isValid); + +// QColor QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color); void qColorFromScriptValue(const QScriptValue& object, QColor& color); QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); void qURLFromScriptValue(const QScriptValue& object, QUrl& url); +// vector QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorVec3FromScriptValue(const QScriptValue& array, QVector& vector); QVector qVectorVec3FromScriptValue(const QScriptValue& array); +// vector QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorQuatFromScriptValue(const QScriptValue& array, QVector& vector); QVector qVectorQuatFromScriptValue(const QScriptValue& array); +// vector QScriptValue qVectorBoolToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorBoolFromScriptValue(const QScriptValue& array, QVector& vector); QVector qVectorBoolFromScriptValue(const QScriptValue& array); +// vector QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector); QVector qVectorFloatFromScriptValue(const QScriptValue& array); From 37ba0ecd9f4b6cdb94fa28279edfaf4d8f8147af Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 4 Mar 2016 11:48:55 -0800 Subject: [PATCH 244/292] MyAvatar: prevent face from being visible when crouching Overall, this should fix many of the issues with the head being visible when it shouldn't. --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 92a449f1dc..21eff99f48 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1340,11 +1340,11 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { _prevShouldDrawHead = shouldDrawHead; } -const float RENDER_HEAD_CUTOFF_DISTANCE = 0.6f; +const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f; bool MyAvatar::cameraInsideHead() const { const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); + return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { From ab5a29b076a37479295061bc764fcadaf8bea470 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Mar 2016 11:50:12 -0800 Subject: [PATCH 245/292] Bit of cleanup --- examples/toybox/flappyAvatars.js | 161 ++++++++++++------------------- 1 file changed, 60 insertions(+), 101 deletions(-) diff --git a/examples/toybox/flappyAvatars.js b/examples/toybox/flappyAvatars.js index 4c54187916..06a0a8e751 100644 --- a/examples/toybox/flappyAvatars.js +++ b/examples/toybox/flappyAvatars.js @@ -1,5 +1,6 @@ // -// flappyBird.js +// flappyAvatars.js +// examples/toybox // // Created by Clement 3/2/16 // Copyright 2015 High Fidelity, Inc. @@ -24,7 +25,7 @@ var entityManager = new EntityManager(); // Class definitions - function Bird(DEFAULT_X, DEFAULT_Y, rotation, to3DPosition) { + function Avatar(DEFAULT_X, DEFAULT_Y, rotation, to3DPosition) { var DIMENSION = 0.15; var JUMP_VELOCITY = 1.0; var xPosition = DEFAULT_X; @@ -140,11 +141,11 @@ this.update = function(deltaTime) { xPosition -= deltaTime * velocity; } - this.isColliding = function(bird) { - var deltaX = Math.abs(this.position().x - bird.position().x); - var deltaY = Math.abs(this.position().Y - bird.position().Y); - if (deltaX < (bird.dimensions().x + dimensions.x) / 2.0 && - deltaX < (bird.dimensions().y + dimensions.y) / 2.0) { + this.isColliding = function(avatar) { + var deltaX = Math.abs(this.position().x - avatar.position().x); + var deltaY = Math.abs(this.position().Y - avatar.position().Y); + if (deltaX < (avatar.dimensions().x + dimensions.x) / 2.0 && + deltaX < (avatar.dimensions().y + dimensions.y) / 2.0) { return true; } @@ -186,12 +187,12 @@ this.update = function(deltaTime) { xPosition -= deltaTime * velocity; } - this.isColliding = function(bird) { - var deltaX = Math.abs(this.position() - bird.position().x); - if (deltaX < (bird.dimensions().z + width) / 2.0) { + this.isColliding = function(avatar) { + var deltaX = Math.abs(this.position() - avatar.position().x); + if (deltaX < (avatar.dimensions().z + width) / 2.0) { var factor = 0.8; - var upDistance = (yPosition - upHeight) - (bird.position().y + bird.dimensions().y * factor); - var downDistance = (bird.position().y - bird.dimensions().y * factor) - height; + var upDistance = (yPosition - upHeight) - (avatar.position().y + avatar.dimensions().y * factor); + var downDistance = (avatar.position().y - avatar.dimensions().y * factor) - height; if (upDistance <= 0 || downDistance <= 0) { return true; } @@ -256,11 +257,11 @@ lastPipe = gameTime; } } - this.isColliding = function(bird) { + this.isColliding = function(avatar) { // Check coin collection var collected = -1; coins.forEach(function(element, index) { - if (element.isColliding(bird)) { + if (element.isColliding(avatar)) { element.clear(); collected = index; moveScore(1); @@ -281,7 +282,7 @@ var isColliding = false; pipes.forEach(function(element) { - isColliding |= element.isColliding(bird); + isColliding |= element.isColliding(avatar); }); return isColliding; @@ -321,11 +322,13 @@ var bottomOffset = Vec3.multiplyQbyV(space.orientation, { x: -0.1, y: 0.0, z: -0.2 }); var bottomLeft = Vec3.sum(space.position, bottomOffset); + var numberDimensions = { x: 0.0660, y: 0.1050, z: 0.0048 }; + function numberUrl(number) { return "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/" + number + ".fbx" } function digitPosition(digit) { - return Vec3.multiplyQbyV(space.orientation, { x: 0.3778 + digit * 0.0760, y: 0.0, z: 0.0 }); + return Vec3.multiplyQbyV(space.orientation, { x: 0.3778 + digit * (numberDimensions.x + 0.01), y: 0.0, z: 0.0 }); } this.score = function() { return score; @@ -334,6 +337,8 @@ return highScore; } + var numDigits = 3; + var bestId = entityManager.add({ type: "Model", modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/best.fbx", @@ -341,27 +346,16 @@ rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), dimensions: { x: 0.2781, y: 0.0063, z: 0.1037 } }); - var best0 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(topLeft, digitPosition(0)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var best1 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(topLeft, digitPosition(1)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var best2 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(topLeft, digitPosition(2)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); + var bestDigitsId = [] + for (var i = 0; i < numDigits; i++) { + bestDigitsId[i] = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(topLeft, digitPosition(i)), + rotation: space.orientation, + dimensions: numberDimensions + }); + } var scoreId = entityManager.add({ type: "Model", @@ -370,27 +364,16 @@ rotation: Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(90, 0, 0)), dimensions: { x: 0.3678, y: 0.0063, z: 0.1037 } }); - var score0 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(bottomLeft, digitPosition(0)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var score1 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(bottomLeft, digitPosition(1)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); - var score2 = entityManager.add({ - type: "Model", - modelURL: numberUrl(0), - position: Vec3.sum(bottomLeft, digitPosition(2)), - rotation: space.orientation, - dimensions: { x: 0.0660, y: 0.1050, z: 0.0048 } - }); + var scoreDigitsId = [] + for (var i = 0; i < numDigits; i++) { + scoreDigitsId[i] = entityManager.add({ + type: "Model", + modelURL: numberUrl(0), + position: Vec3.sum(bottomLeft, digitPosition(i)), + rotation: space.orientation, + dimensions: numberDimensions + }); + } this.moveScore = function(delta) { score += delta; @@ -403,13 +386,13 @@ } this.draw = function() { - Entities.editEntity(best0, { modelURL: numberUrl(Math.floor((highScore / 100) % 10)) }); - Entities.editEntity(best1, { modelURL: numberUrl(Math.floor((highScore / 10) % 10)) }); - Entities.editEntity(best2, { modelURL: numberUrl(Math.floor((highScore / 1) % 10)) }); + for (var i = 0; i < numDigits; i++) { + Entities.editEntity(bestDigitsId[i], { modelURL: numberUrl(Math.floor((highScore / Math.pow(10, numDigits- i - 1)) % 10)) }); + } - Entities.editEntity(score0, { modelURL: numberUrl(Math.floor((score / 100) % 10)) }); - Entities.editEntity(score1, { modelURL: numberUrl(Math.floor((score / 10) % 10)) }); - Entities.editEntity(score2, { modelURL: numberUrl(Math.floor((score / 1) % 10)) }); + for (var i = 0; i < numDigits; i++) { + Entities.editEntity(scoreDigitsId[i], { modelURL: numberUrl(Math.floor(score / Math.pow(10, numDigits - i - 1)) % 10) }); + } } } @@ -444,12 +427,6 @@ draw(); timestamp = now; } - // this.keyPressed = function(event) { - // if (event.text === "SPACE" && (gameTime - lastLost) > coolDown) { - // isJumping = true; - // startedPlaying = true; - // } - // } // Constants var spaceDimensions = { x: 2.0, y: 1.5, z: 0.01 }; @@ -471,9 +448,8 @@ var lastTriggerValue = 0.0; var TRIGGER_THRESHOLD = 0.9; - var space = null - var board = null; - var bird = null; + var space = null; + var avatar = null; var pipes = null; var score = null; @@ -490,8 +466,7 @@ current = 0; } if (current === sequence.length) { - print("KONAMI CODE!!!"); - bird.changeModel("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/mario.fbx"); + avatar.changeModel("https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/mario.fbx"); current = 0; } } @@ -510,24 +485,14 @@ } function setup() { - print("setup"); - space = { position: getSpacePosition(), orientation: getSpaceOrientation(), dimensions: getSpaceDimensions() } - // board = entityManager.add({ - // type: "Box", - // position: space.position, - // rotation: space.orientation, - // dimensions: space.dimensions, - // color: { red: 100, green: 200, blue: 200 } - // }); - var rotation = Quat.multiply(space.orientation, Quat.fromPitchYawRollDegrees(0, 90, 0)); - bird = new Bird(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); + avatar = new Avatar(space.dimensions.x / 2.0, space.dimensions.y / 2.0, rotation, to3DPosition); pipes = new Pipes(space.dimensions.x, space.dimensions.y, to3DPosition, moveScore); score = new Score(space, bestScore); @@ -536,7 +501,7 @@ function inputs(triggerValue) { if (!startedPlaying && !isBoardReset && (gameTime - lastLost) > coolDown) { score.resetScore(); - bird.reset(); + avatar.reset(); pipes.clear(); isBoardReset = true; @@ -551,8 +516,6 @@ lastTriggerValue = triggerValue; } function update(deltaTime) { - //print("update: " + deltaTime); - // Keep entities alive entityManager.update(deltaTime); @@ -560,29 +523,27 @@ return; } - // Update Bird - if (!startedPlaying && bird.position().y < spaceDimensions.y / 2.0) { + // Update Avatar + if (!startedPlaying && avatar.position().y < spaceDimensions.y / 2.0) { isJumping = true; } // Apply jumps if (isJumping) { - bird.jump(); + avatar.jump(); isJumping = false; } - bird.update(deltaTime); + avatar.update(deltaTime); pipes.update(deltaTime, gameTime, startedPlaying); // Check lost - var hasLost = bird.position().y < 0.0 || - bird.position().y > space.dimensions.y || - pipes.isColliding(bird); + var hasLost = avatar.position().y < 0.0 || + avatar.position().y > space.dimensions.y || + pipes.isColliding(avatar); // Cleanup if (hasLost) { - print("Game Over!"); - if (gameOverSound.downloaded && !injector) { injector = Audio.playSound(gameOverSound, { position: space.position, volume: 0.4 }); } else if (injector) { @@ -595,13 +556,11 @@ } } function draw() { - //print("draw"); - bird.draw(); + avatar.draw(); pipes.draw(); score.draw(); } function cleanup() { - print("cleanup"); entityManager.removeAll(); Controller.keyPressEvent.disconnect(keyPress); From 3a5165ab6642c8f46dac6ed2886e69f9924b5fb8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Mar 2016 11:52:42 -0800 Subject: [PATCH 246/292] Add json import for game entity --- .../{ => flappyAvatars}/flappyAvatars.js | 0 .../toybox/flappyAvatars/flappyAvatars.json | 34 +++++++++++++++++++ 2 files changed, 34 insertions(+) rename examples/toybox/{ => flappyAvatars}/flappyAvatars.js (100%) create mode 100644 examples/toybox/flappyAvatars/flappyAvatars.json diff --git a/examples/toybox/flappyAvatars.js b/examples/toybox/flappyAvatars/flappyAvatars.js similarity index 100% rename from examples/toybox/flappyAvatars.js rename to examples/toybox/flappyAvatars/flappyAvatars.js diff --git a/examples/toybox/flappyAvatars/flappyAvatars.json b/examples/toybox/flappyAvatars/flappyAvatars.json new file mode 100644 index 0000000000..ed6dae8851 --- /dev/null +++ b/examples/toybox/flappyAvatars/flappyAvatars.json @@ -0,0 +1,34 @@ +{ + "Entities": [ + { + "collisionsWillMove": 1, + "created": "2016-03-03T19:00:10Z", + "dimensions": { + "x": 0.11497055739164352, + "y": 0.11497056484222412, + "z": 0.11497056484222412 + }, + "dynamic": 1, + "id": "{ee5b25e6-aca2-4dc7-9462-51537d89c126}", + "modelURL": "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/cube.fbx", + "queryAACube": { + "scale": 0.5974045991897583, + "x": -5.1575918197631836, + "y": 23.078603744506836, + "z": 16.521066665649414 + }, + "rotation": { + "w": 0.92288088798522949, + "x": -0.10148775577545166, + "y": -0.13279926776885986, + "z": 0.34688329696655273 + }, + "script": "https://raw.githubusercontent.com/Atlante45/hifi/feat/hackaton/examples/toybox/flappyAvatars/flappyAvatars.js", + "scriptTimestamp": 1457031937425, + "shapeType": "box", + "type": "Model", + "userData": "{\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.07079616189002991,\"y\":0.20177987217903137,\"z\":0.06374628841876984},{\"x\":-0.5863648653030396,\"y\":-0.46007341146469116,\"z\":0.46949487924575806,\"w\":-0.4733745753765106}],\"LeftHand\":[{\"x\":-0.018704339861869812,\"y\":0.20499876141548157,\"z\":0.08445858210325241},{\"x\":0.2061777561903,\"y\":-0.6629757881164551,\"z\":0.5865269303321838,\"w\":0.41706138849258423}]}},\"grabbableKey\":{\"invertSolidWhileHeld\":true},\"resetMe\":{\"resetMe\":true},\"highScore\":0}" + } + ], + "Version": 57 +} From efa46b8c7b5c5d42a7a48a49cd9311cc0b50b3d8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Mar 2016 11:58:46 -0800 Subject: [PATCH 247/292] add option to disable AC child file logging --- assignment-client/src/AssignmentClientApp.cpp | 21 +++-- assignment-client/src/AssignmentClientApp.h | 1 + .../src/AssignmentClientMonitor.cpp | 88 +++++++++++-------- .../src/AssignmentClientMonitor.h | 5 +- 4 files changed, 71 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 3a962d72d2..3ce56266ec 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -96,6 +96,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory"); parser.addOption(logDirectoryOption); + const QCommandLineOption noLogFileOption(ASSIGNMENT_NO_CHILD_LOG_FILE_OPTION, "disable writing of child assignment-client output to file"); + parser.addOption(noLogFileOption); + if (!parser.parse(QCoreApplication::arguments())) { qCritical() << parser.errorText() << endl; parser.showHelp(); @@ -139,13 +142,20 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : httpStatusPort = parser.value(httpStatusPortOption).toUShort(); } + bool wantsChildFileLogging = false; QDir logDirectory { "." }; - if (parser.isSet(logDirectoryOption)) { - logDirectory = parser.value(logDirectoryOption); - } else { - logDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + + if (!parser.isSet(noLogFileOption)) { + wantsChildFileLogging = true; + + if (parser.isSet(logDirectoryOption)) { + logDirectory = parser.value(logDirectoryOption); + } else { + logDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + } } + Assignment::Type requestAssignmentType = Assignment::AllTypes; if (argumentVariantMap.contains(ASSIGNMENT_TYPE_OVERRIDE_OPTION)) { requestAssignmentType = (Assignment::Type) argumentVariantMap.value(ASSIGNMENT_TYPE_OVERRIDE_OPTION).toInt(); @@ -216,7 +226,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, listenPort, walletUUID, assignmentServerHostname, - assignmentServerPort, httpStatusPort, logDirectory); + assignmentServerPort, httpStatusPort, logDirectory, + wantsChildFileLogging); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); } else { diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index 37d3b9cc1d..ce3c3a76fa 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -27,6 +27,7 @@ const QString ASSIGNMENT_MAX_FORKS_OPTION = "max"; const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port"; const QString ASSIGNMENT_HTTP_STATUS_PORT = "http-status-port"; const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory"; +const QString ASSIGNMENT_NO_CHILD_LOG_FILE_OPTION = "no-child-log-files"; class AssignmentClientApp : public QCoreApplication { Q_OBJECT diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index f76434d9c7..7c9bb47467 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -33,7 +33,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory) : + quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory, + bool wantsChildFileLogging) : _logDirectory(logDirectory), _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), @@ -43,7 +44,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen _assignmentPool(assignmentPool), _walletUUID(walletUUID), _assignmentServerHostname(assignmentServerHostname), - _assignmentServerPort(assignmentServerPort) + _assignmentServerPort(assignmentServerPort), + _wantsChildFileLogging(wantsChildFileLogging) { qDebug() << "_requestAssignmentType =" << _requestAssignmentType; @@ -159,52 +161,61 @@ void AssignmentClientMonitor::spawnChildClient() { _childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION); _childArguments.append(QString::number(DependencyManager::get()->getLocalSockAddr().getPort())); - // Setup log files - const QString DATETIME_FORMAT = "yyyyMMdd.hh.mm.ss.zzz"; + QString nowString, stdoutFilenameTemp, stderrFilenameTemp, stdoutPathTemp, stderrPathTemp; - if (!_logDirectory.exists()) { - qDebug() << "Log directory (" << _logDirectory.absolutePath() << ") does not exist, creating."; - _logDirectory.mkpath(_logDirectory.absolutePath()); + + if (_wantsChildFileLogging) { + // Setup log files + const QString DATETIME_FORMAT = "yyyyMMdd.hh.mm.ss.zzz"; + + if (!_logDirectory.exists()) { + qDebug() << "Log directory (" << _logDirectory.absolutePath() << ") does not exist, creating."; + _logDirectory.mkpath(_logDirectory.absolutePath()); + } + + nowString = QDateTime::currentDateTime().toString(DATETIME_FORMAT); + stdoutFilenameTemp = QString("ac-%1-stdout.txt").arg(nowString); + stderrFilenameTemp = QString("ac-%1-stderr.txt").arg(nowString); + stdoutPathTemp = _logDirectory.absoluteFilePath(stdoutFilenameTemp); + stderrPathTemp = _logDirectory.absoluteFilePath(stderrFilenameTemp); + + // reset our output and error files + assignmentClient->setStandardOutputFile(stdoutPathTemp); + assignmentClient->setStandardErrorFile(stderrPathTemp); } - auto nowString = QDateTime::currentDateTime().toString(DATETIME_FORMAT); - auto stdoutFilenameTemp = QString("ac-%1-stdout.txt").arg(nowString); - auto stderrFilenameTemp = QString("ac-%1-stderr.txt").arg(nowString); - QString stdoutPathTemp = _logDirectory.absoluteFilePath(stdoutFilenameTemp); - QString stderrPathTemp = _logDirectory.absoluteFilePath(stderrFilenameTemp); - - // reset our output and error files - assignmentClient->setStandardOutputFile(stdoutPathTemp); - assignmentClient->setStandardErrorFile(stderrPathTemp); - // make sure that the output from the child process appears in our output assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels); - assignmentClient->start(QCoreApplication::applicationFilePath(), _childArguments); - // Update log path to use PID in filename - auto stdoutFilename = QString("ac-%1_%2-stdout.txt").arg(nowString).arg(assignmentClient->processId()); - auto stderrFilename = QString("ac-%1_%2-stderr.txt").arg(nowString).arg(assignmentClient->processId()); - QString stdoutPath = _logDirectory.absoluteFilePath(stdoutFilename); - QString stderrPath = _logDirectory.absoluteFilePath(stderrFilename); + QString stdoutPath, stderrPath; - qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath; - if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) { - qDebug() << "Failed to rename " << stdoutFilenameTemp; - stdoutPath = stdoutPathTemp; - stdoutFilename = stdoutFilenameTemp; + if (_wantsChildFileLogging) { + + // Update log path to use PID in filename + auto stdoutFilename = QString("ac-%1_%2-stdout.txt").arg(nowString).arg(assignmentClient->processId()); + auto stderrFilename = QString("ac-%1_%2-stderr.txt").arg(nowString).arg(assignmentClient->processId()); + stdoutPath = _logDirectory.absoluteFilePath(stdoutFilename); + stderrPath = _logDirectory.absoluteFilePath(stderrFilename); + + qDebug() << "Renaming " << stdoutPathTemp << " to " << stdoutPath; + if (!_logDirectory.rename(stdoutFilenameTemp, stdoutFilename)) { + qDebug() << "Failed to rename " << stdoutFilenameTemp; + stdoutPath = stdoutPathTemp; + stdoutFilename = stdoutFilenameTemp; + } + + qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath; + if (!QFile::rename(stderrPathTemp, stderrPath)) { + qDebug() << "Failed to rename " << stderrFilenameTemp; + stderrPath = stderrPathTemp; + stderrFilename = stderrFilenameTemp; + } + + qDebug() << "Child stdout being written to: " << stdoutFilename; + qDebug() << "Child stderr being written to: " << stderrFilename; } - qDebug() << "Renaming " << stderrPathTemp << " to " << stderrPath; - if (!QFile::rename(stderrPathTemp, stderrPath)) { - qDebug() << "Failed to rename " << stderrFilenameTemp; - stderrPath = stderrPathTemp; - stderrFilename = stderrFilenameTemp; - } - - qDebug() << "Child stdout being written to: " << stdoutFilename; - qDebug() << "Child stderr being written to: " << stderrFilename; - if (assignmentClient->processId() > 0) { auto pid = assignmentClient->processId(); // make sure we hear that this process has finished when it does @@ -212,6 +223,7 @@ void AssignmentClientMonitor::spawnChildClient() { this, [this, pid]() { childProcessFinished(pid); }); qDebug() << "Spawned a child client with PID" << assignmentClient->processId(); + _childProcesses.insert(assignmentClient->processId(), { assignmentClient, stdoutPath, stderrPath }); } } diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index a5ae3cd1af..c04294d5b3 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -38,7 +38,8 @@ public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory); + quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory, + bool wantsChildFileLogging); ~AssignmentClientMonitor(); void stopChildProcesses(); @@ -73,6 +74,8 @@ private: quint16 _assignmentServerPort; QMap _childProcesses; + + bool _wantsChildFileLogging; }; #endif // hifi_AssignmentClientMonitor_h From 0b578bf08661b866d548053d535c04e56bce44fc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Mar 2016 12:56:35 -0800 Subject: [PATCH 248/292] only enable logging if a log directory is passed --- assignment-client/src/AssignmentClientApp.cpp | 19 ++++--------------- assignment-client/src/AssignmentClientApp.h | 1 - .../src/AssignmentClientMonitor.cpp | 12 +++++++----- .../src/AssignmentClientMonitor.h | 5 ++--- 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 3ce56266ec..c425a239dd 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -96,9 +96,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory"); parser.addOption(logDirectoryOption); - const QCommandLineOption noLogFileOption(ASSIGNMENT_NO_CHILD_LOG_FILE_OPTION, "disable writing of child assignment-client output to file"); - parser.addOption(noLogFileOption); - if (!parser.parse(QCoreApplication::arguments())) { qCritical() << parser.errorText() << endl; parser.showHelp(); @@ -142,17 +139,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : httpStatusPort = parser.value(httpStatusPortOption).toUShort(); } - bool wantsChildFileLogging = false; - QDir logDirectory { "." }; + QString logDirectory; - if (!parser.isSet(noLogFileOption)) { - wantsChildFileLogging = true; - - if (parser.isSet(logDirectoryOption)) { - logDirectory = parser.value(logDirectoryOption); - } else { - logDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - } + if (parser.isSet(logDirectoryOption)) { + logDirectory = parser.value(logDirectoryOption); } @@ -226,8 +216,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, requestAssignmentType, assignmentPool, listenPort, walletUUID, assignmentServerHostname, - assignmentServerPort, httpStatusPort, logDirectory, - wantsChildFileLogging); + assignmentServerPort, httpStatusPort, logDirectory); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); } else { diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index ce3c3a76fa..37d3b9cc1d 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -27,7 +27,6 @@ const QString ASSIGNMENT_MAX_FORKS_OPTION = "max"; const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port"; const QString ASSIGNMENT_HTTP_STATUS_PORT = "http-status-port"; const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory"; -const QString ASSIGNMENT_NO_CHILD_LOG_FILE_OPTION = "no-child-log-files"; class AssignmentClientApp : public QCoreApplication { Q_OBJECT diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 7c9bb47467..322fe6e57e 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -33,9 +33,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory, - bool wantsChildFileLogging) : - _logDirectory(logDirectory), + quint16 assignmentServerPort, quint16 httpStatusServerPort, QString logDirectory) : _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), _minAssignmentClientForks(minAssignmentClientForks), @@ -44,12 +42,16 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen _assignmentPool(assignmentPool), _walletUUID(walletUUID), _assignmentServerHostname(assignmentServerHostname), - _assignmentServerPort(assignmentServerPort), - _wantsChildFileLogging(wantsChildFileLogging) + _assignmentServerPort(assignmentServerPort) { qDebug() << "_requestAssignmentType =" << _requestAssignmentType; + if (!logDirectory.isEmpty()) { + _wantsChildFileLogging = true; + _logDirectory = QDir(logDirectory); + } + // start the Logging class with the parent's target name LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index c04294d5b3..a7f69a559b 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -38,8 +38,7 @@ public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, quint16 httpStatusServerPort, QDir logDirectory, - bool wantsChildFileLogging); + quint16 assignmentServerPort, quint16 httpStatusServerPort, QString logDirectory); ~AssignmentClientMonitor(); void stopChildProcesses(); @@ -75,7 +74,7 @@ private: QMap _childProcesses; - bool _wantsChildFileLogging; + bool _wantsChildFileLogging { false }; }; #endif // hifi_AssignmentClientMonitor_h From b4c489d4c6ec393ce320d85e43625b4bedd0667a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Mar 2016 10:17:39 +1300 Subject: [PATCH 249/292] Fix not reliably being able to select "None" in Graphics settings --- interface/resources/qml/controls-uit/ComboBox.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index bad1524719..392d5534c8 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -148,6 +148,7 @@ FocusScope { function previousItem() { listView.currentIndex = (listView.currentIndex + listView.count - 1) % listView.count; } function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; } function selectCurrentItem() { root.currentIndex = listView.currentIndex; hideList(); } + function selectSpecificItem(index) { root.currentIndex = index; hideList(); } Keys.onUpPressed: previousItem(); Keys.onDownPressed: nextItem(); @@ -182,7 +183,7 @@ FocusScope { anchors.fill: parent; hoverEnabled: true onEntered: listView.currentIndex = index; - onClicked: popup.selectCurrentItem() + onClicked: popup.selectSpecificItem(index) } } } From c9cd8eeba62796e761e2889c22f226548cceab75 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:27:43 -0800 Subject: [PATCH 250/292] fix a couple bugs --- examples/tests/avatarAttachmentTest.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/tests/avatarAttachmentTest.js b/examples/tests/avatarAttachmentTest.js index 23b94ba8d5..fff2355ce6 100644 --- a/examples/tests/avatarAttachmentTest.js +++ b/examples/tests/avatarAttachmentTest.js @@ -15,16 +15,17 @@ // Toggle button helper function ToggleButtonBuddy(x, y, width, height, urls) { + print("ToggleButtonBuddy() "+ x+ "," + y + "[" + width + ","+height+"] " + urls); this.up = Overlays.addOverlay("image", { x: x, y: y, width: width, height: height, - subImage: { x: 0, y: height, width: width, height: height}, + subImage: { x: 0, y: 0, width: width, height: height}, imageURL: urls.up, visible: true, alpha: 1.0 }); this.down = Overlays.addOverlay("image", { x: x, y: y, width: width, height: height, - subImage: { x: 0, y: height, width: width, height: height}, + subImage: { x: 0, y: 0, width: width, height: height}, imageURL: urls.down, visible: false, alpha: 1.0 @@ -48,6 +49,7 @@ function ToggleButtonBuddy(x, y, width, height, urls) { }); } ToggleButtonBuddy.prototype.destroy = function () { + print("ToggleButtonBuddy.prototype.destroy() this.up:" + this.up + " this.down:" + this.down); Overlays.deleteOverlay(this.up); Overlays.deleteOverlay(this.down); }; @@ -120,7 +122,6 @@ coatButton.addToggleHandler(function (isDown) { } }); - function wearAttachment(attachment) { MyAvatar.attach(attachment.modelURL, attachment.jointName, @@ -144,5 +145,5 @@ function removeAttachment(attachment) { Script.scriptEnding.connect(function() { hatButton.destroy(); - coatbutton.destroy(); + coatButton.destroy(); }); From 0de19d13c4b0af5c3ab285f3d9f5f61140646da3 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 4 Mar 2016 15:28:38 -0800 Subject: [PATCH 251/292] MyAvatar: open up horizontal leaning threshold --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 21eff99f48..642af5c3e9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1944,7 +1944,7 @@ bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, co bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { - const float CYLINDER_RADIUS = 0.15f; + const float CYLINDER_RADIUS = 0.3f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); glm::vec3 radialOffset(offset.x, 0.0f, offset.z); From 21b66354efe06e4f6be2e19b4d72c4a3486d5a1b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:28:49 -0800 Subject: [PATCH 252/292] remove debug line --- examples/tests/avatarAttachmentTest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tests/avatarAttachmentTest.js b/examples/tests/avatarAttachmentTest.js index fff2355ce6..6b49fdba34 100644 --- a/examples/tests/avatarAttachmentTest.js +++ b/examples/tests/avatarAttachmentTest.js @@ -49,7 +49,6 @@ function ToggleButtonBuddy(x, y, width, height, urls) { }); } ToggleButtonBuddy.prototype.destroy = function () { - print("ToggleButtonBuddy.prototype.destroy() this.up:" + this.up + " this.down:" + this.down); Overlays.deleteOverlay(this.up); Overlays.deleteOverlay(this.down); }; From add7f54af34c926de764680b64ef6afc815f2d0b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:29:32 -0800 Subject: [PATCH 253/292] remove debug line --- examples/tests/avatarAttachmentTest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tests/avatarAttachmentTest.js b/examples/tests/avatarAttachmentTest.js index 6b49fdba34..f287013979 100644 --- a/examples/tests/avatarAttachmentTest.js +++ b/examples/tests/avatarAttachmentTest.js @@ -15,7 +15,6 @@ // Toggle button helper function ToggleButtonBuddy(x, y, width, height, urls) { - print("ToggleButtonBuddy() "+ x+ "," + y + "[" + width + ","+height+"] " + urls); this.up = Overlays.addOverlay("image", { x: x, y: y, width: width, height: height, subImage: { x: 0, y: 0, width: width, height: height}, From d8e7c60ce0a5f5d484e83719e65ce63bbccaa5eb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:47:25 -0800 Subject: [PATCH 254/292] CR feedback --- examples/entityScripts/lighteningEntity.js | 168 ++++++++++----------- examples/shaders/rainyDayNightSkybox.fs | 13 +- examples/zones/RainyDayNightZone.json | 10 +- 3 files changed, 95 insertions(+), 96 deletions(-) diff --git a/examples/entityScripts/lighteningEntity.js b/examples/entityScripts/lighteningEntity.js index 67cc6c8ea6..40c5364a6a 100644 --- a/examples/entityScripts/lighteningEntity.js +++ b/examples/entityScripts/lighteningEntity.js @@ -1,11 +1,11 @@ // -// lighteningEntity.js +// lightningEntity.js // examples/entityScripts // // Created by Brad Hefta-Gaub on 3/1/16. // Copyright 2016 High Fidelity, Inc. // -// This is an example of an entity script which will randomly create a flash of lightening and a thunder sound +// This is an example of an entity script which will randomly create a flash of lightning and a thunder sound // effect, as well as a background rain sound effect. It can be applied to any entity, although it works best // on a zone entity. // @@ -21,31 +21,31 @@ // // You can change these values to change some of the various effects of the rain storm. // These values can also be controlled by setting user properties on the entity that you've attached this script to. - // add a "lightening" section to a JSON encoded portion of the user data... for example: + // add a "lightning" section to a JSON encoded portion of the user data... for example: // { - // "lightening": { + // "lightning": { // "flashMax": 20, // "flashMin": 0, // "flashMaxRandomness": 10, // "flashIntensityStepRandomeness": 2, // "averageLighteningStrikeGap": 120, - // "extraRandomRangeLighteningStrikeGap": 10, + // "extraRandomRangeLightningStrikeGap": 10, // "thunderURL": "atp:1336efe995398f5e0d46b37585785de8ba872fe9a9b718264db03748cd41c758.wav", // "thunderVolume": 0.1, // "rainURL": "atp:e0cc7438aca776636f6e6f731685781d9999b961c945e4e5760d937be5beecdd.wav", // "rainVolume": 0.05 // } - // // NOTE: you can have other user data here as well, so long as it's JSON encoded, it won't impact the lightening script + // // NOTE: you can have other user data here as well, so long as it's JSON encoded, it won't impact the lightning script // } // //////////////////////////////////////////////////////////////////////////////////////////////////////////// - var MAX_FLASH_INTENSITY = 20; // this controls how bright the lightening effect appears - var MIN_FLASH_INTENSITY = 0; // this is probably best at 0, but it could be higher, which will make the lightening not fade completely to darkness before going away. - var MAX_FLASH_INTENSITY_RANDOMNESS = 10; // this will add some randomness to the max brightness of the lightening - var FLASH_INTENSITY_STEP_RANDOMNESS = 2; // as the lightening goes from min to max back to min, this will make it more random in it's brightness - var AVERAGE_LIGHTENING_STRIKE_GAP_IN_SECONDS = 120; // how long on average between lighting - var EXTRA_RANDOM_RANGE_LIGHTENING_STRIKE_GAP_IN_SECONDS = 10; // some randomness to the lightening gap + var MAX_FLASH_INTENSITY = 20; // this controls how bright the lightning effect appears + var MIN_FLASH_INTENSITY = 0; // this is probably best at 0, but it could be higher, which will make the lightning not fade completely to darkness before going away. + var MAX_FLASH_INTENSITY_RANDOMNESS = 10; // this will add some randomness to the max brightness of the lightning + var FLASH_INTENSITY_STEP_RANDOMNESS = 2; // as the lightning goes from min to max back to min, this will make it more random in it's brightness + var AVERAGE_LIGHTNING_STRIKE_GAP_IN_SECONDS = 120; // how long on average between lighting + var EXTRA_RANDOM_RANGE_LIGHTNING_STRIKE_GAP_IN_SECONDS = 10; // some randomness to the lightning gap var THUNDER_SOUND_URL = "https://s3.amazonaws.com/hifi-public/brad/rainstorm/thunder-48k.wav"; // thunder sound effect, must be 48k 16bit PCM var THUNDER_VOLUME = 1; // adjust the volume of the thunder sound effect var RAIN_SOUND_URL = "https://s3.amazonaws.com/hifi-public/brad/rainstorm/rain.wav"; // the background rain, this will loop @@ -84,7 +84,7 @@ } // the "constructor" for our class. pretty simple, it just sets our _this, so we can access it later. - function Lightening() { + function Lightning() { _this = this; } @@ -94,7 +94,7 @@ // This is the class definition/prototype for our class. Funtions declared here will be accessible // via the instance of the entity // - Lightening.prototype = { + Lightning.prototype = { // preload() // This is called by every viewer/interface instance that "sees" the entity you've attached this script to. @@ -110,8 +110,8 @@ _this.lastStrike = now; // some of our other state related items - _this.lighteningID = false; // this will be the entityID for any lightening that we create - _this.lighteningActive = false; // are we actively managing lightening + _this.lightningID = false; // this will be the entityID for any lightning that we create + _this.lightningActive = false; // are we actively managing lightning // Get the entities userData property, to see if someone has overridden any of our default settings var userDataText = Entities.getEntityProperties(entityID, ["userData"]).userData; @@ -119,21 +119,21 @@ if (userDataText !== "") { userData = JSON.parse(userDataText); } - var lighteningUserData = valueOrDefault(userData.lightening, {}); - _this.flashIntensityStepRandomeness = valueOrDefault(lighteningUserData.flashIntensityStepRandomness, FLASH_INTENSITY_STEP_RANDOMNESS); - _this.flashMax = valueOrDefault(lighteningUserData.flashMax, MAX_FLASH_INTENSITY); - _this.flashMin = valueOrDefault(lighteningUserData.flashMin, MIN_FLASH_INTENSITY); - _this.flashMaxRandomness = valueOrDefault(lighteningUserData.flashMaxRandomness, MAX_FLASH_INTENSITY_RANDOMNESS); - _this.averageLighteningStrikeGap = valueOrDefault(lighteningUserData.averageLighteningStrikeGap, AVERAGE_LIGHTENING_STRIKE_GAP_IN_SECONDS); - _this.extraRandomRangeLighteningStrikeGap = valueOrDefault(lighteningUserData.extraRandomRangeLighteningStrikeGap, EXTRA_RANDOM_RANGE_LIGHTENING_STRIKE_GAP_IN_SECONDS); + var lightningUserData = valueOrDefault(userData.lightning, {}); + _this.flashIntensityStepRandomeness = valueOrDefault(lightningUserData.flashIntensityStepRandomness, FLASH_INTENSITY_STEP_RANDOMNESS); + _this.flashMax = valueOrDefault(lightningUserData.flashMax, MAX_FLASH_INTENSITY); + _this.flashMin = valueOrDefault(lightningUserData.flashMin, MIN_FLASH_INTENSITY); + _this.flashMaxRandomness = valueOrDefault(lightningUserData.flashMaxRandomness, MAX_FLASH_INTENSITY_RANDOMNESS); + _this.averageLightningStrikeGap = valueOrDefault(lightningUserData.averageLightningStrikeGap, AVERAGE_LIGHTNING_STRIKE_GAP_IN_SECONDS); + _this.extraRandomRangeLightningStrikeGap = valueOrDefault(lightningUserData.extraRandomRangeLightningStrikeGap, EXTRA_RANDOM_RANGE_LIGHTNING_STRIKE_GAP_IN_SECONDS); - var thunderURL = valueOrDefault(lighteningUserData.thunderURL, THUNDER_SOUND_URL); + var thunderURL = valueOrDefault(lightningUserData.thunderURL, THUNDER_SOUND_URL); _this.thunderSound = SoundCache.getSound(thunderURL); // start downloading the thunder into the cache in case we need it later - _this.thunderVolume = valueOrDefault(lighteningUserData.thunderVolume, THUNDER_VOLUME); + _this.thunderVolume = valueOrDefault(lightningUserData.thunderVolume, THUNDER_VOLUME); - var rainURL = valueOrDefault(lighteningUserData.rainURL, RAIN_SOUND_URL); + var rainURL = valueOrDefault(lightningUserData.rainURL, RAIN_SOUND_URL); _this.rainSound = SoundCache.getSound(rainURL); // start downloading the rain, we will be using it for sure - _this.rainVolume = valueOrDefault(lighteningUserData.rainVolume, RAIN_VOLUME); + _this.rainVolume = valueOrDefault(lightningUserData.rainVolume, RAIN_VOLUME); _this.rainPlaying = false; Script.update.connect(_this.onUpdate); // connect our onUpdate to a regular update signal from the interface @@ -167,17 +167,17 @@ _this.rainPlaying = true; }, - // this handles a single "step" of the lightening flash effect. It assumes a light entity has already been created, + // this handles a single "step" of the lightning flash effect. It assumes a light entity has already been created, // and all it really does is change the intensity of the light based on the settings that are part of this entity's // userData. - flashLightening: function (lighteningID) { - var lighteningProperties = Entities.getEntityProperties(lighteningID, ["userData", "intensity"]); - var lighteningParameters = JSON.parse(lighteningProperties.userData); - var currentIntensity = lighteningProperties.intensity; - var flashDirection = lighteningParameters.flashDirection; - var flashMax = lighteningParameters.flashMax; - var flashMin = lighteningParameters.flashMin; - var flashIntensityStepRandomeness = lighteningParameters.flashIntensityStepRandomeness; + flashLightning: function (lightningID) { + var lightningProperties = Entities.getEntityProperties(lightningID, ["userData", "intensity"]); + var lightningParameters = JSON.parse(lightningProperties.userData); + var currentIntensity = lightningProperties.intensity; + var flashDirection = lightningParameters.flashDirection; + var flashMax = lightningParameters.flashMax; + var flashMin = lightningParameters.flashMin; + var flashIntensityStepRandomeness = lightningParameters.flashIntensityStepRandomeness; var newIntensity = currentIntensity + flashDirection + randFloat(-flashIntensityStepRandomeness, flashIntensityStepRandomeness); if (flashDirection > 0) { @@ -194,14 +194,14 @@ // if we reached 0 intensity, then we're done with this strike... if (newIntensity === 0) { - _this.lighteningActive = false; - Entities.deleteEntity(lighteningID); + _this.lightningActive = false; + Entities.deleteEntity(lightningID); } // FIXME - we probably don't need to re-edit the userData of the light... we're only // changing direction, the rest are the same... we could just store direction in our // own local variable state - var newLighteningParameters = JSON.stringify({ + var newLightningParameters = JSON.stringify({ flashDirection: flashDirection, flashIntensityStepRandomeness: flashIntensityStepRandomeness, flashMax: flashMax, @@ -209,31 +209,31 @@ }); // this is what actually creates the effect, changing the intensity of the light - Entities.editEntity(lighteningID, {intensity: newIntensity, userData: newLighteningParameters}); + Entities.editEntity(lightningID, {intensity: newIntensity, userData: newLightningParameters}); }, - // findMyLightening() is designed to make the script more robust. Since we're an open editable platform - // it's possible that from the time that we started the lightening effect until "now" when we're attempting + // findMyLightning() is designed to make the script more robust. Since we're an open editable platform + // it's possible that from the time that we started the lightning effect until "now" when we're attempting // to change the light, some other client might have deleted our light. Before we proceed in editing // the light, we check to see if it exists. - findMyLightening: function () { - if (_this.lighteningID !== false) { - var lighteningName = Entities.getEntityProperties(_this.lighteningID, "name").name; - if (lighteningName !== undefined) { - return _this.lighteningID; + findMyLightning: function () { + if (_this.lightningID !== false) { + var lightningName = Entities.getEntityProperties(_this.lightningID, "name").name; + if (lightningName !== undefined) { + return _this.lightningID; } } return false; }, - // findOtherLightening() is designed to allow this script to work in a "multi-user" environment, which we + // findOtherLightning() is designed to allow this script to work in a "multi-user" environment, which we // must assume we are in. Since every user/viewer/client that connect to the domain and "sees" our entity - // is going to run this script, any of them could be in charge of flashing the lightening. So before we - // start to flash the lightening, we will first check to see if someone else already is. + // is going to run this script, any of them could be in charge of flashing the lightning. So before we + // start to flash the lightning, we will first check to see if someone else already is. // - // returns true if some other lightening exists... likely because some other viewer is flashing it - // returns false if no other lightening exists... - findOtherLightening: function () { + // returns true if some other lightning exists... likely because some other viewer is flashing it + // returns false if no other lightning exists... + findOtherLightning: function () { var myPosition = Entities.getEntityProperties(_this.entityID, "position").position; // find all entities near me... @@ -245,20 +245,20 @@ checkEntityID = entities[entity]; checkProperties = Entities.getEntityProperties(checkEntityID, ["name", "type"]); - // check to see if they are lightening - if (checkProperties.type === "Light" && checkProperties.name === "lightening for creator:" + _this.entityID) { + // check to see if they are lightning + if (checkProperties.type === "Light" && checkProperties.name === "lightning for creator:" + _this.entityID) { return true; } } return false; }, - // createNewLightening() actually creates new lightening and plays the thunder sound - createNewLightening: function () { + // createNewLightning() actually creates new lightning and plays the thunder sound + createNewLightning: function () { var myPosition = Entities.getEntityProperties(_this.entityID, "position").position; - _this.lighteningID = Entities.addEntity({ + _this.lightningID = Entities.addEntity({ type: "Light", - name: "lightening for creator:" + _this.entityID, + name: "lightning for creator:" + _this.entityID, userData: JSON.stringify({ flashDirection: 1, flashIntensityStepRandomeness: _this.flashIntensityStepRandomeness, @@ -271,7 +271,7 @@ collisionless: true, dimensions: {x: 1000, y: 1000, z: 1000}, color: {red: 255, green: 255, blue: 255}, - lifetime: 10 // lightening only lasts 10 seconds.... + lifetime: 10 // lightning only lasts 10 seconds.... }); // play the thunder... @@ -280,11 +280,11 @@ volume: _this.thunderVolume }); - return _this.lighteningID; + return _this.lightningID; }, // onUpdate() this will be called regularly, approximately every frame of the simulation. We will use - // it to determine if we need to do a lightening/thunder strike + // it to determine if we need to do a lightning/thunder strike onUpdate: function () { var now = Date.now(); @@ -293,40 +293,40 @@ _this.playLocalRain(); } - // NOTE: _this.lighteningActive will only be TRUE if we are the one who created - // the lightening and we are in charge of flashing it... - if (_this.lighteningActive) { - var lighteningID = _this.findMyLightening(); - // if for some reason our lightening is gone... then just return to non-active state - if (lighteningID === false) { - _this.lighteningActive = false; - _this.lighteningID = false; + // NOTE: _this.lightningActive will only be TRUE if we are the one who created + // the lightning and we are in charge of flashing it... + if (_this.lightningActive) { + var lightningID = _this.findMyLightning(); + // if for some reason our lightning is gone... then just return to non-active state + if (lightningID === false) { + _this.lightningActive = false; + _this.lightningID = false; } else { - // otherwise, flash our lightening... - _this.flashLightening(lighteningID); + // otherwise, flash our lightning... + _this.flashLightning(lightningID); } } else { // whether or not it's time for us to strike, we always keep an eye out for anyone else // striking... and if we see someone else striking, we will reset our lastStrike time - if (_this.findOtherLightening()) { + if (_this.findOtherLightning()) { _this.lastStrike = now; } var sinceLastStrike = now - _this.lastStrike; - var nextRandomStrikeTime = _this.averageLighteningStrikeGap - + randFloat(-_this.extraRandomRangeLighteningStrikeGap, - _this.extraRandomRangeLighteningStrikeGap); + var nextRandomStrikeTime = _this.averageLightningStrikeGap + + randFloat(-_this.extraRandomRangeLightningStrikeGap, + _this.extraRandomRangeLightningStrikeGap); if (sinceLastStrike > nextRandomStrikeTime * MSECS_PER_SECOND) { - // so it's time for a strike... let's see if someone else has lightening... - // if no one else is flashing lightening... then we create it... - if (_this.findOtherLightening()) { - _this.lighteningActive = false; - _this.lighteningID = false; + // so it's time for a strike... let's see if someone else has lightning... + // if no one else is flashing lightning... then we create it... + if (_this.findOtherLightning()) { + _this.lightningActive = false; + _this.lightningID = false; } else { - _this.createNewLightening(); - _this.lighteningActive = true; + _this.createNewLightning(); + _this.lightningActive = true; } _this.lastStrike = now; @@ -335,5 +335,5 @@ } }; - return new Lightening(); + return new Lightning(); }); \ No newline at end of file diff --git a/examples/shaders/rainyDayNightSkybox.fs b/examples/shaders/rainyDayNightSkybox.fs index 359bfb1653..a7bcc4b74b 100644 --- a/examples/shaders/rainyDayNightSkybox.fs +++ b/examples/shaders/rainyDayNightSkybox.fs @@ -2,7 +2,7 @@ // Turbulence and Day/Night cycle added by Michael Olson - OMGparticles/2015 // rain effect adapted from Rainy London by David Hoskins. - https://www.shadertoy.com/view/XdSGDc // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. -#line 5 +#line 6 const float PI = 3.14159; uniform float rotationSpeed = 0.005; uniform float gridLevel = 0.0; @@ -96,11 +96,10 @@ vec4 render( in vec3 ro, in vec3 rd ) // stars float fStarContrib = clamp((fSunHeight - fDayHeight) * (-fInverseHL), 0.0, 1.0); - - vec3 vStarDir = rd; - - col = mix(col, stars3(vStarDir), fStarContrib); - col += stars3(vStarDir) * fStarContrib; + if (fStarContrib > 0.0) { + vec3 vStarDir = rd; + col = mix(col, stars3(vStarDir), fStarContrib); + } // Ten layers of rain sheets... float rainBrightness = 0.15; @@ -118,7 +117,7 @@ vec4 render( in vec3 ro, in vec3 rd ) dis += 3.5; } - return vec4( col, 1.0 ); + return vec4(clamp(col,0.0,1.0), 1.0 ); } vec3 getSkyboxColor() { diff --git a/examples/zones/RainyDayNightZone.json b/examples/zones/RainyDayNightZone.json index dc69ca22ac..1efe87c9fb 100644 --- a/examples/zones/RainyDayNightZone.json +++ b/examples/zones/RainyDayNightZone.json @@ -3,9 +3,9 @@ { "backgroundMode": "skybox", "dimensions": { - "x": 30000, - "y": 30000, - "z": 30000 + "x": 10000, + "y": 10000, + "z": 10000 }, "name": "Rainy Day/Night Cycle", "rotation": { @@ -14,13 +14,13 @@ "y": 0, "z": 0 }, - "script": "https://s3.amazonaws.com/hifi-public/brad/rainstorm/lighteningEntity.js", + "script": "https://s3.amazonaws.com/hifi-public/brad/rainstorm/lightningEntity.js", "shapeType": "box", "skybox": { "url": "https://hifi-public.s3.amazonaws.com/images/SkyboxTextures/CloudyDay1.jpg" }, "type": "Zone", - "userData":"{\n\"ProceduralEntity\":{\n\"version\":2,\n\"shaderUrl\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/rainyDayNightSkybox.fs\",\n\"channels\":[\n\"https://hifi-public.s3.amazonaws.com/austin/assets/images/skybox/starmap_8k.jpg\",\n\"https://hifi-public.s3.amazonaws.com/austin/assets/images/skybox/celestial_grid.jpg\",\n\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/noise.jpg\",\n\"https://s3.amazonaws.com/hifi-public/brad/noise.jpg\"\n],\n\"uniforms\":{\n\"rotationSpeed\":0.001,\n\"uDayColor\":[0.4,0.3,0.3],\n\"constellationLevel\":0.0,\n\"constellationBoundaryLevel\":0.00,\n\"gridLevel\":0.0\n}\n},\n\"lightening\":{\n\"flashMax\":20,\n\"flashMin\":0,\n\"flashIntensityStepRandomeness\":2,\n\"flashMaxRandomness\":10,\n\"averageLighteningStrikeGap\":120,\n\"extraRandomRangeLighteningStrikeGap\":5,\n\"thunderURL\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/thunder-48k.wav\",\n\"thunderVolume\":0.1,\n\"rainURL\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/rain.wav\",\n\"rainVolume\":0.05\n}\n}" + "userData":"{\n\"ProceduralEntity\":{\n\"version\":2,\n\"shaderUrl\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/rainyDayNightSkybox.fs\",\n\"channels\":[\n\"https://hifi-public.s3.amazonaws.com/austin/assets/images/skybox/starmap_8k.jpg\",\n\"https://hifi-public.s3.amazonaws.com/austin/assets/images/skybox/celestial_grid.jpg\",\n\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/noise.jpg\",\n\"https://s3.amazonaws.com/hifi-public/brad/noise.jpg\"\n],\n\"uniforms\":{\n\"rotationSpeed\":0.001,\n\"uDayColor\":[0.4,0.3,0.3],\n\"constellationLevel\":0.0,\n\"constellationBoundaryLevel\":0.00,\n\"gridLevel\":0.0\n}\n},\n\"lightning\":{\n\"flashMax\":20,\n\"flashMin\":0,\n\"flashIntensityStepRandomeness\":2,\n\"flashMaxRandomness\":10,\n\"averageLightningStrikeGap\":120,\n\"extraRandomRangeLightningStrikeGap\":5,\n\"thunderURL\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/thunder-48k.wav\",\n\"thunderVolume\":0.1,\n\"rainURL\":\"https://s3.amazonaws.com/hifi-public/brad/rainstorm/rain.wav\",\n\"rainVolume\":0.05\n}\n}" } ], "Version": 57 From e776bf5819be55bfe374bab367eb06978d34c34b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:47:50 -0800 Subject: [PATCH 255/292] CR feedback --- .../entityScripts/{lighteningEntity.js => lightningEntity.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/entityScripts/{lighteningEntity.js => lightningEntity.js} (100%) diff --git a/examples/entityScripts/lighteningEntity.js b/examples/entityScripts/lightningEntity.js similarity index 100% rename from examples/entityScripts/lighteningEntity.js rename to examples/entityScripts/lightningEntity.js From 2b4d206eca12a909170c1ff0136041689dbe854f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:54:28 -0800 Subject: [PATCH 256/292] more CR feedback --- examples/shaders/rainyDayNightSkybox.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/shaders/rainyDayNightSkybox.fs b/examples/shaders/rainyDayNightSkybox.fs index a7bcc4b74b..dd3733088b 100644 --- a/examples/shaders/rainyDayNightSkybox.fs +++ b/examples/shaders/rainyDayNightSkybox.fs @@ -117,7 +117,7 @@ vec4 render( in vec3 ro, in vec3 rd ) dis += 3.5; } - return vec4(clamp(col,0.0,1.0), 1.0 ); + return vec4(clamp(col, vec3(0.0), vec3(1.0)), 1.0); } vec3 getSkyboxColor() { From 6d56a0d05167ac09ddc5fe821dd4e83e63b86a0e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Mar 2016 15:55:08 -0800 Subject: [PATCH 257/292] more CR feedback --- examples/shaders/rainyDayNightSkybox.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/shaders/rainyDayNightSkybox.fs b/examples/shaders/rainyDayNightSkybox.fs index dd3733088b..265cda3e25 100644 --- a/examples/shaders/rainyDayNightSkybox.fs +++ b/examples/shaders/rainyDayNightSkybox.fs @@ -117,7 +117,7 @@ vec4 render( in vec3 ro, in vec3 rd ) dis += 3.5; } - return vec4(clamp(col, vec3(0.0), vec3(1.0)), 1.0); + return vec4(clamp(col, 0.0, 1.0), 1.0); } vec3 getSkyboxColor() { From 87e7dd9ce3088c79bd91e7d19c4be27e7122f983 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Fri, 4 Mar 2016 16:16:05 -0800 Subject: [PATCH 258/292] add vive button mapping --- examples/controllers/handControllerMouse.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerMouse.js b/examples/controllers/handControllerMouse.js index 8807fb9794..e53fc34df1 100644 --- a/examples/controllers/handControllerMouse.js +++ b/examples/controllers/handControllerMouse.js @@ -10,7 +10,6 @@ // var DEBUGGING = false; - var angularVelocityTrailingAverage = 0.0; // Global trailing average used to decide whether to move reticle at all var lastX = 0; var lastY = 0; @@ -39,6 +38,10 @@ if (Controller.Hardware.Hydra !== undefined) { mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); } +if (Controller.Hardware.Vive !== undefined) { + mapping.from(Controller.Hardware.Vive.LeftPrimaryThumb).peek().to(Controller.Actions.ReticleClick); + mapping.from(Controller.Hardware.Vive.RightPrimaryThumb).peek().to(Controller.Actions.ReticleClick); +} mapping.enable(); From 9346171695830c30442ffdd2dc2758e44828aed7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Mar 2016 16:47:30 -0800 Subject: [PATCH 259/292] if entity registration isn't default, adjust physics shapes to match --- .../src/RenderableModelEntityItem.cpp | 2 ++ .../src/RenderablePolyVoxEntityItem.cpp | 1 + libraries/entities/src/EntityItem.cpp | 22 +++++++++++++++++-- libraries/entities/src/EntityItem.h | 2 ++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e3870705c9..1577cac10c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -598,6 +598,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { if (type != SHAPE_TYPE_COMPOUND) { ModelEntityItem::computeShapeInfo(info); info.setParams(type, 0.5f * getDimensions()); + adjustShapeInfoByRegistration(info); } else { const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); @@ -701,6 +702,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 collisionModelDimensions = box.getDimensions(); info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setConvexHulls(_points); + adjustShapeInfoByRegistration(info); } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index ef777df403..8054ed9a8b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1228,6 +1228,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() { _shapeInfoLock.lockForWrite(); _shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, QString(b64)); _shapeInfo.setConvexHulls(points); + adjustShapeInfoByRegistration(_shapeInfo); _shapeInfoLock.unlock(); _meshLock.lockForWrite(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 04ca7559a0..c421f3826d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -677,7 +677,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime); READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); - READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); + READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, updateRegistrationPoint); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); @@ -1120,7 +1120,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { // these (along with "position" above) affect tree structure SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, updateRegistrationPoint); // these (along with all properties above) affect the simulation SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, updateDensity); @@ -1340,6 +1340,15 @@ float EntityItem::getRadius() const { return 0.5f * glm::length(getDimensions()); } +void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const { + if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) { + glm::mat4 scale = glm::scale(getDimensions()); + glm::mat4 registration = scale * glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); + glm::vec3 regTransVec = glm::vec3(registration[3]); // extract position component from matrix + info.setOffset(regTransVec); + } +} + bool EntityItem::contains(const glm::vec3& point) const { if (getShapeType() == SHAPE_TYPE_COMPOUND) { bool success; @@ -1348,12 +1357,21 @@ bool EntityItem::contains(const glm::vec3& point) const { } else { ShapeInfo info; info.setParams(getShapeType(), glm::vec3(0.5f)); + adjustShapeInfoByRegistration(info); return info.contains(worldToEntity(point)); } } void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); + adjustShapeInfoByRegistration(info); +} + +void EntityItem::updateRegistrationPoint(const glm::vec3& value) { + if (value != _registrationPoint) { + setRegistrationPoint(value); + _dirtyFlags |= Simulation::DIRTY_SHAPE; + } } void EntityItem::updatePosition(const glm::vec3& value) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 975f571eb3..d327bd9004 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -305,6 +305,7 @@ public: // TODO: get rid of users of getRadius()... float getRadius() const; + virtual void adjustShapeInfoByRegistration(ShapeInfo& info) const; virtual bool contains(const glm::vec3& point) const; virtual bool isReadyToComputeShape() { return !isDead(); } @@ -319,6 +320,7 @@ public: virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags + void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); void updatePositionFromNetwork(const glm::vec3& value); void updateDimensions(const glm::vec3& value); From 5bb50c7ea0aefb754951b5d66557feb84c753596 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Mar 2016 17:01:54 -0800 Subject: [PATCH 260/292] track api change in packDeferredFragment --- libraries/entities-renderer/src/polyvox.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/polyvox.slf b/libraries/entities-renderer/src/polyvox.slf index 38d9494a61..a77049b733 100644 --- a/libraries/entities-renderer/src/polyvox.slf +++ b/libraries/entities-renderer/src/polyvox.slf @@ -41,5 +41,5 @@ void main(void) { vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x); vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0); - packDeferredFragment(_normal, 1.0, vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR); + packDeferredFragment(_normal, 1.0, vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION); } From d390c60ef799339fe136d0e82a3cb262c5867ef8 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Fri, 4 Mar 2016 17:11:44 -0800 Subject: [PATCH 261/292] CR feedback --- libraries/audio/src/AudioLimiter.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/AudioLimiter.cpp b/libraries/audio/src/AudioLimiter.cpp index 8e6639ddce..d9257b7df5 100644 --- a/libraries/audio/src/AudioLimiter.cpp +++ b/libraries/audio/src/AudioLimiter.cpp @@ -132,6 +132,7 @@ static const int32_t exp2Table[1 << EXP2_TABBITS][3] = { { 0x785c4499, 0x390ecc3a, 0x456188bd }, }; +static const int IEEE754_FABS_MASK = 0x7fffffff; static const int IEEE754_MANT_BITS = 23; static const int IEEE754_EXPN_BIAS = 127; @@ -146,14 +147,16 @@ static inline int32_t peaklog2(float* input) { int32_t u = *(int32_t*)input; // absolute value - int32_t peak = u & 0x7fffffff; + int32_t peak = u & IEEE754_FABS_MASK; // split into e and x - 1.0 int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; // saturate - if (e > 31) return 0x7fffffff; + if (e > 31) { + return 0x7fffffff; + } int k = x >> (31 - LOG2_TABBITS); @@ -181,8 +184,8 @@ static inline int32_t peaklog2(float* input0, float* input1) { int32_t u1 = *(int32_t*)input1; // max absolute value - u0 &= 0x7fffffff; - u1 &= 0x7fffffff; + u0 &= IEEE754_FABS_MASK; + u1 &= IEEE754_FABS_MASK; int32_t peak = MAX(u0, u1); // split into e and x - 1.0 @@ -190,7 +193,9 @@ static inline int32_t peaklog2(float* input0, float* input1) { int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; // saturate - if (e > 31) return 0x7fffffff; + if (e > 31) { + return 0x7fffffff; + } int k = x >> (31 - LOG2_TABBITS); From 3278b76eefb492bf5df9f54236e973b38db1688b Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 4 Mar 2016 18:24:36 -0800 Subject: [PATCH 262/292] Starting investigating the text rendering bug --- libraries/render-utils/src/sdf_text3D.slf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index faa4d02bfa..6355c71737 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -15,6 +15,7 @@ uniform sampler2D Font; uniform bool Outline; uniform vec4 Color; +uniform vec4 backgroundColor = vec4(1.0, 0.0, 0.0, 1.0); // the interpolated normal in vec3 _normal; @@ -30,6 +31,8 @@ const float smoothing = 256.0; const float interiorCutoff = 0.8; const float outlineExpansion = 0.2; + + void main() { // retrieve signed distance float sdf = texture(Font, _texCoord0).g; @@ -60,8 +63,8 @@ void main() { */ packDeferredFragmentLightmap( normalize(_normal), - Color.a * a, - Color.rgb, + 1.0 // Color.a * a, + mix(Color.rgb, backgroundColor, Color.a * a), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR, From e3d11560ebe60dfa8f500a02c4a6ca6f845386a2 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 4 Mar 2016 19:08:48 -0800 Subject: [PATCH 263/292] With a shader compiling --- libraries/render-utils/src/sdf_text3D.slf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 6355c71737..3d229ef359 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -63,10 +63,10 @@ void main() { */ packDeferredFragmentLightmap( normalize(_normal), - 1.0 // Color.a * a, - mix(Color.rgb, backgroundColor, Color.a * a), + step(alphaThreshold, Color.a * a), + mix(Color.rgb, backgroundColor.rgb, Color.a * a), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR, - Color.rgb); + mix(Color.rgb, backgroundColor.rgb, Color.a * a)); } \ No newline at end of file From 076b0b42d76184685fab344037347c0cfeaaf927 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 4 Mar 2016 20:36:32 -0800 Subject: [PATCH 264/292] HandControllerGrab: fixes for distance holding Because controller poses are in avatar space, there is no need to apply delta avatar position changes and rotation changes. --- examples/controllers/handControllerGrab.js | 100 ++++++++------------- 1 file changed, 36 insertions(+), 64 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 2bddc5d677..964fca4136 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1049,9 +1049,14 @@ function MyController(hand) { } this.distanceHolding = function() { - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + + // controller pose is in avatar frame + var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand); + + // transform it into world frame + var controllerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation)); + var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var now = Date.now(); @@ -1059,12 +1064,10 @@ function MyController(hand) { this.currentObjectPosition = grabbedProperties.position; this.currentObjectRotation = grabbedProperties.rotation; this.currentObjectTime = now; - this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); - this.handPreviousRotation = handRotation; this.currentCameraOrientation = Camera.orientation; // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object - this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, controllerPosition) + 1.0); if (this.radiusScalar < 1.0) { this.radiusScalar = 1.0; } @@ -1094,10 +1097,10 @@ function MyController(hand) { this.callEntityMethodOnGrabbed("startDistanceGrab"); } - this.currentAvatarPosition = MyAvatar.position; - this.currentAvatarOrientation = MyAvatar.orientation; - this.turnOffVisualizations(); + + this.previousControllerPosition = controllerPosition; + this.previousControllerRotation = controllerRotation; }; this.continueDistanceHolding = function() { @@ -1109,10 +1112,13 @@ function MyController(hand) { this.heartBeat(this.grabbedEntity); - var handPosition = this.getHandPosition(); - var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; - var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getPoseValue(controllerHandInput).rotation); + // controller pose is in avatar frame + var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand); + + // transform it into world frame + var controllerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation)); + var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); @@ -1125,66 +1131,27 @@ function MyController(hand) { return; } + var now = Date.now(); + this.currentObjectTime = now; // the action was set up on a previous call. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + var radius = Vec3.distance(this.currentObjectPosition, controllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; if (radius < 1.0) { radius = 1.0; } - // how far did avatar move this timestep? - var currentPosition = MyAvatar.position; - var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); - this.currentAvatarPosition = currentPosition; + // scale delta controller hand movement by radius. + var handMoved = Vec3.multiply(Vec3.subtract(controllerPosition, this.previousControllerPosition), radius); - // How far did the avatar turn this timestep? - // Note: The following code is too long because we need a Quat.quatBetween() function - // that returns the minimum quaternion between two quaternions. - var currentOrientation = MyAvatar.orientation; - if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) { - var negativeCurrentOrientation = { - x: -currentOrientation.x, - y: -currentOrientation.y, - z: -currentOrientation.z, - w: -currentOrientation.w - }; - var avatarDeltaOrientation = Quat.multiply(negativeCurrentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } else { - var avatarDeltaOrientation = Quat.multiply(currentOrientation, Quat.inverse(this.currentAvatarOrientation)); - } - var handToAvatar = Vec3.subtract(handControllerPosition, this.currentAvatarPosition); - var objectToAvatar = Vec3.subtract(this.currentObjectPosition, this.currentAvatarPosition); - var handMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, handToAvatar), handToAvatar); - var objectMovementFromTurning = Vec3.subtract(Quat.multiply(avatarDeltaOrientation, objectToAvatar), objectToAvatar); - this.currentAvatarOrientation = currentOrientation; + // double delta controller rotation + var handChange = Quat.multiply(Quat.slerp(this.previousControllerRotation, + controllerRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.previousControllerRotation)); - // how far did hand move this timestep? - var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); - this.handRelativePreviousPosition = handToAvatar; - - // magnify the hand movement but not the change from avatar movement & rotation - handMoved = Vec3.subtract(handMoved, handMovementFromTurning); - var superHandMoved = Vec3.multiply(handMoved, radius); - - // Move the object by the magnified amount and then by amount from avatar movement & rotation - var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); - newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); - newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); - - var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters - var now = Date.now(); - var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - - this.currentObjectPosition = newObjectPosition; - this.currentObjectTime = now; - - // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, - handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); - this.handPreviousRotation = handRotation; + // update the currentObject position and rotation. + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); this.callEntityMethodOnGrabbed("continueDistantGrab"); @@ -1195,6 +1162,7 @@ function MyController(hand) { var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData); + var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position); if (handControllerData.disableMoveWithHead !== true) { // mix in head motion if (MOVE_WITH_HEAD) { @@ -1234,6 +1202,7 @@ function MyController(hand) { } } + var handPosition = this.getHandPosition(); //visualizations if (USE_ENTITY_LINES_FOR_MOVING === true) { @@ -1265,6 +1234,9 @@ function MyController(hand) { } else { print("continueDistanceHolding -- updateAction failed"); } + + this.previousControllerPosition = controllerPosition; + this.previousControllerRotation = controllerRotation; }; this.setupHoldAction = function() { From 2f92a4cccdfde90b9ead3c86c0c77df9e864a645 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 5 Mar 2016 00:45:25 -0800 Subject: [PATCH 265/292] first cut at music player --- .../createNewMusicPlayerOnClick.js | 100 ++++++ examples/toybox/musicPlayer/defaultImage.jpg | Bin 0 -> 58245 bytes examples/toybox/musicPlayer/imageShader.fs | 44 +++ examples/toybox/musicPlayer/musicPlayer.js | 328 ++++++++++++++++++ 4 files changed, 472 insertions(+) create mode 100644 examples/toybox/musicPlayer/createNewMusicPlayerOnClick.js create mode 100644 examples/toybox/musicPlayer/defaultImage.jpg create mode 100644 examples/toybox/musicPlayer/imageShader.fs create mode 100644 examples/toybox/musicPlayer/musicPlayer.js diff --git a/examples/toybox/musicPlayer/createNewMusicPlayerOnClick.js b/examples/toybox/musicPlayer/createNewMusicPlayerOnClick.js new file mode 100644 index 0000000000..68da1d2628 --- /dev/null +++ b/examples/toybox/musicPlayer/createNewMusicPlayerOnClick.js @@ -0,0 +1,100 @@ +// +// createNewMusicPlayerOnClick.js +// +// Created by Brad Hefta-Gaub on 3/3/16. +// Copyright 2016 High Fidelity, Inc. +// +// Entity Script that you can attach to any entity to have it spawn new "music players" +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +(function(){ + + var musicPlayerScript = Script.resolvePath("./musicPlayer.js"); + var imageShader = Script.resolvePath("./imageShader.fs"); + var defaultImage = Script.resolvePath("./defaultImage.jpg"); + + function getPositionToCreateEntity() { + var distance = 0.5; + var direction = Quat.getFront(Camera.orientation); + var offset = Vec3.multiply(distance, direction); + var placementPosition = Vec3.sum(Camera.position, offset); + + var cameraPosition = Camera.position; + + var HALF_TREE_SCALE = 16384; + + var cameraOutOfBounds = Math.abs(cameraPosition.x) > HALF_TREE_SCALE || Math.abs(cameraPosition.y) > HALF_TREE_SCALE || Math.abs(cameraPosition.z) > HALF_TREE_SCALE; + var placementOutOfBounds = Math.abs(placementPosition.x) > HALF_TREE_SCALE || Math.abs(placementPosition.y) > HALF_TREE_SCALE || Math.abs(placementPosition.z) > HALF_TREE_SCALE; + + if (cameraOutOfBounds && placementOutOfBounds) { + return null; + } + + placementPosition.x = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.x)); + placementPosition.y = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.y)); + placementPosition.z = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.z)); + + return placementPosition; + } + + function createNewIPOD() { + var iPodPosition = { x: 0, y: .5, z: 0}; + var iPodDimensions = { x: 0.15, y: 0.3, z: 0.03 }; + var overlayDimensions = { x: 0.13, y: 0.13, z: 0.001 }; + var boxOverlayDimensions = { x: 0.13, y: 0.13, z: 0.0001 }; + + var iPodID = Entities.addEntity({ + type: "Box", + name: "music player", + position: iPodPosition, + dimensions: iPodDimensions, + color: { red: 150, green: 150, blue: 150}, + script: musicPlayerScript, + dynamic: true + }); + print(iPodID); + + var textID = Entities.addEntity({ + type: "Text", + name: "now playing", + position: { x: 0, y: (0.5+0.07), z: 0.0222}, + dimensions: overlayDimensions, + color: { red: 150, green: 150, blue: 150}, + parentID: iPodID, + lineHeight: 0.01, + text: "Pause" + }); + + + var newAlbumArt = JSON.stringify( + { + "ProceduralEntity": { + "version":2, + "shaderUrl":imageShader, + "uniforms":{"iSpeed":0,"iShell":1}, + "channels":[defaultImage] + } + }); + + + var albumArtID = Entities.addEntity({ + type: "Box", + name: "album art", + position: { x: 0, y: (0.5-0.07), z: 0.01506}, + dimensions: boxOverlayDimensions, + color: { red: 255, green: 255, blue: 255}, + userData: newAlbumArt, + parentID: iPodID + }); + Entities.editEntity(iPodID, { position: getPositionToCreateEntity() }); + } + + + this.clickDownOnEntity = function(myID, mouseEvent) { + createNewIPOD(); + }; +}) + + diff --git a/examples/toybox/musicPlayer/defaultImage.jpg b/examples/toybox/musicPlayer/defaultImage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54de95bf42e2981ecdbdf187fbce2112d633cab2 GIT binary patch literal 58245 zcmeFa2UL^U)<66N6l|zSQA7bj0X38)q*2GAi3S*ifJhq%Nem@{6so{D<0zf6(L%Wc zPS7AAAYEmYHuOP6ItUn$-lUg&D?z8+JHB`3{jdM}*7`nwYq4|AKKtym&p!1zPl4OP zeFN-2XJldofIuMNEN~V8xRbk2eRY{ar_e4_yyRf2>Hz9X6Vq)c03P=9=^wyL6P)BT z_5)`H%m5G|@bQPzUmr4IeX?$Psiv|QfcuIgD{TNf{$3R>D*v7M(R}-E;1o?S)@Hsp`fdD|@ zi><#8nq>HCeD!?U!@Rhl({DBBLr@L?w(~*~fEPdkd;vT_1)Kn1z!~rWJOD4i8SwhR za{)X6X8;GdZ~nj0?oeAJX}i6{2~NaCn-v2ZqMe|EF@c z^V0wTH~;{EFh62q@CV((L@I^h^(U4Pg-Rll$apft699lchL$|-=6oIi03yx|I>i`I z##5c?cvqgqR{mc255l{)gn1lZiiszY=eGab^%rDNJ**5bTK(=^p7a0AF{Kglf8q!^ zd(f?%iGSkl#o;|Xtnhwx6WUoTQ;Z9R;=ya>9Us|$65e^4LJc_MK_Y(i)V{6CpZ&<@ zIouUbaAtVW0RY(PgQwE}LfrZz`_JOLU5NS=4+`}U&K2F#|E2M72|OR0QOLaCopg$q zIfG8a|FPrj^1u`5|H0kkLZQmTDTM5zw z0MK?2A6w1=1Obr1w(UZ~J9h5c4f^*)5FjAyZt+6EF7*e0-DSZK#~!96e#ARsEZ z?brdx_A?gFV)EWsp+e#}f6V<-;kd+w=Pob}>bEWW!Y6K7&J4`rXmH82yzdkZZdrNM2h^ntXhZ2mSb~r&sS|VEo9& zcjRezo$&ToA(=PE4?1M*tSr2WaMh-sCbo9NrhN+wLsY9qJ;rs!gD9h^)~iM*tXf;i z`HV@K!C7oUx1GcLMe=5F{n2vyRW9&m*pAs=RZ+DX;5fA-3-_#zQPui`r&Sm8Sf}2&8x|2`93%**()4`M&d#)|1Oiom^n&7j>A%6<8t zwO$ooW;Uk9JhZlOzQOrwb!^@X-dnWU&8pIe_Hcm*T)?59$q*WfqNN-jyadKA6=e4z zJr~^aX|kKQH@odwG7ihO5^sl|w0oNE#dUrCZEHz3X=At~fS|Now_5aCeLQ`fXm+sw ztE)HdE)gpyRoQjO;E;4e<(>HspOFo()v1Oql137f>Fn+rK2E4E>E0-NdMa~CZ$oLL zFoz37W4hErip_bZ9vyF(_+GB4SN44oe9H?GW!VF#fsg3|UHW?feJd2(-I z{o*Dui%>P}pAa|vw)6H6^Z3Hzl4u4#0Ca!?(D)%Q006}Pi-a7Y4_E>k z{Hd5&?c4#Vx;k1@9j*z5$U!tTp-4?Q3IGKE1^V5#e+hilza99O;K%T9J2WAX z;0IYD0015SXgf&e_j-U7|5y(J&_^90Re|4i^L9);@NNG1`+5EPynekN{=9yDUcWxC zU&n8mm~%V1gL^KT=<7Rub-~=o1Y^iw!1kQQkjNB){Q%%erc*B%e<^p-_L7`%6CeQW z1cU$x0661lUZ$2tylXbV#86+3cER||t?8Bz5CAN`=C2??tIFB0J5&(cu9|rG2SP%mMz;z!I-WLD_UjYDc+=Jms0s#JLjJPM> znFav-E2QIeJnk|8@J~bbP^~WL1Hd+I0NAmI_=m8|AHsCJAMXkh(5HC$^RLn5lyN8J zAZRp7?kwKd15c-`eC3RDcc!|^=~FztoXP$GuvKS14)A;{XJV+2fS?fw6{srj+~Fhs z$Hc!0UfXVo&Rg)?3?$j`JMVY=&ZDFO0BQjM1b_IQ=aK*bMc)I!p|0O~$NvQY`>p{% zVe=pABgyM8m+5pbO*J)NUtd)c9;eE4=x_M10)GR4C{LAF-fzB>GuXPMm*Y7VNAaLA zsB$zfXB=Km<=;E;|2pFz@CQ4<7w`l;6;Hr3;G&F1d%}u&=t^kpa{?{ zP$K9@&;w8|s08#JR10bWb%F*!qo6s^s(_%t9szNIqXLQoY62*MGXm!YtOOhchyvaM z0RqCRoHkEB!+sqD zHn44G+vawW?MJqs-mbabWc$VK#O=P@uWygt&e~qEy=r^gcFy)iAt512AtfQC&{-i{ zAvd8wp-7=*p&X%~g<6D$gcgK_g{6c~3+o7*3p)$bg|7=I2tO1q7k(+s5nkT0dxz`} z=nkVDmv)eMe7hrd2Ybh}9WQr`>{#2mf9Hvvnmf&Ry6*Jf8ME`=&eEODJ2^Yoc8Ts% z+NHD0YM0xttGnWNW$&um)w64U_wL>DyV1KXc9V90vpatGqusyk9@xFI=fIv*d-V6% z?_unT-jlKC=RKW!=0!wA6h*!exgyh_A>Vt?tQs; zYTwR%C-$A$=eRFmU+lj8ea-tO_V3)UxL<$2^Zwxd%>5<%+xIVsiitu*%|$&$BSqPw zwW9A12p>>9V0ggwz_kPE2PzH>i3y4+i0O;r#J&@|CsrlK5f>6y5;qZd6ORzj5^oZp zkvJfsAz>}yC&83>D)B~AP*PFSMAAbtMlw(GwdCr-qX*9%#2*Yhn0@f&!KFjehrT$3 zKNNl_=TO_BRVg_sLn(Kun^Hwmy@$6QK6TjQuUA{XXvNV98A+KhWZY!#$UKu7l@*iKl_kmEku8@Ular7; zBj+I(FIOoybL_~mv&R_6emvH6Y)xKC9xMN?e2#pt!Y&1r0zu)9!V86&nVX#@KcvhF;6w07C4PKO*)-?x&^!)j0TgzY2bF1Jt}8Zd{i=322>?gF{at`t>q!cm-Jq5)_=y<>XLdTDxtUnqRx`UUHY zkuxXHxSe@;X6j4zFR5P^e7U5rsUM{Ovw@(2u|c>&li>kFtYM;IpOL%~(J0es#u#oK zX#Dfp?Pt%Qy?M6Xa-w567oY`<$Ge^1t5xwawS;uh*T;ozt8bTufY&TxM|kxH#On>ldzfTu1Rb_*?i9 zf)3#p;T=(jc$+wSS?_Y}}1fuYR!o-yE~>%;U}_O#F|54H`j)~H~v2J`rhl*>+LtRZls283nhg%g~7rS!ZyQQ!|Ni{ zBVr@gBXN;+QIM$kC~h<%x+w+`lk$Vm59A+S-_*N#|CZ>jfLlYiO>Y<8k-HOq=lxx$ zyS1?zv8i#p;uvvn;xX~X3C9zDNLWw2oY=Zb>+!>kC_Mg}?K&HW4aD<2>qJYXMT$7Bj* zGBQUW+CTg?%OI;bTP6F)9Lb!BN5CV-qp{qtb6@A3&wG)N%Flj$;&D=eSV4FpsL;P~ zrs#6fn_}DImXdQNFG{sa3(8c>GM*fJ!h9<6H0If^XV;!_%LB?6e)jr#;yLm8&I)m-4F!$x#)2k9Q(-f* zx%gM~uca;8Eze%+y?owk&|3Y<JvwK*e7e@UzvzLgbXWVOiZQ}Z*=w#BA^3>z$FQyx2F3xafsk7X<$a$&xjQ1MvUo3pJ(6{KhxV99& zEVX=p1+`MMYO^}B=DRMu9=~yNqjdB9W)Ihs%jFJ;-uST3Bhyr!d3Oj@aTHHAKW8sB zh^o38psnZU<&1O3)8$<7L=ss?e!8q&UXJ9dBX0vYRX6q0$6qF$4WQyJ1I(;&0q!`o ztGu4BoVK5)pQo26p6)E?=jlPFY5M8N^Ob9oX_`E?n!Fregzl~*zjao1(ex`heF_yX zr=bc}g{t7x5imJ8Oce%)BA^;zIjFiiN=+T922)popm=9j8W6b;kk^&drn(X|FBlko zD2?h$(2@Vc_SF}rN}&?fAZRpNO&zKRg{n|p2`V&yGTqrvg-lcUsKEeF!%<0I{M{Z; zqq7TzLD!L&|5yo6uiw=ErMEr`y5fG5^I}jv_=UUT)bJj7Pdu4UQ-i2Nev|e3csKpG zEPqn{TQa{nJ{I8T>1AsA*BL&xoTuk+(lolE5B-0Zrtxlqsa?R+C=4nNZ|H+3(-l4z zMkf(|cjupsVSnVC=<9z)r4UFScpdrwxJKmLYig=# zLZ;E3$vC`;fsVYNr;_Ch%|ygkQ(Yps5$}#fqV%;>KmOgfWginAR0!ft-6|; zY8p^*3|^=DnAeq;*WmBv-MZoI?D4W-W07H@L zU?>s-h9Y@!I2ZBgEb&%6pxSQ=SB1LqWO8zD4q-&&6hz#_+g$lG+!GU%_|Yj*NNs? z0#%0~!0KQqSOW|PBfv;73XBFr)WHx47y<=DU|@&_7y<`F5MT%r3_*dR>R>1o426NA z8ek|K4CQqPFcbxbscW4!C;!KE_{TYJ zON>S#(0!e$_%lR2nf~8qTeVNxO(F9hulU_^FK4Q=C!UU{(sbkrREnqE*39TdCd$z% zA0qr|@{=lQ&OX1Z`%6ds*GcgIo+Cb}#$9$M6Y;J(@@o8gsPVQ1Tdk}1?+wpS`@0ibOHf`7Ozv`t8O$FA)=K>~uixs`y`eh>f>5ER_8W1A32 zKw#VMoxJEa(PP_%Ai@VE&RAI8Y}ujV>`l9xJF`a06p;dXOTUhMVm}+Ba1Ziya3s?I=&`8jgW9-XM)y$sN`_>N&*B2B znh(use$M>aVV^t6=YjEgGWa}u{(ou3sD%+Hc?)F-f1za5xUTJAypcVqdwk;<|8+}o&ErAGyJX5jmv6tnw)NqVPoR!?4fE_KnYhN0db?Ux!iI&zV(7Y$ zJGnqT4Av&9zOF)jo;Axps}=o*?V=GHKbf#me5H>_ zY?tCRHlG}TE#*u_ISRNaX}S;#73qt98;j3NuEjT_L!<8}%{SlZ4;QHy6U#0~&y2;S zI$cnqdrxc(2Crvy%diPboo#Bo_cA_(f7C^U6Goh#i_Vnj*8Dtka^`TQ!IPSHXkBChApa19PoK&wm~) zbVBH{0^!kzNk_DTlh1{SeH%`T%s@rame#a%5;!T|9RuWnxrCIQr%FYt*&R!$vC+`h zlXFXfxan}X#ho=x-a9Lw#6LQp7`$mHwVCov(^#sp*0!K2v=yE35`~uvTEw%{UN|cf z;)jiQERO2j?u<)XIIWYKk6y4$K8(RHb;lK%2A|^s1P`ffc|FyDycF%AWJfNL53Id||4+ z{%)XCW<4zsm$~%4R%n5E6HUs11dF|`bIGf@`@m2pOP;#2h6_i2(o?*5g8s>P4Qx3) z!bI3$g|?1iW40j zc6-b2S{$hzlAVprTU(iJ3|IDL$=aJ!A15_or7Ij6F+fn#NvbY*#VW3!OrhrCo~VQ>0mSUy`cC15RY zA}T21VPS6v!;W1_2#a##0+E3WD{HZ-ZeO1&g4gWHZ!YSctnb{Ezh2#u=t96@-q)dK zU+Qi=dZT9Xu*RzT_T*Y?cV>NB0&-8D{=)#K#NhVb#CJMNuvA}+c^*)&&~v56fe z*zy+9RHTkle&>=7hS{srnwCk&VoUR)$rj?9>=9JbgGd%3U{D^GP$v(olm2p3QuZpL z{e5Cbw`^?rSv%%=n*WJP`~2|U$)1YJi`{ku*TYzE2URyc%N}=hE?rJk)YEKZXSYyY zdM!1Y?A+(D%Zz}-b6UAx(z3J_;hsS3*AH9CSs9U?sa2j}yp=(vW0gbp+ZKnO#|f-9 zNXDK%f9rKE9T9(*j^f^!XZGJs!N+oaPUpIl1`w2)GUM$?g_C91%E)i+(k6_&#T-h9 z91pz8nLW3@%cmw?x3b&5AVAyZv2XJ&j}weRpUsKElbZ_UDc0c!?2;-wCSuYuv~y88 ze2mRRkZs5j^!c%{_-32r@m@`rh`WZ*$QIVO4JxZGAyzhGq7W-HZw*cpixw6+5EK??}<+UjCWV`Xm|EWSCLIvEvwd#OT$6q%vK`y$RK0D=)$r(_3>Uz+|nUK|sq zcUJ!sg1lGtMwr&O?{Ktb&lXs5fh=u$(ETD<4#Gv}W)-3>X*ji26Q6C#3bGAaTtu(S zNNc8{pSVyXi<`XL7wV&*+MeEs_%4y1hAt(F9md15Q-c!6o&{#+t+d%C6y0fqBvm^p za{)a?>=fd~dTqh_leu9oP!nlhe$BmNO{-x2RM7s30LuU@)w@{Qy3(e!8+O!eZrT*v zJ<^q&nn%i!CGPW4L>E{@mS5XE%yvs+v))!#j@*8Kx3{scqb%c5q1hyPs=2}=>qf3R z%9EM5=yRY=(yK#T@<1=*;l%=SIEfXm(t@!R6|c7SqCt)@5+)XdHhXqP4ynx#bPW1z zKJS!n&PA}MCMQIqGID)h3ybFaqzFoonZ;KKyCuk(7b6a4wM$q!98_kr-NMscXm8fL z^(4v-FtTYQKT%F}dMlbFK(J5(kGx+?$!bexS*c(S_Xiick zF{ivfmoi)I!Hy5DbAiRjHz_zh$xnuPAw4+o;DmM^YBF`Ke!8e&SDC+iY`{!>Gnfms z4j_g#nro&Ule!9$GL#2De52{FAV6qd=+Uc;xyRIR_m({n{KNIXlG=h!T0(MgPL||4 zF58dTDI3zc#A;~DAIL863vn&;b7Lvo$WtWNZv-jYy}+Uk@F@Y__2%W%6*o@c1g(6q z?KP@sqf3nD)ug+sf*_a`Y0Yn$IA`B@BY!OMeo{KBo~^n1>=N`K9pR)|CRK@P!|DZi zC6!a$VQB4+dr z%Zx)b$w%C^ONbmzyr1G}iK%RaK{PM-^eL#w$tZQ!WUjAig?Lg)SGj=2_344>Rg*bl zL=hpJ?1Dyi6}X&crM3l>1=@%hmX0SCBq~R{y6dqt+=A+4Du&yF33^j?F3|B5%@9hU zNKrYy5$+fo<>EH>l95!*1?~@J9$lOgxX-+Ohq2&Sv$uIZNhMnkWQElX+H6HP;BzG4 zA=|A>4FX}!10~@#oTYrABg&6s)z^+&JW`USJSX(=F8;x4b!fDj)LD&po3& zThI4JSum{q2y7y?d}_rMc6dXE_cg7*#y@G&)mDmjelvP(v+v4*%LQT(QL)MT8utb~~Yt^lR;9Plo z)e*6z=G4~cY~sFL0wJ|U=Mu&zgpA$@U}bc!N!~A!O(R~LNh$AA=&pG{EtITI2@-3Z zXrd-9ujw^8u6G_QValfjg$*wnS(;ldR0kM0Ur)xoemjn9qs@~Mt zVsm|S|Ebo8LYB0TlsmmWu79=DJoqHqzx?{kx&(5uvx{Mm=Q>9vc1MYw!`iDMyCmf zuIz;L70bh|V%h%gVx3E{hk1f@AMqB4R8GxkBDFauGv7R*jk)&sqqD(A*)v;2vTZ`a&v z_R6lltPU9ITyPtxQ>{*9ZCbf&bAe?}cXiO_g$j|W4!EH&E&-C%6kufWa6HB73JNUL z)mu8A$Wm!OoY&mnx$#7DO}eygek`>vnU-?&3N)o>Ze^q^10tPaPaB!bK*cwshPq>u zA7yykWl`f(-!{=;8OV#{?dHUulOBXA8&k{Vr;L=o2d$hqS+|?j6XzZzmdAhj_53plWKgjkdmEUyl9l*Z^ZT$y_Og<1j!&c1O$eZdzjmZQ5!1Tj{2Lg2dyv` zLhc=&Y?cvAv0X6lr_}e(#>Xf9^yZVD;O}o1LBsL{>a_@;VWRRtyIzR*WP*AAjS(}8 zI2m+PqOp7Gi#O~{=Bf*UAdgzprq$;t*GZ6@JCUbzlv#{Omd4oPg4aOo`Kx)0+im2N zvYIXtStTQ}!L+$h`^np-jCKtJyQE>w(R$q`(aq9%`;EIL$W!bDriIv@keVC&Tx$xv z5W#QSv8BYhA=LPA^WJBobCcuPLqR{6+=Z=JzEIRNryO}aw#e|Rk6`8(7qn6R*S0X!E_u0!W0d9|B0m5jeBTgxrOT2R~P=3i^X4`|}2V~7!8 zq_9gPQiXV=f3(@$cV~Tm++fW^ zPJ?Lj+hJ-mvpDdA-ulbR4K8ry@oQqpqINs=Jxx&_-DTh&8x$1c*jKGg(Vc9gmfdWK zOe2CvBNv*ZZ>Khel>X{@w7JBZ)(}Mq8JZptmFY>lVpX+KRpP`2kTn;hDa-9DSAxlk zn{RsR9zPLQc6Z;*2_ILzS6Rzs#?G?UD0A( zKt{Jo7XGMfEyF=JVO7cO86{O}bwMSztwX{tJiiDQ>rZM=u^sPxRkWs$w=uLl(u*>> z*_Je_b0tt`gKaEvH9N(}TWVa&tF^yVrYT!hU{RKdHnaB|(HzwYJ*d)PW?8`w-W=&v zkAXnY=RbXuJ|Ta@ci*hSsN$~+J;s%(_l|vXr>b2^L>t>plY1ICheu+sDBO^NzV%v^ zXQw5NTpQ8!8DWLr5WX6o7aFS^`x==c^$Ah1I?avNrK67Z^JUC1Y)G8!U6|ONQ4BF@d0bX| zl@nBWP)Pz~p?CA)ybF$5O??Tg&yNo9s&|x9sTEG+0?O-o6d_p#8rqYU^R$~HMvb6% zboyx(d33T%)8dn?p-hIe*W;1u%q3+Otcj@Pb0v-owB8-XK9h!l3Xt^yNTu5el`V$# zYX?aeD?Lqry3S&g*e5eZ^Jab3XB{ok)tAg|F6f==e?Jj$kt|bFu-he2IA?idY6^;B5we&W_f3_^OPG-#0p|wvZnVN|# z^m+Zlv7*hY#j3LH`x0uem~K2zDRV=dn_Gj^^>EKX{;>GqL;g3a}S z1d)>NgL6}tHZ%<^(fGCTp&HwP$&UIN!xvT2wk7A{!y=b3G!j>?Tf8*$ed(2mX&dG4s;j-GHNDAMPoTrn(7sx=qY^M8IpC*wD=g4}>MIM*Re3EbGfd>(0i1!wl zHgU^9x50P$SgZm54l!v#(~=X|5^;xYjEs;f)y^QBb@XhMeP2dxyBPG~yE3<`uKR3K z!iyn7kF&Q%Lp8mPF!@V-vLenJ;kju#e6nOcEQ+A;zWHcSl9D;`+bW9UKx27hSU%(q zF-w~oR?pTcS!8_qVtVhpU?;5=fA1#66wUFW&EG5H^yDM(*6C?A`h#`D$o!$s>`U%*E9+(Uo^|q?!RD-k1PIxJ=VEbko`K$4aA1Cmo&B1(RYEWS?^0wJI7Kgdy^X%1g`+|bPCP_ub zQXfa5rJ1GEMFH|INv355mKc0D(@V`L#6VU5skpE4?$Y(!Q^C!hzV~wtrH%b47xM!t zlkT~O8tpXc$E-F~#N#$AQ>zv%O?*VNUWwYOs#CJCxUryJiBHdoF?af63bUb(*65DS zW$q@vL4Va5sJnTZUR1H~dVyJMQDlV$a`FuXIm%)dN2;n`PSQb)mxy<p(dn}D!-m?b18dF#9+Eguo9-FX;5~uv+Y!M zUAU^<#t}sYH6o?F{=uVzZ=T+WIFd_^y5rpw6eqP9GJd{wzWIjh0>T26r8lH^BO)oE z8U&N7oHA>P(kVOFz}a*FO&isQPubj+a<}qo&za8A)u!4t-mKkx-7hlKDV_C5U1Df) zYIYK=_)DkXd3vK|h;&q$DO02E4pyTT-X@B*?+nM;l3SL2H)XFR1<232=OR*0J5Ow6 z)=l;OJm3>MN3lM=&utO8Jw%MaY{~cW>>6bc@2x%@amTjIuq?r$%*{PMEFpB_3GU#% zj5OI}DR%=OMD(Uu`@#s5fkohU3aDt(dE#RC+NrlKSPlE_Gs$Zny#i0MWw`t6{9HW+>oij@c3ndQ_+*rv!T`gEQtb5oQ7MdwV z<%l;~q75vWX`bV6$6T2GzceM%!kQvkrz5!lrrH969)+k^HO};$yU!|#RJFxaU+K%D zH>*BO?*_Z}WxZrFZ0;tNvx%pIZXceB(jyV_QY5>cdj9cgWk*QjB%8Q%)Xs2nah!8 z@(bREl9P5U7@IxDPNXHJDKg?i8w>jfn9I5olidZ6{3-8mb}Y_n+04zX88gtjRd!9) zyHRP2va*GfZKe?Ha#JsTAY*=_4dMW=G#Jm56b60U8LzD?NOV?TKC<^f8^WstbAsu2 zMJK|_$f`S^(57KmgfZSlVku;SWfXLu>iVw__0KK&jB=KrQa$sKuvS60As=0#B$ceO z-i?^T*@9M#rQybpVfj9bic=PP?a0$%Y-(6SJcCoVe3>tC0? zKTNHtQ@ok|*5fHIhYMVCT$`Bi@DsF~uKu#ere0QQUdQh4W51B4yU9UM%|d;@+m~F& zqSm7)n%73wh*L!Kf%CP5dX8A@L3(DFbyir4c?ec71zobq@P5o*-VbBaL46>6%Tp zKyXrMn?TX94sTKWs#ZNImu;yy}dPN`CC)Bfoj@ z=r>ii>?S3V&|C-Wsjd?8{jjjKQbIzCSZu-wb9Yg@w;PL$U9oL2wSY9%pKP~noxYw| zb#$`#)a0h`-21T1P0ecifX74Cy0@7}kr7{;mSig?44_GqD}hhz&lD7T(rv70)X;>* zpz*d-Vp7)=6^rYjuZcydrI{4XHT&(|mgY{5i9zdYO2-cm<#2REx}R_TvxUFF-#-u) zj*lExsOgC#hb3j$r(X+{4=R7mXr68u@S3$UekM;FnA+G3o|4F}|Cz>$rW50k*BGO5 z{W3pw^=`zN))uY865@w28-C_JuD@ip^yW0I=WuEc#c#kimPbbRl=PT3tk*r7H+?ui z+~|}6o~xrqE)(Zk!JUn@HxyC5xsMU#hE6-A=wqLhmdcASzV<@dVI3=7ypdz!DxF2- zUbu}T!|X{HQ8{v$dVQ1&Tt^PzN_(zNZNA{#h}DU?-ff@hseK~Jr=g>x+h_XgBHhL@ z`AoV6nZ!QTg~nR-lt{Fbm9yi+Sn(=R@m5jsY70}ykq(vu=0WJolaY@@BhzGl z*2ZwEsi9#BycIUGp((*<@ydJ@x?Ez)a?wV)FOFG5!40O1-RKp$o9{~#LyUz#Y>DoC z?^rQ-nUyVuMJm@l2#fz3@w`Mf*#N&vi$-Jcsn)^X-LI$JXT0MxV`aXY8{h&zCns=$ zvAEzhEe#KO(#QwH{qK?6}6g;WU( z3yn`2WQ0YzxcFhr?ai%bQhITEa@tr?jRxKy9s&^)6JuG5-K(5QdQU&U{9~{rQ##J{ zWyK-7bw{*ehM6a8kzQDvefgdv@t%c05}#fqkEJ zqb^SI&}7)-#n{?zX_#0(qOh^D|M}$6)QDVawbJgee5+Q6%))F7Q*Q_)$;=jmhiE>+ z1^YsklQ2~!sbgVHDLuo)Yed-LMH1w;sBgKCOHXfn(F?b+$#(S6l9V?tduGBfjXij| z-ZoR$W7+t~vw_QttmbgSlXPY^Q3oEmFlpgecBE&RT3@J*<8-zk^{@E8#Gsm%ZJFY& zb6dB$PcvgN405NzFYuE$KL5dp>FPye7!4ejBV?(AqyBoBpuj|9Fq~M6dke&N-BX!_ z0hi*iVYAy6;DUsD$J+KA-;PYEFyU1NAa z);5WMJur2zXZ->Db%7~F^p5$SVxNXJ>LM)ScJeRGyUwKaeGZIv4GVHxsbXePHWngo zL5`0c%YLu{!5B0&R3eYA%a@DnmX69t7~iu|vD+2eXYa}M%c|=2O#ePZ=jQbsrbAY4 zL~cL|1C{x>(&k2ZmZeo^c~kgG?vcrG`9v3ad3pKxy7(x0c?IRr&{pNp(CA$r9JMOZFLD;HvbwkoBhKK8NUQ$e7DC)i!jK{b=*a`poFtYgg_(tL|(3v89OE?KI<`%MpX=KcB?OZ#5l z@LJRzo8J5S=LuaK-w?rTolF~NoVRsWZ#V5mfng%zdc%6%{Y)w3WGk7o>e*t|LMb>YT`>y3c1gU9QwE^2)i6^tu8lxFlLo|mqqRhOFEvc*=AlqdpW?MQ)v}p9O zN@?L)Jz=3QW zK{s&PQf;p3e)6-lfBQIOpBoN6QJ+(bXcKG7xL$IlU~+YhYIW!|42~CNS+*~1%-5S$ zh2%bxz+%Njt6f~Q^IO5i8+9vF&uS9K^I=B*4Mw&`78QBA{$8`ScbQRTSo;$9)BbI% z)c9y^SmY`f2%$)NQyHZan2x5f_!N%@nv4GvSTm|s6&6Rxiq{k30$((5z^P$3I3d9Z zqTX$?c`hR7&4i2BthFqKB9b`#L?`iNiGf9M_1=xhTnluoMo-4MK`L3_r7G!Yr0&7p zZV`t(blBjFxo+`ky_tvytO%dUR*a#BB{|$BkrW#45?=?cI{;YP^*)o%FD?_7ebU`q z=%pp>JW+NKg6d6wtk#O#N9bh}N?C5HZC3N7qz7q4+uHKWsOoC0jX`m}cG-W!cu-c`kC)JSb*e)t-}YyHOiu zg^S;h$K?i|C%I$~&iZDSz^u3cbiwyjT4=({aK)1>l+ii)>RH43Trq{6D%XgET7|(3eA7~b zi~CbDvq%xvM8p(o_eQ&EHH;z(grZlXtO z*wnGbjYB^@m6m6d9qXcCnYN+rHP8HFTz$3C1x+kAsBBmpT4(qj!%CTxgMuladNS(ouZptn-mKheT799$Y6%8j zoWO$BFBsG`JJ6O+i!iUV*rQ|3IYkce=EYQxx=He4Q}}R?0Wl8Qt-HLm=4X^w8&%)o zP0fUeyTgofWjfaC*^KLMbBxki>_z`@g(&o>UZ!SwVZg#Tvrtxl+9+$7!v*fDG{3E2 zsN1OF5SyBnxLL_}DTL-u1e-PWYgJ#)s%NX2WJG@)*7C^soq5s-cGc-$OX*AUb{X%M zYOTkpcBO|fy0XNnsm6+d*+UVCv|c;o%Z5z4%i{MN^6c!vY>SnHgBOhG?vtY^9clgw+hnr*fRteQ?P>3*AMEiF$E{PH{~m?V<*l z$1Crb)(w5% zyc_#e`ZZ(I!1i+SW?emmg7y$o?2Z9(;x&PuqD{Ph{^Vod7wl=wCc!&rXZy+Vl^UrQ z1w7?Q?^E-6rTo?OnC5&v<}qJcx5oO{>B*f*n32xO*3QH0oIK(iMksq)Mf)d9G@c9m zeDrRG`R3j7rM5N1cc9Gnp|H^P>`Ns`meOj`ZnxPeSX3r%X<})iprAi0bH#UR#L3p$7Rx&Mz{dp z)J8!?0iDpAuNUIMnDNznC$Stu;R5N7y`6#k+;Fp6jkVT#qHcZdy%P>&(>8hcOROwu z(s``Xp}DalQ!ExM5$uX>Ogouj64s-1>lxPfbgXB6r}R>>9dUOdLZ-dqQn_J+PS@$O z@5`_dq5#)?}!Y7#Rwd7@IunWR*&ZEIh zvTdz!w8XKg#)iOoqWEhrOiZKiMNi4f9aD%l3iEb-VMA@>h|iMT6E>y%#9ICLWfZZp zGNX-$N5^BwLaRN>3b4M!!K}7>_N*r-eB9VrX@abc5LXqQ+whp#xaknr8DDURg32%iTdH06;t z43=6_mv}O)=|OxgOKDJIwC#!RZRSSg)9Y1(K13xuLD7(XrQHJLcGH6@Em)r+(vXTV zG%*)Bn!rN8qLth<9*YmXaei&GoMG5tths1AKPXSFgGI8a&6vkcw08EPf+x(8rtI<& zBmcG(EW>@nqB>}$>AZJfz^UxvI0CJ;D5l@W<#F$13A~M>l{z;BNhzsWn!)=jl^Lf} zD>n&Fty}<{KQPS&L{dTo0=Ym!z0FB)IE{rAbZsy%ck5qUttb6@_))NCJF8tKDRDEK z9C)>0q?`3R|M^2>Wjo^p>iQ-jpp6TF=Z2OhU7}|uJJZS%?72X!1={^yv+T20q~!ju99Cd@;-jHULAE8i8qR z_qGMg1gF^5zH2GB(|oOU*`+X5QOj3?xbF$G++l3I=o)L1-lAnr>`GvVt6droR}N>h z*kg%lu&|zXDze=dZP4o(^-L?{@l3bV*ONUG4}Aoszb`ZF_EmAn&}L;au%ZrP$?(<` zZ^)^K`^pjJdeKU0N3~XJUkksKru!I=Q1-sW^^maNenhWTcWv|Gc(u;L?d=gjnd zF3h|0C66%{VxlU_E12H<^`cgGLrw8@D6`zTI$HD|;r@;9G}?mEiJK*_q2sAJj!uYU z(}eorMw&QBv?(l!MSFck&o3si(lbd3QOX6(cP6DrKikZC@|p`sQJC;1d;ea0)N-{W zS!fa>mSW4mcOM>Kni|uOucP|?#c>NCfBUgnnfKnQzDqYwxP*m8!NOh#^bjo$_&rG_eyq$O!Wc^^6lT>5nGc$hOYtH@A zF#BO}e6sRuoLNq4a}2K7=}e6A1Vwedm`bU=zN@NhVzRgBYNm%{5&2Y-Ol`i?uv4X1 zJri!1_NviR^lnp6{>Faa)AT~bAUS1vDtP+Mq{l{7S-0BmeDy7;MT zitP!#L2YHtee2|1>s3)%1uG>jSHs`2(aV97Q|;sh*qvZT&S+8^D|h|J>7220(EvZQ zo7OjD1B}a6luU*?_kjC#=EJhrH|gV8TVpMBRKWardvu8pq~4QauKWM6_U2z{pX>fN zeR|rS4oSA#n8aw}t~u4HiB@sKai6^%I*1-OA~8;lR*18L;(*F-o5nG^Q;mv(oUI8) zP>7-;qLRdc1_Wv-q9PijhzK}~1Jif)`T5(my4LgDf5GR6&$aIRdcWVV>yksf+;Nn9 zLTeL1IOf0g!I=>o9MaY~)gq;_DB_at=+IfK%)He)m`nf?A|HpB=2F>PmL0Fg9PKEU zinctt`0;evzPuwf@p;kI^YHFi-D%LI~aQ6|8Q zQGz!}Z*!Own8T%~RWx~9k(ik95UAs{)i^K7DCd`0*6Magf_*qsa$Teo^6&Oqy>O2= zvQHxP!*rbq5ROgSj*v?%FC}2DLFYqjXeSU`U_;055jYVKt3h`npi_aD-)J+1ESwb+2Fmy=1#M>FOG&U957dSRuH!WeYeW z*uTJCKbPMa=|CnAJUf)KSS*wc;ypC0M7Zji&#NyuS2I9AxMH1Ik}NaG|KGi?|F`pp+tGko zrQjMFv8{YDedn(5)+*4aY|+2X9}lH+=@wwikVKLB{MJ72iyzgpxbrY%jV_go&CUy* z_3x%Ho_S=!Z*D0BgOraIP5(*kv`G&*ah}WdxUKs5>VcN_=Cvp#m57 z9LtZ=-=vaj-ebkmSWPbTWILycnRE-R`F-+GZC)hm98w0I0R=<&LVv5jzOyPe>W%nI zpC12M{MCxVYSiYaI{lm6hL|P8`uNhEFD=c9XLbpnIjoN3ERgI8Cct-OIpq=TGQyn9n)*h{JVCc_3PBttYpvHUnbt>&Z)sFHV$dDH%GE0n=Nz!JWG-gvs2S?gHVe6 zaa0VAKi1FJtQU$ccQ=h{|0VtgnbKqe;6TBUwo$r&(T+x?S^ZProPp&baTVeO2%7gQ z@TG@j?KFem3C*8^bOzYZi>V_Q_mR7g#Awc#TOB? z^myt`Zmidpe@-rrCqKJY6X5benM{zv^TvB{U1F$?m6bKr$S}cexw*KtxNe;G8ug*_ z)1R+CpG?k0tCszL8NZ`_e}9EEmVc^xdAsvm`NBn8cp7n)?Whr;OHw5GK+X<05VvDXmN0pB#4W_Iag?Og+GYvtzBRP1QQ`h)=GU7ahW+*r4@h3BQ30NmP% zb#VpPy^?Bc3mP4TsCkBG=djwi*w&LNESXAO)LjFq9=IiC9e&f^`ba+RLqF0DX;bE} zit86D6l(SHRKlXs1dvuT!_pg>IY#4^GR5y@UjBGnSRqLAMf?{p zk`ROOJ_b!&xB@Rn9OmZ-1(hxLr_T;yE=)tAmxHijL1=`O)N6?_G?@T-Iaun_L(o2| zhOS;2Uw*9A(Sh|nI3eZCshfaYDB>{cVDJ+Et%;MHa|1BF{{=Na-&mCi2}8tlH;JM! zNP_~u!?jPiDx3-2*<7n#z7|mF*N`=EtB~IB8vAF@_17%-{p>{6VAkS-CtSTt&b&1l znT5j%Z1Ek=W_Z9M`DuF#g__ioT1h68kR%6^9lT5UMMcdzqR+d3Lm%(|*=}6d-r>Me z>^uFAw0x#lHOm~a(i7jZBkFHY>+Ro$H1N%#yvCbiS2KKAZX1xQaA@TdZsDoeWpmmk z!7X!kD+db8G6CF@o%41pg|!J=J&1s-vrgM~(iRo#^q{Jf5+leH%0P0RF7t`ziI9q9 zO2+*q5v$f)%FxACyd0U>m2NZ;H6K;pm-wJEL&I&RC z&bb0X^2gJv?ov55LEU=W_zoS&D|a}V7McJTr8YDZV1VX1@lMy#stRZVkhZ?=6PWyb)PU|!<%N>u86H71p6RB3KCN>9%dlgy)*&t5g$K^`)SVv==Hq% zn!_i|$^YEqdG;3u@<_f?{FPo*KHs#Z@Dt=ynp9*Q8MxXo#oYQbI4`cfx^c5=gBb=3 z&J*NGf+H;;P~c^-M+gKQXJ=<;4;%VCaQE8UZI1KRN<1m+@KRcK=7WcQGNv+v5D_nW~0wuXQB=et{(ZR)KYBG?yV~Wa9hg5^YR9$ zxj=a1a7C)osy;5N?Jxnf5{0F<5cBDa#mcHak>AK((C;Q5|L`rhA93l3Blej_0L6_= ztu8=UO0GxD02?FCthY5shkO+JOeL9u0`1gVMrbsv!A=F&JN-z_ z$6L3kl`T8-6Jdz3sTjqS&rr!&Y4}R%f1Y?!8nWV{@&h0wuCB5>Uqc-;uXd|f|{LQ?bU8Rf3ptcqH4lz7qv=abcB%8 z_+XEdDeD^4Ziyzqn$E%Aj2}Sg{>51@|+?iRT0|pHr34sbd z;bUy0jO_nE-V?G04?d*lc4RT0k@bV7pjPsr{dvUu*}eO@IcDFeGFve11KC;1TM)v6+CVZL|5!mTi-f zoyJoVElD2D6@;WRgCYD?kNJ5Dmu-qAO$(MO29uibr-{_?de{{^q;S3= zXJ!3`?BL~eJj*YTjN&b?Tov5Nl+Gp-P;skqr=2cCCV&&7|K@aV1&#!t<{ntX#$ zYXY46ixRa2LcfC{%^if>KEWq|? z1LVqyiEzm2TRZ!j^i?7q7B})Z^Q(5&E-}6YB|tccmN|xJG>rB~2y`CzplC55cl*c$ z__2IpZkRNDSjn{q)hNQ3JHO>fzUwXPVoDm&A#r8Q{Hf|6SrSLZjE~AyyfusM*Uy88 zV1c+~5N?*Zdt@DB0=$Z!CXcI3fGixMv3Fc6)JpD4On`shM8TX(Iwua1MZNnbfNt!X zOViPb=gd1@b*qLr2(Rw5hk=H84esP%?5g)pS`n8ptuQ;K8+&~7iH~y(dxT5xvYTw3 zmkG%+ya02KpT6w0H@T1+5wMO+_sdhYS?1Qxt7270>(05nF9;|TAaZNvY(YxWddmjy z#$H7&?P`yQ_K+sn$o#0CQallcDmE+`u2GKQL_1dW(^hNy(06m_b|VL=?W(xpg0 zO|r%0;Ru+(l3^*y_>tdZ$q4@YZM*ek*IcAlsZm9#7v04`=*U?&{$jXo5)Ri~IT2rp z@2io^{%V6Qa);{?CqCm_1y8p0GJ0BO$bQD+`%6@OUlnz=Ya+>s>Q+%%MWVGm$Sn$g z5$y3cDR3Y0(rtCzTWwf%CcVEsd)a|iaMPg;U8HKOCu)v5E*8{^UE}9ScGu#s4JL2j z*x&1yhSZRf13W@`*NHR@%>r2FhO7IwG_EwaL3ddEdm`f>{_~GI>R!FNRVOArGz+{X zTBmqsfFa>UDHbV#&gPPRZBD|O1%`S2ki_3RU)g|`|H>VGIbe>SC2FVGE@uUocMvAP zXLE)6Y4?3(jgse>8d zj}{^tdj=1T%WvMNCDyi`K&#~TIR(-DO%uTW+pWV}DlJoVzO2l4B$JxQIcvRu2mpol zlA9do<^}rwy$b!$%|fbox_qxZ9{)ILlg!$;5afEKwiWHRQQ14=4>S`{FXytS5^s$F zgWOyVkT)!Nr70xV8zw+g`H6@VdZnDH7jCXvDrs?L%i-NkRt1!{(#r}n*Zq|vU0;2! zOHf>IcYZj&cvwH;fe?N+gzr3eN){fdKyvdolrhQMbKC^zT-V3TmmgiP6gr1%{RB)w zsY{vtmS1Zw;8(2if2()Xn-acKlJnZa2dAf)5hlQmxd#Dzynr*|pvZ|JfvsH+7RF1k z3CyS>|;Io(-uS2>p};z zg8=^)C>iL#ekRxiuo<19e9WV6Y$wX6Aq=mOsgIm^*Qw})%QA~lUz!WQqHTHszt>S- zTV{W7D4qf>$ODV?eczll&eu(|2tJ7D$fmOapdD>a5_LaP&wF?|yjPb_%({Jec*7`q zownlY5t6u6((vfma9d?=c1Q>a_Z$nf|2@|1kE`kDo{X`Zj*!iF1{KH_QE%txm;j&jE`Ef?rD2cUwW*hlTQ7>77-rEIlFOB+A#x{N-<1Z#a zXJ<<6Xr)||HZ3|CvbIysG0ZuwRUN6pkSitEYff38(tkb^$i7@UkN|vLf00gBltoX= ztp5vQsq}!>Oa@I)?{MwxrCaw0N+`=XW~Ct}<>aBc*bmt(qEJi66!H3YnV>sJ1r!hp z(L1^$UGBTZTUfU-kRmEoyromAVirqL7BEsS;kGt(>EU+nF$Nb`dtS+r;!Ckh>E+Ly zLjxYb?d;qo&eW%yCV*cIka_88yS!#S3DtR@?!!5USZ4Wx+!ov+@fDTCWBKI}=F~`; zVKnwz6F@Xs(`lxBhdW@Yfcmv&q-wEyQ`fjyQO^HdE;9js4XmjNbiw~5#c`e1Bw5hF zn~WsivV+aE6fS&*MD8^MMkzefZTw3Pw4X1H#a5x z-UqTzvK1ky({()hvaP+$%+l-qcPJ)+;cv}fbl%T@loIx1s>i$N+< z@kTy~8PyIt#tE+rXpi-}JYCxu!-&&M2U1Odn?8s9N~zF>x~A|!bi&T<(S2{b;p+6i zJaKh>lzWvQKy_BYgt~y=W8wZdH5br$YD|=ISFqGlF6~LL#2DEjCvgV*mXeIj>oOt(%yTkNb7dms?{6P-R=09g+uP?yoi&O#nY# zd?E5d*d*+b;7E~y6bD9G#(ysj3FOo4EsCxXGn;J#1Vblw+DfMLmE$UBXFisez`wRl zqsf1zdR{qcA4X8^ymK~JIRUTK-#Tw3lUjPh#FqRhxkO@lsB;rtH_UguT9@dVbn8tN z7gr&yJ9kL!>18WlEtS}t0R3!-R$sGXhlxyQ@L)XtGjmrxuer3Vl8tVzUC8A46dz>a zF6#>a`I=^IH>enij}`V(x9VS^2|ur??%rZ$RX6aX6&C$DLsdy~SI~?H1m@Dsx0j^_`30}$mc4<5Z0U}0CWS7;rE`O2_g_R|x8p%Vc63wi=ym7RTLtvJrQ@d2S zHb0-^9A2Mql)tK8i0`=0qbX>@>W1fG{HRoOv-1&Wk^_Wj%B$hrM`*f+gjA_gOaS}5 z2}yFR#9dH=eBj>K3cnp} zRy(fr$0sYcv)tZ|i8#Fv7s`?Eo|h0d=wsN{P(%Md8sUb?mpIS1;3+8{Ny&blpa-Q7 z4JJUwsjOu0J6A8~sbb?(9*4Ibw(C{24w5AM=Zn_pzPC|iqzNz_PzA9tDFm#K+w7>@%03Ttl)rPdvUE7t zlFoYMBlNA!JyHwnzJI0hfw!ot+EIqv6NpA^@%TSUNV3PQeZt(2;69oh`kSO#Gi(A( za84enWHlv_c$(y8a{1Z7rIJ$|l-IKHAzc z0kQ_imv6paD9og@S~>L3S+U8Q8=rBVZ%w|*ZA@jCvx1{HsYFTEFg(c-Pk;3f1vNpr ztI>{h`JXHkX4j;7gIoG+lH_H^%{kd9p=zNuF)cYuN>Bdy-pkw6!%Y(9QDm5Sx}BP7 zz0pFhA>x+bf|Ri}2gHLGIpoph-g<0uGFq&`u_D3C)4d@R^R6>zLLh=#u!C8BZ6D)9r9dQ3w-4WH{5AZ*h395SsfPE)zS zW=Q~zxC~=KU(Ln-t;KG6lVCrX4AQ0?U3EGdW}&ZBm-4k(E=uH3*V*uQJFkf1jrOYR zvZkRs(h#~TQw{ngClm2XA4%581iaZhrtDv1@ zc#W~3DTv4I;sxcv_gqIKxOG44@FJO{VOCV6KODu(gQHcX)`#asmJrM7l!g>O*PAn# zPe8TZxVuCcz351DTy+t*(KROqh2MpXS(=a1TU+GRVa2}ouuxE)S&KD#`EMY9#IK9yP+j#nGx0Aw@ZNm_4YvY^E7LDMxvCXe|Bw4;9Zt-hX zZ?<>)$?=Nt7G+xkAE9GiUL(RIe9sU-;dx=owxSd{r#h$Z`FQ=p4yKEnc>UrHap>+X z{e`IkBpIogiN0Jt5bP0_ZsvK-kA!UIc|L!$>q^YPB$Z)T8EYc*UFkB<>V@*lXwJ)o z>P9bA-eB~FVcR5l4YV+AV00B`@1V>C8dGK5v~IlA*)p;_AfR`VMda*Pzj5#_eRgf@>F} z;s?4@9{EGm>J?4xjg2*qjr(G+nRgrE{POoIRzRX-^fVuYG z0(+md2Pg?8=%3#p-v0Ni|JY-1^s-sLAC~J4bk^}#Xd|~R+jq|d_>Prk3`nvC&5OUM zBi)G&{VsCIwwHm~*^qMr)a%ujcAK5}Vue6pFn)?T$+L z!v|iHZ&TvcN*;)uS8JV233$ru^In_czj*<+SQOYL-%Fhr)0PvH7FKV_qqK-l#JK|A z)}MML?$9fdZKG@~s+}}H$L--;hK0n0w1hKDRbpZk6+J11q}{D8*{yt?Y;z8%4Q zT2$V>wa@;Io;robdju`v9w2LuBR=H0oJ$gF zG#gZnha7#)@38WLeIOQrh^BxBwZF>9BNY500ig@&r3t$-(6yed`nc(Ry1?Ea5e|yb zie7{*Qq%E6DvdC}5>u+2b25iUa_YF4vUQKmxSr(~C>7%r;XJZ>Pv0Teabo|AVgIdg z{dTjU3*UdVCP)CIZ}4wrY_z!_V%iG}!+%nvev(ytD(Q)CUCmX#1rE1j zZixVb^1VcQ?-TpZpAv(!BG4&%ueHol=J%8=&23U`N&%UZFk0~f{4>|yC#RrCWWCkh z5&nthgDJ!2=UVC#(@%=dj2lIEy>@69o5w?l(UImr;JET+$7ttk2+lkA36Extf332e#xL(T1LvzBsh_P zJsQ&e;`slMdc1G_TW#`yk4hglm;ea>@2D75B>_=;8(XMSYu*k?KQaN_$Zq)l&KktZ z_NL*u?;5H%7mPLm;-+%L6y}X3-WZIZZ%pT_u^H}&-@f7jsH|J(!z!&evh3HAi*v2c zrKztlf20tq=U89AJCO6xA_Z9SB95eaTKOQgEic6aJ5~7igX)7j@@ohr{b!fYbo=z& z3%k*tV@h?4vuq#=7O~rG{aN<~pV~YGA$m93c_zvPko}qc*SF|(?s%r=!NA~EpQ`ki znWcmW^AaVwncUKyoOAT~5wP+#+<^(={P6d>aKV3T%dhzjA*-2}x-EE@d@<=({o2o9 zH^o`4tZOzEqXqAIwkJCs0Y+6B$8-7Bq#FfV7h-aY4{fT z@+QQYGQ;B4j3shQ$6;7_u4Kx86qk?I4|L`D{_QRqr%>TTZN`L0f9@GX%cxaJwnMLz z%db*LjPdNxa=%|H-l$66huhc2C<3MxeL#uc(J6L5;o(KHkama;Arz&%g7oy_r6p;- zWmz7_>&x0aK^&qk0q=X>=v$;BI|F^N4 zHnj?3_Wj(W7vYJcP{q~DK-bq90z@rIL9`MmCLl=)jeo8;yeV9ndY9AP*632>DA zL}+v`sh6nLvf2(lShKR=c{wlQvr@c$n;#IZl0O_kFGdC}wiD{M!)+ZeP?!~vlV>dbM*D`1(K~>h2eryG!BmY z*A2vD#`Wg#uTDOa`|yC@n$WM`5ZT1K(XUbo^+Q&4 zLU9hyU^x7@(DFzq{yiu550lI9*ey=TNikCi+q)gjFJX^^w9~2LmDPhE^Lw`^z`xBO z!V6i6dAeeQN-;dNK^g`U0>e`GOaRpUmHK)Yrr$z?wAB&{1c@YDk|RlZ@0|T-t#G@M z0I1w-8dpj1>E|WF*`7Nlz;|BGdD+Cj=*C|K%y1y6yIb$iR<~aJ&GS;2%eA?s z58rux@@*>b##`WK!OL@(BQnC!hY^T!>wbxM8zVTdX1QI=KU&Nr@&uYUSg-V~M?>>E zQE)3Neldi@1iQ~qLC=eT)AO@E2~?)&tG5VHBLV*;i?(h8m_g4+xDCU}@KkPBWz8`r z2_vt)M#R6JEus4{ak0+Hu4$wR^UnEg6-XUix(I#C=Ak#w>W zua4-4RJz+;m6a_d4^BJ=m&xl@%$D%mDQ&k6y48Db*HA}DGMTO)IV2?^ zSGGl3qaNj3KPtwnQ__v|xOG)q?#g^4+YXCN86J5>kLMLZf?cD8UjDW~T!jix=lTH~ zSJ^*=wy$Mfv~LY<@?V?Z&Cbrohnz!WeHKNi_nxUm@g8q)@}nkWGJU-=q0vPXDBzQ& zu#I;+>NwY$)Xr~C{k~z^Jzq`j$lR;%zuswezkMuIg|SCK)32oICn9`tD6{+2@Gs}r-MB`ZCazy&|-;fDlx(~^tBW$l?g)?uqM{LVbt#Ps@J#KNk4?6tF6}3J2 z_yftk!(;Wig0jotGg9cpAHvz8Or$O1k69Oi4o{+0-XDj z6{i?a924Q>^4CQ%3w*nOV6uNm<{(4v$Zq{A*I^ZY4 z*>Hw4X!hEk!Wg(q$X{(t9AQ1x`y0$WiH{4Mr0=3rU&DyT%J((o1dZ(Ou z(tn3cYjqc+ERn(;Q4k^uQb33b3eQ|(K+v9^>sjklviRi}(&rhOKhk%kUWhxH5U~6F z_?=8hnivEzGlzLLE5dIJ$p5tQZMsg+l1m?;dBy&R=zwsxrjHMC=N@0uXg|N7`6{u5Un72 z8_qt4nyL~7mL)8X>7f@s(n5j|l8D4hwIf6FrltX;=LMHmsF_7N(ApLyI^roN|Ap!3 zC*c_SpSgBKjb>A`saC-e_L#D}_yFkcI_I!(S7k8Nz63cgv4(tyK7m$?g7r6bms-7S zyGb(X#hbGBr}+KKs;9MAk2YM65vTviFaf@#h494--uV2BM?BOHx&Vc_At`p6jGKI; znQ>1}X8=7!X>!(J4+MxuJ>`LL=xdyWUkdT`8eN{o1c+zfFbpA-0~<}OfJW#9+yZ z1N)ch2X;13z@gvGLE=I;gbtOWaXB$jSoJ1@u)vI((RWD{ zf>2n_kx|{SsCh-Ey&|qC9{B8gmo2~b#_XHtc>S479tYnld25G%dl#=1-Wb^3+}wOM zNBoQRkK0}jvCAy!L#FPsQ7qMAER#RDH@>0~C(1?0p{m`B@Rl?^E4tk-jr?@|w_(P> z)+{ga29UL}U#Ldy~yaG2whXT&sD-2z%?w3Ss4edFSJ2hh8qUTwlMf0GlD5 z$hLMV&2LHrjB*M4Ekya{j|blzWGy|Q|1c%(9gCIRA7!;ZNpqg`ZgHJs!R)%@FSI8O zZw#c#7VJ{FAaSn9Uh#@McKp`!zSG^++#&MrrS61lW>pjMtSB*3t`6pIEs}>jK@)obl?voYtj({%8P zHY04xtSpy$>l%+fXs~L|TwbaPT*um=5o-Iope zj&sMe@!XmI&o5Qq8oA)c9|^x`o-{<|>n^5NY2q1isZfgCW}5?gDp7+~`s~ zp;(tPTk!VXV{8`tNwhl2s{@^JXVAq7WBviM2iM;tCCPe5)5IQe4_f<+8iWDE`_vl= zEly16!Ul=_wz=|wdr`(3u;}RBBJ`Fr`~HhbHJII(3)>l5yy`ZI-mGqu=FU@kAIHhNQPaV6a8BazA-}dGV_a zvSM$KfUG1Tq^{#M2F)dHCNq;y#joz|a}fzybP4g?hnwpE8PbTTEhMZsCAx1REH7_kl#myJz1qz#_!NP5 z-tQuEH4jpar#eOX=s&(G2$w_5Pq3X}5L4Bd$WCI-`?ki%%~cnRU5UzB``^B2j@8N@ zdL(gANe}3%&2B(X5pX)o_l8S|5)Ubk-e7Dt)^?qgO?NJ~MK}tCd-gFT)VfmqSclMU z2#mqZvr7;3OE=4hTM4XV{^*ErqIvSiKRo}Y8;0y+B8TsiSifQSF$|9&2^1RYX@_vg z%00#wzq`e0AKbXZs4m=T2KR7hWiMk`16l$vDz5X6lo{-C02e4k`eBVcC~@?BB-(i< z{=CF}dRiM9VE)p6n^C^#_q|=2Mc|vY~c<^@Y^drYspX zk5qM?lt#vU+Ch7}tn5U*4sFzQ&g=>N-K_&>bb(pq;trXU{SB^rc7^U>kPi=GoH8;3F@6se-Il<@!>ky&lU z?{6Qba8dY8E>H*(#s~DiynskgYA0_RyZ2W?r4vE{HpRS>g_lSPky}DAmQfe?_X=iQ zA)<*f-u1h?I{q-Y_QC7Q)hlf5e88k2Lo|Nlt%t@9rur499rN=bp~f;NW$R7$4Jk7X>xQh& ziu4GL;=sI(C zoE6ub^8;Sx_-l_QlV!NTVT(pr>wGSe&RdS!C~ zqk9KGpguJLYDV-wNc<7u%(|?|m&jGnw7%I_S-#=&3j5@~Ch1z*H#yReu{lHO4|~1n zAHu6#-4m+Z=m;D487ORLWP{{Xm0DdN;p<3mZv1z`qq2K(PWI|?#5z>(9u{5{6ck<> z>FR13hM}uw9>NXMH15&vlv z`IVGDu_j7DoHeo3oPVm6ZmUq2vLYPGca1>`KjE=f)pT}b?5lD3UVdUg;6qn@&bqF2 zxir1C7vx3pNj@$fQuztbQvKXCcnJs1^q}~n^nMD`h=7gH*Y-u^G2L6z+sV%kCQzw_ z)QVa&yf#$$Vs5#e{qG3JvVTd(@6BPpW8JE5j+pK^*1Vm(MV{r%Ye6$7P3e9;M_1lp68BS7YSN!$242;}EF%*T*ZJx~&VEkuv+MYpQ3jrB%Lvc?b@he2D zI208)fkyDy;oTC^wy;a#0nAPHY~t^&2l~Tl3c!Ej2UMG1F`{EqyXDlfEn0Hp%cZsw zq3@01&hkq_mt8V_{+1v!YFZ*``Zhm*V)w^InTF!28Xy$O8z1gzb+-B1yRUBYmp&xP z+3P80W*|gEewoo2aO2h55r$ON4Lz9;^}%=eBSisY)FoVsX7;I(+W28$i*)R z@84D&wF+`UI`8`l3Cm_d*(QL!RXz9qc5*>1)~f)XZ8yoe%}m=ePrZ}zHkBbHrRsU+ z=qeMy?$8W4%?v}em$vx)$3eILLh9)2SkcDOz+F}rnf8{vI7&y_QgRz4?%$vva61X+ zJ)S!Ucitx7==iEdhh%L`axdCpA}sp~bh+9k_1kBXbh=lrF3>Fby<&1&OH$4;tMMtL z*pcVG&WTHz`n0OG;3sBVo+!x!M{p3>`45*WC(}JUKg$o!NBoFeH9NImo+q+s3;)i= zKavn~^`65j_nZeP;TIKau3>*&_kt zJL`PhxtJ>^K(T$<#|+8?!f4sQj*p+OB=7ZJICAWk~QM6`3hcZe08He z!5rvk1=!1dgzWQd2-jr9S&%bl?$6J~dfFX`%xqdKsp9isojAo>^=Jy! z;I!{N*83LWP?x=2o^j}BFlav~ikd{`DE~i!K3!nR26~$_LXI>2{Pkzov-FD{$K7Qj zW~gUP(7YhM^V~g!31A+NZE}}fAXPRC;O>7qsF5!hGjA=ID&!xOqWOld5e%npGC8+^ zmOz$YO3RWlkxL(cXaR-E?>yU$n}Lgg=VwA1U!WvFOd~u5O*QuVB1v-+2gEf{UVMUWmI}%!*4V7vuhk$gzT}=p1fZF|C7X1%5-T=%@)WifPPaCnkoT2gx zj7Bx2Tp5mNIzb)Z2!goM5>T2Ij;sMO&-s3A-YVpJYY|kVKx~~T8b=e%o+xDm#z}sp z-$tdtO@K%+mvRidjo__>15}{XNiQDkYJj}NX89+A;0bTG`y->T+NqU%MG#bCnd0hC zO#C1-;a&pHSGmFF)^g+@=eagH-)U!EDqWlNNT40xWcH;|D@T(KyVr^Q3Q}de#@(3W zC&+-BMJYxV?MF}S?b;s2wW|3hz?v>?eiSP8d@A+5Am`=wqn&@z52ua(IC+aSOzv!j zM)JuxvYlgR+pGXWYhiP)5F>W12X=c zs%&n-H}K=KBhR6hv=g;womGr^G&4>W(7d_6yxckzvQL&YxWWrZSLF|c}l=JqrT z@$UCL8@j>_3GY%!YDdu;7AkIf|89E{!GUDkEb1QnhY9c>&T;6QQb~bR_Le|<2cAae zQ;u9Om4rp&<>0)9myj@6L+T@l<>A^(*{Vt%=0y)%x9@?Y%m25@MH--3TV-Bc_VbwDTZhq~a^Z;bjnQbPRu^XfzeJb0s;-W6 zKaZU(QpxQO74!X}zJC1%SUXTHqss;3< zAS(i#Vq9lnN<6pJTMsND@zGCdX2p64&~oOyEtGM+8NYtb z9==#@Jd;q@T7Ah6d)<5V3HR)4#)YlK7t6SLolomQ7?d!)1It)qhWZ4OhHdTKo15-R ze|Y6(@7JW3TG{7%{r%3?)}JTO&xGz=`ozCGI5I57yujju2~fd`j!R=A$)tRo01i8w z95BZ%W~Z6}=5m+6d~)~T@j=I$bOutN*~Qiw`qlGPadm$NxH?!``sv_cxm@h|`Ow$q z@j#dl8J979EG)&Wvy*E-I4O|+z`<+f1k71@gcZCy*0Z%Q%rkfm&_V=d-<8oR$Sr0+dPL$Bw)2i+i;3_F+Jbr%($2?*4B|h!f z{5tBsjbM~t9dyg~lq$ptP!)(D0}b>W*wG2Nn$mw;fKdX25#?XD*mru}I?L7(C!u+3 zb62(nrTRkek0pW8xebad!=c3E|E6}~nzbqokv%5->+dz`fA}>IDD9E>Xib1jU+cE3 z+L#pA#{v|!D8;7em>hT3nQTY!2D@&ldD~ycl~xZpwht#0UZys4i$+^80Vs8?lZ@s2 zBA(f9yEdVmdWs)dRj+K%)VJbB#ZvNw5%Ed8Jz>0DBXJcUOoLx64?k^n^+Huv2nliN zJ|%m*=ocH2N+#F7eai$;^A8q#x{&L9X7OatnvBArY#0XUq~RnDs}bwgVry{cLlf^eubq<+1lOi948~oviPJ{VUA_Sn^WDXUC=qPTw(Qxl_})t>NPK@> z>^~600Is^fx)k34Pwu5>#Ie!~3eqMQR^jTn{}AgbQ86tl66FvA_DEpjCl*^s zZ5d(z*u-ENTJk2-4DH74Zg)J=q3T-CdGRpmEa*u!ZdzfvKeVgC_i0m!v6l*33!RuA z3M4$=1ZXG~+LTc~8ytKBl|-S2_z;lLml2W8EvB)<}kJj9au*w z0lZXXU3R!xJKZ-kxk$~^7#Fl-zdQNwkLyDK%jq2aPd$qjD^d>qi_KGJoc~E>=V4gR zQHu37ZXsIrQ72-R)Y8?4&b_Pz?VMsdW#d2oJf};@6o{BG^6?5J4$BorEdS+ z2saAM?rsa5jO51F7k^xK)B304&m003}~-LwqT3KD%8ne&Wz)qp5VOm<`<<*4&B!RLecP-v9=yy&+% zpn{l?tpC&AxkjaR3lisoby}z{P#Zl?Ein$dLUNN5y!7A4xi^=!Wusx_?_@qiPPuuFR)p8nS&EnSHX5$wHqr8&eq`gbJ=-zxO^!hde&}3tuU;LPr5w9cT0UlOX#+!X$U$X zTWs2H8-yP7k;Z75&e_th3}Kn=0mKfrvw2Li!^{S}=wAA)$#dxOfkZxdh)2OxJS(Az z?8aUf7~lMh2$V05O@Lji!mKAwPx{?h)%R8RAt79_UB4Q#JZpz`;>Ahe*DXKT&e}yJ zSd@K9N5EGz>e>eE;E=4{7KKxg9L@d5=DJ=x&gYqbSy9uriOZU+t}B|>OZ9{~mOs+F zbhE6mz)eqUzqhd|UXM@yjucxEsI569L>1&JF-j~o$A)x(%q{D=-M^sbVFz7o z3cLTi(DezXlBIvOnvz_qy$7I!hI0%r{<=MZt@#D-gjz?R&@J*WJl`Cfd5F@PxH-9a zS4UJ`8p|dRSmxM;eAtgRBb-SvSUe$>DVbTq(p^H~{mWoR7Id@e;z({JDn4H!(}O^7seOW@y}dsi z2uK5vE}tp9{X?T2Ul=@nfBRB=>7Py^7IM*yePbqjyfIyjV%0iGe?p!@;$^=A$EnQv zv&Vr`Vwx7o850B#W>xy&wj^dWAzs;cpfl&oim&*?4Q|_HKCxnsH5x?j8;pRawtfMXXQ|awD+>9)CLWc7LePL7~$sM zNv0}bDrN&z-UlRxk5&Y%ZmS!%Lx9$;qNlH0skw(_VvtSVi6zklG;?i+idpSfNvkUs z3^j=m*jd-+5hT)!o}A=m8VwqjME|~FaK2_CGRAr;)>jppIDy-BDJIo|qh$vV5*dH) z5*#3~cxNJ)(3N54Mvq}JwAZsCNi#pMWzWYhVS-^P)zSXjk#{o1pZH#?Jo=)ZAe%s? zj_OjJ0*MwFWghW26a$k>Ceu1q`8YA8{OHiPpBep>eVLeQ@lP4!Q!OggifnXLT`pw>>h#pN@~oXRsj0vcwfXKkur9`96+%ligO z4riRKlBDMz?~Aexhf9n2h4aOl;Ls>f6f$p_;bHD^vVsm@4mpHyU%1hcd8=(ec415G zbN%2lXS)#XPbcZ_&vbHCI<#%1DkLGyUJ>-)KM+y5#VH03`O_**!5mS{~%5#J`(<$Fc@(Zb6ARi)|~?*+pLs+YCP_nH|6DVl}#RYNX}n!EUGH)()w~=*L1t8e1-Ym38f;0D zXQpw37Lg~ZRNv3u&dwUo*S~XI3=WOcm613RK~|73O}mPSaVB}36oNg^NWeZf09P+o zc?DRyUYk<$sf^m)v6)iTC!a&W4T38nwMCt`xI9npH@pv(<4l@^Z!>S4VnSkD9hB@`|$;Pxk%WdPbz+NYrD)9ZHE`|oYP8m(j;^sPIT}mE2#M# zdamT-jNRvWw=J>J6nAxP2S;6q^L{H-1h^$3oqKz|hQrIYwRxu&jdafkzG4*GPGUUf zW=p9^&*g-ZbR_%(JB}=lu$x&%W4d<(^mdkK6AE|VF1GC@WQKuE*HtA%Gk^NRfK;U%Z~%=YLZK(l7(l#XChq*(-Q?KbdarNS3x-> zJ%W8MI@+Zb1^V3xsar~RZ(qxM-3aN;(|$m&c6V<#{3R+eWhjE9amsU>?oX-a_MO5` zBC!g^mSpV8M)y=HlURo*iVlHWueIFBkE4#2-(0Q?&5r!o__EdzhHRfU<)zj#@Cl&_ zW2sw{`EdQHto&-Ud6-#FERWiki3=O;R8c<5HDs!I@!^zK@zk zI+!VMb3t-c-!gak1Y81!_M3!pB6hCsi?W%3CTYwV$+kL6g1E~$nqn}*{* zouDf0RIO;Goyo7IJJgr%K$0stHYCTMPx=u;2CjkYA?k6N?VBH(;{@WwoJVM`Ci0JY zfM`zl+LpA3!8XX{EAlF_nctcnxfUc60!ad0XkFF<@x?BqObb>Cyn{R|SwTzvz{fH`d@61BLJax%3Hk1dZVI zU>8{r&OJ>6TL{6aLzn#w%BD2VPnztJ)KZo-kQAGcqOmlx{=xZ4Lmz=qWwZ_&v(3Al zWAGe^z2dv6^a;~ukGk_`LWx~wfg7hK>I!dHa~4W(6*=Y{lJz#Lv3mX&d{}5sQ$R-% z2i8sMC%Qfz`82CC+*sO4Efx^P1`dCb{k6Jwq<(k1uHBICZ6bVvQ2t>ZKBPi33Qmel zRuJz%k@63G@`Qo6BS7NRdJ^WnoFl@xbg`D{a(p2sOW{ByGR!}oSL95t4rCdrXe+3` zG=iYzGCXJQd(O^dn*rCQs3AWV!rq7Bgl*iI9Z!n(KH|pNjo+9^mK(tL?ha<`tkf-e zz@-e_QKCL<%|5jNG0Bh3nxHiypn=%cg$86pzhWtE!qwZj+(a3@lYU1~OfBZtGT2~_ z#^7&C%pR4%QW_8sIq#Y%-A_;QTXmu}N0E@F@E;Rhdu>yA^BN(qqRPoyy-7!WAz%_F z@>0M-P{m(ZIee}qF<0enfSxu4$xhcprBKMIdv6zhIgovRGAQ}Dc}!;o2})CGLzyU& z+vz(qox%NDGx|8WXmv#-pRGx+>std_C~8H3Ya8)2XK1~&#&KG);P~#d%%qrp94FF-^!{Q{UGLML9Pi(j z_>p#G5r;dqaZZw`I-Eq?9*nMz_LQ~~RjUQ;OgLd84ohbGZ!#d+erkazDN(beQ-l4L zh9T2c#pz6kaZ-IlyW6Rto$ckR#nTx(fXGlI zOfE|dw6J{OKN91|RLm~Cdd;%!mp`@4qVH^pKC7ksEknW%wG|?y$8rwCFPopM9OqQ} zo%HHv-_w$SlPd<5#$eG0C$O^^If=_)gH~h?@`>|aHLA5WuPb@6$BlPEHrLpBI*NR# zQ^(ZA5>jTr5BJ?1r5tpFHTF@ei7jW4`EE%*Vp#7Mt;6u??4Yv2Zsd$U62qNcn5hZ< zb+o=M3hLfv1rgMGW>m)}{RH6kn@fbZ&ZJLqrnf+bR)8~;SPGNG)kI9zF2E785A@4< z!gbaY$2=sv1qgh)i>S)Dt^)urgFia%*w*3=mBbPs+L~PAI_{+@5Dk}mp$i}M{NUdo z9u+e|jBb)+5~DnlkvB)$k`Ye5!br@uszoH0wz4|uVnS<;E^+yE@SqDNHeN51Mc#@# zhYm1#nM^f<>5MiP!^YZcYvSzH8%PWG{CQ2p_{CzDCtyrOYNWiTQ&%DxO!O*mWo#4y zZr_FR;wEV!N%0ZUYa+F&#|k2IAPo7R455+Gfw*ZWlFK$=a?w2BFo)w9cUda<4tEk6 zc(*~rkw>fiikZ2=rtE?xU4p7IOx93Pm{~c$+E9shy8L*hz^I*e64p1#JTt9 z0cmM^Q7Kh)eS7%z2c!Sj_4YEA_^)~6Z00v%50jk#n*BT5JNwS|&c3s~v+r#0>^s{# z`_A^xzO%iv?`-evJKH<^&i2l}v%RzLZ14Q9GiJuYhO%8>TPx@e-wNtrG_O+9oWd0O zJ)%Ep{h`O^*K@?L_%Ag^iVY_s*&{r_`lH%RC(IZoRN1!{Ets4Sd#$K2+ ubNCC6=>3!Th3z+z{TE|D80<&S|5rT*^Sb3#S84M 1.0) { + float offset = aspectCorrection - 1.0; + float halfOffset = offset / 2.0; + uv.y -= halfOffset; + uv.y *= aspectCorrection; + } else { + float offset = 1.0 - aspectCorrection; + float halfOffset = offset / 2.0; + uv.x -= halfOffset; + uv.x /= aspectCorrection; + } + + if (any(lessThan(uv, vec2(0.0)))) { + return vec3(0.0); + } + + if (any(greaterThan(uv, vec2(1.0)))) { + return vec3(0.0); + } + + vec4 color = texture(iChannel0, uv); + return color.rgb * max(0.5, sourceAspect) * max(0.9, fract(iWorldPosition.x)); +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + if (_position.z > -0.49) { + discard; + } + + specular = indexedTexture(); + return 1.0; +} \ No newline at end of file diff --git a/examples/toybox/musicPlayer/musicPlayer.js b/examples/toybox/musicPlayer/musicPlayer.js new file mode 100644 index 0000000000..674d9019d1 --- /dev/null +++ b/examples/toybox/musicPlayer/musicPlayer.js @@ -0,0 +1,328 @@ +// +// musicPlayer.js +// +// Created by Brad Hefta-Gaub on 3/3/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ + +(function() { + + var imageShader = Script.resolvePath("./imageShader.fs"); + var defaultImage = Script.resolvePath("./defaultImage.jpg"); + + var MAPPING_NAME = "com.highfidelity.musicPlayerEntity"; + + var SONG_VOLUME = 0.1; + var HEADPHONES_ATTACHMENT = { + modelURL: "https://s3.amazonaws.com/hifi-public/brad/musicplayer/headphones2-v2.fbx", + jointName: "Head", + translation: {"x": 0, "y": 0.19, "z": 0.06}, + rotation: {"x":0,"y":0.7071067690849304,"z":0.7071067690849304,"w":0}, + scale: 0.435, + isSoft: false + }; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Various helper functions... + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // Helper function for returning either a value, or the default value if the value is undefined. This is + // is handing in parsing JSON where you don't know if the values have been set or not. + function valueOrDefault(value, defaultValue) { + if (value !== undefined) { + return value; + } + return defaultValue; + } + + // return a random float between high and low + function randFloat(low, high) { + return low + Math.random() * (high - low); + } + + // wears an attachment on MyAvatar + function wearAttachment(attachment) { + MyAvatar.attach(attachment.modelURL, + attachment.jointName, + attachment.translation, + attachment.rotation, + attachment.scale, + attachment.isSoft); + } + + // un-wears an attachment from MyAvatar + function removeAttachment(attachment) { + var attachments = MyAvatar.attachmentData; + var i, l = attachments.length; + for (i = 0; i < l; i++) { + if (attachments[i].modelURL === attachment.modelURL) { + attachments.splice(i, 1); + MyAvatar.attachmentData = attachments; + break; + } + } + } + + var _this; + MusicPlayer = function() { + _this = this; + this.equipped = false; + }; + + MusicPlayer.prototype = { + preload: function(entityID) { + print("preload"); + //print("rotation:" + JSON.stringify(Quat.fromPitchYawRollDegrees(-90,180,0))); + this.entityID = entityID; + + // Get the entities userData property, to see if someone has overridden any of our default settings + var userDataText = Entities.getEntityProperties(entityID, ["userData"]).userData; + //print(userDataText); + var userData = {}; + if (userDataText !== "") { + //print("calling JSON.parse"); + userData = JSON.parse(userDataText); + //print("userData:" + JSON.stringify(userData)); + } + var musicPlayerUserData = valueOrDefault(userData.musicPlayer, {}); + this.headphonesAttachment = valueOrDefault(musicPlayerUserData.headphonesAttachment, HEADPHONES_ATTACHMENT); + + this.track = 0; // start at the first track + this.songVolume = valueOrDefault(musicPlayerUserData.songVolume, SONG_VOLUME); + this.songPlaying = false; + + this.loadPlayList(); + + // Find my screen and any controlls + var children = Entities.getChildrenIDsOfJoint(entityID, 65535); + for (var child in children) { + var childID = children[child]; + var childProperties = Entities.getEntityProperties(childID,["type", "name"]); + if (childProperties.type == "Text" && childProperties.name == "now playing") { + this.nowPlayingID = childID; + } + if (childProperties.type == "Box" && childProperties.name == "album art") { + this.albumArt = childID; + } + } + }, + + unload: function() { + print("unload"); + if (_this.songInjector !== undefined) { + _this.songInjector.stop(); + } + }, + + loadPlayList: function() { + print("loadPlayList"); + var req = new XMLHttpRequest(); + req.open("GET", "https://spreadsheets.google.com/feeds/cells/1x-ceGPGHldkHadARABFWfujLPTOWzXJPhrf2bTwg2cQ/od6/public/basic?alt=json", false); + req.send(); + + var entries = JSON.parse(req.responseText).feed.entry; + + for (entry in entries) { + var cellDetails = entries[entry]; + var cellName = cellDetails.title.$t; + var column = Number(cellName.charCodeAt(0)) - Number("A".charCodeAt(0)); + var row = Number(cellName.slice(1)) - 1; + var cellContent = cellDetails.content.$t; + //print(JSON.stringify(cellDetails)); + //print("["+column +"/"+ row +":"+cellContent+"]"); + if (_this.playList === undefined) { + _this.playList = new Array(); + } + if (_this.playList[row] === undefined) { + _this.playList[row] = { }; + } + switch (column) { + case 0: + _this.playList[row].title = cellContent; + break; + case 1: + _this.playList[row].artist = cellContent; + break; + case 2: + _this.playList[row].album = cellContent; + break; + case 3: + _this.playList[row].url = cellContent; + _this.playList[row].sound = SoundCache.getSound(cellContent); + break; + case 4: + _this.playList[row].albumArtURL = cellContent; + break; + } + } + //print(req.responseText); + print(JSON.stringify(_this.playList)); + }, + + startEquip: function(id, params) { + var whichHand = params[0]; // "left" or "right" + print("I am equipped in the " + whichHand + " hand...."); + this.equipped = true; + this.hand = whichHand; + + this.loadPlayList(); // reload the playlist in case... + + this.mapHandButtons(whichHand); + wearAttachment(HEADPHONES_ATTACHMENT); + }, + + continueEquip: function(id, params) { + if (!this.equipped) { + return; + } + }, + releaseEquip: function(id, params) { + print("I am NO LONGER equipped...."); + this.hand = null; + this.equipped = false; + Controller.disableMapping(MAPPING_NAME); + removeAttachment(HEADPHONES_ATTACHMENT); + this.pause(); + }, + + mapHandButtons: function(hand) { + var mapping = Controller.newMapping(MAPPING_NAME); + if (hand === "left") { + mapping.from(Controller.Standard.LS).peek().to(this.playOrPause); + mapping.from(Controller.Standard.LX).peek().to(this.seek); + mapping.from(Controller.Standard.LY).peek().to(this.volume); + } else { + mapping.from(Controller.Standard.RS).peek().to(this.playOrPause); + mapping.from(Controller.Standard.RX).peek().to(this.seek); + mapping.from(Controller.Standard.RY).peek().to(this.volume); + } + Controller.enableMapping(MAPPING_NAME); + }, + + playOrPause: function(value) { + print("[playOrPause: "+value+"]"); + if (value === 1) { + if (!_this.songPlaying) { + _this.play(); + } else { + _this.pause(); + } + } + }, + + play: function() { + print("play current track:" + _this.track); + if (!_this.playList[_this.track].sound.downloaded) { + print("still waiting on track to download...."); + return; // not yet ready + } + + var statusText = "Song:" + _this.playList[_this.track].title + "\n" + + "Artist:" + _this.playList[_this.track].artist + "\n" + + "Album:" + _this.playList[_this.track].album; + + Entities.editEntity(_this.nowPlayingID, { text: statusText }); + + var newAlbumArt = JSON.stringify( + { + "ProceduralEntity": { + "version":2, + "shaderUrl":imageShader, + "uniforms":{"iSpeed":0,"iShell":1}, + "channels":[_this.playList[_this.track].albumArtURL] + } + }); + + Entities.editEntity(_this.albumArt, { userData: newAlbumArt }); + + + _this.songInjector = Audio.playSound(_this.playList[_this.track].sound, { + position: MyAvatar.position, + volume: _this.songVolume, + loop: false, + localOnly: true + }); + _this.songPlaying = true; + }, + + pause: function() { + print("pause"); + Entities.editEntity(_this.nowPlayingID, { text: "Paused" }); + if (_this.songInjector !== undefined) { + _this.songInjector.stop(); + } + var newAlbumArt = JSON.stringify( + { + "ProceduralEntity": { + "version":2, + "shaderUrl":imageShader, + "uniforms":{"iSpeed":0,"iShell":1}, + "channels":[defaultImage] + } + }); + + Entities.editEntity(_this.albumArt, { userData: newAlbumArt }); + + + _this.songPlaying = false; + }, + + seek: function(value) { + print("[seek: " + value + "]"); + if (value > 0.9) { + _this.next(); + } else if (value < -0.9) { + _this.previous(); + } + }, + + volume: function(value) { + print("adjusting volume disabled because of a bug in audio injectors...."); + /* + var scaledValue = value / 20; + _this.songVolume += scaledValue; + print("[volume: " + value + "] new volume:" + _this.songVolume); + if (_this.songInjector !== undefined) { + print("[volume: attempting to set options...."); + var newOptions = { + position: MyAvatar.position, + volume: _this.songVolume, + loop: false, + localOnly: true + }; + + _this.songInjector.options = newOptions; + print("[volume: attempting to set options.... RESULT:" + JSON.stringify(_this.songInjector.options)); + } + */ + }, + + previous: function() { + print("[previous]"); + _this.pause(); + _this.track--; + if (_this.track < 0) { + _this.track = (_this.playList.length - 1); + } + _this.play(); + }, + + next: function() { + print("[next]"); + _this.pause(); + _this.track++; + if (_this.track >= _this.playList.length) { + _this.track = 0; + } + _this.play(); + }, + + }; + + // entity scripts always need to return a newly constructed object of our type + return new MusicPlayer(); +}); From 168fd2d72f661a70b70dbb701abc0e90072980ad Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 5 Mar 2016 01:07:20 -0800 Subject: [PATCH 266/292] read playlist URL from userData --- examples/toybox/musicPlayer/musicPlayer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/toybox/musicPlayer/musicPlayer.js b/examples/toybox/musicPlayer/musicPlayer.js index 674d9019d1..4a7655efcc 100644 --- a/examples/toybox/musicPlayer/musicPlayer.js +++ b/examples/toybox/musicPlayer/musicPlayer.js @@ -16,6 +16,7 @@ var MAPPING_NAME = "com.highfidelity.musicPlayerEntity"; + var PLAYLIST_URL = "https://spreadsheets.google.com/feeds/cells/1x-ceGPGHldkHadARABFWfujLPTOWzXJPhrf2bTwg2cQ/od6/public/basic?alt=json"; var SONG_VOLUME = 0.1; var HEADPHONES_ATTACHMENT = { modelURL: "https://s3.amazonaws.com/hifi-public/brad/musicplayer/headphones2-v2.fbx", @@ -92,6 +93,7 @@ this.headphonesAttachment = valueOrDefault(musicPlayerUserData.headphonesAttachment, HEADPHONES_ATTACHMENT); this.track = 0; // start at the first track + this.playlistURL = valueOrDefault(musicPlayerUserData.playlistURL, PLAYLIST_URL); this.songVolume = valueOrDefault(musicPlayerUserData.songVolume, SONG_VOLUME); this.songPlaying = false; @@ -121,7 +123,7 @@ loadPlayList: function() { print("loadPlayList"); var req = new XMLHttpRequest(); - req.open("GET", "https://spreadsheets.google.com/feeds/cells/1x-ceGPGHldkHadARABFWfujLPTOWzXJPhrf2bTwg2cQ/od6/public/basic?alt=json", false); + req.open("GET", _this.playlistURL, false); req.send(); var entries = JSON.parse(req.responseText).feed.entry; From 8bc2c76a8b59c995db92a65179e6d13e3b160586 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 5 Mar 2016 08:01:30 -0800 Subject: [PATCH 267/292] change shape-key when registration point changes so shape cache doesn't incorrectly reuse the old shape --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 6 +++++- .../entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 1577cac10c..3b100cc4dd 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -700,7 +700,11 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } glm::vec3 collisionModelDimensions = box.getDimensions(); - info.setParams(type, collisionModelDimensions, _compoundShapeURL); + QString shapeKey = _compoundShapeURL + "," + + QString::number(_registrationPoint.x) + "," + + QString::number(_registrationPoint.y) + "," + + QString::number(_registrationPoint.z); + info.setParams(type, collisionModelDimensions, shapeKey); info.setConvexHulls(_points); adjustShapeInfoByRegistration(info); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 8054ed9a8b..f59a943353 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1224,9 +1224,12 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() { } glm::vec3 collisionModelDimensions = box.getDimensions(); - QByteArray b64 = _voxelData.toBase64(); + QString shapeKey = QString(_voxelData.toBase64()) + "," + + QString::number(_registrationPoint.x) + "," + + QString::number(_registrationPoint.y) + "," + + QString::number(_registrationPoint.z); _shapeInfoLock.lockForWrite(); - _shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, QString(b64)); + _shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey); _shapeInfo.setConvexHulls(points); adjustShapeInfoByRegistration(_shapeInfo); _shapeInfoLock.unlock(); From 2d3f0b12f56b8d341b576c9383aa2ed39ae7a9e6 Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 5 Mar 2016 10:18:50 -0800 Subject: [PATCH 268/292] Simple fix to the text bug --- libraries/render-utils/src/sdf_text3D.slf | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 3d229ef359..55952e1c3d 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -15,16 +15,10 @@ uniform sampler2D Font; uniform bool Outline; uniform vec4 Color; -uniform vec4 backgroundColor = vec4(1.0, 0.0, 0.0, 1.0); // the interpolated normal in vec3 _normal; in vec2 _texCoord0; -/* -layout(location = 0) out vec4 _fragColor0; -layout(location = 1) out vec4 _fragColor1; -layout(location = 2) out vec4 _fragColor2; -*/ const float gamma = 2.2; const float smoothing = 256.0; @@ -52,21 +46,17 @@ void main() { // gamma correction for linear attenuation a = pow(a, 1.0 / gamma); + // discard if unvisible if (a < 0.01) { discard; } - // final color - /* _fragColor0 = vec4(Color.rgb, Color.a * a); - _fragColor1 = vec4(normalize(_normal.xyz), 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5); - _fragColor2 = vec4(Color.rgb, 10 / 128.0); - */ packDeferredFragmentLightmap( normalize(_normal), - step(alphaThreshold, Color.a * a), - mix(Color.rgb, backgroundColor.rgb, Color.a * a), + 1.0, + Color.rgb, DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR, - mix(Color.rgb, backgroundColor.rgb, Color.a * a)); + Color.rgb); } \ No newline at end of file From d3b84311c5a55b24a2903103dafd5aff88e2149d Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 5 Mar 2016 10:36:45 -0800 Subject: [PATCH 269/292] FIxing the color --- libraries/render-utils/src/sdf_text3D.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 55952e1c3d..1e11cd984d 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -54,7 +54,7 @@ void main() { packDeferredFragmentLightmap( normalize(_normal), 1.0, - Color.rgb, + vec3(1.0), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_SPECULAR, From 193b98f24fb35580faed499bdcb952712d96ba1a Mon Sep 17 00:00:00 2001 From: samcake Date: Sat, 5 Mar 2016 10:59:03 -0800 Subject: [PATCH 270/292] Gamma correct the text color --- libraries/render-utils/src/text/Font.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 2e86d09fe0..762a7fb723 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include "sdf_text3D_vert.h" @@ -354,7 +356,10 @@ void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, c batch.setPipeline(layered ? _layeredPipeline : _pipeline); batch.setResourceTexture(_fontLoc, _texture); batch._glUniform1i(_outlineLoc, (effectType == OUTLINE_EFFECT)); - batch._glUniform4fv(_colorLoc, 1, (const float*)color); + + // need the gamma corrected color here + glm::vec4 lrgba = glm::vec4(ColorUtils::toLinearVec3(glm::vec3(*color)), color->a); + batch._glUniform4fv(_colorLoc, 1, (const float*)&lrgba); batch.setInputFormat(_format); batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); From 5241dc5394551a0c37aff3b84dff2e802fb25698 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Mar 2016 12:48:01 -0800 Subject: [PATCH 271/292] this seems to be working now. more cleanups to come --- .../src/RenderableModelEntityItem.cpp | 61 ++++++++++++------- .../src/RenderableModelEntityItem.h | 1 + libraries/physics/src/ShapeFactory.cpp | 17 +++++- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3b100cc4dd..3f46c5bf83 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -336,6 +336,37 @@ bool RenderableModelEntityItem::getAnimationFrame() { return newFrame; } +void RenderableModelEntityItem::updateModelBounds() { + if (!hasModel() || !_model) { + return; + } + if (_model->getRegistrationPoint() != getRegistrationPoint()) { + qDebug() << "HERE: " << _model->getRegistrationPoint() << getRegistrationPoint(); + } + + bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething(); + if ((movingOrAnimating || + _needsInitialSimulation || + _model->getTranslation() != getPosition() || + _model->getRotation() != getRotation() || + _model->getRegistrationPoint() != getRegistrationPoint()) + && _model->isActive() && _dimensionsInitialized) { + _model->setScaleToFit(true, getDimensions()); + _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); + _model->setRotation(getRotation()); + _model->setTranslation(getPosition()); + + // make sure to simulate so everything gets set up correctly for rendering + { + PerformanceTimer perfTimer("_model->simulate"); + _model->simulate(0.0f); + } + + _needsInitialSimulation = false; + } +} + + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles // the per frame simulation/update that might be required if the models properties changed. void RenderableModelEntityItem::render(RenderArgs* args) { @@ -414,27 +445,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } } }); - - bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething(); - if ((movingOrAnimating || - _needsInitialSimulation || - _model->getTranslation() != getPosition() || - _model->getRotation() != getRotation() || - _model->getRegistrationPoint() != getRegistrationPoint()) - && _model->isActive() && _dimensionsInitialized) { - _model->setScaleToFit(true, getDimensions()); - _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); - _model->setRotation(getRotation()); - _model->setTranslation(getPosition()); - - // make sure to simulate so everything gets set up correctly for rendering - { - PerformanceTimer perfTimer("_model->simulate"); - _model->simulate(0.0f); - } - - _needsInitialSimulation = false; - } + updateModelBounds(); } } } else { @@ -599,7 +610,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ModelEntityItem::computeShapeInfo(info); info.setParams(type, 0.5f * getDimensions()); adjustShapeInfoByRegistration(info); + assert(false); // XXX } else { + updateModelBounds(); const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); // should never fall in here when collision model not fully loaded @@ -693,6 +706,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { for (int j = 0; j < _points[i].size(); j++) { // compensate for registraion _points[i][j] += _model->getOffset(); + // _points[i][j] += info.getOffset(); // scale so the collision points match the model points _points[i][j] *= scale; box += _points[i][j]; @@ -704,9 +718,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { QString::number(_registrationPoint.x) + "," + QString::number(_registrationPoint.y) + "," + QString::number(_registrationPoint.z); + + qDebug() << "NEW SHAPE FOR" << getName() << shapeKey; + qDebug() << " model-offset:" << _model->getOffset(); + info.setParams(type, collisionModelDimensions, shapeKey); info.setConvexHulls(_points); adjustShapeInfoByRegistration(info); + qDebug() << " info-offset:" << info.getOffset(); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index d6deaa5d8d..69c1c13151 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -49,6 +49,7 @@ public: virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + void updateModelBounds(); virtual void render(RenderArgs* args) override; virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index f138587030..b7eb417bca 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -15,7 +15,7 @@ #include "ShapeFactory.h" #include "BulletUtil.h" - +#include "StreamUtils.h" btConvexHullShape* ShapeFactory::createConvexHull(const QVector& points) { @@ -65,6 +65,11 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector& poin hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false); } hull->recalcLocalAabb(); + + qDebug() << "------- NEW COMPOUND SHAPE ------"; + qDebug() << " low = " << minCorner; + qDebug() << " high = " << maxCorner; + return hull; } @@ -92,11 +97,13 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { const QVector>& points = info.getPoints(); uint32_t numSubShapes = info.getNumSubShapes(); if (numSubShapes == 1) { + // XXX offset? shape = createConvexHull(info.getPoints()[0]); } else { auto compound = new btCompoundShape(); btTransform trans; trans.setIdentity(); + // trans.setOrigin(-glmToBullet(info.getOffset())); foreach (QVector hullPoints, points) { btConvexHullShape* hull = createConvexHull(hullPoints); compound->addChildShape (trans, hull); @@ -110,7 +117,7 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) { // this shape has an offset, which we support by wrapping the true shape // in a btCompoundShape with a local transform - auto compound = new btCompoundShape(); + auto compound = new btCompoundShape(); btTransform trans; trans.setIdentity(); trans.setOrigin(glmToBullet(info.getOffset())); @@ -118,5 +125,11 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { shape = compound; } } + + if (type == SHAPE_TYPE_COMPOUND) { + qDebug() << " offset = " << info.getOffset(); + } + + return shape; } From 59804a0f54df433a8ca89e014ee4fc131127f489 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Mar 2016 12:58:30 -0800 Subject: [PATCH 272/292] cleanups --- .../src/RenderableModelEntityItem.cpp | 10 +--------- libraries/physics/src/ShapeFactory.cpp | 16 +--------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3f46c5bf83..52fcda7f3e 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -704,10 +704,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { AABox box; for (int i = 0; i < _points.size(); i++) { for (int j = 0; j < _points[i].size(); j++) { - // compensate for registraion - _points[i][j] += _model->getOffset(); - // _points[i][j] += info.getOffset(); - // scale so the collision points match the model points _points[i][j] *= scale; box += _points[i][j]; } @@ -719,13 +715,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { QString::number(_registrationPoint.y) + "," + QString::number(_registrationPoint.z); - qDebug() << "NEW SHAPE FOR" << getName() << shapeKey; - qDebug() << " model-offset:" << _model->getOffset(); - info.setParams(type, collisionModelDimensions, shapeKey); info.setConvexHulls(_points); - adjustShapeInfoByRegistration(info); - qDebug() << " info-offset:" << info.getOffset(); + info.setOffset(_model->getOffset()); } } diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index b7eb417bca..0ed4b1d0a9 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -15,8 +15,6 @@ #include "ShapeFactory.h" #include "BulletUtil.h" -#include "StreamUtils.h" - btConvexHullShape* ShapeFactory::createConvexHull(const QVector& points) { assert(points.size() > 0); @@ -65,11 +63,6 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector& poin hull->addPoint(btVector3(correctedPoint[0], correctedPoint[1], correctedPoint[2]), false); } hull->recalcLocalAabb(); - - qDebug() << "------- NEW COMPOUND SHAPE ------"; - qDebug() << " low = " << minCorner; - qDebug() << " high = " << maxCorner; - return hull; } @@ -97,13 +90,11 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { const QVector>& points = info.getPoints(); uint32_t numSubShapes = info.getNumSubShapes(); if (numSubShapes == 1) { - // XXX offset? shape = createConvexHull(info.getPoints()[0]); } else { auto compound = new btCompoundShape(); btTransform trans; trans.setIdentity(); - // trans.setOrigin(-glmToBullet(info.getOffset())); foreach (QVector hullPoints, points) { btConvexHullShape* hull = createConvexHull(hullPoints); compound->addChildShape (trans, hull); @@ -113,7 +104,7 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { } break; } - if (shape && type != SHAPE_TYPE_COMPOUND) { + if (shape) { if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) { // this shape has an offset, which we support by wrapping the true shape // in a btCompoundShape with a local transform @@ -126,10 +117,5 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { } } - if (type == SHAPE_TYPE_COMPOUND) { - qDebug() << " offset = " << info.getOffset(); - } - - return shape; } From dcb720a8324b841be4204d2e1202bbc61b23bb73 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Mar 2016 14:09:45 -0800 Subject: [PATCH 273/292] fix polyvox hull when registration changes. --- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 10 ++++++++-- .../src/RenderablePolyVoxEntityItem.h | 2 ++ libraries/entities/src/EntityItem.h | 2 +- libraries/physics/src/ShapeFactory.cpp | 3 ++- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 52fcda7f3e..7cda62f74d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -610,7 +610,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { ModelEntityItem::computeShapeInfo(info); info.setParams(type, 0.5f * getDimensions()); adjustShapeInfoByRegistration(info); - assert(false); // XXX } else { updateModelBounds(); const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); @@ -704,6 +703,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { AABox box; for (int i = 0; i < _points.size(); i++) { for (int j = 0; j < _points[i].size(); j++) { + // scale so the collision points match the model points _points[i][j] *= scale; box += _points[i][j]; } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index f59a943353..147905b72a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -142,7 +142,7 @@ glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const { glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units bool success; // TODO -- Does this actually have to happen in world space? - glm::vec3 center = getCenterPosition(success); + glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes glm::vec3 position = getPosition(success); glm::vec3 positionToCenter = center - position; @@ -430,6 +430,13 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const { return SHAPE_TYPE_COMPOUND; } +void RenderablePolyVoxEntityItem::updateRegistrationPoint(const glm::vec3& value) { + if (value != _registrationPoint) { + _meshDirty = true; + EntityItem::updateRegistrationPoint(value); + } +} + bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { _meshLock.lockForRead(); if (_meshDirty) { @@ -1231,7 +1238,6 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() { _shapeInfoLock.lockForWrite(); _shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey); _shapeInfo.setConvexHulls(points); - adjustShapeInfoByRegistration(_shapeInfo); _shapeInfoLock.unlock(); _meshLock.lockForWrite(); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index fdbaefb0c3..b40507f36a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -116,6 +116,8 @@ public: virtual void rebakeMesh(); + virtual void updateRegistrationPoint(const glm::vec3& value); + private: // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions // may not match _voxelVolumeSize. diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d327bd9004..62cc8ad69a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -320,7 +320,7 @@ public: virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags - void updateRegistrationPoint(const glm::vec3& value); + virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); void updatePositionFromNetwork(const glm::vec3& value); void updateDimensions(const glm::vec3& value); diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 0ed4b1d0a9..f956e562cd 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -16,6 +16,8 @@ #include "ShapeFactory.h" #include "BulletUtil.h" + + btConvexHullShape* ShapeFactory::createConvexHull(const QVector& points) { assert(points.size() > 0); @@ -116,6 +118,5 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { shape = compound; } } - return shape; } From 5c585acd9a0f0e30a8f50d96fe8fe4c7bd5a0e8e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Mar 2016 14:29:30 -0800 Subject: [PATCH 274/292] offset is included in shape key for models --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 7 +------ .../entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 3 +++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7cda62f74d..fb79b8d5b2 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -710,12 +710,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } glm::vec3 collisionModelDimensions = box.getDimensions(); - QString shapeKey = _compoundShapeURL + "," + - QString::number(_registrationPoint.x) + "," + - QString::number(_registrationPoint.y) + "," + - QString::number(_registrationPoint.z); - - info.setParams(type, collisionModelDimensions, shapeKey); + info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setConvexHulls(_points); info.setOffset(_model->getOffset()); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 147905b72a..5118664268 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1231,6 +1231,8 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() { } glm::vec3 collisionModelDimensions = box.getDimensions(); + // include the registrationPoint in the shape key, because the offset is already + // included in the points and the shapeManager wont know that the shape has changed. QString shapeKey = QString(_voxelData.toBase64()) + "," + QString::number(_registrationPoint.x) + "," + QString::number(_registrationPoint.y) + "," + @@ -1238,6 +1240,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() { _shapeInfoLock.lockForWrite(); _shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey); _shapeInfo.setConvexHulls(points); + // adjustShapeInfoByRegistration(_shapeInfo); _shapeInfoLock.unlock(); _meshLock.lockForWrite(); From c95d1f68f6a7d8988fe8e015336e81ed4f063e7c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Mar 2016 14:38:03 -0800 Subject: [PATCH 275/292] remove debug print --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index fb79b8d5b2..57dcf3d519 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -340,10 +340,6 @@ void RenderableModelEntityItem::updateModelBounds() { if (!hasModel() || !_model) { return; } - if (_model->getRegistrationPoint() != getRegistrationPoint()) { - qDebug() << "HERE: " << _model->getRegistrationPoint() << getRegistrationPoint(); - } - bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething(); if ((movingOrAnimating || _needsInitialSimulation || From 9a860bd31a897b3bb871d87f118ab9e8899b7acb Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 6 Mar 2016 15:01:35 -0800 Subject: [PATCH 276/292] update ping pong gun model url --- .../toybox/ping_pong_gun/createPingPongGun.js | 88 +++++++++++-------- examples/toybox/ping_pong_gun/pingPongGun.js | 16 ++-- unpublishedScripts/hiddenEntityReset.js | 5 +- unpublishedScripts/masterReset.js | 4 +- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index d9f47eda37..4dac9e73a1 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -11,53 +11,63 @@ /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath('pingPongGun.js'); +var scriptURL = Script.resolvePath('pingPongGun.js?' + Math.random()); -var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx' -var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_convex.obj'; +var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.fbx' +var COLLISION_HULL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.obj'; var COLLISION_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/plastic_impact.L.wav'; var center = Vec3.sum(Vec3.sum(MyAvatar.position, { - x: 0, - y: 0.5, - z: 0 + x: 0, + y: 0.5, + z: 0 }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); var pingPongGun = Entities.addEntity({ - type: "Model", - modelURL: MODEL_URL, - shapeType: 'compound', - compoundShapeURL: COLLISION_HULL_URL, - script: scriptURL, - position: center, - dimensions: { - x: 0.08, - y: 0.21, - z: 0.47 + type: "Model", + modelURL: MODEL_URL, + shapeType: 'compound', + compoundShapeURL: COLLISION_HULL_URL, + script: scriptURL, + position: center, + dimensions: { + x: 0.08, + y: 0.21, + z: 0.47 + }, + dynamic: true, + collisionSoundURL: COLLISION_SOUND_URL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true }, - dynamic: true, - collisionSoundURL: COLLISION_SOUND_URL, - userData: JSON.stringify({ - grabbableKey: { - invertSolidWhileHeld: true - }, - wearable:{joints:{RightHand:[{x:0.1177130937576294, - y:0.12922893464565277, - z:0.08307232707738876}, - {x:0.4934672713279724, - y:0.3605862259864807, - z:0.6394805908203125, - w:-0.4664038419723511}], - LeftHand:[{x:0.09151676297187805, - y:0.13639454543590546, - z:0.09354984760284424}, - {x:-0.19628101587295532, - y:0.6418180465698242, - z:0.2830369472503662, - w:0.6851521730422974}]}} - }) + wearable: { + joints: { + RightHand: [{ + x: 0.1177130937576294, + y: 0.12922893464565277, + z: 0.08307232707738876 + }, { + x: 0.4934672713279724, + y: 0.3605862259864807, + z: 0.6394805908203125, + w: -0.4664038419723511 + }], + LeftHand: [{ + x: 0.09151676297187805, + y: 0.13639454543590546, + z: 0.09354984760284424 + }, { + x: -0.19628101587295532, + y: 0.6418180465698242, + z: 0.2830369472503662, + w: 0.6851521730422974 + }] + } + } + }) }); function cleanUp() { - Entities.deleteEntity(pingPongGun); + Entities.deleteEntity(pingPongGun); } -Script.scriptEnding.connect(cleanUp); +Script.scriptEnding.connect(cleanUp); \ No newline at end of file diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js index 29eb2e3057..46c555e5a1 100644 --- a/examples/toybox/ping_pong_gun/pingPongGun.js +++ b/examples/toybox/ping_pong_gun/pingPongGun.js @@ -22,7 +22,7 @@ //if the trigger value goes below this value, reload the gun. var RELOAD_THRESHOLD = 0.95; - var GUN_TIP_FWD_OFFSET =-0.35; + var GUN_TIP_FWD_OFFSET = -0.35; var GUN_TIP_UP_OFFSET = 0.040; var GUN_FORCE = 9; var BALL_RESTITUTION = 0.6; @@ -45,12 +45,12 @@ green: 255, blue: 255 }; - + var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT, ]; - + PingPongGun.prototype = { hand: null, @@ -98,8 +98,8 @@ var properties = { // type: 'Model', // modelURL:PING_PONG_BALL_URL, - shapeType:'sphere', - type:'Sphere', + shapeType: 'sphere', + type: 'Sphere', color: BALL_COLOR, dimensions: BALL_DIMENSIONS, damping: BALL_LINEAR_DAMPING, @@ -126,6 +126,10 @@ Audio.playSound(this.SHOOTING_SOUND, audioProperties); }, + clickDownOnEntity: function(entityID, mouseEvent) { + this.shootBall() + }, + getGunTipPosition: function(properties) { //the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position var frontVector = Quat.getFront(properties.rotation); @@ -148,4 +152,4 @@ // entity scripts always need to return a newly constructed object of our type return new PingPongGun(); -}); +}); \ No newline at end of file diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 4a64b34510..bc33d0f14e 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1241,8 +1241,9 @@ } function createPingPongBallGun() { - var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx'; - var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_convex.obj'; + + var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.fbx'; + var COLLISION_HULL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.obj'; var COLLISION_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/plastic_impact.L.wav'; var position = { x: 548.6, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index c5669b9ac0..025a1adcca 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -720,8 +720,8 @@ MasterReset = function() { function createTargets() { - var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx'; - var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj'; + var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.fbx'; + var COLLISION_HULL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.obj'; var MINIMUM_MOVE_LENGTH = 0.05; var RESET_DISTANCE = 0.5; From 830a61b8748d19b6317b3c29680353b35eb4d8db Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 6 Mar 2016 15:04:47 -0800 Subject: [PATCH 277/292] update --- examples/toybox/ping_pong_gun/pingPongGun.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js index 46c555e5a1..32e9baa1c9 100644 --- a/examples/toybox/ping_pong_gun/pingPongGun.js +++ b/examples/toybox/ping_pong_gun/pingPongGun.js @@ -125,11 +125,7 @@ Audio.playSound(this.SHOOTING_SOUND, audioProperties); }, - - clickDownOnEntity: function(entityID, mouseEvent) { - this.shootBall() - }, - + getGunTipPosition: function(properties) { //the tip of the gun is going to be in a different place than the center, so we move in space relative to the model to find that position var frontVector = Quat.getFront(properties.rotation); From aefeff249346dc823c09b1fb17512d0d41aaeadd Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 7 Mar 2016 09:50:38 -0800 Subject: [PATCH 278/292] MyAvatar: Use a box instead of a sphere for horizontal re-centering --- interface/src/avatar/MyAvatar.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 642af5c3e9..7ffd138f26 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1944,13 +1944,26 @@ bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, co bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { - const float CYLINDER_RADIUS = 0.3f; - + // -z axis of currentBodyMatrix in world space. + glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][3], -currentBodyMatrix[1][3], -currentBodyMatrix[2][3])); + // x axis of currentBodyMatrix in world space. + glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0])); glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - glm::vec3 radialOffset(offset.x, 0.0f, offset.z); - float radialDistance = glm::length(radialOffset); - return radialDistance > CYLINDER_RADIUS; + float forwardLeanAmount = glm::dot(forward, offset); + float lateralLeanAmount = glm::dot(right, offset); + + const float MAX_LATERAL_LEAN = 0.3f; + const float MAX_FORWARD_LEAN = 0.15f; + const float MAX_BACKWARD_LEAN = 0.1f; + + if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { + return true; + } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { + return true; + } + + return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { From 2cbb41fd387a3d866b70503cf3fbca055641f2ac Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Mon, 7 Mar 2016 10:11:22 -0800 Subject: [PATCH 279/292] MyAvatar: bug fix for forward/backward lean detection --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7ffd138f26..fb309509a5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1945,7 +1945,7 @@ bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, co bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { // -z axis of currentBodyMatrix in world space. - glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][3], -currentBodyMatrix[1][3], -currentBodyMatrix[2][3])); + glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2])); // x axis of currentBodyMatrix in world space. glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0])); glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); From 8b8604f9b0e518a5fde950ab06053c53efaaf07b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Mar 2016 11:32:25 -0800 Subject: [PATCH 280/292] move offset handling for models back to how it was before this PR --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 57dcf3d519..53b7674b11 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -699,6 +699,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { AABox box; for (int i = 0; i < _points.size(); i++) { for (int j = 0; j < _points[i].size(); j++) { + // compensate for registration + _points[i][j] += _model->getOffset(); // scale so the collision points match the model points _points[i][j] *= scale; box += _points[i][j]; @@ -708,7 +710,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 collisionModelDimensions = box.getDimensions(); info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setConvexHulls(_points); - info.setOffset(_model->getOffset()); } } From 6d82dcb5333d45ac56cf940d281a6258891815e4 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 11:38:05 -0800 Subject: [PATCH 281/292] not the targets --- unpublishedScripts/masterReset.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 025a1adcca..71ab270403 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -720,8 +720,9 @@ MasterReset = function() { function createTargets() { - var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.fbx'; - var COLLISION_HULL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.obj'; + + var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target.fbx'; + var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/target_collision_hull.obj'; var MINIMUM_MOVE_LENGTH = 0.05; var RESET_DISTANCE = 0.5; @@ -1228,8 +1229,9 @@ MasterReset = function() { } function createPingPongBallGun() { - var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx'; - var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_convex.obj'; + var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.fbx'; + var COLLISION_HULL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.obj'; + var COLLISION_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/plastic_impact.L.wav'; var position = { x: 548.6, From 40c953e0b9d0770111cb6a6349cb95766413923e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Mar 2016 11:40:18 -0800 Subject: [PATCH 282/292] fix model hulls --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 53b7674b11..71b04d06a1 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -703,6 +703,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { _points[i][j] += _model->getOffset(); // scale so the collision points match the model points _points[i][j] *= scale; + // this next subtraction is done so we can give info the offset, which will cause + // the shape-key to change. + _points[i][j] -= _model->getOffset(); box += _points[i][j]; } } @@ -710,6 +713,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 collisionModelDimensions = box.getDimensions(); info.setParams(type, collisionModelDimensions, _compoundShapeURL); info.setConvexHulls(_points); + info.setOffset(_model->getOffset()); } } From 15feb7a414bca01da5300d4122007f847fe19ea8 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 12:07:22 -0800 Subject: [PATCH 283/292] add falloffRadius to sconce lights in toybox --- unpublishedScripts/hiddenEntityReset.js | 10 ++++++++++ unpublishedScripts/masterReset.js | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 4a64b34510..f9003e4413 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -973,6 +973,8 @@ y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1001,6 +1003,8 @@ y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1074,6 +1078,8 @@ y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1103,6 +1109,8 @@ y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1131,6 +1139,8 @@ y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index c5669b9ac0..1aa302354e 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -960,6 +960,8 @@ MasterReset = function() { y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -988,6 +990,8 @@ MasterReset = function() { y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1061,6 +1065,8 @@ MasterReset = function() { y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1090,6 +1096,8 @@ MasterReset = function() { y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, @@ -1118,6 +1126,8 @@ MasterReset = function() { y: 2.545, z: 2.545 }, + intensity: 1.0, + falloffRadius: 0.3, cutoff: 90, color: { red: 217, From 9cd0762040fa7c9b87fa5e28bf24e7fe02bda305 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 12:26:21 -0800 Subject: [PATCH 284/292] brighter --- examples/toybox/flashlight/flashlight.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/toybox/flashlight/flashlight.js b/examples/toybox/flashlight/flashlight.js index 19cbc422f4..02a2e07985 100644 --- a/examples/toybox/flashlight/flashlight.js +++ b/examples/toybox/flashlight/flashlight.js @@ -104,8 +104,9 @@ green: 255, blue: 255 }, - intensity: 2, - exponent: 0.3, + intensity: 1, + falloffRadius:0.9, + exponent: 0.5, cutoff: 20, lifetime: LIFETIME, position: lightTransform.p, @@ -128,6 +129,8 @@ blue: 255 }, exponent: 0, + intensity:1.0, + falloffRadius:0.3, lifetime: LIFETIME, cutoff: 90, // in degrees position: glowLightTransform.p, From e6b81b31d8148407fc7094acd1736aa6cf012091 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Mar 2016 09:59:00 +1300 Subject: [PATCH 285/292] Fix Running Script's tree view --- interface/resources/qml/controls-uit/Tree.qml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 0981999568..18741d6420 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -58,21 +58,12 @@ TreeView { text: styleData.isExpanded ? hifi.glyphs.caratDn : hifi.glyphs.caratR size: hifi.fontSizes.carat color: colorScheme == hifi.colorSchemes.light - ? (styleData.selected - ? hifi.colors.black - : (iconArea.pressed ? hifi.colors.white : hifi.colors.baseGrayHighlight)) - : (styleData.selected - ? hifi.colors.black - : (iconArea.pressed ? hifi.colors.white : hifi.colors.lightGrayText)) + ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) + : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) anchors { left: parent ? parent.left : undefined leftMargin: hifi.dimensions.tablePadding / 2 } - MouseArea { - id: iconArea - anchors.fill: parent - propagateComposedEvents: true - } } handle: Item { From caca60c0390770c66e82f8c5def0639be06837c6 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 7 Mar 2016 14:09:21 -0800 Subject: [PATCH 286/292] added headers to tutorial code --- .../chapter1/fireworksLaunchButtonEntityScript.js | 10 +++++++++- .../chapter1/fireworksLaunchButtonSpawner.js | 11 +++++++++-- .../chapter2/fireworksLaunchButtonEntityScript.js | 10 +++++++++- .../chapter2/fireworksLaunchButtonSpawner.js | 11 +++++++++-- .../chapter3/fireworksLaunchButtonEntityScript.js | 10 +++++++++- .../chapter3/fireworksLaunchButtonSpawner.js | 11 +++++++++-- 6 files changed, 54 insertions(+), 9 deletions(-) diff --git a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js index 1f361656f1..9afe453c66 100644 --- a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js @@ -1,4 +1,12 @@ -// Chapter 1: fireworksLaunchButtonEntityScript.js +// +// fireworksLaunchButtonEntityScript.js +// +// Created by Eric Levin on 3/7/2017 +// Copyright 2016 High Fidelity, Inc. +// +// This is the chapter 1 entity script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) +// +// Distributed under the Apache License, Version 2.0. (function() { Script.include("../../libraries/utils.js"); diff --git a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js index a4969aa8ed..7af0dadf8e 100644 --- a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js @@ -1,5 +1,12 @@ - - // Chapter1 : fireworksLaumchButtonSpawner.js +// +// fireworksLaunchButtonSpawner.js +// +// Created by Eric Levin on 3/7/2017 +// Copyright 2016 High Fidelity, Inc. +// +// This is the chapter 1 interface script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) +// +// Distributed under the Apache License, Version 2.0. var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js index 142c8ffa96..62127f9a91 100644 --- a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js @@ -1,4 +1,12 @@ -// Chapter 2: fireworksLaunchButtonEntityScript.js +// +// fireworksLaunchButtonEntityScript.js +// +// Created by Eric Levin on 3/7/2017 +// Copyright 2016 High Fidelity, Inc. +// +// This is the chapter 2 entity script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) +// +// Distributed under the Apache License, Version 2.0. (function() { Script.include("../../libraries/utils.js"); diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js index 2fc4364c5a..bf494db324 100644 --- a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js @@ -1,5 +1,12 @@ - - // Chapter 2 : fireworksLaumchButtonSpawner.js +// +// fireworksLaunchButtonSpawner.js +// +// Created by Eric Levin on 3/7/2017 +// Copyright 2016 High Fidelity, Inc. +// +// This is the chapter 2 interface script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) +// +// Distributed under the Apache License, Version 2.0. var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); diff --git a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js index f4332eccb6..fc387b4990 100644 --- a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js @@ -1,4 +1,12 @@ -// Chapter 3: fireworksLaunchButtonEntityScript.js +// +// fireworksLaunchButtonEntityScript.js +// +// Created by Eric Levin on 3/7/2017 +// Copyright 2016 High Fidelity, Inc. +// +// This is the chapter 3 entity script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) +// +// Distributed under the Apache License, Version 2.0. (function() { Script.include("../../libraries/utils.js"); diff --git a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js index 2fc4364c5a..80ba3f5e1d 100644 --- a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js @@ -1,5 +1,12 @@ - - // Chapter 2 : fireworksLaumchButtonSpawner.js +// +// fireworksLaunchButtonSpawner.js +// +// Created by Eric Levin on 3/7/2017 +// Copyright 2016 High Fidelity, Inc. +// +// This is the chapter 3 interface script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) +// +// Distributed under the Apache License, Version 2.0. var orientation = Camera.getOrientation(); orientation = Quat.safeEulerAngles(orientation); From 567039ef821132c78ad865e60a9cab71364817c8 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 14:28:16 -0800 Subject: [PATCH 287/292] Update createPingPongGun.js --- examples/toybox/ping_pong_gun/createPingPongGun.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 4dac9e73a1..2315e4a4d7 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -11,7 +11,7 @@ /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath('pingPongGun.js?' + Math.random()); +var scriptURL = Script.resolvePath('pingPongGun.js'); var MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.fbx' var COLLISION_HULL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Pingpong-Gun-New.obj'; @@ -70,4 +70,4 @@ var pingPongGun = Entities.addEntity({ function cleanUp() { Entities.deleteEntity(pingPongGun); } -Script.scriptEnding.connect(cleanUp); \ No newline at end of file +Script.scriptEnding.connect(cleanUp); From ca747bb4e95bf31bc2b624fb37057dac151eb6c8 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 7 Mar 2016 14:29:17 -0800 Subject: [PATCH 288/292] fixed dates --- .../fireworks/chapter1/fireworksLaunchButtonEntityScript.js | 2 +- .../fireworks/chapter1/fireworksLaunchButtonSpawner.js | 2 +- .../fireworks/chapter2/fireworksLaunchButtonEntityScript.js | 2 +- .../fireworks/chapter2/fireworksLaunchButtonSpawner.js | 2 +- .../fireworks/chapter3/fireworksLaunchButtonEntityScript.js | 2 +- .../fireworks/chapter3/fireworksLaunchButtonSpawner.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js index 9afe453c66..1232bfc843 100644 --- a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonEntityScript.js @@ -1,7 +1,7 @@ // // fireworksLaunchButtonEntityScript.js // -// Created by Eric Levin on 3/7/2017 +// Created by Eric Levin on 3/7/2016 // Copyright 2016 High Fidelity, Inc. // // This is the chapter 1 entity script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) diff --git a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js index 7af0dadf8e..31d5e00e00 100644 --- a/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter1/fireworksLaunchButtonSpawner.js @@ -1,7 +1,7 @@ // // fireworksLaunchButtonSpawner.js // -// Created by Eric Levin on 3/7/2017 +// Created by Eric Levin on 3/7/2016 // Copyright 2016 High Fidelity, Inc. // // This is the chapter 1 interface script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js index 62127f9a91..66d2e96858 100644 --- a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonEntityScript.js @@ -1,7 +1,7 @@ // // fireworksLaunchButtonEntityScript.js // -// Created by Eric Levin on 3/7/2017 +// Created by Eric Levin on 3/7/2016 // Copyright 2016 High Fidelity, Inc. // // This is the chapter 2 entity script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) diff --git a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js index bf494db324..19fd67f6c4 100644 --- a/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter2/fireworksLaunchButtonSpawner.js @@ -1,7 +1,7 @@ // // fireworksLaunchButtonSpawner.js // -// Created by Eric Levin on 3/7/2017 +// Created by Eric Levin on 3/7/2016 // Copyright 2016 High Fidelity, Inc. // // This is the chapter 2 interface script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) diff --git a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js index fc387b4990..f811d95315 100644 --- a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js +++ b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonEntityScript.js @@ -1,7 +1,7 @@ // // fireworksLaunchButtonEntityScript.js // -// Created by Eric Levin on 3/7/2017 +// Created by Eric Levin on 3/7/2016 // Copyright 2016 High Fidelity, Inc. // // This is the chapter 3 entity script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) diff --git a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js index 80ba3f5e1d..6b77b2609a 100644 --- a/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js +++ b/examples/tutorials/fireworks/chapter3/fireworksLaunchButtonSpawner.js @@ -1,7 +1,7 @@ // // fireworksLaunchButtonSpawner.js // -// Created by Eric Levin on 3/7/2017 +// Created by Eric Levin on 3/7/2016 // Copyright 2016 High Fidelity, Inc. // // This is the chapter 3 interface script of the fireworks tutorial (https://docs.highfidelity.com/docs/fireworks-scripting-tutorial) From ee55721f79bf7b319aaf1cba621fb17d529559bc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Mar 2016 15:13:24 -0800 Subject: [PATCH 289/292] allow sending interface-local messsages --- libraries/networking/src/MessagesClient.cpp | 25 ++++++++++++++------- libraries/networking/src/MessagesClient.h | 5 +++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/libraries/networking/src/MessagesClient.cpp b/libraries/networking/src/MessagesClient.cpp index 3a03027da0..d8c63c4294 100644 --- a/libraries/networking/src/MessagesClient.cpp +++ b/libraries/networking/src/MessagesClient.cpp @@ -79,20 +79,29 @@ void MessagesClient::handleMessagesPacket(QSharedPointer receiv QString channel, message; QUuid senderID; decodeMessagesPacket(receivedMessage, channel, message, senderID); - emit messageReceived(channel, message, senderID); + emit messageReceived(channel, message, senderID, false); } -void MessagesClient::sendMessage(QString channel, QString message) { +void MessagesClient::sendMessage(QString channel, QString message, bool localOnly) { auto nodeList = DependencyManager::get(); - SharedNodePointer messagesMixer = nodeList->soloNodeOfType(NodeType::MessagesMixer); - - if (messagesMixer) { + if (localOnly) { QUuid senderID = nodeList->getSessionUUID(); - auto packetList = encodeMessagesPacket(channel, message, senderID); - nodeList->sendPacketList(std::move(packetList), *messagesMixer); + emit messageReceived(channel, message, senderID, true); + } else { + SharedNodePointer messagesMixer = nodeList->soloNodeOfType(NodeType::MessagesMixer); + + if (messagesMixer) { + QUuid senderID = nodeList->getSessionUUID(); + auto packetList = encodeMessagesPacket(channel, message, senderID); + nodeList->sendPacketList(std::move(packetList), *messagesMixer); + } } } +void MessagesClient::sendLocalMessage(QString channel, QString message) { + sendMessage(channel, message, true); +} + void MessagesClient::subscribe(QString channel) { _subscribedChannels << channel; auto nodeList = DependencyManager::get(); @@ -123,4 +132,4 @@ void MessagesClient::handleNodeActivated(SharedNodePointer node) { subscribe(channel); } } -} \ No newline at end of file +} diff --git a/libraries/networking/src/MessagesClient.h b/libraries/networking/src/MessagesClient.h index ff7874fd8e..b624acccb7 100644 --- a/libraries/networking/src/MessagesClient.h +++ b/libraries/networking/src/MessagesClient.h @@ -29,7 +29,8 @@ public: Q_INVOKABLE void init(); - Q_INVOKABLE void sendMessage(QString channel, QString message); + Q_INVOKABLE void sendMessage(QString channel, QString message, bool localOnly = false); + Q_INVOKABLE void sendLocalMessage(QString channel, QString message); Q_INVOKABLE void subscribe(QString channel); Q_INVOKABLE void unsubscribe(QString channel); @@ -38,7 +39,7 @@ public: signals: - void messageReceived(QString channel, QString message, QUuid senderUUID); + void messageReceived(QString channel, QString message, QUuid senderUUID, bool localOnly); private slots: void handleMessagesPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode); From fbe640e351f0ebbff89fead7f19ca95dcdffe28e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 16:38:15 -0800 Subject: [PATCH 290/292] the model was different so adjust things --- examples/toybox/ping_pong_gun/createPingPongGun.js | 6 +++--- examples/toybox/ping_pong_gun/pingPongGun.js | 2 +- unpublishedScripts/hiddenEntityReset.js | 6 +++--- unpublishedScripts/masterReset.js | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 2315e4a4d7..467a05b5b6 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -30,9 +30,9 @@ var pingPongGun = Entities.addEntity({ script: scriptURL, position: center, dimensions: { - x: 0.08, - y: 0.21, - z: 0.47 + x: 0.125, + y: 0.3875, + z: 0.9931 }, dynamic: true, collisionSoundURL: COLLISION_SOUND_URL, diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js index 32e9baa1c9..415913ea6d 100644 --- a/examples/toybox/ping_pong_gun/pingPongGun.js +++ b/examples/toybox/ping_pong_gun/pingPongGun.js @@ -23,7 +23,7 @@ //if the trigger value goes below this value, reload the gun. var RELOAD_THRESHOLD = 0.95; var GUN_TIP_FWD_OFFSET = -0.35; - var GUN_TIP_UP_OFFSET = 0.040; + var GUN_TIP_UP_OFFSET = 0.12; var GUN_FORCE = 9; var BALL_RESTITUTION = 0.6; var BALL_LINEAR_DAMPING = 0.4; diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index ef696258a7..08c5b5857a 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1278,9 +1278,9 @@ }, restitution: 0, dimensions: { - x: 0.08, - y: 0.21, - z: 0.47 + x: 0.125, + y: 0.3875, + z: 0.9931 }, dynamic: true, collisionSoundURL: COLLISION_SOUND_URL, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 90a9c710dc..cbcee30b0b 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1266,9 +1266,9 @@ MasterReset = function() { }, restitution: 0, dimensions: { - x: 0.08, - y: 0.21, - z: 0.47 + x: 0.125, + y: 0.3875, + z: 0.9931 }, dynamic: true, collisionSoundURL: COLLISION_SOUND_URL, From 482964d8adc697493de3299d17ec06369c6f2aca Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 20:37:14 -0800 Subject: [PATCH 291/292] hide this for now --- examples/edit.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index 59e1f74d20..bc0665213e 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -89,6 +89,9 @@ var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus"; var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode"; var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode"; + +// marketplace info, etc. not quite ready yet. +var SHOULD_SHOW_PROPERTY_MENU = false; var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain." var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain." @@ -1022,6 +1025,9 @@ function mouseClickEvent(event) { } else if (event.isRightButton) { var result = findClickedEntity(event); if (result) { + if (SHOULD_SHOW_PROPERTY_MENU !== true) { + return; + } var properties = Entities.getEntityProperties(result.entityID); if (properties.marketplaceID) { propertyMenu.marketplaceID = properties.marketplaceID; @@ -1895,9 +1901,11 @@ PopupMenu = function() { return this; }; + var propertyMenu = PopupMenu(); propertyMenu.onSelectMenuItem = function(name) { + if (propertyMenu.marketplaceID) { showMarketplace(propertyMenu.marketplaceID); } From 2e9ebfb1785df132548665373555bbc6f4160523 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 7 Mar 2016 21:03:11 -0800 Subject: [PATCH 292/292] remove avatar head and body from pacakage model selections --- interface/src/ModelSelector.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/interface/src/ModelSelector.cpp b/interface/src/ModelSelector.cpp index c4922bdd70..2f85849fbe 100644 --- a/interface/src/ModelSelector.cpp +++ b/interface/src/ModelSelector.cpp @@ -18,8 +18,6 @@ #include "ModelSelector.h" -static const QString AVATAR_HEAD_STRING = "Avatar Head Only"; -static const QString AVATAR_BODY_STRING = "Avatar Body Only"; static const QString AVATAR_HEAD_AND_BODY_STRING = "Avatar Body with Head"; static const QString AVATAR_ATTACHEMENT_STRING = "Avatar Attachment"; static const QString ENTITY_MODEL_STRING = "Entity Model"; @@ -35,8 +33,7 @@ ModelSelector::ModelSelector() { form->addRow("Model File:", _browseButton); _modelType = new QComboBox(this); - _modelType->addItem(AVATAR_HEAD_STRING); - _modelType->addItem(AVATAR_BODY_STRING); + _modelType->addItem(AVATAR_HEAD_AND_BODY_STRING); _modelType->addItem(AVATAR_ATTACHEMENT_STRING); _modelType->addItem(ENTITY_MODEL_STRING); @@ -55,11 +52,7 @@ QFileInfo ModelSelector::getFileInfo() const { FSTReader::ModelType ModelSelector::getModelType() const { QString text = _modelType->currentText(); - if (text == AVATAR_HEAD_STRING) { - return FSTReader::HEAD_MODEL; - } else if (text == AVATAR_BODY_STRING) { - return FSTReader::BODY_ONLY_MODEL; - } else if (text == AVATAR_HEAD_AND_BODY_STRING) { +if (text == AVATAR_HEAD_AND_BODY_STRING) { return FSTReader::HEAD_AND_BODY_MODEL; } else if (text == AVATAR_ATTACHEMENT_STRING) { return FSTReader::ATTACHMENT_MODEL;