From 71d361ed3bc7f31cec1d2d09d2cf674a90432877 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 30 Nov 2015 17:06:35 -0800 Subject: [PATCH 001/318] fixed hydra paint, adding more interactive brushes --- examples/example/painting/hydraPaint.js | 12 +++---- .../src/RenderablePolyLineEntityItem.cpp | 32 ++++++++++++++----- .../src/RenderablePolyLineEntityItem.h | 4 +++ .../entities-renderer/src/paintStroke.slf | 14 +++++--- .../entities-renderer/src/paintStroke.slv | 2 ++ libraries/entities/src/PolyLineEntityItem.cpp | 2 ++ libraries/entities/src/PolyLineEntityItem.h | 4 ++- 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/examples/example/painting/hydraPaint.js b/examples/example/painting/hydraPaint.js index 36137945cc..14ea256369 100644 --- a/examples/example/painting/hydraPaint.js +++ b/examples/example/painting/hydraPaint.js @@ -67,12 +67,12 @@ var colorPalette = [{ var MIN_STROKE_WIDTH = 0.002; var MAX_STROKE_WIDTH = 0.05; -function controller(side, cycleColorButton) { +function controller(side, triggerAction) { this.triggerHeld = false; this.triggerThreshold = 0.9; this.side = side; - this.trigger = side == LEFT ? Controller.Stantard.LT : Controller.Standard.RT; - this.cycleColorButton = side == LEFT ? Controller.Stantard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; + this.triggerAction = triggerAction; + this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; this.points = []; this.normals = []; @@ -174,7 +174,7 @@ function controller(side, cycleColorButton) { this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; - this.triggerValue = Controller.getValue(this.trigger); + this.triggerValue = Controller.getActionValue(this.triggerAction); if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { @@ -212,8 +212,8 @@ function vectorIsZero(v) { } -var rightController = new controller(RIGHT); -var leftController = new controller(LEFT); +var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 036d37a95b..63a03bb8e7 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -24,14 +24,22 @@ +struct PolyLineUniforms { + float time; +}; + EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return EntityItemPointer(new RenderablePolyLineEntityItem(entityID, properties)); } RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : -PolyLineEntityItem(entityItemID, properties) { - _numVertices = 0; +PolyLineEntityItem(entityItemID, properties), +_counter(0.0f), +_numVertices(0) +{ _vertices = QVector(0.0f); + PolyLineUniforms uniforms; + _uniformBuffer = std::make_shared(sizeof(PolyLineUniforms), (const gpu::Byte*) &uniforms); } @@ -161,6 +169,18 @@ void RenderablePolyLineEntityItem::updateVertices() { } +void RenderablePolyLineEntityItem::update(const quint64& now) { + PolyLineUniforms uniforms; + _counter += 0.01; + uniforms.time = _counter; + memcpy(&_uniformBuffer.edit(), &uniforms, sizeof(PolyLineUniforms)); + + if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { + updateVertices(); + updateGeometry(); + } + +} void RenderablePolyLineEntityItem::render(RenderArgs* args) { QWriteLocker lock(&_quadReadWriteLock); @@ -181,17 +201,13 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyLineEntityItem::render"); Q_ASSERT(getType() == EntityTypes::PolyLine); - Q_ASSERT(args->_batch); - if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { - updateVertices(); - updateGeometry(); - } gpu::Batch& batch = *args->_batch; Transform transform = Transform(); transform.setTranslation(getPosition()); transform.setRotation(getRotation()); + batch.setUniformBuffer(0, _uniformBuffer); batch.setModelTransform(transform); batch.setPipeline(_pipeline); @@ -200,7 +216,7 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) { } else { batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, args->_whiteTexture); } - + batch.setInputFormat(_format); batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index c49777cfa3..658614e72e 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -29,6 +29,8 @@ public: RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual void render(RenderArgs* args); + virtual void update(const quint64& now) override; + virtual bool needsToCallUpdate() const { return true; }; SIMPLE_RENDERABLE(); @@ -42,8 +44,10 @@ protected: void updateGeometry(); void updateVertices(); gpu::BufferPointer _verticesBuffer; + gpu::BufferView _uniformBuffer; unsigned int _numVertices; QVector _vertices; + float _counter; }; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 4e2bc8d097..48de1274f4 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -23,11 +23,15 @@ in vec3 interpolatedNormal; in vec2 varTexcoord; in vec4 varColor; -float rand(vec2 point){ - return fract(sin(dot(point.xy ,vec2(12.9898,78.233))) * 43758.5453); -} +flat in int varVertexId; +struct PolyLineUniforms { + float time; +}; +uniform polyLineBuffer { + PolyLineUniforms polyline; +}; void main(void) { @@ -35,11 +39,13 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; vec3 color = varColor.rgb; + color.g = 1.0 + sin(polyline.time) * 0.5; + //texel.a = varVertexId / 20.0; //vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, - color *texel.rgb, + color * texel.rgb, vec3(0.01, 0.01, 0.01), 10.0); } diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv index 7d7523deb9..25f046456a 100644 --- a/libraries/entities-renderer/src/paintStroke.slv +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -24,6 +24,7 @@ out vec3 interpolatedNormal; out vec2 varTexcoord; out vec4 varColor; +flat out int varVertexId; void main(void) { @@ -31,6 +32,7 @@ void main(void) { // pass along the diffuse color varColor = inColor; + varVertexId = gl_VertexID; // standard transform TransformCamera cam = getTransformCamera(); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 012ec3ca4a..f2cdd6c1c1 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -90,6 +90,7 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } + bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { if (_points.size() > MAX_POINTS_PER_LINE - 1) { qDebug() << "MAX POINTS REACHED!"; @@ -105,6 +106,7 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { return true; } + bool PolyLineEntityItem::setStrokeWidths(const QVector& strokeWidths) { _strokeWidths = strokeWidths; _strokeWidthsChanged = true; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 4da52f3f21..1610bf87b5 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -75,7 +75,9 @@ class PolyLineEntityItem : public EntityItem { _texturesChangedFlag = true; } } - + + virtual bool needsToCallUpdate() const { return true; } + virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; } // never have a ray intersection pick a PolyLineEntityItem. From 191cab2e5f5fd60f40c5310cb8c35d564b1a4157 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 10:15:47 -0800 Subject: [PATCH 002/318] adding light trail app --- examples/flowArts/lightTrails.js | 223 ++++++++++++++++++++++++++++++ examples/lightTrails.js | 224 +++++++++++++++++++++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 examples/flowArts/lightTrails.js create mode 100644 examples/lightTrails.js diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js new file mode 100644 index 0000000000..60754f42a8 --- /dev/null +++ b/examples/flowArts/lightTrails.js @@ -0,0 +1,223 @@ +// +// hydraPaint.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var LEFT = 0; +var RIGHT = 1; +var LASER_WIDTH = 3; +var LASER_COLOR = { + red: 50, + green: 150, + blue: 200 +}; +var TRIGGER_THRESHOLD = .1; + +var MAX_POINTS_PER_LINE = 40; + +var LIFETIME = 6000; +var DRAWING_DEPTH = 1; +var LINE_DIMENSIONS = 20; + + +var MIN_POINT_DISTANCE = 0.01; + +var MIN_BRUSH_RADIUS = 0.08; +var MAX_BRUSH_RADIUS = 0.1; + +var RIGHT_BUTTON_1 = 7 +var RIGHT_BUTTON_2 = 8 +var RIGHT_BUTTON_3 = 9; +var RIGHT_BUTTON_4 = 10 +var LEFT_BUTTON_1 = 1; +var LEFT_BUTTON_2 = 2; +var LEFT_BUTTON_3 = 3; +var LEFT_BUTTON_4 = 4; + +var colorPalette = [{ + red: 250, + green: 0, + blue: 0 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var MIN_STROKE_WIDTH = 0.002; +var MAX_STROKE_WIDTH = 0.05; + +function controller(side, triggerAction) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.triggerAction = triggerAction; + this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; + + this.points = []; + this.normals = []; + this.strokeWidths = []; + + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + + var self = this; + + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: this.currentColor, + dimensions: { + x: MIN_BRUSH_RADIUS, + y: MIN_BRUSH_RADIUS, + z: MIN_BRUSH_RADIUS + } + }); + + this.cycleColor = function() { + this.currentColor = colorPalette[++this.currentColorIndex]; + if (this.currentColorIndex === colorPalette.length - 1) { + this.currentColorIndex = -1; + } + } + this.newLine = function(position) { + this.linePosition = position; + this.line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + textures: "http://localhost:8080/trails.png", + lifetime: LIFETIME + }); + this.points = []; + this.normals = [] + this.strokeWidths = []; + } + + this.update = function(deltaTime) { + this.updateControllerState(); + var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); + var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) + Entities.editEntity(this.brush, { + position: newBrushPos, + color: this.currentColor, + dimensions: { + x: brushRadius, + y: brushRadius, + z: brushRadius + } + }); + + + if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + this.newLine(newBrushPos); + this.drawing = true; + } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { + this.drawing = false; + } + + if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { + var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + + this.points.push(localPoint); + var normal = computeNormal(newBrushPos, Camera.getPosition()); + + this.normals.push(normal); + var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + this.strokeWidths.push(strokeWidth); + Entities.editEntity(this.line, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + color: this.currentColor + }); + + } + } + + + this.updateControllerState = function() { + this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); + this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; + this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; + this.triggerValue = Controller.getActionValue(this.triggerAction); + + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + this.cycleColor(); + Entities.editEntity(this.brush, { + // color: this.currentColor + }); + } + + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + + } + + this.cleanup = function() { + Entities.deleteEntity(self.brush); + } +} + +function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); +} + +function update(deltaTime) { + leftController.update(deltaTime); + rightController.update(deltaTime); +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); +} + +function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; +} + + +var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file diff --git a/examples/lightTrails.js b/examples/lightTrails.js new file mode 100644 index 0000000000..fc8d7082e4 --- /dev/null +++ b/examples/lightTrails.js @@ -0,0 +1,224 @@ +// +// hydraPaint.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var LEFT = 0; +var RIGHT = 1; +var LASER_WIDTH = 3; +var LASER_COLOR = { + red: 50, + green: 150, + blue: 200 +}; +var TRIGGER_THRESHOLD = .1; + +var MAX_POINTS_PER_LINE = 40; + +var LIFETIME = 6000; +var DRAWING_DEPTH = 1; +var LINE_DIMENSIONS = 20; + + +var MIN_POINT_DISTANCE = 0.01; + +var MIN_BRUSH_RADIUS = 0.08; +var MAX_BRUSH_RADIUS = 0.1; + +var RIGHT_BUTTON_1 = 7 +var RIGHT_BUTTON_2 = 8 +var RIGHT_BUTTON_3 = 9; +var RIGHT_BUTTON_4 = 10 +var LEFT_BUTTON_1 = 1; +var LEFT_BUTTON_2 = 2; +var LEFT_BUTTON_3 = 3; +var LEFT_BUTTON_4 = 4; + +var colorPalette = [{ + red: 250, + green: 0, + blue: 0 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var MIN_STROKE_WIDTH = 0.002; +var MAX_STROKE_WIDTH = 0.05; + +function controller(side, triggerAction) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.triggerAction = triggerAction; + this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; + + this.points = []; + this.normals = []; + this.strokeWidths = []; + + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + + var self = this; + + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: this.currentColor, + dimensions: { + x: MIN_BRUSH_RADIUS, + y: MIN_BRUSH_RADIUS, + z: MIN_BRUSH_RADIUS + } + }); + + this.cycleColor = function() { + this.currentColor = colorPalette[++this.currentColorIndex]; + if (this.currentColorIndex === colorPalette.length - 1) { + this.currentColorIndex = -1; + } + } + this.newLine = function(position) { + this.linePosition = position; + this.line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + textures: "http://localhost:8080/trails.png", + lifetime: LIFETIME + }); + this.points = []; + this.normals = [] + this.strokeWidths = []; + } + + this.update = function(deltaTime) { + this.updateControllerState(); + var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); + var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) + Entities.editEntity(this.brush, { + position: newBrushPos, + color: this.currentColor, + dimensions: { + x: brushRadius, + y: brushRadius, + z: brushRadius + } + }); + + + if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + this.newLine(newBrushPos); + this.drawing = true; + } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { + this.drawing = false; + } + + if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { + var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + + this.points.push(localPoint); + var normal = computeNormal(newBrushPos, Camera.getPosition()); + + this.normals.push(normal); + var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + this.strokeWidths.push(strokeWidth); + Entities.editEntity(this.line, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + color: this.currentColor + }); + } + + // Once we get to max points + } + + + this.updateControllerState = function() { + this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); + this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; + this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; + this.triggerValue = Controller.getActionValue(this.triggerAction); + + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + this.cycleColor(); + Entities.editEntity(this.brush, { + // color: this.currentColor + }); + } + + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + + } + + this.cleanup = function() { + Entities.deleteEntity(self.brush); + } +} + +function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); +} + +function update(deltaTime) { + leftController.update(deltaTime); + rightController.update(deltaTime); +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); +} + +function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; +} + + +var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file From a83f374036727eab11afe3616f5f8299814c1e97 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 10:50:25 -0800 Subject: [PATCH 003/318] tweaking light trail --- examples/flowArts/lightTrails.js | 103 +++++++++++-------------------- 1 file changed, 36 insertions(+), 67 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 60754f42a8..c01fc1c4d3 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -33,14 +33,6 @@ var MIN_POINT_DISTANCE = 0.01; var MIN_BRUSH_RADIUS = 0.08; var MAX_BRUSH_RADIUS = 0.1; -var RIGHT_BUTTON_1 = 7 -var RIGHT_BUTTON_2 = 8 -var RIGHT_BUTTON_3 = 9; -var RIGHT_BUTTON_4 = 10 -var LEFT_BUTTON_1 = 1; -var LEFT_BUTTON_2 = 2; -var LEFT_BUTTON_3 = 3; -var LEFT_BUTTON_4 = 4; var colorPalette = [{ red: 250, @@ -73,94 +65,73 @@ function controller(side, triggerAction) { this.side = side; this.triggerAction = triggerAction; this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; - + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + this.trail = Entities.addEntity({ + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + textures: "http://localhost:8080/trails.png", + lifetime: LIFETIME + }); this.points = []; this.normals = []; this.strokeWidths = []; - - this.currentColorIndex = 0; - this.currentColor = colorPalette[this.currentColorIndex]; - var self = this; - this.brush = Entities.addEntity({ - type: 'Sphere', - position: { - x: 0, - y: 0, - z: 0 - }, - color: this.currentColor, - dimensions: { - x: MIN_BRUSH_RADIUS, - y: MIN_BRUSH_RADIUS, - z: MIN_BRUSH_RADIUS - } - }); - this.cycleColor = function() { this.currentColor = colorPalette[++this.currentColorIndex]; if (this.currentColorIndex === colorPalette.length - 1) { this.currentColorIndex = -1; } } - this.newLine = function(position) { - this.linePosition = position; - this.line = Entities.addEntity({ - position: position, - type: "PolyLine", - color: this.currentColor, - dimensions: { - x: LINE_DIMENSIONS, - y: LINE_DIMENSIONS, - z: LINE_DIMENSIONS - }, - textures: "http://localhost:8080/trails.png", - lifetime: LIFETIME + + this.setTrailPosition = function(position) { + this.trailPosition = position; + Entities.editEntity(this.trail, { + position: this.trailPosition }); - this.points = []; - this.normals = [] - this.strokeWidths = []; } + this.update = function(deltaTime) { this.updateControllerState(); - var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); - var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); - var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) - Entities.editEntity(this.brush, { - position: newBrushPos, - color: this.currentColor, - dimensions: { - x: brushRadius, - y: brushRadius, - z: brushRadius - } - }); + var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { - this.newLine(newBrushPos); + this.setTrailPosition(newTrailPos); this.drawing = true; } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { this.drawing = false; } - if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { - var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (this.drawing) { + var localPoint = Vec3.subtract(newTrailPos, this.trailPosition); if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { //Need a minimum distance to avoid binormal NANs return; } + if (this.points.length === MAX_POINTS_PER_LINE) { + this.points.shift(); + this.normals.shift(); + this.strokeWidths.shift(); + } + this.points.push(localPoint); - var normal = computeNormal(newBrushPos, Camera.getPosition()); + var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); this.strokeWidths.push(strokeWidth); - Entities.editEntity(this.line, { + Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, strokeWidths: this.strokeWidths, @@ -175,9 +146,9 @@ function controller(side, triggerAction) { this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; - this.triggerValue = Controller.getActionValue(this.triggerAction); + this.triggerValue = Controller.getActionValue(this.triggerAction); + - if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { this.cycleColor(); Entities.editEntity(this.brush, { @@ -189,9 +160,7 @@ function controller(side, triggerAction) { } - this.cleanup = function() { - Entities.deleteEntity(self.brush); - } + this.cleanup = function() {} } function computeNormal(p1, p2) { @@ -204,7 +173,7 @@ function update(deltaTime) { } function scriptEnding() { - leftController.cleanup(); + leftController.cleanup(); rightController.cleanup(); } From 191f7f2c228771d55c544d2fb497ae34e2d0527e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 1 Dec 2015 16:22:11 -0800 Subject: [PATCH 004/318] no audio for now --- examples/flowArts/lightTrails.js | 22 ++++++++-------- .../src/RenderablePolyLineEntityItem.cpp | 25 +++---------------- .../entities-renderer/src/paintStroke.slf | 7 ++---- 3 files changed, 16 insertions(+), 38 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index c01fc1c4d3..8251803a5f 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -19,19 +19,17 @@ var LASER_COLOR = { green: 150, blue: 200 }; -var TRIGGER_THRESHOLD = .1; -var MAX_POINTS_PER_LINE = 40; +var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 1; +var DRAWING_DEPTH = 0.3; var LINE_DIMENSIONS = 20; -var MIN_POINT_DISTANCE = 0.01; +var MIN_POINT_DISTANCE = 0.03; + -var MIN_BRUSH_RADIUS = 0.08; -var MAX_BRUSH_RADIUS = 0.1; var colorPalette = [{ @@ -75,7 +73,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, - textures: "http://localhost:8080/trails.png", + textures: "http://localhost:8080/trails.png?v1" + Math.random(), lifetime: LIFETIME }); this.points = []; @@ -105,11 +103,9 @@ function controller(side, triggerAction) { var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); - if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + if (!this.drawing) { this.setTrailPosition(newTrailPos); this.drawing = true; - } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { - this.drawing = false; } if (this.drawing) { @@ -129,7 +125,7 @@ function controller(side, triggerAction) { var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); - var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + var strokeWidth = MAX_STROKE_WIDTH; this.strokeWidths.push(strokeWidth); Entities.editEntity(this.trail, { linePoints: this.points, @@ -160,7 +156,9 @@ function controller(side, triggerAction) { } - this.cleanup = function() {} + this.cleanup = function() { + Entities.deleteEntity(this.trail); + } } function computeNormal(p1, p2) { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 63a03bb8e7..bfb27a93b9 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -80,30 +80,12 @@ void RenderablePolyLineEntityItem::updateGeometry() { _verticesBuffer.reset(new gpu::Buffer()); int vertexIndex = 0; vec2 uv; - float tailStart = 0.0f; - float tailEnd = 0.25f; - float tailLength = tailEnd - tailStart; - - float headStart = 0.76f; - float headEnd = 1.0f; - float headLength = headEnd - headStart; float uCoord, vCoord; - - int numTailStrips = 5; - int numHeadStrips = 10; - int startHeadIndex = _vertices.size() / 2 - numHeadStrips; + uCoord = 0.0f; + float uCoordInc = 1.0 / (_vertices.size() / 2); for (int i = 0; i < _vertices.size() / 2; i++) { - uCoord = 0.26f; vCoord = 0.0f; - //tail - if (i < numTailStrips) { - uCoord = float(i) / numTailStrips * tailLength + tailStart; - } - - //head - if (i > startHeadIndex) { - uCoord = float((i + 1) - startHeadIndex) / numHeadStrips * headLength + headStart; - } + uv = vec2(uCoord, vCoord); @@ -121,6 +103,7 @@ void RenderablePolyLineEntityItem::updateGeometry() { vertexIndex++; _numVertices += 2; + uCoord += uCoordInc; } _pointsChanged = false; _normalsChanged = false; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 48de1274f4..6c51b4c979 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -38,14 +38,11 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; - vec3 color = varColor.rgb; - color.g = 1.0 + sin(polyline.time) * 0.5; - //texel.a = varVertexId / 20.0; - //vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess + vec3 color = varColor.rgb; packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, - color * texel.rgb, + texel.rgb, vec3(0.01, 0.01, 0.01), 10.0); } From 8aeb5598488905b7b47bca4db686874ec1ad51fa Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 15:58:30 -0800 Subject: [PATCH 005/318] flowy --- examples/flowArts/lightTrails.js | 45 +++++-- examples/lightTrails.js | 224 ------------------------------- 2 files changed, 36 insertions(+), 233 deletions(-) delete mode 100644 examples/lightTrails.js diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 8251803a5f..8d88957f03 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -11,6 +11,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +var eraseTrail = true; +var ugLSD = 25; +// var eraseTrail = false; var LEFT = 0; var RIGHT = 1; var LASER_WIDTH = 3; @@ -23,13 +27,11 @@ var LASER_COLOR = { var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 0.3; +var DRAWING_DEPTH = 0.2; var LINE_DIMENSIONS = 20; -var MIN_POINT_DISTANCE = 0.03; - - +var MIN_POINT_DISTANCE = 0.02; var colorPalette = [{ @@ -54,8 +56,7 @@ var colorPalette = [{ blue: 122 }]; -var MIN_STROKE_WIDTH = 0.002; -var MAX_STROKE_WIDTH = 0.05; +var STROKE_WIDTH = 0.05; function controller(side, triggerAction) { this.triggerHeld = false; @@ -65,6 +66,16 @@ function controller(side, triggerAction) { this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; this.currentColorIndex = 0; this.currentColor = colorPalette[this.currentColorIndex]; + var textures = "http://localhost:8080/trails.png?v2" + Math.random(); + + // this.light = Entities.addEntity({ + // type: 'Light', + // position: MyAvatar.position, + // dimensions: {x: 20, y: 20, z: 20}, + // color: {red: 60, green: 10, blue: 100}, + // intensity: 10 + // }); + this.trail = Entities.addEntity({ type: "PolyLine", color: this.currentColor, @@ -73,7 +84,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, - textures: "http://localhost:8080/trails.png?v1" + Math.random(), + textures: textures, lifetime: LIFETIME }); this.points = []; @@ -81,6 +92,18 @@ function controller(side, triggerAction) { this.strokeWidths = []; var self = this; + this.trailEraseInterval = Script.setInterval(function() { + if (self.points.length > 0 && eraseTrail) { + self.points.shift(); + self.normals.shift(); + self.strokeWidths.shift(); + Entities.editEntity(self.trail, { + linePoints: self.points, + strokeWidths: self.strokeWidths, + normals: self.normals + }); + } + }, ugLSD); this.cycleColor = function() { this.currentColor = colorPalette[++this.currentColorIndex]; @@ -101,6 +124,9 @@ function controller(side, triggerAction) { this.updateControllerState(); var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); + // Entities.editEntity(this.light, { + // position: newTrailPos + // }); if (!this.drawing) { @@ -125,8 +151,7 @@ function controller(side, triggerAction) { var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); - var strokeWidth = MAX_STROKE_WIDTH; - this.strokeWidths.push(strokeWidth); + this.strokeWidths.push(STROKE_WIDTH); Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, @@ -158,6 +183,8 @@ function controller(side, triggerAction) { this.cleanup = function() { Entities.deleteEntity(this.trail); + // Entities.deleteEntity(this.light); + Script.clearInterval(this.trailEraseInterval); } } diff --git a/examples/lightTrails.js b/examples/lightTrails.js deleted file mode 100644 index fc8d7082e4..0000000000 --- a/examples/lightTrails.js +++ /dev/null @@ -1,224 +0,0 @@ -// -// hydraPaint.js -// examples -// -// Created by Eric Levin on 5/14/15. -// Copyright 2014 High Fidelity, Inc. -// -// This script allows you to paint with the hydra! -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -var LEFT = 0; -var RIGHT = 1; -var LASER_WIDTH = 3; -var LASER_COLOR = { - red: 50, - green: 150, - blue: 200 -}; -var TRIGGER_THRESHOLD = .1; - -var MAX_POINTS_PER_LINE = 40; - -var LIFETIME = 6000; -var DRAWING_DEPTH = 1; -var LINE_DIMENSIONS = 20; - - -var MIN_POINT_DISTANCE = 0.01; - -var MIN_BRUSH_RADIUS = 0.08; -var MAX_BRUSH_RADIUS = 0.1; - -var RIGHT_BUTTON_1 = 7 -var RIGHT_BUTTON_2 = 8 -var RIGHT_BUTTON_3 = 9; -var RIGHT_BUTTON_4 = 10 -var LEFT_BUTTON_1 = 1; -var LEFT_BUTTON_2 = 2; -var LEFT_BUTTON_3 = 3; -var LEFT_BUTTON_4 = 4; - -var colorPalette = [{ - red: 250, - green: 0, - blue: 0 -}, { - red: 214, - green: 91, - blue: 67 -}, { - red: 192, - green: 41, - blue: 66 -}, { - red: 84, - green: 36, - blue: 55 -}, { - red: 83, - green: 119, - blue: 122 -}]; - -var MIN_STROKE_WIDTH = 0.002; -var MAX_STROKE_WIDTH = 0.05; - -function controller(side, triggerAction) { - this.triggerHeld = false; - this.triggerThreshold = 0.9; - this.side = side; - this.triggerAction = triggerAction; - this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; - - this.points = []; - this.normals = []; - this.strokeWidths = []; - - this.currentColorIndex = 0; - this.currentColor = colorPalette[this.currentColorIndex]; - - var self = this; - - - this.brush = Entities.addEntity({ - type: 'Sphere', - position: { - x: 0, - y: 0, - z: 0 - }, - color: this.currentColor, - dimensions: { - x: MIN_BRUSH_RADIUS, - y: MIN_BRUSH_RADIUS, - z: MIN_BRUSH_RADIUS - } - }); - - this.cycleColor = function() { - this.currentColor = colorPalette[++this.currentColorIndex]; - if (this.currentColorIndex === colorPalette.length - 1) { - this.currentColorIndex = -1; - } - } - this.newLine = function(position) { - this.linePosition = position; - this.line = Entities.addEntity({ - position: position, - type: "PolyLine", - color: this.currentColor, - dimensions: { - x: LINE_DIMENSIONS, - y: LINE_DIMENSIONS, - z: LINE_DIMENSIONS - }, - textures: "http://localhost:8080/trails.png", - lifetime: LIFETIME - }); - this.points = []; - this.normals = [] - this.strokeWidths = []; - } - - this.update = function(deltaTime) { - this.updateControllerState(); - var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); - var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); - var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) - Entities.editEntity(this.brush, { - position: newBrushPos, - color: this.currentColor, - dimensions: { - x: brushRadius, - y: brushRadius, - z: brushRadius - } - }); - - - if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { - this.newLine(newBrushPos); - this.drawing = true; - } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { - this.drawing = false; - } - - if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { - var localPoint = Vec3.subtract(newBrushPos, this.linePosition); - if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { - //Need a minimum distance to avoid binormal NANs - return; - } - - this.points.push(localPoint); - var normal = computeNormal(newBrushPos, Camera.getPosition()); - - this.normals.push(normal); - var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); - this.strokeWidths.push(strokeWidth); - Entities.editEntity(this.line, { - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - color: this.currentColor - }); - } - - // Once we get to max points - } - - - this.updateControllerState = function() { - this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); - this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; - this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; - this.triggerValue = Controller.getActionValue(this.triggerAction); - - - if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { - this.cycleColor(); - Entities.editEntity(this.brush, { - // color: this.currentColor - }); - } - - this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; - - } - - this.cleanup = function() { - Entities.deleteEntity(self.brush); - } -} - -function computeNormal(p1, p2) { - return Vec3.normalize(Vec3.subtract(p2, p1)); -} - -function update(deltaTime) { - leftController.update(deltaTime); - rightController.update(deltaTime); -} - -function scriptEnding() { - leftController.cleanup(); - rightController.cleanup(); -} - -function vectorIsZero(v) { - return v.x === 0 && v.y === 0 && v.z === 0; -} - - -var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK")); -var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK")); -Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); - -function map(value, min1, max1, min2, max2) { - return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); -} \ No newline at end of file From d2d0326c02268b4cf8cd496de12d5e23888910b9 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 16:44:47 -0800 Subject: [PATCH 006/318] using deployed texture --- examples/flowArts/lightTrails.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 8d88957f03..a494f9a810 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -66,7 +66,7 @@ function controller(side, triggerAction) { this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; this.currentColorIndex = 0; this.currentColor = colorPalette[this.currentColorIndex]; - var textures = "http://localhost:8080/trails.png?v2" + Math.random(); + var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; // this.light = Entities.addEntity({ // type: 'Light', @@ -84,7 +84,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, - textures: textures, + textures: texture, lifetime: LIFETIME }); this.points = []; From 762a241fa6b66540d2c196f64d6331cf471888ba Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 18:03:58 -0800 Subject: [PATCH 007/318] Adding specific path for loading lightmaps --- .../src/model-networking/ModelCache.cpp | 3 +- .../src/model-networking/TextureCache.h | 2 +- libraries/model/src/model/TextureMap.cpp | 88 ++++++++++++++++++- libraries/model/src/model/TextureMap.h | 2 + 4 files changed, 91 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index c7d3523496..ddb6449dc7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -308,10 +308,9 @@ 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)), EMISSIVE_TEXTURE, material.emissiveTexture.content); + networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), LIGHTMAP_TEXTURE, material.emissiveTexture.content); networkMaterial->emissiveTextureName = material.emissiveTexture.name; - //checkForTexcoordLightmap = true; auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource); diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index cc22509631..4171b6c1cb 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, CUSTOM_TEXTURE }; +enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_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 d443522a6f..453bb17a4b 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -119,7 +119,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con if ((image.width() > 0) && (image.height() > 0)) { // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); + bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); @@ -520,3 +520,89 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c return theTexture; } + + +gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { + QImage image = srcImage; + + int imageArea = image.width() * image.height(); + + int opaquePixels = 0; + int translucentPixels = 0; + //bool isTransparent = false; + int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; + const int EIGHT_BIT_MAXIMUM = 255; + QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM); + + if (!image.hasAlphaChannel()) { + if (image.format() != QImage::Format_RGB888) { + image = image.convertToFormat(QImage::Format_RGB888); + } + // int redTotal = 0, greenTotal = 0, blueTotal = 0; + for (int y = 0; y < image.height(); y++) { + for (int x = 0; x < image.width(); x++) { + QRgb rgb = image.pixel(x, y); + redTotal += qRed(rgb); + greenTotal += qGreen(rgb); + blueTotal += qBlue(rgb); + } + } + if (imageArea > 0) { + averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea); + } + } else { + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); + } + + // check for translucency/false transparency + // int opaquePixels = 0; + // int translucentPixels = 0; + // int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; + for (int y = 0; y < image.height(); y++) { + for (int x = 0; x < image.width(); x++) { + QRgb rgb = image.pixel(x, y); + redTotal += qRed(rgb); + greenTotal += qGreen(rgb); + blueTotal += qBlue(rgb); + int alpha = qAlpha(rgb); + alphaTotal += alpha; + if (alpha == EIGHT_BIT_MAXIMUM) { + opaquePixels++; + } else if (alpha != 0) { + translucentPixels++; + } + } + } + if (opaquePixels == imageArea) { + qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str()); + image = image.convertToFormat(QImage::Format_RGB888); + } + + averageColor = QColor(redTotal / imageArea, + greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea); + + //isTransparent = (translucentPixels >= imageArea / 2); + } + + 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::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + if (image.hasAlphaChannel()) { + formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + } + + + 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); + } + + return theTexture; +} diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index 107ca2e879..6bc5b8228c 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -35,6 +35,8 @@ 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* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName); + static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName); + }; From 2336dd96dd934f5efc1832db5815bf2dc87f3c21 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 18:10:45 -0800 Subject: [PATCH 008/318] lights --- examples/flowArts/lightTrails.js | 108 ++++++++++++++----------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index a494f9a810..4a7f9de277 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -12,73 +12,82 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("../libraries/utils.js"); + var eraseTrail = true; var ugLSD = 25; // var eraseTrail = false; var LEFT = 0; var RIGHT = 1; -var LASER_WIDTH = 3; -var LASER_COLOR = { - red: 50, - green: 150, - blue: 200 -}; - var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 0.2; +var DRAWING_DEPTH = 0.6; var LINE_DIMENSIONS = 20; +var lightZone = Entities.addEntity({ + type: "Zone", + shapeType: 'box', + keyLightIntensity: 0.02, + keyLightColor: { + red: 5, + green: 0, + blue: 5 + }, + keyLightAmbientIntensity: .05, + position: MyAvatar.position, + dimensions: { + x: 100, + y: 100, + z: 100 + } +}); + var MIN_POINT_DISTANCE = 0.02; var colorPalette = [{ red: 250, - green: 0, - blue: 0 + green: 137, + blue: 162 }, { - red: 214, - green: 91, - blue: 67 + red: 204, + green: 244, + blue: 249 }, { - red: 192, - green: 41, - blue: 66 + red: 146, + green: 206, + blue: 116 }, { - red: 84, - green: 36, - blue: 55 -}, { - red: 83, - green: 119, - blue: 122 + red: 240, + green: 87, + blue: 129 }]; -var STROKE_WIDTH = 0.05; +var STROKE_WIDTH = 0.03; function controller(side, triggerAction) { this.triggerHeld = false; this.triggerThreshold = 0.9; this.side = side; this.triggerAction = triggerAction; - this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb; - this.currentColorIndex = 0; - this.currentColor = colorPalette[this.currentColorIndex]; var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; - // this.light = Entities.addEntity({ - // type: 'Light', - // position: MyAvatar.position, - // dimensions: {x: 20, y: 20, z: 20}, - // color: {red: 60, green: 10, blue: 100}, - // intensity: 10 - // }); + this.light = Entities.addEntity({ + type: 'Light', + position: MyAvatar.position, + dimensions: { + x: 20, + y: 20, + z: 20 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 20 + }); this.trail = Entities.addEntity({ type: "PolyLine", - color: this.currentColor, dimensions: { x: LINE_DIMENSIONS, y: LINE_DIMENSIONS, @@ -105,12 +114,6 @@ function controller(side, triggerAction) { } }, ugLSD); - this.cycleColor = function() { - this.currentColor = colorPalette[++this.currentColorIndex]; - if (this.currentColorIndex === colorPalette.length - 1) { - this.currentColorIndex = -1; - } - } this.setTrailPosition = function(position) { this.trailPosition = position; @@ -124,9 +127,9 @@ function controller(side, triggerAction) { this.updateControllerState(); var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset); - // Entities.editEntity(this.light, { - // position: newTrailPos - // }); + Entities.editEntity(this.light, { + position: newTrailPos + }); if (!this.drawing) { @@ -151,12 +154,11 @@ function controller(side, triggerAction) { var normal = computeNormal(newTrailPos, Camera.getPosition()); this.normals.push(normal); - this.strokeWidths.push(STROKE_WIDTH); + this.strokeWidths.push(STROKE_WIDTH + Math.random() * 0.01); Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, strokeWidths: this.strokeWidths, - color: this.currentColor }); } @@ -164,26 +166,15 @@ function controller(side, triggerAction) { this.updateControllerState = function() { - this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton); this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation; this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation; this.triggerValue = Controller.getActionValue(this.triggerAction); - - if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { - this.cycleColor(); - Entities.editEntity(this.brush, { - // color: this.currentColor - }); - } - - this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; - } this.cleanup = function() { Entities.deleteEntity(this.trail); - // Entities.deleteEntity(this.light); + Entities.deleteEntity(this.light); Script.clearInterval(this.trailEraseInterval); } } @@ -200,6 +191,7 @@ function update(deltaTime) { function scriptEnding() { leftController.cleanup(); rightController.cleanup(); + Entities.deleteEntity(lightZone); } function vectorIsZero(v) { From a5475ed14d2089e7e63d5fb294b71da87b6f2658 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 3 Dec 2015 10:41:32 -0800 Subject: [PATCH 009/318] Early try fixing the lighting --- .../render-utils/src/DeferredLighting.slh | 2 +- .../src/DeferredLightingEffect.cpp | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index 888742bb18..53ffdee0ca 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -33,7 +33,7 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 sp vec3 schlick = specular * (1.0 - shlickPower5) + vec3(shlickPower5); vec3 reflect = specularPower * schlick; - return vec4(reflect, diffuse); + return vec4(reflect, diffuse * (1 - length(schlick))); } <@endfunc@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 57e3129ef8..4370f8279e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -143,7 +143,39 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { { //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS(); - auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); + const char BlitTextureGamma_frag[] = R"SCRIBE(#version 410 core + // Generated on Sat Oct 24 09:34:37 2015 + // + // Draw texture 0 fetched at texcoord.xy + // + // Created by Sam Gateau on 6/22/2015 + // Copyright 2015 High Fidelity, Inc. + // + // Distributed under the Apache License, Version 2.0. + // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + // + + + uniform sampler2D colorMap; + + in vec2 varTexCoord0; + out vec4 outFragColor; + + void main(void) { + outFragColor = texture(colorMap, varTexCoord0); + if (gl_FragCoord.x > 1000) { + outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0/2.2) ); + } + } + + )SCRIBE"; + auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(BlitTextureGamma_frag))); + + //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); + auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); + + //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); gpu::Shader::makeProgram(*blitProgram); auto blitState = std::make_shared(); blitState->setBlendFunction(true, From 5f881e765093d62d9ecc0031b3883ff31acb5505 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 3 Dec 2015 13:46:29 -0800 Subject: [PATCH 010/318] polylines now take color as a uniform --- examples/flowArts/lightTrails.js | 7 ++++--- examples/painting/closePaint.js | 5 ++++- .../painting/whiteboard/whiteboardEntityScript.js | 3 +++ .../src/RenderablePolyLineEntityItem.cpp | 13 +++---------- .../src/RenderablePolyLineEntityItem.h | 1 - libraries/entities-renderer/src/paintStroke.slf | 6 ++---- libraries/entities-renderer/src/paintStroke.slv | 3 --- libraries/entities/src/PolyLineEntityItem.h | 2 +- 8 files changed, 17 insertions(+), 23 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 4a7f9de277..e063897eb8 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -22,7 +22,7 @@ var RIGHT = 1; var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; -var DRAWING_DEPTH = 0.6; +var DRAWING_DEPTH = 0.8; var LINE_DIMENSIONS = 20; var lightZone = Entities.addEntity({ @@ -65,7 +65,7 @@ var colorPalette = [{ blue: 129 }]; -var STROKE_WIDTH = 0.03; +var STROKE_WIDTH = 0.04; function controller(side, triggerAction) { this.triggerHeld = false; @@ -83,7 +83,7 @@ function controller(side, triggerAction) { z: 20 }, color: colorPalette[randInt(0, colorPalette.length)], - intensity: 20 + intensity: 5 }); this.trail = Entities.addEntity({ @@ -93,6 +93,7 @@ function controller(side, triggerAction) { y: LINE_DIMENSIONS, z: LINE_DIMENSIONS }, + color: {red: 255, green: 255, blue: 255}, textures: texture, lifetime: LIFETIME }); diff --git a/examples/painting/closePaint.js b/examples/painting/closePaint.js index 60b4ac2e25..bea4d9c9aa 100644 --- a/examples/painting/closePaint.js +++ b/examples/painting/closePaint.js @@ -43,6 +43,8 @@ var MAX_STROKE_WIDTH = 0.04; var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(Camera.getOrientation()))); +var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png"; + function MyController(hand, triggerAction) { @@ -148,7 +150,8 @@ function MyController(hand, triggerAction) { y: 50, z: 50 }, - lifetime: 200 + lifetime: 200, + textures: textureURL }); this.strokePoints = []; this.strokeNormals = []; diff --git a/examples/painting/whiteboard/whiteboardEntityScript.js b/examples/painting/whiteboard/whiteboardEntityScript.js index 61d7291e11..374ec8b873 100644 --- a/examples/painting/whiteboard/whiteboardEntityScript.js +++ b/examples/painting/whiteboard/whiteboardEntityScript.js @@ -29,6 +29,8 @@ var MIN_STROKE_WIDTH = 0.0005; var MAX_STROKE_WIDTH = 0.03; + var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png"; + var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT, @@ -168,6 +170,7 @@ type: "PolyLine", name: "paintStroke", color: this.strokeColor, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png", dimensions: { x: 50, y: 50, diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index bfb27a93b9..d38da0d3f7 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -25,7 +25,7 @@ struct PolyLineUniforms { - float time; + glm::vec3 color; }; EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -34,7 +34,6 @@ EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& enti RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : PolyLineEntityItem(entityItemID, properties), -_counter(0.0f), _numVertices(0) { _vertices = QVector(0.0f); @@ -49,13 +48,11 @@ int32_t RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT; void RenderablePolyLineEntityItem::createPipeline() { static const int NORMAL_OFFSET = 12; - static const int COLOR_OFFSET = 24; - static const int TEXTURE_OFFSET = 28; + static const int TEXTURE_OFFSET = 24; _format.reset(new gpu::Stream::Format()); _format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); _format->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), NORMAL_OFFSET); - _format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET); _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET); auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(paintStroke_vert))); @@ -91,14 +88,12 @@ void RenderablePolyLineEntityItem::updateGeometry() { _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex)); _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i)); - _verticesBuffer->append(sizeof(int), (gpu::Byte*)&_color); _verticesBuffer->append(sizeof(glm::vec2), (gpu::Byte*)&uv); vertexIndex++; uv.y = 1.0f; _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex)); _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i)); - _verticesBuffer->append(sizeof(int), (gpu::Byte*)_color); _verticesBuffer->append(sizeof(glm::vec2), (const gpu::Byte*)&uv); vertexIndex++; @@ -154,10 +149,8 @@ void RenderablePolyLineEntityItem::updateVertices() { void RenderablePolyLineEntityItem::update(const quint64& now) { PolyLineUniforms uniforms; - _counter += 0.01; - uniforms.time = _counter; + uniforms.color = toGlm(getXColor()); memcpy(&_uniformBuffer.edit(), &uniforms, sizeof(PolyLineUniforms)); - if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { updateVertices(); updateGeometry(); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 658614e72e..411b856d91 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -47,7 +47,6 @@ protected: gpu::BufferView _uniformBuffer; unsigned int _numVertices; QVector _vertices; - float _counter; }; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 6c51b4c979..1a87f84bfd 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -21,12 +21,11 @@ uniform sampler2D originalTexture; // the interpolated normal in vec3 interpolatedNormal; in vec2 varTexcoord; -in vec4 varColor; flat in int varVertexId; struct PolyLineUniforms { - float time; + vec3 color; }; uniform polyLineBuffer { @@ -38,11 +37,10 @@ void main(void) { vec4 texel = texture(originalTexture, varTexcoord); int frontCondition = 1 -int(gl_FrontFacing) * 2; - vec3 color = varColor.rgb; packDeferredFragmentTranslucent( interpolatedNormal * frontCondition, texel.a, - texel.rgb, + polyline.color * texel.rgb, vec3(0.01, 0.01, 0.01), 10.0); } diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv index 25f046456a..5c368f9c0f 100644 --- a/libraries/entities-renderer/src/paintStroke.slv +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -23,15 +23,12 @@ out vec3 interpolatedNormal; //the diffuse texture out vec2 varTexcoord; -out vec4 varColor; flat out int varVertexId; void main(void) { varTexcoord = inTexCoord0.st; - // pass along the diffuse color - varColor = inColor; varVertexId = gl_VertexID; // standard transform diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 1610bf87b5..20549d1bbd 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -49,7 +49,7 @@ class PolyLineEntityItem : public EntityItem { memcpy(_color, value, sizeof(_color)); } void setColor(const xColor& value) { - + _color[RED_INDEX] = value.red; _color[GREEN_INDEX] = value.green; _color[BLUE_INDEX] = value.blue; From 72d393905b36cbf65c7686ee67210c3beaaa1fab Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 3 Dec 2015 16:03:32 -0800 Subject: [PATCH 011/318] Introducing the Lighting Buffer where all the lighting is beeing accumulated, apply a manual gamma correction when copying back into the main color buffer --- .../src/DeferredLightingEffect.cpp | 26 +++++++------------ .../render-utils/src/FramebufferCache.cpp | 22 ++++++++++++++++ libraries/render-utils/src/FramebufferCache.h | 9 ++++++- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 4370f8279e..371a3d705e 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -163,9 +163,10 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { void main(void) { outFragColor = texture(colorMap, varTexCoord0); - if (gl_FragCoord.x > 1000) { - outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0/2.2) ); - } + // if (gl_FragCoord.x > 1000) { + // Manually gamma correct from Ligthing BUffer to color buffer + outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0 / 2.2) ); + // } } )SCRIBE"; @@ -178,9 +179,6 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); gpu::Shader::makeProgram(*blitProgram); auto blitState = std::make_shared(); - blitState->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); blitState->setColorWriteMask(true, true, true, false); _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); } @@ -386,8 +384,6 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { }); } -gpu::FramebufferPointer _copyFBO; - void DeferredLightingEffect::render(RenderArgs* args) { gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { @@ -407,13 +403,13 @@ void DeferredLightingEffect::render(RenderArgs* args) { QSize framebufferSize = framebufferCache->getFrameBufferSize(); // binding the first framebuffer - _copyFBO = framebufferCache->getFramebuffer(); - batch.setFramebuffer(_copyFBO); + auto lightingFBO = framebufferCache->getLightingFramebuffer(); + batch.setFramebuffer(lightingFBO); // Clearing it batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); - batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); + batch.clearColorFramebuffer(lightingFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); // BInd the G-Buffer surfaces batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); @@ -718,11 +714,8 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) { batch.enableStereo(false); QSize framebufferSize = framebufferCache->getFrameBufferSize(); - // TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror. - // auto destFbo = framebufferCache->getPrimaryFramebuffer(); + auto lightingBuffer = framebufferCache->getLightingTexture(); auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor(); - // gpu::Vec4i vp = args->_viewport; - // batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp); batch.setFramebuffer(destFbo); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); @@ -739,12 +732,11 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) { batch.setModelTransform(model); } - batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0)); + batch.setResourceTexture(0, lightingBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); args->_context->render(batch); }); - framebufferCache->releaseFramebuffer(_copyFBO); } void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) { diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 5907d3fa27..2a8033be0d 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -41,6 +41,8 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { _primarySpecularTexture.reset(); _selfieFramebuffer.reset(); _cachedFramebuffers.clear(); + _lightingTexture.reset(); + _lightingFramebuffer.reset(); } } @@ -74,6 +76,12 @@ void FramebufferCache::createPrimaryFramebuffer() { _selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); _selfieFramebuffer->setRenderBuffer(0, tex); + + _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), width, height, defaultSampler)); + //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::SRGBA), width, height, defaultSampler)); + // _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); + _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); } gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() { @@ -118,6 +126,20 @@ gpu::TexturePointer FramebufferCache::getPrimarySpecularTexture() { return _primarySpecularTexture; } +gpu::FramebufferPointer FramebufferCache::getLightingFramebuffer() { + if (!_lightingFramebuffer) { + createPrimaryFramebuffer(); + } + return _lightingFramebuffer; +} + +gpu::TexturePointer FramebufferCache::getLightingTexture() { + if (!_lightingTexture) { + createPrimaryFramebuffer(); + } + return _lightingTexture; +} + gpu::FramebufferPointer FramebufferCache::getFramebuffer() { if (_cachedFramebuffers.isEmpty()) { _cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, _frameBufferSize.width(), _frameBufferSize.height()))); diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index e9a1bbf8e8..610609e7c9 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -37,6 +37,10 @@ public: gpu::TexturePointer getPrimaryNormalTexture(); gpu::TexturePointer getPrimarySpecularTexture(); + + gpu::TexturePointer getLightingTexture(); + gpu::FramebufferPointer getLightingFramebuffer(); + /// Returns the framebuffer object used to render shadow maps; gpu::FramebufferPointer getShadowFramebuffer(); @@ -63,7 +67,10 @@ private: gpu::TexturePointer _primaryColorTexture; gpu::TexturePointer _primaryNormalTexture; gpu::TexturePointer _primarySpecularTexture; - + + gpu::TexturePointer _lightingTexture; + gpu::FramebufferPointer _lightingFramebuffer; + gpu::FramebufferPointer _shadowFramebuffer; gpu::FramebufferPointer _selfieFramebuffer; From d593b824e94cd384614c275b0cefae9f7939db9b Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 3 Dec 2015 17:26:54 -0800 Subject: [PATCH 012/318] Introducing a true Primary Framebuffer and a different Deferred Framebuffer --- interface/src/Application.cpp | 10 +-- .../src/AmbientOcclusionEffect.cpp | 4 +- .../render-utils/src/AntialiasingEffect.cpp | 4 +- .../src/DeferredLightingEffect.cpp | 10 +-- .../render-utils/src/FramebufferCache.cpp | 76 ++++++++++++------- libraries/render-utils/src/FramebufferCache.h | 20 +++-- .../render-utils/src/RenderDeferredTask.cpp | 16 ++-- 7 files changed, 86 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ef10ad4464..6648a131c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -676,9 +676,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _applicationStateDevice->addInputVariant(QString("ComfortMode"), controller::StateController::ReadLambda([]() -> float { return (float)Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode); })); - _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { - return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); - })); + _applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float { + return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); + })); userInputMapper->registerDevice(_applicationStateDevice); @@ -1347,7 +1347,7 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/compositor"); PerformanceTimer perfTimer("compositor"); - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); + auto primaryFbo = framebufferCache->getPrimaryFramebufferDepthColor(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFbo)); if (displayPlugin->isStereo()) { QRect currentViewport(QPoint(0, 0), QSize(size.width() / 2, size.height())); @@ -1372,7 +1372,7 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); + auto primaryFbo = framebufferCache->getPrimaryFramebufferDepthColor(); GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0)); // Ensure the rendering context commands are completed when rendering GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 456a6430a7..3d2a5ef43b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -201,7 +201,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons // Occlusion step getOcclusionPipeline(); batch.setResourceTexture(0, framebufferCache->getPrimaryDepthTexture()); - batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture()); + batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture()); _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); batch.setFramebuffer(_occlusionBuffer); @@ -276,7 +276,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons // Blend step getBlendPipeline(); batch.setResourceTexture(0, _hBlurTexture); - batch.setFramebuffer(framebufferCache->getPrimaryFramebuffer()); + batch.setFramebuffer(framebufferCache->getDeferredFramebuffer()); // Bind the fourth gpu::Pipeline we need - for blending the primary color buffer with blurred occlusion texture batch.setPipeline(getBlendPipeline()); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index aaef67542f..2abb9f085e 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -123,7 +123,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re // FXAA step getAntialiasingPipeline(); - batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); + batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); batch.setFramebuffer(_antialiasingBuffer); batch.setPipeline(getAntialiasingPipeline()); @@ -153,7 +153,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re // Blend step getBlendPipeline(); batch.setResourceTexture(0, _antialiasingTexture); - batch.setFramebuffer(framebufferCache->getPrimaryFramebuffer()); + batch.setFramebuffer(framebufferCache->getDeferredFramebuffer()); batch.setPipeline(getBlendPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 371a3d705e..9ade2f5cea 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -374,9 +374,9 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { batch.enableStereo(false); batch.setStateScissorRect(args->_viewport); - auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer(); + auto deferredFbo = DependencyManager::get()->getDeferredFramebuffer(); - batch.setFramebuffer(primaryFbo); + batch.setFramebuffer(deferredFbo); // clear the normal and specular buffers batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); const float MAX_SPECULAR_EXPONENT = 128.0f; @@ -412,9 +412,9 @@ void DeferredLightingEffect::render(RenderArgs* args) { batch.clearColorFramebuffer(lightingFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); // BInd the G-Buffer surfaces - batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture()); - batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture()); - batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture()); + batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); + batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture()); + batch.setResourceTexture(2, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture()); // THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport) diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 2a8033be0d..b39b8cc7e5 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -33,12 +33,14 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { //If the size changed, we need to delete our FBOs if (_frameBufferSize != frameBufferSize) { _frameBufferSize = frameBufferSize; - _primaryFramebufferFull.reset(); _primaryFramebufferDepthColor.reset(); _primaryDepthTexture.reset(); _primaryColorTexture.reset(); - _primaryNormalTexture.reset(); - _primarySpecularTexture.reset(); + _deferredFramebuffer.reset(); + _deferredFramebufferDepthColor.reset(); + _deferredColorTexture.reset(); + _deferredNormalTexture.reset(); + _deferredSpecularTexture.reset(); _selfieFramebuffer.reset(); _cachedFramebuffers.clear(); _lightingTexture.reset(); @@ -47,8 +49,9 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { } void FramebufferCache::createPrimaryFramebuffer() { - _primaryFramebufferFull = gpu::FramebufferPointer(gpu::Framebuffer::create()); _primaryFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _frameBufferSize.width(); @@ -56,23 +59,30 @@ void FramebufferCache::createPrimaryFramebuffer() { auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - _primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - - _primaryFramebufferFull->setRenderBuffer(0, _primaryColorTexture); - _primaryFramebufferFull->setRenderBuffer(1, _primaryNormalTexture); - _primaryFramebufferFull->setRenderBuffer(2, _primarySpecularTexture); _primaryFramebufferDepthColor->setRenderBuffer(0, _primaryColorTexture); + _deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + + _deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture); + _deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture); + _deferredFramebuffer->setRenderBuffer(2, _deferredSpecularTexture); + + _deferredFramebufferDepthColor->setRenderBuffer(0, _deferredColorTexture); + // auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); - - _primaryFramebufferFull->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); _primaryFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - + + _deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + + _deferredFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); + + _selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); _selfieFramebuffer->setRenderBuffer(0, tex); @@ -84,13 +94,6 @@ void FramebufferCache::createPrimaryFramebuffer() { _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); } -gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() { - if (!_primaryFramebufferFull) { - createPrimaryFramebuffer(); - } - return _primaryFramebufferFull; -} - gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferDepthColor() { if (!_primaryFramebufferDepthColor) { createPrimaryFramebuffer(); @@ -112,18 +115,39 @@ gpu::TexturePointer FramebufferCache::getPrimaryColorTexture() { return _primaryColorTexture; } -gpu::TexturePointer FramebufferCache::getPrimaryNormalTexture() { - if (!_primaryNormalTexture) { +gpu::FramebufferPointer FramebufferCache::getDeferredFramebuffer() { + if (!_deferredFramebuffer) { createPrimaryFramebuffer(); } - return _primaryNormalTexture; + return _deferredFramebuffer; } -gpu::TexturePointer FramebufferCache::getPrimarySpecularTexture() { - if (!_primarySpecularTexture) { +gpu::FramebufferPointer FramebufferCache::getDeferredFramebufferDepthColor() { + if (!_deferredFramebufferDepthColor) { createPrimaryFramebuffer(); } - return _primarySpecularTexture; + return _deferredFramebufferDepthColor; +} + +gpu::TexturePointer FramebufferCache::getDeferredColorTexture() { + if (!_deferredColorTexture) { + createPrimaryFramebuffer(); + } + return _deferredColorTexture; +} + +gpu::TexturePointer FramebufferCache::getDeferredNormalTexture() { + if (!_deferredNormalTexture) { + createPrimaryFramebuffer(); + } + return _deferredNormalTexture; +} + +gpu::TexturePointer FramebufferCache::getDeferredSpecularTexture() { + if (!_deferredSpecularTexture) { + createPrimaryFramebuffer(); + } + return _deferredSpecularTexture; } gpu::FramebufferPointer FramebufferCache::getLightingFramebuffer() { diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index 610609e7c9..6633301d0c 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -29,13 +29,17 @@ public: /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is /// used for scene rendering. - gpu::FramebufferPointer getPrimaryFramebuffer(); gpu::FramebufferPointer getPrimaryFramebufferDepthColor(); gpu::TexturePointer getPrimaryDepthTexture(); gpu::TexturePointer getPrimaryColorTexture(); - gpu::TexturePointer getPrimaryNormalTexture(); - gpu::TexturePointer getPrimarySpecularTexture(); + + gpu::FramebufferPointer getDeferredFramebuffer(); + gpu::FramebufferPointer getDeferredFramebufferDepthColor(); + + gpu::TexturePointer getDeferredColorTexture(); + gpu::TexturePointer getDeferredNormalTexture(); + gpu::TexturePointer getDeferredSpecularTexture(); gpu::TexturePointer getLightingTexture(); @@ -60,13 +64,17 @@ private: void createPrimaryFramebuffer(); - gpu::FramebufferPointer _primaryFramebufferFull; gpu::FramebufferPointer _primaryFramebufferDepthColor; gpu::TexturePointer _primaryDepthTexture; gpu::TexturePointer _primaryColorTexture; - gpu::TexturePointer _primaryNormalTexture; - gpu::TexturePointer _primarySpecularTexture; + + gpu::FramebufferPointer _deferredFramebuffer; + gpu::FramebufferPointer _deferredFramebufferDepthColor; + + gpu::TexturePointer _deferredColorTexture; + gpu::TexturePointer _deferredNormalTexture; + gpu::TexturePointer _deferredSpecularTexture; gpu::TexturePointer _lightingTexture; gpu::FramebufferPointer _lightingFramebuffer; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e65018ad3d..bf5f621726 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -38,13 +38,13 @@ void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderCon RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - auto primaryFbo = DependencyManager::get()->getPrimaryFramebufferDepthColor(); + auto deferredFbo = DependencyManager::get()->getDeferredFramebufferDepthColor(); batch.enableStereo(false); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); - batch.setFramebuffer(primaryFbo); + batch.setFramebuffer(deferredFbo); batch.clearFramebuffer( gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH | @@ -332,11 +332,11 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - auto primaryFboColorDepthStencil = DependencyManager::get()->getPrimaryFramebufferDepthColor(); + auto deferredFboColorDepthStencil = DependencyManager::get()->getDeferredFramebufferDepthColor(); batch.enableStereo(false); - batch.setFramebuffer(primaryFboColorDepthStencil); + batch.setFramebuffer(deferredFboColorDepthStencil); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); @@ -367,12 +367,12 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - auto primaryFboColorDepthStencil = DependencyManager::get()->getPrimaryFramebufferDepthColor(); - auto primaryFboFull = DependencyManager::get()->getPrimaryFramebuffer(); + auto deferredFboColorDepthStencil = DependencyManager::get()->getDeferredFramebufferDepthColor(); + auto deferredFboFull = DependencyManager::get()->getDeferredFramebuffer(); batch.enableSkybox(true); - batch.setFramebuffer(primaryFboColorDepthStencil); + batch.setFramebuffer(deferredFboColorDepthStencil); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); @@ -387,7 +387,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const renderItems(sceneContext, renderContext, inItems); - batch.setFramebuffer(primaryFboFull); + batch.setFramebuffer(deferredFboFull); }); args->_batch = nullptr; From baf93e8a084f03a5a8c2facfb5b803e14da299be Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Dec 2015 15:54:53 -0800 Subject: [PATCH 013/318] Add basic DebugDeferredBuffer job --- .../render-utils/src/DebugDeferredBuffer.cpp | 72 +++++++++++++++++++ .../render-utils/src/DebugDeferredBuffer.h | 29 ++++++++ libraries/render-utils/src/HitEffect.cpp | 1 + libraries/render-utils/src/HitEffect.h | 8 +-- .../render-utils/src/RenderDeferredTask.cpp | 7 +- .../render-utils/src/RenderDeferredTask.h | 4 +- .../src/debug_deferred_buffer.slf | 21 ++++++ .../src/debug_deferred_buffer.slv | 19 +++++ libraries/render-utils/src/hit_effect.slf | 8 +-- 9 files changed, 155 insertions(+), 14 deletions(-) create mode 100644 libraries/render-utils/src/DebugDeferredBuffer.cpp create mode 100644 libraries/render-utils/src/DebugDeferredBuffer.h create mode 100644 libraries/render-utils/src/debug_deferred_buffer.slf create mode 100644 libraries/render-utils/src/debug_deferred_buffer.slv diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp new file mode 100644 index 0000000000..e1c31f943e --- /dev/null +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -0,0 +1,72 @@ +// +// DebugDeferredBuffer.cpp +// libraries/render-utils/src +// +// Created by Clement on 12/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DebugDeferredBuffer.h" + +#include +#include +#include +#include + +#include "GeometryCache.h" + +#include "debug_deferred_buffer_vert.h" +#include "debug_deferred_buffer_frag.h" + +using namespace render; + +const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline() { + if (!_pipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex({ debug_deferred_buffer_vert })); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel({ debug_deferred_buffer_frag })); + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + auto state = std::make_shared(); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + // Good to go add the brand new pipeline + _pipeline.reset(gpu::Pipeline::create(program, state)); + } + return _pipeline; +} + + +void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + RenderArgs* args = renderContext->args; + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + batch.setPipeline(getPipeline()); + + glm::vec4 color(0.0f, 0.0f, 1.0f, 1.0f); + glm::vec2 bottomLeft(0.0f, -1.0f); + glm::vec2 topRight(1.0f, 1.0f); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, color); + }); +} \ No newline at end of file diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h new file mode 100644 index 0000000000..827a3271f0 --- /dev/null +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -0,0 +1,29 @@ +// +// DebugDeferredBuffer.h +// libraries/render-utils/src +// +// Created by Clement on 12/3/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_DebugDeferredBuffer_h +#define hifi_DebugDeferredBuffer_h + +#include + +class DebugDeferredBuffer { +public: + using JobModel = render::Job::Model; + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + +private: + const gpu::PipelinePointer& getPipeline(); + + gpu::PipelinePointer _pipeline; +}; + +#endif // hifi_DebugDeferredBuffer_h \ No newline at end of file diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index 06bd07b456..f33dc5b3b9 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -14,6 +14,7 @@ #include +#include #include #include diff --git a/libraries/render-utils/src/HitEffect.h b/libraries/render-utils/src/HitEffect.h index b560cf5550..0a96a5300d 100644 --- a/libraries/render-utils/src/HitEffect.h +++ b/libraries/render-utils/src/HitEffect.h @@ -9,11 +9,7 @@ #ifndef hifi_hitEffect_h #define hifi_hitEffect_h -#include -#include "render/DrawTask.h" - -class AbstractViewStateInterface; -class ProgramObject; +#include class HitEffect { public: @@ -23,7 +19,7 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); typedef render::Job::Model JobModel; - const gpu::PipelinePointer& getHitEffectPipeline(); + const gpu::PipelinePointer& getHitEffectPipeline(); private: gpu::PipelinePointer _hitEffectPipeline; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index bf5f621726..43ddd5b7ae 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -18,10 +18,11 @@ #include #include -#include "FramebufferCache.h" +#include "DebugDeferredBuffer.h" #include "DeferredLightingEffect.h" -#include "TextureCache.h" +#include "FramebufferCache.h" #include "HitEffect.h" +#include "TextureCache.h" #include "render/DrawStatus.h" #include "AmbientOcclusionEffect.h" @@ -112,6 +113,8 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); + // Grab a texture map representing the different status icons and assign that to the drawStatsuJob auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 6daa90b1ed..e75edd20da 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -80,9 +80,9 @@ class DrawOverlay3D { static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable public: static const gpu::PipelinePointer& getOpaquePipeline(); - + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - + typedef render::Job::Model JobModel; }; diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf new file mode 100644 index 0000000000..c33773aa40 --- /dev/null +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -0,0 +1,21 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// debug_deferred_buffer.slf +// fragment shader +// +// Created by Clement on 12/3 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include DeferredBufferWrite.slh@> + +out vec4 outFragColor; + +void main(void) { + outFragColor = vec4(0.0, 0.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/libraries/render-utils/src/debug_deferred_buffer.slv b/libraries/render-utils/src/debug_deferred_buffer.slv new file mode 100644 index 0000000000..b1b7b18f86 --- /dev/null +++ b/libraries/render-utils/src/debug_deferred_buffer.slv @@ -0,0 +1,19 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// debug_deferred_buffer.slv +// vertex shader +// +// Created by Clement on 12/3 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> + +void main(void) { + gl_Position = inPosition; +} \ No newline at end of file diff --git a/libraries/render-utils/src/hit_effect.slf b/libraries/render-utils/src/hit_effect.slf index c059488ba1..cc4484442f 100644 --- a/libraries/render-utils/src/hit_effect.slf +++ b/libraries/render-utils/src/hit_effect.slf @@ -20,8 +20,8 @@ in vec2 varQuadPosition; out vec4 outFragColor; void main(void) { - vec2 center = vec2(0.0, 0.0); - float distFromCenter = distance( vec2(0.0, 0.0), varQuadPosition); - float alpha = mix(0.0, 0.5, pow(distFromCenter,5.)); - outFragColor = vec4(1.0, 0.0, 0.0, alpha); + vec2 center = vec2(0.0, 0.0); + float distFromCenter = distance( vec2(0.0, 0.0), varQuadPosition); + float alpha = mix(0.0, 0.5, pow(distFromCenter,5.)); + outFragColor = vec4(1.0, 0.0, 0.0, alpha); } \ No newline at end of file From c27944ae28532fc14ec6f8886b6966e50314c8bc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Dec 2015 17:13:41 -0800 Subject: [PATCH 014/318] Simple normal map debug --- examples/utilities/tools/renderEngineDebug.js | 6 ++++++ interface/src/Application.cpp | 4 +++- .../render-utils/src/DebugDeferredBuffer.cpp | 18 ++++++++---------- .../render-utils/src/RenderDeferredTask.cpp | 7 ++++++- .../render-utils/src/RenderDeferredTask.h | 13 ++++++++++--- .../render-utils/src/debug_deferred_buffer.slf | 5 +++-- .../render-utils/src/debug_deferred_buffer.slv | 3 +++ libraries/render/src/render/Engine.h | 1 + .../src/SceneScriptingInterface.h | 8 ++++++-- 9 files changed, 46 insertions(+), 19 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index cca97b7184..940eeda02d 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -66,6 +66,12 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", var showDisplayStatusFlag = 1; var showNetworkStatusFlag = 2; +panel.newCheckbox("Debug deferred buffer", + function(value) { Scene.setEngineDisplayDebugDeferredBuffer(value > 0); }, + function() { return Scene.doEngineDisplayDebugDeferredBuffer() > 0; }, + function(value) { return value > 0; } +); + panel.newCheckbox("Display status", function(value) { Scene.setEngineDisplayItemStatus(value ? Scene.doEngineDisplayItemStatus() | showDisplayStatusFlag : diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cc9a47f793..8fa772e316 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3621,7 +3621,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); - + + renderContext._drawDebugDeferredBuffer = sceneInterface->doEngineDisplayDebugDeferredBuffer(); + renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { renderContext._drawItemStatus |= render::showNetworkStatusFlag; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index e1c31f943e..efb78c888c 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -17,6 +17,7 @@ #include #include "GeometryCache.h" +#include "FramebufferCache.h" #include "debug_deferred_buffer_vert.h" #include "debug_deferred_buffer_frag.h" @@ -33,16 +34,8 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline() { gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); - auto state = std::make_shared(); - - state->setDepthTest(false, false, gpu::LESS_EQUAL); - - // Blend on transparent - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - // Good to go add the brand new pipeline - _pipeline.reset(gpu::Pipeline::create(program, state)); + _pipeline.reset(gpu::Pipeline::create(program, std::make_shared())); } return _pipeline; } @@ -53,6 +46,9 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + auto geometryBuffer = DependencyManager::get(); + auto framebufferCache = DependencyManager::get(); + glm::mat4 projMat; Transform viewMat; @@ -64,9 +60,11 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setPipeline(getPipeline()); + batch.setResourceTexture(0, framebufferCache->getPrimaryNormalTexture()); + glm::vec4 color(0.0f, 0.0f, 1.0f, 1.0f); glm::vec2 bottomLeft(0.0f, -1.0f); glm::vec2 topRight(1.0f, 1.0f); - DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, color); + geometryBuffer->renderQuad(batch, bottomLeft, topRight, color); }); } \ No newline at end of file diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 43ddd5b7ae..0f939682c8 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -114,6 +114,8 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); + _jobs.back().setEnabled(false); + _drawDebugDeferredBufferIndex = _jobs.size() - 1; // Grab a texture map representing the different status icons and assign that to the drawStatsuJob auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; @@ -154,10 +156,13 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend return; } + // Make sure we turn the deferred buffer debug on/off + setDrawDebugDeferredBuffer(renderContext->_drawDebugDeferredBuffer); + // Make sure we turn the displayItemStatus on/off setDrawItemStatus(renderContext->_drawItemStatus); - //Make sure we display hit effect on screen, as desired from a script + // Make sure we display hit effect on screen, as desired from a script setDrawHitEffect(renderContext->_drawHitEffect); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index e75edd20da..09a2761926 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -93,16 +93,23 @@ public: ~RenderDeferredTask(); render::Jobs _jobs; - + + int _drawDebugDeferredBufferIndex = -1; int _drawStatusJobIndex = -1; int _drawHitEffectJobIndex = -1; - + + void setDrawDebugDeferredBuffer(int draw) { + if (_drawDebugDeferredBufferIndex >= 0) { + _jobs[_drawDebugDeferredBufferIndex].setEnabled(draw > 0); + } + } + bool doDrawDebugDeferredBuffer() const { if (_drawDebugDeferredBufferIndex >= 0) { return _jobs[_drawDebugDeferredBufferIndex].isEnabled(); } else { return false; } } + void setDrawItemStatus(int draw) { if (_drawStatusJobIndex >= 0) { _jobs[_drawStatusJobIndex].setEnabled(draw > 0); } } - bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } } void setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } } diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index c33773aa40..212a51c1ed 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -12,10 +12,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include DeferredBufferWrite.slh@> +<@include DeferredBuffer.slh@> +in vec2 uv; out vec4 outFragColor; void main(void) { - outFragColor = vec4(0.0, 0.0, 1.0, 1.0); + outFragColor = texture(normalMap, uv); } \ No newline at end of file diff --git a/libraries/render-utils/src/debug_deferred_buffer.slv b/libraries/render-utils/src/debug_deferred_buffer.slv index b1b7b18f86..85ff2b651d 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slv +++ b/libraries/render-utils/src/debug_deferred_buffer.slv @@ -14,6 +14,9 @@ <@include gpu/Inputs.slh@> +out vec2 uv; + void main(void) { + uv = (inPosition.xy + 1.0) * 0.5; gl_Position = inPosition; } \ No newline at end of file diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 7c11246cff..ab56d68291 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -53,6 +53,7 @@ public: int _numDrawnOverlay3DItems = 0; int _maxDrawnOverlay3DItems = -1; + int _drawDebugDeferredBuffer = 0; int _drawItemStatus = 0; bool _drawHitEffect = false; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 6be0ce44a8..eac35ad5bb 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -106,7 +106,10 @@ public: Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; } Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } - + + Q_INVOKABLE void setEngineDisplayDebugDeferredBuffer(int display) { _drawDebugDeferredBuffer = display; } + Q_INVOKABLE int doEngineDisplayDebugDeferredBuffer() { return _drawDebugDeferredBuffer; } + Q_INVOKABLE void setEngineDisplayItemStatus(int display) { _drawItemStatus = display; } Q_INVOKABLE int doEngineDisplayItemStatus() { return _drawItemStatus; } @@ -142,7 +145,8 @@ protected: int _maxDrawnOpaqueItems = -1; int _maxDrawnTransparentItems = -1; int _maxDrawnOverlay3DItems = -1; - + + int _drawDebugDeferredBuffer = 0; int _drawItemStatus = 0; bool _drawHitEffect = false; From ba2e7e1f29df15dd6e8e0551dde243cb01488283 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 11:15:06 -0800 Subject: [PATCH 015/318] Debug diffuse buffer --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 2 +- libraries/render-utils/src/debug_deferred_buffer.slf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index efb78c888c..c71c6ba1a9 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -60,7 +60,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setPipeline(getPipeline()); - batch.setResourceTexture(0, framebufferCache->getPrimaryNormalTexture()); + batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); glm::vec4 color(0.0f, 0.0f, 1.0f, 1.0f); glm::vec2 bottomLeft(0.0f, -1.0f); diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 212a51c1ed..efb1c25628 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -18,5 +18,5 @@ in vec2 uv; out vec4 outFragColor; void main(void) { - outFragColor = texture(normalMap, uv); + outFragColor = texture(diffuseMap, uv); } \ No newline at end of file From 3c18664c57ce86647e3aa40c825b7fa7cbcd5e2f Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 4 Dec 2015 11:47:57 -0800 Subject: [PATCH 016/318] Cleaning all the deferred buffers in the Prepare call --- libraries/render-utils/src/DeferredLightingEffect.cpp | 10 ++++++++++ libraries/render-utils/src/RenderDeferredTask.cpp | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 9ade2f5cea..7ecef1155c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -372,11 +372,21 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu void DeferredLightingEffect::prepare(RenderArgs* args) { gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); + // batch.setStateScissorRect(args->_viewport); + batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); auto deferredFbo = DependencyManager::get()->getDeferredFramebuffer(); batch.setFramebuffer(deferredFbo); + + // Clear Color, Depth and Stencil + batch.clearFramebuffer( + gpu::Framebuffer::BUFFER_COLOR0 | + gpu::Framebuffer::BUFFER_DEPTH | + gpu::Framebuffer::BUFFER_STENCIL, + vec4(vec3(0), 1), 1.0, 0.0, true); + // clear the normal and specular buffers batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); const float MAX_SPECULAR_EXPONENT = 128.0f; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index bf5f621726..6237534fee 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,7 +35,7 @@ using namespace render; void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - RenderArgs* args = renderContext->args; +/* RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { auto deferredFbo = DependencyManager::get()->getDeferredFramebufferDepthColor(); @@ -51,6 +51,7 @@ void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderCon gpu::Framebuffer::BUFFER_STENCIL, vec4(vec3(0), 1), 1.0, 0.0, true); }); + */ } void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { From ef7ddce2b64d6d33593d5b55f134f10d26f8ab4e Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 4 Dec 2015 16:52:14 -0800 Subject: [PATCH 017/318] Trying to fix the problem of the background not showing correctly --- libraries/model/src/model/Skybox.slf | 3 ++- .../render-utils/src/DeferredBufferWrite.slh | 7 +++---- .../render-utils/src/DeferredLighting.slh | 4 +++- .../src/DeferredLightingEffect.cpp | 5 ++++- .../render-utils/src/RenderDeferredTask.cpp | 21 ------------------- 5 files changed, 12 insertions(+), 28 deletions(-) diff --git a/libraries/model/src/model/Skybox.slf b/libraries/model/src/model/Skybox.slf index 6246bbd9d3..9b642f138e 100755 --- a/libraries/model/src/model/Skybox.slf +++ b/libraries/model/src/model/Skybox.slf @@ -52,7 +52,8 @@ void main(void) { } } - vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction + // vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction + vec3 pixel = color; _fragColor = vec4(pixel, 0.0); #endif diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 1c1330f0c0..573146a0af 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -51,7 +51,7 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, discard; } - _fragColor0 = vec4(diffuse.rgb, alpha); + _fragColor0 = vec4(diffuse.rgb, 1.0); // Opaque _fragColor1 = vec4(bestFitNormal(normal), 1.0); _fragColor2 = vec4(specular, shininess / 128.0); } @@ -61,9 +61,8 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s discard; } - _fragColor0 = vec4(diffuse.rgb, alpha); - //_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); - _fragColor1 = vec4(bestFitNormal(normal), 0.5); + _fragColor0 = vec4(diffuse.rgb, 0.5); + _fragColor1 = vec4(bestFitNormal(normal), 1.0); _fragColor2 = vec4(emissive, shininess / 128.0); } diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index 53ffdee0ca..d01b36f553 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -33,7 +33,9 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 sp vec3 schlick = specular * (1.0 - shlickPower5) + vec3(shlickPower5); vec3 reflect = specularPower * schlick; - return vec4(reflect, diffuse * (1 - length(schlick))); + // FIXME: + //return vec4(reflect, diffuse * (1 - length(schlick))); + return vec4(reflect, diffuse); } <@endfunc@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 7ecef1155c..7eace8d302 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -179,7 +179,10 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); gpu::Shader::makeProgram(*blitProgram); auto blitState = std::make_shared(); - blitState->setColorWriteMask(true, true, true, false); + /* blitState->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);*/ + blitState->setColorWriteMask(true, true, true, true); _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 572a3fd842..a55dcbac89 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,25 +35,6 @@ using namespace render; -void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { -/* RenderArgs* args = renderContext->args; - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - - auto deferredFbo = DependencyManager::get()->getDeferredFramebufferDepthColor(); - - batch.enableStereo(false); - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - batch.setFramebuffer(deferredFbo); - batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | - gpu::Framebuffer::BUFFER_DEPTH | - gpu::Framebuffer::BUFFER_STENCIL, - vec4(vec3(0), 1), 1.0, 0.0, true); - }); - */ -} void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { DependencyManager::get()->prepare(renderContext->args); @@ -69,8 +50,6 @@ void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderC } RenderDeferredTask::RenderDeferredTask() : Task() { - _jobs.push_back(Job(new SetupDeferred::JobModel("SetupFramebuffer"))); - _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems( From 5bfcd4ed91e5b135a0df219b7e86390f290a6809 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 15:51:37 -0800 Subject: [PATCH 018/318] Fix scripted checkbox --- examples/utilities/tools/cookies.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index d9fa999a13..edb0fb4330 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -384,10 +384,10 @@ var CHECK_MARK_COLOR = { y: newY }); Overlays.editOverlay(this.checkMark, { - y: newY + y: newY + (0.25 * this.thumbSize) }); Overlays.editOverlay(this.unCheckMark, { - y: newY + y: newY + (0.25 * this.thumbSize) }); }; @@ -399,10 +399,10 @@ var CHECK_MARK_COLOR = { y: this.y }); Overlays.editOverlay(this.checkMark, { - y: this.y + y: this.y + (0.25 * this.thumbSize) }); Overlays.editOverlay(this.unCheckMark, { - y: this.y + y: this.y+ (0.25 * this.thumbSize) }); }; From b45b1cc513ca9ed43a07de1bcfbe4b48d7e0f29c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 17:43:00 -0800 Subject: [PATCH 019/318] More work on live g-buffer debug --- examples/utilities/tools/renderEngineDebug.js | 20 +++++++--- interface/src/Menu.cpp | 20 ++++++++++ interface/src/Menu.h | 2 + .../src/scripting/MenuScriptingInterface.cpp | 13 +++++++ .../src/scripting/MenuScriptingInterface.h | 4 ++ .../render-utils/src/DebugDeferredBuffer.cpp | 38 +++++++++++++++---- .../render-utils/src/DebugDeferredBuffer.h | 14 ++++++- libraries/render-utils/src/DeferredBuffer.slh | 3 ++ .../src/debug_deferred_buffer.slf | 6 ++- 9 files changed, 103 insertions(+), 17 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 940eeda02d..b300ff2ea8 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -10,6 +10,9 @@ Script.include("cookies.js"); +var MENU = "Developer>Render>Debug Deferred Buffer"; +var ACTIONS = ["Off", "Diffuse", "Normal", "Specular", "Depth", "Lighting"]; + var panel = new Panel(10, 100); function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) { @@ -61,17 +64,18 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", function () { return Scene.getEngineMaxDrawnOverlay3DItems(); } ); +function menuItemEvent(menuItem) { + var index = ACTIONS.indexOf(menuItem); + if (index >= 0) { + Scene.setEngineDisplayDebugDeferredBuffer(index); + print(menuItem); + } +} // see libraries/render/src/render/Engine.h var showDisplayStatusFlag = 1; var showNetworkStatusFlag = 2; -panel.newCheckbox("Debug deferred buffer", - function(value) { Scene.setEngineDisplayDebugDeferredBuffer(value > 0); }, - function() { return Scene.doEngineDisplayDebugDeferredBuffer() > 0; }, - function(value) { return value > 0; } -); - panel.newCheckbox("Display status", function(value) { Scene.setEngineDisplayItemStatus(value ? Scene.doEngineDisplayItemStatus() | showDisplayStatusFlag : @@ -101,7 +105,11 @@ Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return p Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); +Menu.menuItemEvent.connect(menuItemEvent); +Menu.addActionGroup(MENU, ACTIONS, ACTIONS[0]); + function scriptEnding() { panel.destroy(); + Menu.removeActionGroup(MENU); } Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 86b3987af1..66c1824176 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -985,6 +985,26 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { return false; }; +void Menu::addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected) { + auto menu = addMenu(groupName); + + QActionGroup* actionGroup = new QActionGroup(menu); + actionGroup->setExclusive(true); + + auto menuScriptingInterface = MenuScriptingInterface::getInstance(); + for (auto action : actionList) { + auto item = addCheckableActionToQMenuAndActionHash(menu, action, 0, action == selected, + menuScriptingInterface, + SLOT(menuItemTriggered())); + actionGroup->addAction(item); + } + + QMenuBar::repaint(); +} + +void Menu::removeActionGroup(const QString& groupName) { + removeMenu(groupName); +} MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) { VrMenu::executeOrQueue([=](VrMenu* vrMenu) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3ff0b149f4..49759c8beb 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -100,6 +100,8 @@ public slots: void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); bool menuItemExists(const QString& menuName, const QString& menuitem); + void addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected = QString()); + void removeActionGroup(const QString& groupName); bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index ff7784b9ae..087d391daa 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -84,6 +84,19 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& return result; } +void MenuScriptingInterface::addActionGroup(const QString& groupName, const QStringList& actionList, + const QString& selected) { + QMetaObject::invokeMethod(Menu::getInstance(), "addActionGroup", + Q_ARG(const QString&, groupName), + Q_ARG(const QStringList&, actionList), + Q_ARG(const QString&, selected)); +} + +void MenuScriptingInterface::removeActionGroup(const QString& groupName) { + QMetaObject::invokeMethod(Menu::getInstance(), "removeActionGroup", + Q_ARG(const QString&, groupName)); +} + bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { bool result; QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index 5c01318a38..51399c2fa5 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -42,6 +42,10 @@ public slots: void removeMenuItem(const QString& menuName, const QString& menuitem); bool menuItemExists(const QString& menuName, const QString& menuitem); + void addActionGroup(const QString& groupName, const QStringList& actionList, + const QString& selected = QString()); + void removeActionGroup(const QString& groupName); + bool isOptionChecked(const QString& menuOption); void setIsOptionChecked(const QString& menuOption, bool isChecked); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 5510d9c3fc..3b4e3d2bd5 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -24,20 +24,38 @@ using namespace render; -const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline() { - if (!_pipeline) { +static const std::string PLACEHOLDER { "DEBUG_PLACEHOLDER" }; +static const std::array SLOT_NAMES {{ + "diffuseMap", + "normalMap", + "specularMap", + "depthMap", + "lightingMap" +}}; + +std::string getCode(int slot) { + return std::string("return texture(").append(SLOT_NAMES[slot]).append(", uv);"); +} + +const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(int slot) { + if (!_pipelines[slot]) { + std::string fragmentShader = debug_deferred_buffer_frag; + fragmentShader.replace(fragmentShader.find(PLACEHOLDER), PLACEHOLDER.size(), getCode(slot)); + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex({ debug_deferred_buffer_vert })); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel({ debug_deferred_buffer_frag })); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShader)); auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); - gpu::Shader::BindingSet slotBindings; + for (int slot = 0; slot < NUM_SLOTS; ++slot) { + slotBindings.insert(gpu::Shader::Binding(SLOT_NAMES[slot], slot)); + } gpu::Shader::makeProgram(*program, slotBindings); // Good to go add the brand new pipeline - _pipeline = gpu::Pipeline::create(program, std::make_shared()); + _pipelines[slot] = gpu::Pipeline::create(program, std::make_shared()); } - return _pipeline; + return _pipelines[slot]; } @@ -58,9 +76,13 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); - batch.setPipeline(getPipeline()); + batch.setPipeline(getPipeline((DebugDeferredBufferSlot)(renderContext->_drawDebugDeferredBuffer - 1))); - batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); + batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture()); + batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture()); + batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture()); + batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); + batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); glm::vec4 color(0.0f, 0.0f, 1.0f, 1.0f); glm::vec2 bottomLeft(0.0f, -1.0f); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 827a3271f0..95865cc12a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -18,12 +18,22 @@ class DebugDeferredBuffer { public: using JobModel = render::Job::Model; + enum DebugDeferredBufferSlot : int { + Diffuse = 0, + Normal, + Specular, + Depth, + Lighting, + + NUM_SLOTS + }; + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); private: - const gpu::PipelinePointer& getPipeline(); + const gpu::PipelinePointer& getPipeline(int slot); - gpu::PipelinePointer _pipeline; + std::array _pipelines; }; #endif // hifi_DebugDeferredBuffer_h \ No newline at end of file diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh index 275966534a..18606f2525 100755 --- a/libraries/render-utils/src/DeferredBuffer.slh +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -24,6 +24,9 @@ uniform sampler2D specularMap; // the depth texture uniform sampler2D depthMap; +// the lighting texture +uniform sampler2D lightingMap; + struct DeferredTransform { mat4 projection; diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index efb1c25628..55632eb337 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -17,6 +17,10 @@ in vec2 uv; out vec4 outFragColor; +vec4 getFragmentColor() { + DEBUG_PLACEHOLDER +} + void main(void) { - outFragColor = texture(diffuseMap, uv); + outFragColor = getFragmentColor(); } \ No newline at end of file From 41af3778784b537b27f23d8be3090c756d6c2d2a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 18:33:11 -0800 Subject: [PATCH 020/318] More g-buffer debugging options --- examples/utilities/tools/renderEngineDebug.js | 2 +- .../render-utils/src/DebugDeferredBuffer.cpp | 66 ++++++++++++++++--- .../render-utils/src/DebugDeferredBuffer.h | 28 ++++---- 3 files changed, 73 insertions(+), 23 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index b300ff2ea8..ab266620ab 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -11,7 +11,7 @@ Script.include("cookies.js"); var MENU = "Developer>Render>Debug Deferred Buffer"; -var ACTIONS = ["Off", "Diffuse", "Normal", "Specular", "Depth", "Lighting"]; +var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "Custom"]; var panel = new Panel(10, 100); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 3b4e3d2bd5..d3879dacf3 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -11,6 +11,8 @@ #include "DebugDeferredBuffer.h" +#include + #include #include #include @@ -24,8 +26,16 @@ using namespace render; -static const std::string PLACEHOLDER { "DEBUG_PLACEHOLDER" }; -static const std::array SLOT_NAMES {{ +enum Slots { + Diffuse = 0, + Normal, + Specular, + Depth, + Lighting, + + NUM_SLOTS +}; +static const std::array SLOT_NAMES {{ "diffuseMap", "normalMap", "specularMap", @@ -33,14 +43,50 @@ static const std::array SLOT_NAMES "lightingMap" }}; -std::string getCode(int slot) { - return std::string("return texture(").append(SLOT_NAMES[slot]).append(", uv);"); +static const std::string PLACEHOLDER { "DEBUG_PLACEHOLDER" }; + +std::string DebugDeferredBuffer::getCode(Modes mode) { + switch (mode) { + case DiffuseMode: { + QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; + return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString(); + } + case AlphaMode: { + QString code = "return vec4(vec3(texture(%1, uv).a), 1.0);"; + return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString(); + } + case SpecularMode: { + QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; + return code.arg(SLOT_NAMES[Specular].c_str()).toStdString(); + } + case RoughnessMode: { + QString code = "return vec4(vec3(texture(%1, uv).a), 1.0);"; + return code.arg(SLOT_NAMES[Specular].c_str()).toStdString(); + } + case NormalMode: { + QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; + return code.arg(SLOT_NAMES[Normal].c_str()).toStdString(); + } + case DepthMode: { + QString code = "return vec4(vec3(texture(%1, uv).x), 1.0);"; + return code.arg(SLOT_NAMES[Depth].c_str()).toStdString(); + } + case LightingMode: { + QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; + return code.arg(SLOT_NAMES[Lighting].c_str()).toStdString(); + } + case CustomMode: + return std::string("return vec4(1.0);"); + case NUM_MODES: + Q_UNIMPLEMENTED(); + return std::string("return vec4(1.0);"); + } } -const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(int slot) { - if (!_pipelines[slot]) { +const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode) { + if (!_pipelines[mode]) { std::string fragmentShader = debug_deferred_buffer_frag; - fragmentShader.replace(fragmentShader.find(PLACEHOLDER), PLACEHOLDER.size(), getCode(slot)); + fragmentShader.replace(fragmentShader.find(PLACEHOLDER), PLACEHOLDER.size(), getCode(mode)); auto vs = gpu::ShaderPointer(gpu::Shader::createVertex({ debug_deferred_buffer_vert })); auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShader)); @@ -53,9 +99,9 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(int slot) { gpu::Shader::makeProgram(*program, slotBindings); // Good to go add the brand new pipeline - _pipelines[slot] = gpu::Pipeline::create(program, std::make_shared()); + _pipelines[mode] = gpu::Pipeline::create(program, std::make_shared()); } - return _pipelines[slot]; + return _pipelines[mode]; } @@ -76,7 +122,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); - batch.setPipeline(getPipeline((DebugDeferredBufferSlot)(renderContext->_drawDebugDeferredBuffer - 1))); + batch.setPipeline(getPipeline(Modes(renderContext->_drawDebugDeferredBuffer - 1))); batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture()); batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture()); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 95865cc12a..8628d9e21e 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -18,22 +18,26 @@ class DebugDeferredBuffer { public: using JobModel = render::Job::Model; - enum DebugDeferredBufferSlot : int { - Diffuse = 0, - Normal, - Specular, - Depth, - Lighting, - - NUM_SLOTS - }; - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); private: - const gpu::PipelinePointer& getPipeline(int slot); + enum Modes : int { + DiffuseMode = 0, + AlphaMode, + SpecularMode, + RoughnessMode, + NormalMode, + DepthMode, + LightingMode, + CustomMode, + + NUM_MODES + }; - std::array _pipelines; + const gpu::PipelinePointer& getPipeline(Modes mode); + std::string getCode(Modes mode); + + std::array _pipelines; }; #endif // hifi_DebugDeferredBuffer_h \ No newline at end of file From acb9e2774e65494d151ddd1dd91a84722a150d14 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 20:28:38 -0800 Subject: [PATCH 021/318] Basic implementation of debug zone resizing --- examples/utilities/tools/renderEngineDebug.js | 51 +++++++++++++++++-- interface/src/Application.cpp | 3 +- .../render-utils/src/DebugDeferredBuffer.cpp | 14 ++--- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderDeferredTask.h | 2 +- .../src/debug_deferred_buffer.slf | 4 +- libraries/render/src/render/Engine.h | 3 +- .../src/SceneScriptingInterface.h | 9 ++-- 8 files changed, 70 insertions(+), 18 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index ab266620ab..c37c104498 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -13,6 +13,10 @@ Script.include("cookies.js"); var MENU = "Developer>Render>Debug Deferred Buffer"; var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "Custom"]; +Number.prototype.clamp = function(min, max) { + return Math.min(Math.max(this, min), max); +}; + var panel = new Panel(10, 100); function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) { @@ -64,10 +68,23 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", function () { return Scene.getEngineMaxDrawnOverlay3DItems(); } ); +var resizing = false; +Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size + +function setEngineDeferredDebugSize(eventX) { + var scaledX = (2.0 * (eventX / Window.innerWidth) - 1.0).clamp(-1.0, 1.0); + Scene.setEngineDeferredDebugSize({ x: scaledX, y: -1.0, z: 1.0, w: 1.0 }); +} +function shouldStartResizing(eventX) { + var x = Math.abs(eventX - Window.innerWidth * (1.0 + Scene.getEngineDeferredDebugSize().x) / 2.0); + var mode = Scene.getEngineDeferredDebugMode(); + return mode !== -1 && x < 20; +} + function menuItemEvent(menuItem) { var index = ACTIONS.indexOf(menuItem); if (index >= 0) { - Scene.setEngineDisplayDebugDeferredBuffer(index); + Scene.setEngineDeferredDebugMode(index - 1); print(menuItem); } } @@ -101,9 +118,33 @@ function updateCounters() { } Script.setInterval(updateCounters, tickTackPeriod); -Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); -Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); -Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); +function mouseMoveEvent(event) { + if (resizing) { + setEngineDeferredDebugSize(event.x); + } else { + panel.mouseMoveEvent(event); + } +} + +function mousePressEvent(event) { + if (shouldStartResizing(event.x)) { + resizing = true; + } else { + panel.mousePressEvent(event); + } +} + +function mouseReleaseEvent(event) { + if (resizing) { + resizing = false; + } else { + panel.mouseReleaseEvent(event); + } +} + +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Menu.menuItemEvent.connect(menuItemEvent); Menu.addActionGroup(MENU, ACTIONS, ACTIONS[0]); @@ -111,5 +152,7 @@ Menu.addActionGroup(MENU, ACTIONS, ACTIONS[0]); function scriptEnding() { panel.destroy(); Menu.removeActionGroup(MENU); + Scene.setEngineDeferredDebugMode(-1); + Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size } Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d9fea20ad5..78724862de 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3622,7 +3622,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); - renderContext._drawDebugDeferredBuffer = sceneInterface->doEngineDisplayDebugDeferredBuffer(); + renderContext._deferredDebugMode = sceneInterface->getEngineDeferredDebugMode(); + renderContext._deferredDebugSize = sceneInterface->getEngineDeferredDebugSize(); renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index d3879dacf3..842729144d 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -43,7 +43,8 @@ static const std::array SLOT_NAMES {{ "lightingMap" }}; -static const std::string PLACEHOLDER { "DEBUG_PLACEHOLDER" }; +static const std::string COMPUTE_PLACEHOLDER { "/*COMPUTE_PLACEHOLDER*/" }; // required +static const std::string FUNCTIONS_PLACEHOLDER { "/*FUNCTIONS_PLACEHOLDER*/" }; // optional std::string DebugDeferredBuffer::getCode(Modes mode) { switch (mode) { @@ -86,7 +87,8 @@ std::string DebugDeferredBuffer::getCode(Modes mode) { const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode) { if (!_pipelines[mode]) { std::string fragmentShader = debug_deferred_buffer_frag; - fragmentShader.replace(fragmentShader.find(PLACEHOLDER), PLACEHOLDER.size(), getCode(mode)); + fragmentShader.replace(fragmentShader.find(COMPUTE_PLACEHOLDER), COMPUTE_PLACEHOLDER.size(), + getCode(mode)); auto vs = gpu::ShaderPointer(gpu::Shader::createVertex({ debug_deferred_buffer_vert })); auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShader)); @@ -122,7 +124,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); - batch.setPipeline(getPipeline(Modes(renderContext->_drawDebugDeferredBuffer - 1))); + batch.setPipeline(getPipeline(Modes(renderContext->_deferredDebugMode))); batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture()); batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture()); @@ -130,9 +132,9 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); - glm::vec4 color(0.0f, 0.0f, 1.0f, 1.0f); - glm::vec2 bottomLeft(0.0f, -1.0f); - glm::vec2 topRight(1.0f, 1.0f); + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); + glm::vec2 topRight(renderContext->_deferredDebugSize.z, renderContext->_deferredDebugSize.w); geometryBuffer->renderQuad(batch, bottomLeft, topRight, color); }); } \ No newline at end of file diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1272e1a131..f04394750b 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -157,7 +157,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend } // Make sure we turn the deferred buffer debug on/off - setDrawDebugDeferredBuffer(renderContext->_drawDebugDeferredBuffer); + setDrawDebugDeferredBuffer(renderContext->_deferredDebugMode); // Make sure we turn the displayItemStatus on/off setDrawItemStatus(renderContext->_drawItemStatus); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 09a2761926..f128d186cc 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -100,7 +100,7 @@ public: void setDrawDebugDeferredBuffer(int draw) { if (_drawDebugDeferredBufferIndex >= 0) { - _jobs[_drawDebugDeferredBufferIndex].setEnabled(draw > 0); + _jobs[_drawDebugDeferredBufferIndex].setEnabled(draw >= 0); } } bool doDrawDebugDeferredBuffer() const { if (_drawDebugDeferredBufferIndex >= 0) { return _jobs[_drawDebugDeferredBufferIndex].isEnabled(); } else { return false; } } diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 55632eb337..d8ff6e71a9 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -17,8 +17,10 @@ in vec2 uv; out vec4 outFragColor; +/*FUNCTIONS_PLACEHOLDER*/ + vec4 getFragmentColor() { - DEBUG_PLACEHOLDER + /*COMPUTE_PLACEHOLDER*/ } void main(void) { diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index ab56d68291..26bd6f2154 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -53,7 +53,8 @@ public: int _numDrawnOverlay3DItems = 0; int _maxDrawnOverlay3DItems = -1; - int _drawDebugDeferredBuffer = 0; + int _deferredDebugMode = -1; + glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f }; int _drawItemStatus = 0; bool _drawHitEffect = false; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 583f416576..78261dfdc7 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -107,8 +107,10 @@ public: Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } - Q_INVOKABLE void setEngineDisplayDebugDeferredBuffer(int display) { _drawDebugDeferredBuffer = display; } - Q_INVOKABLE int doEngineDisplayDebugDeferredBuffer() { return _drawDebugDeferredBuffer; } + Q_INVOKABLE void setEngineDeferredDebugMode(int mode) { _deferredDebugMode = mode; } + Q_INVOKABLE int getEngineDeferredDebugMode() { return _deferredDebugMode; } + Q_INVOKABLE void setEngineDeferredDebugSize(glm::vec4 size) { _deferredDebugSize = size; } + Q_INVOKABLE glm::vec4 getEngineDeferredDebugSize() { return _deferredDebugSize; } Q_INVOKABLE void setEngineDisplayItemStatus(int display) { _drawItemStatus = display; } Q_INVOKABLE int doEngineDisplayItemStatus() { return _drawItemStatus; } @@ -146,7 +148,8 @@ protected: int _maxDrawnTransparentItems = -1; int _maxDrawnOverlay3DItems = -1; - int _drawDebugDeferredBuffer = 0; + int _deferredDebugMode = -1; + glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f }; int _drawItemStatus = 0; bool _drawHitEffect = false; From 0603ead972cf4823d8a45bc32b1f0a39ac77bca1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 20:59:21 -0800 Subject: [PATCH 022/318] Have panels collapsed by default --- examples/utilities/tools/renderEngineDebug.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index c37c104498..60686912e8 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -156,3 +156,9 @@ function scriptEnding() { Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size } Script.scriptEnding.connect(scriptEnding); + + +// Collapse items +panel.mousePressEvent({ x: panel.x, y: panel.items["Overlays"].y}); +panel.mousePressEvent({ x: panel.x, y: panel.items["Transparents"].y}); +panel.mousePressEvent({ x: panel.x, y: panel.items["Opaques"].y}); From a018c51945dc527aa0a1a6ade4bf696a3d7336e9 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Sun, 6 Dec 2015 23:51:29 -0800 Subject: [PATCH 023/318] Drawing background first in the Lighting buffer then lighting passes with stencil test --- .../src/DeferredLightingEffect.cpp | 46 +++++---------- .../render-utils/src/DeferredLightingEffect.h | 12 ---- .../render-utils/src/FramebufferCache.cpp | 1 + .../render-utils/src/RenderDeferredTask.cpp | 5 +- .../src/directional_ambient_light.slf | 1 - ...onal_ambient_light_cascaded_shadow_map.slf | 57 ------------------ .../directional_ambient_light_shadow_map.slf | 56 ------------------ .../directional_light_cascaded_shadow_map.slf | 59 ------------------- .../src/directional_light_shadow_map.slf | 58 ------------------ ...ional_skybox_light_cascaded_shadow_map.slf | 59 ------------------- .../directional_skybox_light_shadow_map.slf | 58 ------------------ 11 files changed, 18 insertions(+), 394 deletions(-) delete mode 100755 libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf delete mode 100755 libraries/render-utils/src/directional_ambient_light_shadow_map.slf delete mode 100644 libraries/render-utils/src/directional_light_cascaded_shadow_map.slf delete mode 100644 libraries/render-utils/src/directional_light_shadow_map.slf delete mode 100755 libraries/render-utils/src/directional_skybox_light_cascaded_shadow_map.slf delete mode 100755 libraries/render-utils/src/directional_skybox_light_shadow_map.slf diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 82cd0dc00f..af67f6b870 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -34,16 +34,8 @@ #include "deferred_light_spot_vert.h" #include "directional_light_frag.h" -#include "directional_light_shadow_map_frag.h" -#include "directional_light_cascaded_shadow_map_frag.h" - #include "directional_ambient_light_frag.h" -#include "directional_ambient_light_shadow_map_frag.h" -#include "directional_ambient_light_cascaded_shadow_map_frag.h" - #include "directional_skybox_light_frag.h" -#include "directional_skybox_light_shadow_map_frag.h" -#include "directional_skybox_light_cascaded_shadow_map_frag.h" #include "point_light_frag.h" #include "spot_light_frag.h" @@ -51,8 +43,6 @@ static const std::string glowIntensityShaderHandle = "glowIntensity"; struct LightLocations { - int shadowDistances; - int shadowScale; int radius; int ambientSphere; int lightBufferUnit; @@ -107,34 +97,16 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { _viewState = viewState; _directionalLightLocations = std::make_shared(); - _directionalLightShadowMapLocations = std::make_shared(); - _directionalLightCascadedShadowMapLocations = std::make_shared(); _directionalAmbientSphereLightLocations = std::make_shared(); - _directionalAmbientSphereLightShadowMapLocations = std::make_shared(); - _directionalAmbientSphereLightCascadedShadowMapLocations = std::make_shared(); _directionalSkyboxLightLocations = std::make_shared(); - _directionalSkyboxLightShadowMapLocations = std::make_shared(); - _directionalSkyboxLightCascadedShadowMapLocations = std::make_shared(); _pointLightLocations = std::make_shared(); _spotLightLocations = std::make_shared(); loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations); - loadLightProgram(deferred_light_vert, directional_light_shadow_map_frag, false, _directionalLightShadowMap, - _directionalLightShadowMapLocations); - loadLightProgram(deferred_light_vert, directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap, - _directionalLightCascadedShadowMapLocations); loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); - loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap, - _directionalAmbientSphereLightShadowMapLocations); - loadLightProgram(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap, - _directionalAmbientSphereLightCascadedShadowMapLocations); loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_map_frag, false, _directionalSkyboxLightShadowMap, - _directionalSkyboxLightShadowMapLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag, false, _directionalSkyboxLightCascadedShadowMap, - _directionalSkyboxLightCascadedShadowMapLocations); loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); @@ -379,6 +351,15 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); + // Clear Lighting buffer + auto lightingFbo = DependencyManager::get()->getLightingFramebuffer(); + + batch.setFramebuffer(lightingFbo); + batch.clearFramebuffer( + gpu::Framebuffer::BUFFER_COLOR0, + vec4(vec3(0), 0), 1.0, 0.0, true); + + // Clear deferred auto deferredFbo = DependencyManager::get()->getDeferredFramebuffer(); batch.setFramebuffer(deferredFbo); @@ -422,7 +403,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { // Clearing it batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); - batch.clearColorFramebuffer(lightingFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); + // batch.clearColorFramebuffer(lightingFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); // BInd the G-Buffer surfaces batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); @@ -768,7 +749,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3)); - slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4)); slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5)); const int LIGHT_GPU_SLOT = 3; slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT)); @@ -779,8 +759,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo gpu::Shader::makeProgram(*program, slotBindings); - locations->shadowDistances = program->getUniforms().findLocation("shadowDistances"); - locations->shadowScale = program->getUniforms().findLocation("shadowScale"); locations->radius = program->getUniforms().findLocation("radius"); locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00"); @@ -793,6 +771,10 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer"); auto state = std::make_shared(); + + // Stencil test all the light passes for objects pixels only, not the background + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); + if (lightVolume) { state->setCullMode(gpu::State::CULL_BACK); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9c4809a82e..bf5db30310 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -106,24 +106,12 @@ private: gpu::PipelinePointer _directionalSkyboxLight; LightLocationsPtr _directionalSkyboxLightLocations; - gpu::PipelinePointer _directionalSkyboxLightShadowMap; - LightLocationsPtr _directionalSkyboxLightShadowMapLocations; - gpu::PipelinePointer _directionalSkyboxLightCascadedShadowMap; - LightLocationsPtr _directionalSkyboxLightCascadedShadowMapLocations; gpu::PipelinePointer _directionalAmbientSphereLight; LightLocationsPtr _directionalAmbientSphereLightLocations; - gpu::PipelinePointer _directionalAmbientSphereLightShadowMap; - LightLocationsPtr _directionalAmbientSphereLightShadowMapLocations; - gpu::PipelinePointer _directionalAmbientSphereLightCascadedShadowMap; - LightLocationsPtr _directionalAmbientSphereLightCascadedShadowMapLocations; gpu::PipelinePointer _directionalLight; LightLocationsPtr _directionalLightLocations; - gpu::PipelinePointer _directionalLightShadowMap; - LightLocationsPtr _directionalLightShadowMapLocations; - gpu::PipelinePointer _directionalLightCascadedShadowMap; - LightLocationsPtr _directionalLightCascadedShadowMapLocations; gpu::PipelinePointer _pointLight; LightLocationsPtr _pointLightLocations; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index b39b8cc7e5..2d3884d81d 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -92,6 +92,7 @@ void FramebufferCache::createPrimaryFramebuffer() { // _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); + _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); } gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferDepthColor() { diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 90805ca2f8..72ade5315a 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -355,7 +355,8 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - auto deferredFboColorDepthStencil = DependencyManager::get()->getDeferredFramebufferDepthColor(); + // auto deferredFboColorDepthStencil = DependencyManager::get()->getDeferredFramebufferDepthColor(); + auto deferredFboColorDepthStencil = DependencyManager::get()->getLightingFramebuffer(); auto deferredFboFull = DependencyManager::get()->getDeferredFramebuffer(); batch.enableSkybox(true); @@ -375,7 +376,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const renderItems(sceneContext, renderContext, inItems); - batch.setFramebuffer(deferredFboFull); + // batch.setFramebuffer(deferredFboFull); }); args->_batch = nullptr; diff --git a/libraries/render-utils/src/directional_ambient_light.slf b/libraries/render-utils/src/directional_ambient_light.slf index 52ecc71a14..ae3b05862e 100755 --- a/libraries/render-utils/src/directional_ambient_light.slf +++ b/libraries/render-utils/src/directional_ambient_light.slf @@ -27,7 +27,6 @@ void main(void) { DeferredTransform deferredTransform = getDeferredTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - // Light mapped or not ? if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { vec3 color = evalLightmappedColor( deferredTransform.viewInverse, diff --git a/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf deleted file mode 100755 index 8b0212636e..0000000000 --- a/libraries/render-utils/src/directional_ambient_light_cascaded_shadow_map.slf +++ /dev/null @@ -1,57 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// directional_light.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/3/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Everything about deferred buffer -<@include DeferredBuffer.slh@> - -<@include DeferredGlobalLight.slh@> - -<$declareEvalLightmappedColor()$> -<$declareEvalAmbientSphereGlobalColor()$> - -// Everything about shadow -<@include Shadow.slh@> - -in vec2 _texCoord0; -out vec4 _fragColor; - -void main(void) { - DeferredTransform deferredTransform = getDeferredTransform(); - DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - - // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position); - float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - - // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - vec3 color = evalLightmappedColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.normal, - frag.diffuse, - frag.specularVal.xyz); - _fragColor = vec4(color, 1.0); - } else { - vec3 color = evalAmbienSphereGlobalColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.position.xyz, - frag.normal, - frag.diffuse, - frag.specular, - frag.gloss); - _fragColor = vec4(color, frag.normalVal.a); - } -} diff --git a/libraries/render-utils/src/directional_ambient_light_shadow_map.slf b/libraries/render-utils/src/directional_ambient_light_shadow_map.slf deleted file mode 100755 index 97d69f2e63..0000000000 --- a/libraries/render-utils/src/directional_ambient_light_shadow_map.slf +++ /dev/null @@ -1,56 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// directional_light.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/3/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Everything about deferred buffer -<@include DeferredBuffer.slh@> - -<@include DeferredGlobalLight.slh@> -<$declareEvalLightmappedColor()$> -<$declareEvalAmbientSphereGlobalColor()$> - -// Everything about shadow -<@include Shadow.slh@> - -in vec2 _texCoord0; -out vec4 _fragColor; - -void main(void) { - DeferredTransform deferredTransform = getDeferredTransform(); - DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - - // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalShadowTexcoord(frag.position); - float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - - // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - vec3 color = evalLightmappedColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.normal, - frag.diffuse, - frag.specularVal.xyz); - _fragColor = vec4(color, 1.0); - } else { - vec3 color = evalAmbienSphereGlobalColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.position.xyz, - frag.normal, - frag.diffuse, - frag.specular, - frag.gloss); - _fragColor = vec4(color, frag.normalVal.a); - } -} diff --git a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf deleted file mode 100644 index 4abe8e2e9d..0000000000 --- a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf +++ /dev/null @@ -1,59 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// directional_light.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/3/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Everything about deferred buffer -<@include DeferredBuffer.slh@> - -<@include DeferredGlobalLight.slh@> - -<$declareEvalLightmappedColor()$> -<$declareEvalAmbientGlobalColor()$> - -// Everything about shadow -<@include Shadow.slh@> - -in vec2 _texCoord0; -out vec4 _fragColor; - -void main(void) { - DeferredTransform deferredTransform = getDeferredTransform(); - DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - - - // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position); - float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - - // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - vec3 color = evalLightmappedColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.normal, - frag.diffuse, - frag.specularVal.xyz); - _fragColor = vec4(color, 1.0); - } else { - vec3 color = evalAmbienGlobalColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.position.xyz, - frag.normal, - frag.diffuse, - frag.specular, - frag.gloss); - - _fragColor = vec4(color, frag.normalVal.a); - } -} diff --git a/libraries/render-utils/src/directional_light_shadow_map.slf b/libraries/render-utils/src/directional_light_shadow_map.slf deleted file mode 100644 index 4249b2787c..0000000000 --- a/libraries/render-utils/src/directional_light_shadow_map.slf +++ /dev/null @@ -1,58 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// directional_light.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/3/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Everything about deferred buffer -<@include DeferredBuffer.slh@> - -<@include DeferredGlobalLight.slh@> - -<$declareEvalLightmappedColor()$> -<$declareEvalAmbientGlobalColor()$> - -// Everything about shadow -<@include Shadow.slh@> - -in vec2 _texCoord0; -out vec4 _fragColor; - -void main(void) { - DeferredTransform deferredTransform = getDeferredTransform(); - DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - - // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalShadowTexcoord(frag.position); - float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - - // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - vec3 color = evalLightmappedColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.normal, - frag.diffuse, - frag.specularVal.xyz); - _fragColor = vec4(color, 1.0); - } else { - vec3 color = evalAmbienGlobalColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.position.xyz, - frag.normal, - frag.diffuse, - frag.specular, - frag.gloss); - - _fragColor = vec4(color, frag.normalVal.a); - } -} diff --git a/libraries/render-utils/src/directional_skybox_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_skybox_light_cascaded_shadow_map.slf deleted file mode 100755 index 3c09bf62b6..0000000000 --- a/libraries/render-utils/src/directional_skybox_light_cascaded_shadow_map.slf +++ /dev/null @@ -1,59 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// directional_light.frag -// fragment shader -// -// Created by Sam Gateau on 5/8/2015. -// 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 -// - -// Everything about deferred buffer -<@include DeferredBuffer.slh@> - -<@include DeferredGlobalLight.slh@> - -<$declareEvalLightmappedColor()$> -<$declareEvalSkyboxGlobalColor()$> - -// Everything about shadow -<@include Shadow.slh@> - -in vec2 _texCoord0; -out vec4 _fragColor; - -void main(void) { - DeferredTransform deferredTransform = getDeferredTransform(); - DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - - // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position); - float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - - // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - vec3 color = evalLightmappedColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.normal, - frag.diffuse, - frag.specularVal.xyz); - - _fragColor = vec4(color, 1.0); - } else { - vec3 color = evalSkyboxGlobalColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.position.xyz, - frag.normal, - frag.diffuse, - frag.specular, - frag.gloss); - - _fragColor = vec4(color, frag.normalVal.a); - } -} diff --git a/libraries/render-utils/src/directional_skybox_light_shadow_map.slf b/libraries/render-utils/src/directional_skybox_light_shadow_map.slf deleted file mode 100755 index 6f709f31fa..0000000000 --- a/libraries/render-utils/src/directional_skybox_light_shadow_map.slf +++ /dev/null @@ -1,58 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// directional_light.frag -// fragment shader -// -// Created by Sam Gateau on 5/8/2015. -// 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 -// - -// Everything about deferred buffer -<@include DeferredBuffer.slh@> - -<@include DeferredGlobalLight.slh@> - -<$declareEvalLightmappedColor()$> -<$declareEvalSkyboxGlobalColor()$> - -// Everything about shadow -<@include Shadow.slh@> - -in vec2 _texCoord0; -out vec4 _fragColor; - -void main(void) { - DeferredTransform deferredTransform = getDeferredTransform(); - DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - - // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalShadowTexcoord(frag.position); - float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - - // Light mapped or not ? - if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) { - vec3 color = evalLightmappedColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.normal, - frag.diffuse, - frag.specularVal.xyz); - _fragColor = vec4(color, 1.0); - } else { - vec3 color = evalSkyboxGlobalColor( - deferredTransform.viewInverse, - shadowAttenuation, - frag.position.xyz, - frag.normal, - frag.diffuse, - frag.specular, - frag.gloss); - - _fragColor = vec4(color, frag.normalVal.a); - } -} From 01d48b29aaf8ce8ab6558d7c5e8bf4b22ad0e631 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 7 Dec 2015 01:03:14 -0800 Subject: [PATCH 024/318] cleaning code and removing cruft --- libraries/render-utils/src/DeferredLightingEffect.cpp | 6 +----- libraries/render-utils/src/RenderDeferredTask.cpp | 8 ++------ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index af67f6b870..40f6d4c5eb 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -355,9 +355,7 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { auto lightingFbo = DependencyManager::get()->getLightingFramebuffer(); batch.setFramebuffer(lightingFbo); - batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0, - vec4(vec3(0), 0), 1.0, 0.0, true); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(vec3(0), 0), true); // Clear deferred auto deferredFbo = DependencyManager::get()->getDeferredFramebuffer(); @@ -400,10 +398,8 @@ void DeferredLightingEffect::render(RenderArgs* args) { auto lightingFBO = framebufferCache->getLightingFramebuffer(); batch.setFramebuffer(lightingFBO); - // Clearing it batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); - // batch.clearColorFramebuffer(lightingFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true); // BInd the G-Buffer surfaces batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture()); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 72ade5315a..aeacc95f96 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -355,13 +355,11 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; - // auto deferredFboColorDepthStencil = DependencyManager::get()->getDeferredFramebufferDepthColor(); - auto deferredFboColorDepthStencil = DependencyManager::get()->getLightingFramebuffer(); - auto deferredFboFull = DependencyManager::get()->getDeferredFramebuffer(); + auto lightingFBO = DependencyManager::get()->getLightingFramebuffer(); batch.enableSkybox(true); - batch.setFramebuffer(deferredFboColorDepthStencil); + batch.setFramebuffer(lightingFBO); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); @@ -376,8 +374,6 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const renderItems(sceneContext, renderContext, inItems); - // batch.setFramebuffer(deferredFboFull); - }); args->_batch = nullptr; } From 3595d0d719d22819b4361e8e1a5b75052d6c5ca4 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 7 Dec 2015 01:15:10 -0800 Subject: [PATCH 025/318] less commented stuff --- libraries/model/src/model/Skybox.slf | 4 +--- libraries/render-utils/src/DeferredLightingEffect.cpp | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/model/src/model/Skybox.slf b/libraries/model/src/model/Skybox.slf index 9b642f138e..f8a568bcf9 100755 --- a/libraries/model/src/model/Skybox.slf +++ b/libraries/model/src/model/Skybox.slf @@ -52,9 +52,7 @@ void main(void) { } } - // vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction - vec3 pixel = color; - _fragColor = vec4(pixel, 0.0); + _fragColor = vec4(color, 0.0); #endif diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 40f6d4c5eb..92009ebf07 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -151,9 +151,6 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); gpu::Shader::makeProgram(*blitProgram); auto blitState = std::make_shared(); - /* blitState->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);*/ blitState->setColorWriteMask(true, true, true, true); _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); } @@ -347,7 +344,6 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu void DeferredLightingEffect::prepare(RenderArgs* args) { gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); - // batch.setStateScissorRect(args->_viewport); batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); From 7e59d5cc04af8e3f770f9c8fcd41c370015e1f50 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 7 Dec 2015 01:27:50 -0800 Subject: [PATCH 026/318] Fixing the failing test for shader compilations (because we removed the shadowing shaders) --- tests/shaders/src/main.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 52e43e2faa..40686f5639 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -35,16 +35,10 @@ #include "deferred_light_limited_vert.h" #include "directional_light_frag.h" -#include "directional_light_shadow_map_frag.h" -#include "directional_light_cascaded_shadow_map_frag.h" #include "directional_ambient_light_frag.h" -#include "directional_ambient_light_shadow_map_frag.h" -#include "directional_ambient_light_cascaded_shadow_map_frag.h" #include "directional_skybox_light_frag.h" -#include "directional_skybox_light_shadow_map_frag.h" -#include "directional_skybox_light_cascaded_shadow_map_frag.h" #include "point_light_frag.h" #include "spot_light_frag.h" @@ -185,14 +179,8 @@ void QTestWindow::draw() { testShaderBuild(simple_vert, simple_textured_frag); testShaderBuild(simple_vert, simple_textured_emisive_frag); testShaderBuild(deferred_light_vert, directional_light_frag); - testShaderBuild(deferred_light_vert, directional_light_shadow_map_frag); - testShaderBuild(deferred_light_vert, directional_light_cascaded_shadow_map_frag); testShaderBuild(deferred_light_vert, directional_ambient_light_frag); - testShaderBuild(deferred_light_vert, directional_ambient_light_shadow_map_frag); - testShaderBuild(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag); testShaderBuild(deferred_light_vert, directional_skybox_light_frag); - testShaderBuild(deferred_light_vert, directional_skybox_light_shadow_map_frag); - testShaderBuild(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag); testShaderBuild(deferred_light_limited_vert, point_light_frag); testShaderBuild(deferred_light_limited_vert, spot_light_frag); testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag); From 5d207d0c9c82433995f3850327238978a7c26f29 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 7 Dec 2015 13:19:43 -0800 Subject: [PATCH 027/318] INtroducing the tonemapping job in its separate file and clean DeferredLightingEffect --- .../src/DeferredLightingEffect.cpp | 78 +------------- .../render-utils/src/DeferredLightingEffect.h | 8 +- .../render-utils/src/RenderDeferredTask.cpp | 87 +++++++++------ .../render-utils/src/RenderDeferredTask.h | 8 +- .../render-utils/src/ToneMappingEffect.cpp | 102 ++++++++++++++++++ .../render-utils/src/ToneMappingEffect.h | 46 ++++++++ 6 files changed, 209 insertions(+), 120 deletions(-) create mode 100644 libraries/render-utils/src/ToneMappingEffect.cpp create mode 100644 libraries/render-utils/src/ToneMappingEffect.h diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 92009ebf07..c8996801f1 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -82,7 +82,7 @@ gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config return pipeline; } -void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { +void DeferredLightingEffect::init() { auto VS = gpu::Shader::createVertex(std::string(simple_vert)); auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)); @@ -95,7 +95,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { gpu::Shader::makeProgram(*_simpleShader, slotBindings); gpu::Shader::makeProgram(*_emissiveShader, slotBindings); - _viewState = viewState; + _directionalLightLocations = std::make_shared(); _directionalAmbientSphereLightLocations = std::make_shared(); _directionalSkyboxLightLocations = std::make_shared(); @@ -112,49 +112,6 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations); loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations); - { - //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS(); - const char BlitTextureGamma_frag[] = R"SCRIBE(#version 410 core - // Generated on Sat Oct 24 09:34:37 2015 - // - // Draw texture 0 fetched at texcoord.xy - // - // Created by Sam Gateau on 6/22/2015 - // Copyright 2015 High Fidelity, Inc. - // - // Distributed under the Apache License, Version 2.0. - // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - // - - - uniform sampler2D colorMap; - - in vec2 varTexCoord0; - out vec4 outFragColor; - - void main(void) { - outFragColor = texture(colorMap, varTexCoord0); - // if (gl_FragCoord.x > 1000) { - // Manually gamma correct from Ligthing BUffer to color buffer - outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0 / 2.2) ); - // } - } - - )SCRIBE"; - auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(BlitTextureGamma_frag))); - - //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); - auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); - - //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); - gpu::Shader::makeProgram(*blitProgram); - auto blitState = std::make_shared(); - blitState->setColorWriteMask(true, true, true, true); - _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); - } - // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light _globalLights.push_back(0); _allocatedLights.push_back(std::make_shared()); @@ -694,37 +651,6 @@ void DeferredLightingEffect::render(RenderArgs* args) { } -void DeferredLightingEffect::copyBack(RenderArgs* args) { - auto framebufferCache = DependencyManager::get(); - gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { - batch.enableStereo(false); - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - - auto lightingBuffer = framebufferCache->getLightingTexture(); - auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor(); - batch.setFramebuffer(destFbo); - batch.setViewportTransform(args->_viewport); - batch.setProjectionTransform(glm::mat4()); - batch.setViewTransform(Transform()); - { - float sMin = args->_viewport.x / (float)framebufferSize.width(); - float sWidth = args->_viewport.z / (float)framebufferSize.width(); - float tMin = args->_viewport.y / (float)framebufferSize.height(); - float tHeight = args->_viewport.w / (float)framebufferSize.height(); - Transform model; - batch.setPipeline(_blitLightBuffer); - model.setTranslation(glm::vec3(sMin, tMin, 0.0)); - model.setScale(glm::vec3(sWidth, tHeight, 1.0)); - batch.setModelTransform(model); - } - - batch.setResourceTexture(0, lightingBuffer); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - args->_context->render(batch); - }); -} - void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) { auto globalLight = _allocatedLights[_globalLights.front()]; args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index bf5db30310..efb84f2101 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -21,7 +21,6 @@ #include "model/Stage.h" #include "model/Geometry.h" -class AbstractViewStateInterface; class RenderArgs; class SimpleProgramKey; struct LightLocations; @@ -78,7 +77,6 @@ public: void prepare(RenderArgs* args); void render(RenderArgs* args); - void copyBack(RenderArgs* args); void setupTransparent(RenderArgs* args, int lightBufferUnit); @@ -101,9 +99,7 @@ private: gpu::ShaderPointer _simpleShader; gpu::ShaderPointer _emissiveShader; QHash _simplePrograms; - - gpu::PipelinePointer _blitLightBuffer; - + gpu::PipelinePointer _directionalSkyboxLight; LightLocationsPtr _directionalSkyboxLightLocations; @@ -143,8 +139,6 @@ private: std::vector _globalLights; std::vector _pointLights; std::vector _spotLights; - - AbstractViewStateInterface* _viewState; int _ambientLightMode = 0; model::AtmospherePointer _atmosphere; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index aeacc95f96..c8eefe65ac 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -44,67 +44,85 @@ void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderCo DependencyManager::get()->render(renderContext->args); } -void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - PerformanceTimer perfTimer("ResolveDeferred"); - DependencyManager::get()->copyBack(renderContext->args); +void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + PerformanceTimer perfTimer("ToneMappingDeferred"); + _toneMappingEffect.render(renderContext->args); } RenderDeferredTask::RenderDeferredTask() : Task() { - _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); + // CPU only, create the list of renderedOpaques items _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems( - [] (const RenderContextPointer& context, int count) { - context->_numFeedOpaqueItems = count; - } + [](const RenderContextPointer& context, int count) { + context->_numFeedOpaqueItems = count; + } ) - ))); + ))); _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); auto& renderedOpaques = _jobs.back().getOutput(); - _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput()))); + // CPU only, create the list of renderedTransparents items + _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", + FetchItems( + ItemFilter::Builder::transparentShape().withoutLayered(), + [](const RenderContextPointer& context, int count) { + context->_numFeedTransparentItems = count; + } + ) + ))); + _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); + _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); + auto& renderedTransparents = _jobs.back().getOutput(); + + // GPU Jobs: Start preparing the deferred and lighting buffer + _jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred"))); + + // Render opaque objects in DeferredBuffer + _jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", renderedOpaques))); + + // Once opaque is all rendered create stencil background _jobs.push_back(Job(new DrawStencilDeferred::JobModel("DrawOpaqueStencil"))); + + // Use Stencil and start drawing background in Lighting buffer _jobs.push_back(Job(new DrawBackgroundDeferred::JobModel("DrawBackgroundDeferred"))); + // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. _jobs.push_back(Job(new DrawLight::JobModel("DrawLight"))); - _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); - _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred"))); - _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); + // DeferredBuffer is complete, now let's shade it into the LightingBuffer + _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); + + // AO job, to be revisited + _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); _jobs.back().setEnabled(false); _occlusionJobIndex = _jobs.size() - 1; + // AA job to be revisited _jobs.push_back(Job(new Antialiasing::JobModel("Antialiasing"))); - _jobs.back().setEnabled(false); _antialiasingJobIndex = _jobs.size() - 1; - _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", - FetchItems( - ItemFilter::Builder::transparentShape().withoutLayered(), - [] (const RenderContextPointer& context, int count) { - context->_numFeedTransparentItems = count; - } - ) - ))); - _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); - - - _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); - _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); + // Render transparent objects forward in LigthingBuffer + _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", renderedTransparents))); + // Lighting Buffer ready for tone mapping + _jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping"))); + + // Debugging Deferred buffer job _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); _jobs.back().setEnabled(false); _drawDebugDeferredBufferIndex = _jobs.size() - 1; - - // Grab a texture map representing the different status icons and assign that to the drawStatsuJob - auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; - auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath); - _jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap)))); - - _jobs.back().setEnabled(false); - _drawStatusJobIndex = _jobs.size() - 1; + // Status icon rendering job + { + // Grab a texture map representing the different status icons and assign that to the drawStatsuJob + auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; + auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath); + _jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap)))); + _jobs.back().setEnabled(false); + _drawStatusJobIndex = _jobs.size() - 1; + } _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); @@ -112,7 +130,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.back().setEnabled(false); _drawHitEffectJobIndex = _jobs.size() -1; - // Give ourselves 3 frmaes of timer queries _timerQueries.push_back(std::make_shared()); _timerQueries.push_back(std::make_shared()); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index f128d186cc..009e6f23b2 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -16,6 +16,8 @@ #include "gpu/Pipeline.h" +#include "ToneMappingEffect.h" + class SetupDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); @@ -38,11 +40,13 @@ public: typedef render::Job::Model JobModel; }; -class ResolveDeferred { +class ToneMappingDeferred { public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; + ToneMappingEffect _toneMappingEffect; + + typedef render::Job::Model JobModel; }; class DrawOpaqueDeferred { diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp new file mode 100644 index 0000000000..ac5bbc69e5 --- /dev/null +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -0,0 +1,102 @@ +// +// ToneMappingEffect.cpp +// libraries/render-utils/src +// +// Created by Sam Gateau on 12/7/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ToneMappingEffect.h" + +#include +#include + +#include + +#include "FramebufferCache.h" + + +ToneMappingEffect::ToneMappingEffect() { + +} + +void ToneMappingEffect::init() { + //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS(); + const char BlitTextureGamma_frag[] = R"SCRIBE(#version 410 core + // Generated on Sat Oct 24 09:34:37 2015 + // + // Draw texture 0 fetched at texcoord.xy + // + // Created by Sam Gateau on 6/22/2015 + // Copyright 2015 High Fidelity, Inc. + // + // Distributed under the Apache License, Version 2.0. + // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + // + + + uniform sampler2D colorMap; + + in vec2 varTexCoord0; + out vec4 outFragColor; + + void main(void) { + outFragColor = texture(colorMap, varTexCoord0); + // if (gl_FragCoord.x > 1000) { + // Manually gamma correct from Ligthing BUffer to color buffer + outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0 / 2.2) ); + // } + } + + )SCRIBE"; + auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(BlitTextureGamma_frag))); + + //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); + auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); + + //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); + gpu::Shader::makeProgram(*blitProgram); + auto blitState = std::make_shared(); + blitState->setColorWriteMask(true, true, true, true); + _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); +} + + +void ToneMappingEffect::render(RenderArgs* args) { + if (!_blitLightBuffer) { + init(); + } + auto framebufferCache = DependencyManager::get(); + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { + batch.enableStereo(false); + QSize framebufferSize = framebufferCache->getFrameBufferSize(); + + auto lightingBuffer = framebufferCache->getLightingTexture(); + auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor(); + batch.setFramebuffer(destFbo); + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.setViewTransform(Transform()); + { + float sMin = args->_viewport.x / (float)framebufferSize.width(); + float sWidth = args->_viewport.z / (float)framebufferSize.width(); + float tMin = args->_viewport.y / (float)framebufferSize.height(); + float tHeight = args->_viewport.w / (float)framebufferSize.height(); + Transform model; + batch.setPipeline(_blitLightBuffer); + model.setTranslation(glm::vec3(sMin, tMin, 0.0)); + model.setScale(glm::vec3(sWidth, tHeight, 1.0)); + batch.setModelTransform(model); + } + + batch.setResourceTexture(0, lightingBuffer); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + args->_context->render(batch); + }); +} \ No newline at end of file diff --git a/libraries/render-utils/src/ToneMappingEffect.h b/libraries/render-utils/src/ToneMappingEffect.h new file mode 100644 index 0000000000..9b07c0f7df --- /dev/null +++ b/libraries/render-utils/src/ToneMappingEffect.h @@ -0,0 +1,46 @@ +// +// ToneMappingEffect.h +// libraries/render-utils/src +// +// Created by Sam Gateau on 12/7/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ToneMappingEffect_h +#define hifi_ToneMappingEffect_h + +#include +#include + +#include +#include + +class RenderArgs; + +class ToneMappingEffect { +public: + ToneMappingEffect(); + virtual ~ToneMappingEffect() {} + + void render(RenderArgs* args); + +private: + + gpu::PipelinePointer _blitLightBuffer; + + // Class describing the uniform buffer with all the parameters common to the tone mapping shaders + class Parameters { + public: + + Parameters() {} + }; + typedef gpu::BufferView UniformBufferView; + gpu::BufferView _parametersBuffer; + + void init(); +}; + +#endif // hifi_ToneMappingEffect_h From 9ddc3c27bf7e35ad4f963f949741415ce682bacd Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 7 Dec 2015 13:25:55 -0800 Subject: [PATCH 028/318] compilation errors fixed --- interface/src/Application.cpp | 2 +- libraries/render-utils/src/DeferredLightingEffect.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 78724862de..99519256bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2499,7 +2499,7 @@ void Application::init() { _environment.init(); - DependencyManager::get()->init(this); + DependencyManager::get()->init(); DependencyManager::get()->init(); _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index efb84f2101..78b8e924ae 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -33,7 +33,7 @@ public: static const int NORMAL_FITTING_MAP_SLOT = 10; static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2; - void init(AbstractViewStateInterface* viewState); + void init(); /// Sets up the state necessary to render static untextured geometry with the simple program. gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, From 9faec326da023116577a45ef0a3792bb2894c875 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Tue, 8 Dec 2015 08:34:42 -0800 Subject: [PATCH 029/318] CHanging the lighting BUffer format and adding tone mapping --- libraries/gpu/src/gpu/Format.h | 3 + libraries/gpu/src/gpu/GLBackendTexture.cpp | 58 +++++++++++++++++++ libraries/gpu/src/gpu/Texture.h | 2 +- .../input-plugins/ViveControllerManager.cpp | 4 +- .../src/model-networking/TextureCache.cpp | 18 +++--- libraries/model/src/model/TextureMap.cpp | 42 +++++++------- .../src/procedural/ProceduralSkybox.slf | 4 +- .../render-utils/src/DeferredBufferWrite.slh | 2 +- .../src/DeferredLightingEffect.cpp | 1 + .../render-utils/src/FramebufferCache.cpp | 6 +- .../render-utils/src/SkyFromAtmosphere.slf | 3 +- .../render-utils/src/ToneMappingEffect.cpp | 14 ++++- libraries/render-utils/src/text/Font.cpp | 8 +-- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 14 files changed, 120 insertions(+), 47 deletions(-) diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 3022f47b51..41a95e2578 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -160,6 +160,7 @@ enum Semantic { RGB, RGBA, BGRA, + XY, XYZ, XYZW, @@ -176,6 +177,8 @@ enum Semantic { SRGBA, SBGRA, + R11G11B10, + UNIFORM, UNIFORM_BUFFER, SAMPLER, diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 71c5a83331..dbf29d6ab3 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -224,6 +224,11 @@ public: case gpu::SRGBA: texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color break; + case gpu::R11G11B10: { + // the type should be float + texel.internalFormat = GL_R11F_G11F_B10F; + break; + } default: qCDebug(gpulogging) << "Unknown combination of texel format"; } @@ -240,6 +245,59 @@ public: break; case gpu::RGBA: texel.internalFormat = GL_RGBA; + switch (dstFormat.getType()) { + case gpu::UINT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32UI; + break; + case gpu::INT32: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA32I; + break; + case gpu::FLOAT: + texel.internalFormat = GL_RGBA32F; + break; + case gpu::UINT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16UI; + break; + case gpu::INT16: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA16I; + break; + case gpu::NUINT16: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16; + break; + case gpu::NINT16: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16_SNORM; + break; + case gpu::HALF: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA16F; + break; + case gpu::UINT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8UI; + break; + case gpu::INT8: + texel.format = GL_RGBA_INTEGER; + texel.internalFormat = GL_RGBA8I; + break; + case gpu::NUINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8; + break; + case gpu::NINT8: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA8_SNORM; + break; + case gpu::NUINT32: + case gpu::NINT32: + case gpu::NUM_TYPES: // quiet compiler + Q_UNREACHABLE(); + } break; case gpu::SRGB: texel.internalFormat = GL_SRGB; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index c3e2809c4b..6e8eb10380 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -407,7 +407,7 @@ public: TexturePointer _texture = TexturePointer(NULL); uint16 _subresource = 0; - Element _element = Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); + Element _element = Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); TextureView() {}; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index b315a7a3d9..c26e6e6bf9 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -104,8 +104,8 @@ void ViveControllerManager::activate() { // sizeof(vr::RenderModel_Vertex_t), // gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW))); - gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); - gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); + gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); _texture = gpu::TexturePointer( gpu::Texture::create2D(formatGPU, model.diffuseTexture.unWidth, model.diffuseTexture.unHeight, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3e80b6c7aa..ae705faf86 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -85,7 +85,7 @@ const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() { data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f; } - _permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2)); + _permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), 256, 2)); _permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data); } return _permutationNormalTexture; @@ -98,7 +98,7 @@ const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF }; const gpu::TexturePointer& TextureCache::getWhiteTexture() { if (!_whiteTexture) { - _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); + _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE); } return _whiteTexture; @@ -106,7 +106,7 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() { const gpu::TexturePointer& TextureCache::getGrayTexture() { if (!_grayTexture) { - _grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); + _grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY); } return _grayTexture; @@ -114,7 +114,7 @@ const gpu::TexturePointer& TextureCache::getGrayTexture() { const gpu::TexturePointer& TextureCache::getBlueTexture() { if (!_blueTexture) { - _blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); + _blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE); } return _blueTexture; @@ -122,7 +122,7 @@ const gpu::TexturePointer& TextureCache::getBlueTexture() { const gpu::TexturePointer& TextureCache::getBlackTexture() { if (!_blackTexture) { - _blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); + _blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); _blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK); } return _blackTexture; @@ -151,11 +151,11 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type /// Returns a texture version of an image file gpu::TexturePointer TextureCache::getImageTexture(const QString& path) { QImage image = QImage(path).mirrored(false, true); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::BGRA); } gpu::TexturePointer texture = gpu::TexturePointer( gpu::Texture::create2D(formatGPU, image.width(), image.height(), diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 453bb17a4b..a86c7cdbec 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -121,11 +121,11 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } @@ -156,11 +156,11 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src bool isLinearRGB = true; - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); @@ -246,11 +246,11 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } @@ -368,11 +368,11 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c // bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } @@ -589,13 +589,13 @@ gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImag 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); + bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB)); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA)); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA)); } diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.slf b/libraries/procedural/src/procedural/ProceduralSkybox.slf index 382801f52d..8705278bee 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.slf +++ b/libraries/procedural/src/procedural/ProceduralSkybox.slf @@ -42,8 +42,8 @@ void main(void) { vec3 coord = normalize(_normal); vec3 texel = texture(cubeMap, coord).rgb; vec3 color = texel * _skybox._color.rgb; - vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction - _fragColor = vec4(pixel, 0.0); + // vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction + _fragColor = vec4(color, 0.0); #endif diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index 573146a0af..d3a5ff1e31 100755 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -62,7 +62,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s } _fragColor0 = vec4(diffuse.rgb, 0.5); - _fragColor1 = vec4(bestFitNormal(normal), 1.0); + _fragColor1 = vec4(bestFitNormal(normal), 0.5); _fragColor2 = vec4(emissive, shininess / 128.0); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c8996801f1..f1469a2a03 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -689,6 +689,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer"); auto state = std::make_shared(); + state->setColorWriteMask(true, true, true, false); // Stencil test all the light passes for objects pixels only, not the background state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 2d3884d81d..83ba8b6950 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -53,7 +53,7 @@ void FramebufferCache::createPrimaryFramebuffer() { _deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create()); - auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto colorFormat = gpu::Element::COLOR_RGBA_32; auto width = _frameBufferSize.width(); auto height = _frameBufferSize.height(); @@ -87,8 +87,8 @@ void FramebufferCache::createPrimaryFramebuffer() { auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); _selfieFramebuffer->setRenderBuffer(0, tex); - _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), width, height, defaultSampler)); - //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::SRGBA), width, height, defaultSampler)); + //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler)); + _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); // _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); diff --git a/libraries/render-utils/src/SkyFromAtmosphere.slf b/libraries/render-utils/src/SkyFromAtmosphere.slf index c2a3635f07..10b39dc210 100755 --- a/libraries/render-utils/src/SkyFromAtmosphere.slf +++ b/libraries/render-utils/src/SkyFromAtmosphere.slf @@ -108,5 +108,6 @@ void main (void) vec3 finalColor = frontColor.rgb + fMiePhase * secondaryFrontColor.rgb; outFragColor.a = finalColor.b; - outFragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2)); + // outFragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2)); + outFragColor.rgb = finalColor.rgb; } diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index ac5bbc69e5..ea38884fac 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -45,10 +45,20 @@ void ToneMappingEffect::init() { out vec4 outFragColor; void main(void) { - outFragColor = texture(colorMap, varTexCoord0); + vec4 fragColor = texture(colorMap, varTexCoord0); // if (gl_FragCoord.x > 1000) { // Manually gamma correct from Ligthing BUffer to color buffer - outFragColor.xyz = pow( outFragColor.xyz , vec3(1.0 / 2.2) ); + // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); + + fragColor *= 4.0; // Hardcoded Exposure Adjustment + vec3 x = max(vec3(0.0),fragColor.xyz-0.004); + vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); + + // fragColor *= 8; // Hardcoded Exposure Adjustment + // fragColor = fragColor/(1.0+fragColor); + // vec3 retColor = pow(fragColor.xyz,vec3(1/2.2)); + + outFragColor = vec4(retColor, 1.0); // } } diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 5587185ead..43202c29c2 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -198,11 +198,11 @@ void Font::read(QIODevice& in) { image = image.convertToFormat(QImage::Format_RGBA8888); - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA); + formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::BGRA); } _texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR))); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 73c4b7e22b..d0cdbc48bf 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -82,7 +82,7 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { } Q_DECLARE_METATYPE(controller::InputController*) -static int inputControllerPointerId = qRegisterMetaType(); +//static int inputControllerPointerId = qRegisterMetaType(); QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) { return engine->newQObject(in); From 4a18b5ffe4f31d0a7671651f1ab620ed210cc406 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 8 Dec 2015 20:29:18 +0100 Subject: [PATCH 030/318] small update to have the bow shoot arrows with the creatorSessionUUID in the userData --- examples/toybox/bow/bow.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 90199fb70f..1ea3e39b02 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -259,9 +259,9 @@ userData: JSON.stringify({ grabbableKey: { grabbable: false - } + }, + creatorSessionUUID: MyAvatar.sessionUUID }) - }); var makeArrowStick = function(entityA, entityB, collision) { From 2fb318cc5366afe54e8794f33094e5bca6d84969 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 8 Dec 2015 17:52:23 -0800 Subject: [PATCH 031/318] work with clements branch --- examples/controllers/handControllerGrab.js | 161 +++++++++++++++++++-- 1 file changed, 149 insertions(+), 12 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 138240f5d6..20ca3811c0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -251,9 +251,10 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - + this.overlayLine = null; - + this.particleBeam = null; + this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -398,6 +399,119 @@ function MyController(hand) { } }; + + //test particles instead of overlays + + + this.handleParticleBeam = function(position, orientation) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + + if (this.particleBeam === null) { + print('create beam') + this.createParticleBeam(position, finalRotation) + } else { + print('update beam') + this.updateParticleBeam(position, finalRotation) + } + } + + this.createParticleBeam = function(position, orientation) { + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": { + "red": 110, + "green": 118.52941176470593, + "blue": 255 + }, + "maxParticles": 1000, + "lifespan": 3, + "emitRate": 20, + "emitSpeed": 10, + "speedSpread": 0, + "emitOrientation": { + "x": -0.7000000000000001, + "y": 0, + "z": 0, + "w": 0.7071068286895752 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.02, + "radiusSpread": 0, + "radiusStart": 0.01, + "radiusFinish": 0.01, + "colorSpread": { + "red": 0, + "green": 0, + "blue": 0 + }, + "colorStart": { + "red": 110, + "green": 118.52941176470593, + "blue": 255 + }, + "colorFinish": { + "red": 110, + "green": 118.52941176470593, + "blue": 255 + }, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 0, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + } + + this.updateParticleBeam = function(position, orientation, acceleration) { + print('O IN UPDATE:::' + JSON.stringify(orientation)) + + // var beamProps = Entities.getEntityProperties(this.particleBeam); + + Entities.editEntity(this.particleBeam, { + //rotation:rotation, + rotation: orientation, + position: position, + + }) + + // var emitO = Entities.getEntityProperties(this.particleBeam, "emitOrientation").emitOrientation; + // print('EMIT o :::' + JSON.stringify(emitO)); + } + this.lineOff = function() { if (this.pointer !== null) { Entities.deleteEntity(this.pointer); @@ -412,6 +526,14 @@ function MyController(hand) { this.overlayLine = null; }; + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.deleteEntity(this.particleBeam) + } + + this.particleBeam = null; + } + this.triggerPress = function(value) { _this.rawTriggerValue = value; }; @@ -662,6 +784,9 @@ function MyController(hand) { //this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation()); + + }; this.distanceHolding = function() { @@ -715,6 +840,7 @@ function MyController(hand) { this.currentAvatarOrientation = MyAvatar.orientation; this.overlayLineOff(); + this.particleBeamOff(); }; this.continueDistanceHolding = function() { @@ -808,8 +934,16 @@ function MyController(hand) { // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); - var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); var change = Vec3.subtract(before, after); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); @@ -837,6 +971,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); + this.particleBeamOff(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); this.activateEntity(this.grabbedEntity, grabbedProperties); @@ -975,6 +1110,7 @@ function MyController(hand) { this.pullTowardEquipPosition = function() { this.lineOff(); this.overlayLineOff(); + this.particleBeamOff(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); @@ -1164,6 +1300,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); + this.particleBeamOff(); if (this.grabbedEntity !== null) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1285,10 +1422,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND && handToDisable!=='both') { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { rightController.update(); } } @@ -1296,7 +1433,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; @@ -1304,11 +1441,11 @@ handleHandDisablerMessages = function(channel, message, sender) { if (message === 'right') { handToDisable = RIGHT_HAND; } - if(message==='both'){ - handToDisable='both'; + if (message === 'both') { + handToDisable = 'both'; } - if(message==='none'){ - handToDisable='none'; + if (message === 'none') { + handToDisable = 'none'; } } @@ -1323,4 +1460,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); +Script.update.connect(update); \ No newline at end of file From d811660ed6f0da1574aadb2d114f1649ae84eb81 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 9 Dec 2015 11:07:10 -0800 Subject: [PATCH 032/318] DO NOT MERGE - Testing PR environment --- README.md | 2 ++ cmake/modules/FindOpenSSL.cmake | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index a2eb058ae6..7741445842 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +### TESTING BUILD - DO NOT MERGE ### + High Fidelity (hifi) is an early-stage technology lab experimenting with Virtual Worlds and VR. In this repository you'll find the source to many of the components in our diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 9d9557ad9e..6893948d01 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -256,6 +256,7 @@ if (WIN32) # For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this # but for now resorting to the following interm solution if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) + message(STATUS "*********** Copying SSL DLL from ${OPENSSL_DLL_PATH}/ssleay32.dll") add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/full-stack-deployment/ From 1134d12ea0e9f92de38646e6d45c45e91f86bac3 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 9 Dec 2015 16:08:32 -0800 Subject: [PATCH 033/318] particles --- examples/controllers/handControllerGrab.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 20ca3811c0..b2af86c479 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -399,10 +399,7 @@ function MyController(hand) { } }; - //test particles instead of overlays - - this.handleParticleBeam = function(position, orientation) { var rotation = Quat.angleAxis(0, { @@ -435,11 +432,11 @@ function MyController(hand) { "green": 118.52941176470593, "blue": 255 }, - "maxParticles": 1000, + "maxParticles": 2000, "lifespan": 3, - "emitRate": 20, - "emitSpeed": 10, - "speedSpread": 0, + "emitRate": 50, + "emitSpeed": 2, + "speedSpread": 0.1, "emitOrientation": { "x": -0.7000000000000001, "y": 0, From 31526091d323a5ed8ad5038fa533697a6ac257bf Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 11:13:35 -0800 Subject: [PATCH 034/318] create beams at start --- examples/controllers/handControllerGrab.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index b2af86c479..4348722df0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -425,6 +425,7 @@ function MyController(hand) { type: "ParticleEffect", isEmitting: true, position: position, + visible: false, //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": { @@ -436,12 +437,12 @@ function MyController(hand) { "lifespan": 3, "emitRate": 50, "emitSpeed": 2, - "speedSpread": 0.1, + "speedSpread": 0, "emitOrientation": { - "x": -0.7000000000000001, + "x": -1, "y": 0, "z": 0, - "w": 0.7071068286895752 + "w": 1 }, "emitDimensions": { "x": 0, @@ -486,7 +487,7 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 0, + "additiveBlending": 1, "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" } @@ -502,6 +503,7 @@ function MyController(hand) { //rotation:rotation, rotation: orientation, position: position, + visible: true }) @@ -525,10 +527,12 @@ function MyController(hand) { this.particleBeamOff = function() { if (this.particleBeam !== null) { - Entities.deleteEntity(this.particleBeam) + Entities.editEntity(this.particleBeam, { + visible: false + }) } - this.particleBeam = null; + //this.particleBeam = null; } this.triggerPress = function(value) { @@ -1314,6 +1318,7 @@ function MyController(hand) { this.cleanup = function() { this.release(); this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); }; this.activateEntity = function(entityID, grabbedProperties) { @@ -1404,6 +1409,8 @@ function MyController(hand) { var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); +rightController.createParticleBeam(); +leftController.createParticleBeam(); var MAPPING_NAME = "com.highfidelity.handControllerGrab"; From 1000b602808f4a487012be55df9ec685824a8f29 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 12:21:50 -0800 Subject: [PATCH 035/318] far beams --- examples/controllers/handControllerGrab.js | 65 ++++++++++++---------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4348722df0..812eef07f8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -400,7 +400,7 @@ function MyController(hand) { }; //test particles instead of overlays - this.handleParticleBeam = function(position, orientation) { + this.handleParticleBeam = function(position, orientation, color) { var rotation = Quat.angleAxis(0, { x: 1, @@ -409,18 +409,36 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); + // var finalRotation = orientation + + if (this.particleBeam === null) { + print('create beam') + this.createParticleBeam(position, finalRotation, color) + } else { + print('update beam') + this.updateParticleBeam(position, finalRotation, color) + } + } + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1,Vec3.UP), handToObject); + + if (this.particleBeam === null) { print('create beam') - this.createParticleBeam(position, finalRotation) + this.createParticleBeam(objectPosition, finalRotation, color) } else { print('update beam') - this.updateParticleBeam(position, finalRotation) + this.updateParticleBeam(objectPosition, finalRotation, color) } } - this.createParticleBeam = function(position, orientation) { + this.createParticleBeam = function(position, orientation, color) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, @@ -428,15 +446,11 @@ function MyController(hand) { visible: false, //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", - "color": { - "red": 110, - "green": 118.52941176470593, - "blue": 255 - }, + "color": color, "maxParticles": 2000, "lifespan": 3, "emitRate": 50, - "emitSpeed": 2, + "emitSpeed": 20, "speedSpread": 0, "emitOrientation": { "x": -1, @@ -473,16 +487,8 @@ function MyController(hand) { "green": 0, "blue": 0 }, - "colorStart": { - "red": 110, - "green": 118.52941176470593, - "blue": 255 - }, - "colorFinish": { - "red": 110, - "green": 118.52941176470593, - "blue": 255 - }, + "colorStart": color, + "colorFinish": color, "alpha": 1, "alphaSpread": 0, "alphaStart": 1, @@ -494,21 +500,19 @@ function MyController(hand) { this.particleBeam = Entities.addEntity(particleBeamProperties); } - this.updateParticleBeam = function(position, orientation, acceleration) { + this.updateParticleBeam = function(position, orientation, color) { print('O IN UPDATE:::' + JSON.stringify(orientation)) // var beamProps = Entities.getEntityProperties(this.particleBeam); Entities.editEntity(this.particleBeam, { - //rotation:rotation, rotation: orientation, position: position, - visible: true + visible: true, + color: color }) - // var emitO = Entities.getEntityProperties(this.particleBeam, "emitOrientation").emitOrientation; - // print('EMIT o :::' + JSON.stringify(emitO)); } this.lineOff = function() { @@ -784,8 +788,8 @@ function MyController(hand) { } //this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation()); + //this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); }; @@ -867,9 +871,8 @@ function MyController(hand) { return; } - this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - - // the action was set up on a previous call. update the targets. + // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + // the action was set up on a previous call. update the targets. var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; if (radius < 1.0) { @@ -950,6 +953,8 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } + this.handleDistantParticleBeam(handPosition, grabbedProperties.position,this.currentObjectRotation, INTERSECT_COLOR) + Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, From c3e9cde7fbc59ce8dafb0f8c7c443212bd08662c Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 13:44:53 -0800 Subject: [PATCH 036/318] beamz --- examples/controllers/handControllerGrab.js | 31 +++++++++++++--------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 812eef07f8..1106295cde 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -423,22 +423,25 @@ function MyController(hand) { this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { - var handToObject = Vec3.subtract(objectPosition, handPosition); - var finalRotation = Quat.rotationBetween(Vec3.multiply(-1,Vec3.UP), handToObject); - + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + var lifepsan = distance / speed; + var lifespan = 1; if (this.particleBeam === null) { print('create beam') - this.createParticleBeam(objectPosition, finalRotation, color) + this.createParticleBeam(objectPosition, finalRotation, color, speed) } else { print('update beam') - this.updateParticleBeam(objectPosition, finalRotation, color) + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan) } } - this.createParticleBeam = function(position, orientation, color) { + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, @@ -448,9 +451,9 @@ function MyController(hand) { "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": 3, + "lifespan": 1, "emitRate": 50, - "emitSpeed": 20, + "emitSpeed": 1, "speedSpread": 0, "emitOrientation": { "x": -1, @@ -500,7 +503,7 @@ function MyController(hand) { this.particleBeam = Entities.addEntity(particleBeamProperties); } - this.updateParticleBeam = function(position, orientation, color) { + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { print('O IN UPDATE:::' + JSON.stringify(orientation)) // var beamProps = Entities.getEntityProperties(this.particleBeam); @@ -509,7 +512,9 @@ function MyController(hand) { rotation: orientation, position: position, visible: true, - color: color + color: color, + emitSpeed: speed, + lifepsan: lifepsan }) @@ -871,8 +876,8 @@ function MyController(hand) { return; } - // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); - // the action was set up on a previous call. update the targets. + // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + // the action was set up on a previous call. update the targets. var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; if (radius < 1.0) { @@ -953,7 +958,7 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } - this.handleDistantParticleBeam(handPosition, grabbedProperties.position,this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, From efaa30a509148a6f0da8921d88c0c4c732aa04ca Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 16:18:40 -0800 Subject: [PATCH 037/318] rotatable light --- examples/controllers/handControllerGrab.js | 91 ++++++++++++++++++---- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d92cb35b43..4e612799f7 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -116,6 +116,17 @@ var DEFAULT_GRABBABLE_DATA = { invertSolidWhileHeld: false }; +var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 +}; +var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 +}); + // states for the state machine var STATE_OFF = 0; @@ -137,6 +148,7 @@ var STATE_WAITING_FOR_BUMPER_RELEASE = 15; var STATE_EQUIP_SPRING = 16; + function stateToName(state) { switch (state) { case STATE_OFF: @@ -218,6 +230,7 @@ function getSpatialOffsetPosition(hand, spatialKey) { } var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + function getSpatialOffsetRotation(hand, spatialKey) { var rotation = Quat.IDENTITY; @@ -264,7 +277,8 @@ function MyController(hand) { this.overlayLine = null; this.particleBeam = null; - + this.spotlight = null; + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -420,7 +434,6 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - // var finalRotation = orientation if (this.particleBeam === null) { print('create beam') @@ -433,7 +446,6 @@ function MyController(hand) { this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { - var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); @@ -453,6 +465,7 @@ function MyController(hand) { } this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, @@ -463,7 +476,7 @@ function MyController(hand) { "color": color, "maxParticles": 2000, "lifespan": 1, - "emitRate": 50, + "emitRate": 15, "emitSpeed": 1, "speedSpread": 0, "emitOrientation": { @@ -494,21 +507,21 @@ function MyController(hand) { }, "particleRadius": 0.02, "radiusSpread": 0, - "radiusStart": 0.01, - "radiusFinish": 0.01, - "colorSpread": { - "red": 0, - "green": 0, - "blue": 0 - }, - "colorStart": color, - "colorFinish": color, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, "alpha": 1, "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, "additiveBlending": 1, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); @@ -531,6 +544,49 @@ function MyController(hand) { } + + this.evalLightWorldTransform = function(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + } + + this.createSpotlight = function(parentID, position) { + var LIFETIME = 100; + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + //this light casts the beam + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + rotation: lightTransform.q, + }; + + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + + } + } + this.lineOff = function() { if (this.pointer !== null) { Entities.deleteEntity(this.pointer); @@ -555,6 +611,11 @@ function MyController(hand) { //this.particleBeam = null; } + this.spotlightOff = function() { + // Entities.deleteEntity(this.spotlight); + // this.spotlight = null; + } + this.triggerPress = function(value) { _this.rawTriggerValue = value; }; @@ -970,6 +1031,7 @@ function MyController(hand) { } this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.createSpotlight(this.grabbedEntity); Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, @@ -1331,6 +1393,7 @@ function MyController(hand) { this.lineOff(); this.overlayLineOff(); this.particleBeamOff(); + this.spotlightOff(); if (this.grabbedEntity !== null) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); From 16ab7e74de0c12813694e4f006c21f8c89e6f739 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 16:53:13 -0800 Subject: [PATCH 038/318] cleanup spotlights --- examples/controllers/handControllerGrab.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4e612799f7..b787d8f0df 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -476,7 +476,7 @@ function MyController(hand) { "color": color, "maxParticles": 2000, "lifespan": 1, - "emitRate": 15, + "emitRate": 300, "emitSpeed": 1, "speedSpread": 0, "emitOrientation": { @@ -505,7 +505,7 @@ function MyController(hand) { "y": 0, "z": 0 }, - "particleRadius": 0.02, + "particleRadius": 0.01, "radiusSpread": 0, // "radiusStart": 0.01, // "radiusFinish": 0.01, @@ -583,7 +583,10 @@ function MyController(hand) { if (this.spotlight === null) { this.spotlight = Entities.addEntity(lightProperties); } else { - + // var rotationBetween = Quat.rotationBetween(Vec3.UP, ) + // Entities.editEntity(this.spotlight, { + // rotation: lightTransform.q + // }) } } @@ -612,8 +615,10 @@ function MyController(hand) { } this.spotlightOff = function() { - // Entities.deleteEntity(this.spotlight); - // this.spotlight = null; + if (this.spotlight !== null) { + Overlays.deleteOverlay(this.spotlight); + } + this.spotlight = null; } this.triggerPress = function(value) { From 2acc0df1f0bf29315d146b63d4e0f46342f63f37 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 10 Dec 2015 17:39:29 -0800 Subject: [PATCH 039/318] beams with spotlights --- examples/controllers/handControllerGrab.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index b787d8f0df..58eeb83b0e 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -559,7 +559,7 @@ function MyController(hand) { //this light casts the beam var lightProperties = { type: "Light", - isSpotlight: true, + isSpotlight: false, dimensions: { x: 2, y: 2, @@ -576,17 +576,18 @@ function MyController(hand) { cutoff: 20, lifetime: LIFETIME, position: lightTransform.p, - rotation: lightTransform.q, + // rotation: lightTransform.q, }; if (this.spotlight === null) { this.spotlight = Entities.addEntity(lightProperties); } else { - // var rotationBetween = Quat.rotationBetween(Vec3.UP, ) - // Entities.editEntity(this.spotlight, { - // rotation: lightTransform.q - // }) + Entities.editEntity(this.spotlight, { + parentID:parentID, + position:lightTransform.p, + visible:true + }) } } @@ -616,9 +617,13 @@ function MyController(hand) { this.spotlightOff = function() { if (this.spotlight !== null) { - Overlays.deleteOverlay(this.spotlight); + print('SHOULD DELETE SPOTLIGHT' + this.spotlight) + Entities.editEntity(this.spotlight,{ + visible:false + }) + //Entities.deleteEntity(this.spotlight); } - this.spotlight = null; + //this.spotlight = null; } this.triggerPress = function(value) { @@ -1416,6 +1421,7 @@ function MyController(hand) { this.release(); this.endHandGrasp(); Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); }; this.activateEntity = function(entityID, grabbedProperties) { From c74bbda663028c8ec621c899396899891931e5f4 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 10 Dec 2015 18:02:02 -0800 Subject: [PATCH 040/318] Nothing fancy --- libraries/render-utils/src/FramebufferCache.cpp | 6 +++--- libraries/render-utils/src/ToneMappingEffect.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 83ba8b6950..e0ad3dedd2 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -88,9 +88,9 @@ void FramebufferCache::createPrimaryFramebuffer() { _selfieFramebuffer->setRenderBuffer(0, tex); //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler)); - _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); - // _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); - _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + //lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); + _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); + _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); } diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index ea38884fac..1857d76cbf 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -50,7 +50,7 @@ void ToneMappingEffect::init() { // Manually gamma correct from Ligthing BUffer to color buffer // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); - fragColor *= 4.0; // Hardcoded Exposure Adjustment + fragColor *= 2.0; // Hardcoded Exposure Adjustment vec3 x = max(vec3(0.0),fragColor.xyz-0.004); vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); From 4e9d81f18737203e4bbdd60343aab98d65a210a1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 11:38:16 -0800 Subject: [PATCH 041/318] add support for various beam visualizations --- examples/controllers/handControllerGrab.js | 269 ++++++++++++++------- 1 file changed, 178 insertions(+), 91 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 58eeb83b0e..9e2f55b238 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -116,17 +116,14 @@ var DEFAULT_GRABBABLE_DATA = { invertSolidWhileHeld: false }; -var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 -}; -var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 -}); - +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LASERS_FOR_SEARCHING = false; +var USE_ENTITY_LASERS_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = false; +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = false; // states for the state machine var STATE_OFF = 0; @@ -275,9 +272,13 @@ function MyController(hand) { this.rawTriggerValue = 0; this.rawBumperValue = 0; + //for visualizations this.overlayLine = null; this.particleBeam = null; + + //for lights this.spotlight = null; + this.pointlight = null; this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; @@ -366,33 +367,6 @@ function MyController(hand) { }); } - this.overlayLineOn = function(closePoint, farPoint, color) { - if (this.overlayLine === null) { - var lineProperties = { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - ignoreRayIntersection: true, // always ignore this - visible: true, - alpha: 1 - }; - - this.overlayLine = Overlays.addOverlay("line3d", lineProperties); - - } else { - var success = Overlays.editOverlay(this.overlayLine, { - lineWidth: 5, - start: closePoint, - end: farPoint, - color: color, - visible: true, - ignoreRayIntersection: true, // always ignore this - alpha: 1 - }); - } - } - this.lineOn = function(closePoint, farPoint, color) { // draw a line if (this.pointer === null) { @@ -424,7 +398,33 @@ function MyController(hand) { } }; - //test particles instead of overlays + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + } + this.handleParticleBeam = function(position, orientation, color) { var rotation = Quat.angleAxis(0, { @@ -437,10 +437,10 @@ function MyController(hand) { if (this.particleBeam === null) { print('create beam') - this.createParticleBeam(position, finalRotation, color) + this.createParticleBeam(position, finalRotation, color); } else { print('update beam') - this.updateParticleBeam(position, finalRotation, color) + this.updateParticleBeam(position, finalRotation, color); } } @@ -456,11 +456,9 @@ function MyController(hand) { var lifespan = 1; if (this.particleBeam === null) { - print('create beam') - this.createParticleBeam(objectPosition, finalRotation, color, speed) + this.createParticleBeam(objectPosition, finalRotation, color, speed); } else { - print('update beam') - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan) + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); } } @@ -475,10 +473,10 @@ function MyController(hand) { "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": 1, - "emitRate": 300, - "emitSpeed": 1, - "speedSpread": 0, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, "emitOrientation": { "x": -1, "y": 0, @@ -528,9 +526,6 @@ function MyController(hand) { } this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - print('O IN UPDATE:::' + JSON.stringify(orientation)) - - // var beamProps = Entities.getEntityProperties(this.particleBeam); Entities.editEntity(this.particleBeam, { rotation: orientation, @@ -544,19 +539,72 @@ function MyController(hand) { } - this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + return { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) }; } - this.createSpotlight = function(parentID, position) { + this.handleSpotlight = function(parentID, position) { var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + parentID: parentID, + position: lightTransform.p, + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + visible: true + }) + } + } + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - //this light casts the beam + var lightProperties = { type: "Light", isSpotlight: false, @@ -576,17 +624,18 @@ function MyController(hand) { cutoff: 20, lifetime: LIFETIME, position: lightTransform.p, - // rotation: lightTransform.q, }; + if (this.pointlight === null) { - if (this.spotlight === null) { - this.spotlight = Entities.addEntity(lightProperties); + print('create pointlight') + this.pointlight = Entities.addEntity(lightProperties); } else { - Entities.editEntity(this.spotlight, { - parentID:parentID, - position:lightTransform.p, - visible:true + print('update pointlight') + Entities.editEntity(this.pointlight, { + parentID: parentID, + position: lightTransform.p, + visible: true }) } } @@ -611,19 +660,25 @@ function MyController(hand) { visible: false }) } - - //this.particleBeam = null; } - this.spotlightOff = function() { + this.turnLightsOff = function() { + //use visibility for now instead of creating and deleting since deleting seems to crash if (this.spotlight !== null) { - print('SHOULD DELETE SPOTLIGHT' + this.spotlight) - Entities.editEntity(this.spotlight,{ - visible:false - }) - //Entities.deleteEntity(this.spotlight); + Entities.editEntity(this.spotlight, { + visible: false + }) + //Entities.deleteEntity(this.spotlight); + //this.spotLight=null; + } + + if (this.pointlight !== null) { + Entities.editEntity(this.pointlight, { + visible: false + }) + //Entities.deleteEntity(this.pointlight); + //this.pointlight = null; } - //this.spotlight = null; } this.triggerPress = function(value) { @@ -634,7 +689,6 @@ function MyController(hand) { _this.rawBumperValue = value; }; - this.updateSmoothedTrigger = function() { var triggerValue = this.rawTriggerValue; // smooth out trigger value @@ -663,7 +717,6 @@ function MyController(hand) { return _this.rawBumperValue < BUMPER_ON_VALUE; } - this.off = function() { if (this.triggerSmoothedSqueezed()) { this.lastPickTime = 0; @@ -874,10 +927,18 @@ function MyController(hand) { } } - //this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - //this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); - this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + //search line visualizations + if (USE_ENTITY_LASERS_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } }; @@ -931,10 +992,22 @@ function MyController(hand) { this.currentAvatarPosition = MyAvatar.position; this.currentAvatarOrientation = MyAvatar.orientation; - this.overlayLineOff(); - this.particleBeamOff(); + this.turnOffVisualizations(); }; + this.turnOffVisualizations = function() { + if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { + this.lineOff(); + } + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + } + this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); @@ -958,7 +1031,7 @@ function MyController(hand) { return; } - // this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + // the action was set up on a previous call. update the targets. var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; @@ -1040,8 +1113,22 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) - this.createSpotlight(this.grabbedEntity); + + //visualizations + if (USE_ENTITY_LASERS_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, @@ -1050,6 +1137,7 @@ function MyController(hand) { angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, ttl: ACTION_TTL }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); }; @@ -1063,9 +1151,7 @@ function MyController(hand) { return; } - this.lineOff(); - this.overlayLineOff(); - this.particleBeamOff(); + this.turnOffVisualizations(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); this.activateEntity(this.grabbedEntity, grabbedProperties); @@ -1207,9 +1293,8 @@ function MyController(hand) { }; this.pullTowardEquipPosition = function() { - this.lineOff(); - this.overlayLineOff(); - this.particleBeamOff(); + + this.turnOffVisualizations(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); @@ -1400,10 +1485,9 @@ function MyController(hand) { this.release = function() { - this.lineOff(); - this.overlayLineOff(); - this.particleBeamOff(); - this.spotlightOff(); + this.turnLightsOff(); + this.turnOffVisualizations(); + if (this.grabbedEntity !== null) { if (this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1422,6 +1506,7 @@ function MyController(hand) { this.endHandGrasp(); Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); }; this.activateEntity = function(entityID, grabbedProperties) { @@ -1512,6 +1597,8 @@ function MyController(hand) { var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); + +//reload the particle beams rightController.createParticleBeam(); leftController.createParticleBeam(); From 11aaeb1ec00a76273f639648d47a00e4f691e0aa Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 14:48:07 -0800 Subject: [PATCH 042/318] only create particle beams if set --- examples/controllers/handControllerGrab.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9e2f55b238..217b5b6632 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1599,8 +1599,10 @@ var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); //reload the particle beams -rightController.createParticleBeam(); -leftController.createParticleBeam(); +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} var MAPPING_NAME = "com.highfidelity.handControllerGrab"; From 1b1edf6f7ab8a8e94e7d78df9eaf2b42d81c703b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 17:23:35 -0800 Subject: [PATCH 043/318] actually delete lights now that it doesnt crash --- examples/controllers/handControllerGrab.js | 30 +++++----------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 217b5b6632..ae95ab47fd 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -122,7 +122,7 @@ var USE_ENTITY_LASERS_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; -var USE_SPOTLIGHT = false; +var USE_SPOTLIGHT = true; var USE_POINTLIGHT = false; // states for the state machine @@ -436,10 +436,8 @@ function MyController(hand) { var finalRotation = Quat.multiply(orientation, rotation); if (this.particleBeam === null) { - print('create beam') this.createParticleBeam(position, finalRotation, color); } else { - print('update beam') this.updateParticleBeam(position, finalRotation, color); } } @@ -590,11 +588,8 @@ function MyController(hand) { this.spotlight = Entities.addEntity(lightProperties); } else { Entities.editEntity(this.spotlight, { - parentID: parentID, - position: lightTransform.p, //without this, this light would maintain rotation with its parent rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), - visible: true }) } } @@ -627,16 +622,9 @@ function MyController(hand) { }; if (this.pointlight === null) { - - print('create pointlight') this.pointlight = Entities.addEntity(lightProperties); } else { - print('update pointlight') - Entities.editEntity(this.pointlight, { - parentID: parentID, - position: lightTransform.p, - visible: true - }) + } } @@ -665,19 +653,13 @@ function MyController(hand) { this.turnLightsOff = function() { //use visibility for now instead of creating and deleting since deleting seems to crash if (this.spotlight !== null) { - Entities.editEntity(this.spotlight, { - visible: false - }) - //Entities.deleteEntity(this.spotlight); - //this.spotLight=null; + Entities.deleteEntity(this.spotlight); + this.spotlight = null; } if (this.pointlight !== null) { - Entities.editEntity(this.pointlight, { - visible: false - }) - //Entities.deleteEntity(this.pointlight); - //this.pointlight = null; + Entities.deleteEntity(this.pointlight); + this.pointlight = null; } } From 70a0e51cc9b5898dc49b1134f84a6f96d50b7aff Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 11 Dec 2015 17:59:03 -0800 Subject: [PATCH 044/318] back to default state --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ae95ab47fd..fc217de03a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -122,7 +122,7 @@ var USE_ENTITY_LASERS_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; -var USE_SPOTLIGHT = true; +var USE_SPOTLIGHT = false; var USE_POINTLIGHT = false; // states for the state machine From cb948e0608502d38cafac927b682d9759818ee23 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 12 Dec 2015 21:15:06 +0100 Subject: [PATCH 045/318] allow entity scripts to attach entities to a hand with handControllerGrab.js --- examples/controllers/handControllerGrab.js | 40 +++++++++++++--------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 138240f5d6..7976e5286f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -968,7 +968,6 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); Entities.callEntityMethod(this.grabbedEntity, "unequip"); this.endHandGrasp(); - } }; @@ -1288,33 +1287,40 @@ function update() { if (handToDisable !== LEFT_HAND && handToDisable!=='both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { rightController.update(); } } Messages.subscribe('Hifi-Hand-Disabler'); +Messages.subscribe('Hifi-Hand-Grab'); -handleHandDisablerMessages = function(channel, message, sender) { - +handleHandMessages = function(channel, message, sender) { if (sender === MyAvatar.sessionUUID) { - if (message === 'left') { - handToDisable = LEFT_HAND; - } - if (message === 'right') { - handToDisable = RIGHT_HAND; - } - if(message==='both'){ - handToDisable='both'; - } - if(message==='none'){ - handToDisable='none'; + if (channel === 'Hifi-Hand-Disabler') { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both' || message === 'none') { + handToDisable = handToDisable; + } + } else if (channel === 'Hifi-Hand-Grab') { + try { + var data = JSON.parse(message); + var selectedController = (data.hand === 'left') ? leftController : rightController; + selectedController.release(); + selectedController.setState(STATE_EQUIP); + selectedController.grabbedEntity = data.entityID; + + } catch (e) { } } } - } -Messages.messageReceived.connect(handleHandDisablerMessages); +Messages.messageReceived.connect(handleHandMessages); function cleanup() { rightController.cleanup(); From fe05542440f2c74668cbec2859c2c8227eb91e42 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 14:30:34 -0800 Subject: [PATCH 046/318] more vis --- examples/controllers/handControllerGrab.js | 80 ++++++++++++---------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index fc217de03a..afad62412e 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1,5 +1,4 @@ // handControllerGrab.js -// examples // // Created by Eric Levin on 9/2/15 // Additions by James B. Pollack @imgntn on 9/24/2015 @@ -7,6 +6,7 @@ // Copyright 2015 High Fidelity, Inc. // // Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -14,7 +14,6 @@ Script.include("../libraries/utils.js"); - // // add lines where the hand ray picking is happening // @@ -54,6 +53,7 @@ var LINE_ENTITY_DIMENSIONS = { y: 1000, z: 1000 }; + var LINE_LENGTH = 500; var PICK_MAX_DISTANCE = 500; // max length of pick-ray @@ -120,6 +120,7 @@ var DEFAULT_GRABBABLE_DATA = { var USE_ENTITY_LASERS_FOR_SEARCHING = false; var USE_ENTITY_LASERS_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; var USE_SPOTLIGHT = false; @@ -345,7 +346,7 @@ function MyController(hand) { print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); } this.state = newState; - } + }; this.debugLine = function(closePoint, farPoint, color) { Entities.addEntity({ @@ -365,7 +366,7 @@ function MyController(hand) { } }) }); - } + }; this.lineOn = function(closePoint, farPoint, color) { // draw a line @@ -423,7 +424,7 @@ function MyController(hand) { alpha: 1 }); } - } + }; this.handleParticleBeam = function(position, orientation, color) { @@ -440,7 +441,7 @@ function MyController(hand) { } else { this.updateParticleBeam(position, finalRotation, color); } - } + }; this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { @@ -458,7 +459,7 @@ function MyController(hand) { } else { this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); } - } + }; this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { @@ -521,7 +522,7 @@ function MyController(hand) { } this.particleBeam = Entities.addEntity(particleBeamProperties); - } + }; this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { @@ -535,7 +536,7 @@ function MyController(hand) { }) - } + }; this.evalLightWorldTransform = function(modelPos, modelRot) { @@ -555,7 +556,7 @@ function MyController(hand) { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) }; - } + }; this.handleSpotlight = function(parentID, position) { var LIFETIME = 100; @@ -592,7 +593,7 @@ function MyController(hand) { rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), }) } - } + }; this.handlePointLight = function(parentID, position) { var LIFETIME = 100; @@ -626,7 +627,7 @@ function MyController(hand) { } else { } - } + }; this.lineOff = function() { if (this.pointer !== null) { @@ -651,7 +652,6 @@ function MyController(hand) { } this.turnLightsOff = function() { - //use visibility for now instead of creating and deleting since deleting seems to crash if (this.spotlight !== null) { Entities.deleteEntity(this.spotlight); this.spotlight = null; @@ -661,7 +661,22 @@ function MyController(hand) { Entities.deleteEntity(this.pointlight); this.pointlight = null; } - } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; this.triggerPress = function(value) { _this.rawTriggerValue = value; @@ -693,11 +708,11 @@ function MyController(hand) { this.bumperSqueezed = function() { return _this.rawBumperValue > BUMPER_ON_VALUE; - } + }; this.bumperReleased = function() { return _this.rawBumperValue < BUMPER_ON_VALUE; - } + }; this.off = function() { if (this.triggerSmoothedSqueezed()) { @@ -710,7 +725,7 @@ function MyController(hand) { this.setState(STATE_EQUIP_SEARCHING); return; } - } + }; this.search = function() { this.grabbedEntity = null; @@ -977,19 +992,6 @@ function MyController(hand) { this.turnOffVisualizations(); }; - this.turnOffVisualizations = function() { - if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { - this.lineOff(); - } - if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { - this.overlayLineOff(); - } - - if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.particleBeamOff(); - } - } - this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); @@ -1100,14 +1102,15 @@ function MyController(hand) { if (USE_ENTITY_LASERS_FOR_MOVING === true) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) } - if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); } - if (USE_SPOTLIGHT === true) { this.handleSpotlight(this.grabbedEntity); } @@ -1399,6 +1402,7 @@ function MyController(hand) { }; _this.allTouchedIDs = {}; + this.touchTest = function() { var maxDistance = 0.05; var leftHandPosition = MyAvatar.getLeftPalmPosition(); @@ -1559,28 +1563,29 @@ function MyController(hand) { } //return an object with our updated settings return result; - } + }; this.graspHandler = null + this.startHandGrasp = function() { if (this.hand === RIGHT_HAND) { this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); } else if (this.hand === LEFT_HAND) { this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); } - } + }; this.endHandGrasp = function() { // Tell the animation system we don't need any more callbacks. MyAvatar.removeAnimationStateHandler(this.graspHandler); - } + }; -} +}; var rightController = new MyController(RIGHT_HAND); var leftController = new MyController(LEFT_HAND); -//reload the particle beams +//preload the particle beams so that they are full length when you start searching if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { rightController.createParticleBeam(); leftController.createParticleBeam(); @@ -1597,6 +1602,7 @@ mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); Controller.enableMapping(MAPPING_NAME); +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items var handToDisable = 'none'; function update() { From 0fe4803b04dc9e2554d1ef5335ce98e498c05cde Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 16:17:00 -0800 Subject: [PATCH 047/318] start --- examples/lights/box.js | 31 +++++++++ examples/lights/light_modifier.js | 103 ++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 examples/lights/box.js create mode 100644 examples/lights/light_modifier.js diff --git a/examples/lights/box.js b/examples/lights/box.js new file mode 100644 index 0000000000..711f5487b2 --- /dev/null +++ b/examples/lights/box.js @@ -0,0 +1,31 @@ +(function() { + + function Box () { + this.oldColor = {}; + this.oldColorKnown = false; + } + + Box.prototype = { + preload: function(entityID) { + print("preload"); + + this.entityID = entityID; + this.storeOldColor(entityID); + }, + startDistantGrab:function(){ + + }, + continueDistantGrab:function(){ + + }, + releaseGrab:function(){ + + } + setHand:function(){ + + } + + }; + + return new Box(); +}); \ No newline at end of file diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js new file mode 100644 index 0000000000..fd49690088 --- /dev/null +++ b/examples/lights/light_modifier.js @@ -0,0 +1,103 @@ +// given a selected light, instantiate some entities that represent various values you can dynamically adjust +// + +var BOX_SCRIPT_URL = Script.resolvePath('box.js'); + +function entitySlider(color) { + this.color = color; + return this; +} + +var RED = { + r: 255, + g: 0, + b: 0 +}; + +var GREEN = { + r: 0, + g: 255, + b: 0 +}; + +var BLUE = { + r: 0, + g: 0, + b: 255 +}; + +var PURPLE = { + r: 255, + g: 0, + b: 255 +}; + +var WHITE = { + r: 255 + g: 255, + b: 255 +}; + +//what's the ux for adjusting values? start with simple entities, try image overlays etc +entitySlider.prototype = { + createAxis: function() { + var properties = { + type: 'Line', + color: this.color, + collisionsWillMove: false, + ignoreForCollisions: true, + }; + + this.axis = Entities.addEntity(properties); + }, + createBoxIndicator: function() { + var properties = { + type: 'Box', + dimensions: { + x: 0.04, + y: 0.04, + z: 0.04 + }, + color: this.color, + position: position, + script: BOX_SCRIPT_URL + }; + + + + this.boxIndicator = Entities.addEntity(properties); + }, + moveIndicatorAlongAxis: function(direction) { + + } +}; + +//create them for this light +function makeSliders(light) { + if (light.type === 'spotlight') { + var USE_COLOR_SLIDER = true; + var USE_INTENSITY_SLIDER = true; + var USE_CUTOFF_SLIDER = true; + var USE_EXPONENT_SLIDER = true; + } + if (light.type === 'pointlight') { + var USE_COLOR_SLIDER = true; + var USE_INTENSITY_SLIDER = true; + var USE_CUTOFF_SLIDER = false; + var USE_EXPONENT_SLIDER = false; + } + if (USE_COLOR_SLIDER === true) { + var r = new entitySlider(RED); + var g = new entitySlider(GREEN); + var b = new entitySlider(BLUE); + } + if (USE_INTENSITY_SLIDER === true) { + var intensity = new entitySlider(WHITE); + } + if (USE_CUTOFF_SLIDER === true) { + var cutoff = new entitySlider(PURPLE); + } + if (USE_EXPONENT_SLIDER === true) { + var exponent = new entitySlider(PURPLE); + } +}; \ No newline at end of file From 0ddc2ba76e22359f202cb2205efbf6da24ec08a1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 16:18:15 -0800 Subject: [PATCH 048/318] rename lasers to lines --- examples/controllers/handControllerGrab.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index afad62412e..f8fe1b821c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -117,8 +117,8 @@ var DEFAULT_GRABBABLE_DATA = { }; //we've created various ways of visualizing looking for and moving distant objects -var USE_ENTITY_LASERS_FOR_SEARCHING = false; -var USE_ENTITY_LASERS_FOR_MOVING = true; +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_ENTITY_LINES_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; @@ -665,7 +665,7 @@ function MyController(hand) { this.turnOffVisualizations = function() { - if (USE_ENTITY_LASERS_FOR_SEARCHING === true || USE_ENTITY_LASERS_FOR_MOVING === true) { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { this.lineOff(); } @@ -925,7 +925,7 @@ function MyController(hand) { } //search line visualizations - if (USE_ENTITY_LASERS_FOR_SEARCHING === true) { + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } @@ -1099,7 +1099,7 @@ function MyController(hand) { //visualizations - if (USE_ENTITY_LASERS_FOR_MOVING === true) { + if (USE_ENTITY_LINES_FOR_MOVING === true) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); } if (USE_OVERLAY_LINES_FOR_MOVING === true) { From 7cace240025b3f950a91cbf072e2dbd664fa3235 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:14:43 -0800 Subject: [PATCH 049/318] light editing framework --- examples/lights/box.js | 65 ++++++++++++----- examples/lights/light_modifier.js | 116 +++++++++++++++++++++++++----- 2 files changed, 148 insertions(+), 33 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 711f5487b2..3a24ef1568 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -1,29 +1,62 @@ (function() { - function Box () { - this.oldColor = {}; - this.oldColorKnown = false; + function Box() { + return this; } Box.prototype = { preload: function(entityID) { - print("preload"); - this.entityID = entityID; - this.storeOldColor(entityID); }, - startDistantGrab:function(){ - + startNearGrab: function() { + this.setInitialProperties(); }, - continueDistantGrab:function(){ - + startDistantGrab: function() { + this.setInitialProperties(); }, - releaseGrab:function(){ - - } - setHand:function(){ - - } + setInitialProperties: function() { + this.initialProperties = Entities.getEntityProperties(this.entityID); + }, + getClampedPosition: function() { + return position; + }, + getClampedRotation: function() { + var rotation = initialProperties.rotation; + return rotation; + }, + continueDistantGrab: function() { + var currentPosition = this.getClampedPosition(); + var distance = Vec3.distance(this.initialProperties.position, currentPosition); + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + Entities.editEntity(this.entityID) { + position: currentPosition, + rotation: this.getClampedRotation() + } + }, + releaseGrab: function() { + Entities.editEntity(this.entityID, { + velocity: { + x: 0, + y: 0, + z: 0 + } + }) + this.sendValueToSlider(); + }, + scaleValueBasedOnDistanceFromStart: function(value, min1, max1, min2, max2) { + var min1 = 0; + var max1 = 1; + var min2 = 0; + var max2 = 255; + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); + }, + sendValueToSlider: function() { + var message = { + lightID: this.entityID, + sliderValue: this.sliderValue + } + Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); + }; }; diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index fd49690088..71d3d38c64 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,8 +3,10 @@ var BOX_SCRIPT_URL = Script.resolvePath('box.js'); -function entitySlider(color) { +function entitySlider(color, sliderType, verticalOffset) { this.color = color; + this.sliderType = sliderType; + this.verticalOffset = verticalOffset; return this; } @@ -38,6 +40,13 @@ var WHITE = { b: 255 }; +var AXIS_SCALE = 1; +var BOX_DIMENSIONS = { + x: 0.04, + y: 0.04, + z: 0.04 +} + //what's the ux for adjusting values? start with simple entities, try image overlays etc entitySlider.prototype = { createAxis: function() { @@ -53,27 +62,98 @@ entitySlider.prototype = { createBoxIndicator: function() { var properties = { type: 'Box', - dimensions: { - x: 0.04, - y: 0.04, - z: 0.04 - }, + dimensions: BOX_DIMENSIONS, color: this.color, position: position, script: BOX_SCRIPT_URL }; - - this.boxIndicator = Entities.addEntity(properties); }, - moveIndicatorAlongAxis: function(direction) { + handleValueMessages: function(channel, message, sender) { + //easily protect from other people editing your values, but group editing might be fun so lets try that first. + // if (sender !== MyAvatar.sessionUUID) { + // return; + // } + var parsedMessage = JSON.parse(message); + setValueFromMessage(parsedMessage); + }, + setValueFromMessage: function(message) { + var lightProperties = Entities.getEntitiyProperties(message.lightID); + if (this.sliderType === 'color_red') { + Entities.editEntity(message.lightID, { + color: { + red: message.sliderValue, + green: lightProperties.color.g, + blue: lightProperties.color.b + } + }) + } + + if (this.sliderType === 'color_green') { + Entities.editEntity(message.lightID, { + color: { + red: lightProperties.color.r + green: message.sliderValue, + blue: lightProperties.color.b + } + }) + } + + if (this.sliderType === 'color_blue') { + Entities.editEntity(message.lightID, { + color: { + red: lightProperties.color.r, + green: lightProperties.color.g, + blue: message.sliderValue, + } + }) + } + + if (this.sliderType === 'intensity') { + Entities.editEntity(message.lightID, { + intensity: message.sliderValue + }) + } + + if (this.sliderType === 'cutoff') { + Entities.editEntity(message.lightID, { + cutoff: message.sliderValue + }) + } + + if (this.sliderType === 'exponent') { + Entities.editEntity(message.lightID, { + exponent: message.sliderValue + }) + } + }, + subscribeToBoxMessages: function() { + Messages.subscribe('Hifi-Slider-Value-Reciever'); + Messages.messageReceived.connect(this.handleValueMessages); + }, + cleanup: function() { + Entities.deleteEntity(this.boxIndicator); + Entities.deleteEntity(this.axis); + Messages.messageReceived.disconnect(this.handleValueMessages); } }; -//create them for this light +//create them for a given light function makeSliders(light) { + var initialPosition = { + x: 0, + y: 0, + z: 0 + }; + + var perRowOffset = { + x: 0, + y: 0.2, + z: 0 + }; + if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -87,17 +167,19 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - var r = new entitySlider(RED); - var g = new entitySlider(GREEN); - var b = new entitySlider(BLUE); + var r = new entitySlider(RED, 'color_red', Vec3.multiply(1, perRowOffset)); + var g = new entitySlider(GREEN, 'color_green', Vec3.multiply(2, perRowOffset)); + var b = new entitySlider(BLUE, 'color_blue', Vec3.multiply(3, perRowOffset)); } if (USE_INTENSITY_SLIDER === true) { - var intensity = new entitySlider(WHITE); + var intensity = new entitySlider(WHITE, 'intensity', Vec3.multiply(4, perRowOffset)); } if (USE_CUTOFF_SLIDER === true) { - var cutoff = new entitySlider(PURPLE); + var cutoff = new entitySlider(PURPLE, 'cutoff', Vec3.multiply(5, perRowOffset)); } if (USE_EXPONENT_SLIDER === true) { - var exponent = new entitySlider(PURPLE); + var exponent = new entitySlider(PURPLE, 'exponent', Vec3.multiply(6, perRowOffset)); } -}; \ No newline at end of file +}; + +makeSliders(light) \ No newline at end of file From 231bcdb8f0fbf0eb8b608f3f89e9f64ed6098f54 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:22:57 -0800 Subject: [PATCH 050/318] name some things better and cleanup --- examples/lights/box.js | 4 +- examples/lights/light_modifier.js | 74 +++++++++++++++---------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 3a24ef1568..27bffe6e33 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -28,6 +28,7 @@ var currentPosition = this.getClampedPosition(); var distance = Vec3.distance(this.initialProperties.position, currentPosition); this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + Entities.editEntity(this.entityID) { position: currentPosition, rotation: this.getClampedRotation() @@ -41,6 +42,7 @@ z: 0 } }) + this.sendValueToSlider(); }, scaleValueBasedOnDistanceFromStart: function(value, min1, max1, min2, max2) { @@ -52,7 +54,7 @@ }, sendValueToSlider: function() { var message = { - lightID: this.entityID, + boxID: this.entityID, sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 71d3d38c64..9c841eeb24 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,10 +3,11 @@ var BOX_SCRIPT_URL = Script.resolvePath('box.js'); -function entitySlider(color, sliderType, verticalOffset) { +function entitySlider(light, color, sliderType, row) { + this.light = light; this.color = color; this.sliderType = sliderType; - this.verticalOffset = verticalOffset; + this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET);; return this; } @@ -42,20 +43,27 @@ var WHITE = { var AXIS_SCALE = 1; var BOX_DIMENSIONS = { - x: 0.04, - y: 0.04, - z: 0.04 -} + x: 0.05, + y: 0.05, + z: 0.05 +}; +var PER_ROW_OFFSET = { + x: 0, + y: 0.2, + z: 0 +}; //what's the ux for adjusting values? start with simple entities, try image overlays etc entitySlider.prototype = { createAxis: function() { - var properties = { - type: 'Line', - color: this.color, - collisionsWillMove: false, - ignoreForCollisions: true, - }; + var position = + var properties = { + type: 'Line', + color: this.color, + collisionsWillMove: false, + ignoreForCollisions: true, + position: position, + }; this.axis = Entities.addEntity(properties); }, @@ -79,54 +87,54 @@ entitySlider.prototype = { setValueFromMessage(parsedMessage); }, setValueFromMessage: function(message) { - var lightProperties = Entities.getEntitiyProperties(message.lightID); + var lightProperties = Entities.getEntityProperties(this.lightID); if (this.sliderType === 'color_red') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { color: { red: message.sliderValue, green: lightProperties.color.g, blue: lightProperties.color.b } - }) + }); } if (this.sliderType === 'color_green') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { color: { red: lightProperties.color.r green: message.sliderValue, blue: lightProperties.color.b } - }) + }); } if (this.sliderType === 'color_blue') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { color: { red: lightProperties.color.r, green: lightProperties.color.g, blue: message.sliderValue, } - }) + }); } if (this.sliderType === 'intensity') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { intensity: message.sliderValue - }) + }); } if (this.sliderType === 'cutoff') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { cutoff: message.sliderValue - }) + }); } if (this.sliderType === 'exponent') { - Entities.editEntity(message.lightID, { + Entities.editEntity(this.lightID, { exponent: message.sliderValue - }) + }); } }, subscribeToBoxMessages: function() { @@ -142,17 +150,6 @@ entitySlider.prototype = { //create them for a given light function makeSliders(light) { - var initialPosition = { - x: 0, - y: 0, - z: 0 - }; - - var perRowOffset = { - x: 0, - y: 0.2, - z: 0 - }; if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; @@ -167,7 +164,7 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - var r = new entitySlider(RED, 'color_red', Vec3.multiply(1, perRowOffset)); + var r = new entitySlider(RED, 'color_red', 1); var g = new entitySlider(GREEN, 'color_green', Vec3.multiply(2, perRowOffset)); var b = new entitySlider(BLUE, 'color_blue', Vec3.multiply(3, perRowOffset)); } @@ -182,4 +179,5 @@ function makeSliders(light) { } }; -makeSliders(light) \ No newline at end of file + +makeSliders(light); \ No newline at end of file From 77969e14810ab20d689dff5e65c3bcd6591b65d9 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:31:49 -0800 Subject: [PATCH 051/318] breaktime --- examples/lights/light_modifier.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 9c841eeb24..d6c964bf55 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -179,5 +179,4 @@ function makeSliders(light) { } }; - makeSliders(light); \ No newline at end of file From a0b698c0283ce162720ad13465d04ccb8105439d Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 12 Dec 2015 17:33:54 -0800 Subject: [PATCH 052/318] reorg props --- examples/controllers/handControllerGrab.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f8fe1b821c..382d5cac7a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -118,11 +118,13 @@ var DEFAULT_GRABBABLE_DATA = { //we've created various ways of visualizing looking for and moving distant objects var USE_ENTITY_LINES_FOR_SEARCHING = false; -var USE_ENTITY_LINES_FOR_MOVING = true; var USE_OVERLAY_LINES_FOR_SEARCHING = true; -var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; var USE_PARTICLE_BEAM_FOR_MOVING = false; + var USE_SPOTLIGHT = false; var USE_POINTLIGHT = false; From ab5b783cb7dbb3bf6f1878bf2f2e134ef331406e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 14 Dec 2015 09:01:45 -0800 Subject: [PATCH 053/318] zone tweal --- examples/flowArts/lightTrails.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index e063897eb8..8e0dc98bbb 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -23,7 +23,7 @@ var MAX_POINTS_PER_LINE = 50; var LIFETIME = 6000; var DRAWING_DEPTH = 0.8; -var LINE_DIMENSIONS = 20; +var LINE_DIMENSIONS = 100; var lightZone = Entities.addEntity({ type: "Zone", @@ -78,9 +78,9 @@ function controller(side, triggerAction) { type: 'Light', position: MyAvatar.position, dimensions: { - x: 20, - y: 20, - z: 20 + x: 30, + y: 30, + z: 30 }, color: colorPalette[randInt(0, colorPalette.length)], intensity: 5 From 1698e903c94ef65de1366e30de692beafc3352c9 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 11:25:30 -0800 Subject: [PATCH 054/318] midday --- examples/lights/box.js | 6 +- examples/lights/light_modifier.js | 114 ++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 27bffe6e33..ac3cac7ab3 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -18,7 +18,11 @@ this.initialProperties = Entities.getEntityProperties(this.entityID); }, getClampedPosition: function() { - return position; + dPosition = Vec3.subtract(MyAvatar.position, previousPosition); + //convert to localFrame + dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); + + return dPosition; }, getClampedRotation: function() { var rotation = initialProperties.rotation; diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index d6c964bf55..6ae702bf7f 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,14 +3,6 @@ var BOX_SCRIPT_URL = Script.resolvePath('box.js'); -function entitySlider(light, color, sliderType, row) { - this.light = light; - this.color = color; - this.sliderType = sliderType; - this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET);; - return this; -} - var RED = { r: 255, g: 0, @@ -42,6 +34,7 @@ var WHITE = { }; var AXIS_SCALE = 1; + var BOX_DIMENSIONS = { x: 0.05, y: 0.05, @@ -53,17 +46,54 @@ var PER_ROW_OFFSET = { z: 0 }; +function entitySlider(light, color, sliderType, row) { + this.light = light; + this.lightID = light.id; + this.initialProperties = light.initialProperties; + this.color = color; + this.sliderType = sliderType; + this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + + var formattedMessage = { + 'color_red': this.initialProperties.color.r, + 'color_green': this.initialProperties.color.g, + 'color_blue': this.initialProperties.color.b, + 'intensity': this.initialProperties.intensity, + 'exponent': this.initialProperties.exponent, + 'cutoff': this.initialProperties.cutoff, + } + + this.setValueFromMessage(formattedMessage); + this.setInitialSliderPositions(); + + return this; +} + //what's the ux for adjusting values? start with simple entities, try image overlays etc entitySlider.prototype = { createAxis: function() { - var position = - var properties = { - type: 'Line', - color: this.color, - collisionsWillMove: false, - ignoreForCollisions: true, - position: position, - }; + //start of line + var position; + //1 meter along orientationAxis + var endOfAxis; + var properties = { + type: 'Line', + color: this.color, + collisionsWillMove: false, + ignoreForCollisions: true, + dimensions: { + x: 3, + y: 3, + z: 3 + }, + position: position, + linePoints: [{ + x: 0, + y: 0, + z: 0 + }, endOfAxis], + lineWidth: 5, + }; this.axis = Entities.addEntity(properties); }, @@ -79,6 +109,9 @@ entitySlider.prototype = { this.boxIndicator = Entities.addEntity(properties); }, handleValueMessages: function(channel, message, sender) { + if (channel !== 'Hifi-Slider-Value-Reciever') { + return; + } //easily protect from other people editing your values, but group editing might be fun so lets try that first. // if (sender !== MyAvatar.sessionUUID) { // return; @@ -141,6 +174,15 @@ entitySlider.prototype = { Messages.subscribe('Hifi-Slider-Value-Reciever'); Messages.messageReceived.connect(this.handleValueMessages); }, + setInitialSliderPositions:function(){ + + var distanceRed = (this.initialProperties.color.r / 255) * AXIS_SCALE; + var distanceGreen = (this.initialProperties.color.g / 255) * AXIS_SCALE; + var distanceBlue = (this.initialProperties.color.b / 255) * AXIS_SCALE; + var distanceIntensity = (this.initialProperties.intensity / 255) * AXIS_SCALE; + var distanceCutoff = (this.initialProperties.cutoff / 360) * AXIS_SCALE; + var distanceExponent = (this.initialProperties.exponent / 255) * AXIS_SCALE; + }, cleanup: function() { Entities.deleteEntity(this.boxIndicator); Entities.deleteEntity(this.axis); @@ -150,7 +192,6 @@ entitySlider.prototype = { //create them for a given light function makeSliders(light) { - if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -165,18 +206,45 @@ function makeSliders(light) { } if (USE_COLOR_SLIDER === true) { var r = new entitySlider(RED, 'color_red', 1); - var g = new entitySlider(GREEN, 'color_green', Vec3.multiply(2, perRowOffset)); - var b = new entitySlider(BLUE, 'color_blue', Vec3.multiply(3, perRowOffset)); + var g = new entitySlider(GREEN, 'color_green', 2); + var b = new entitySlider(BLUE, 'color_blue', 3); } if (USE_INTENSITY_SLIDER === true) { - var intensity = new entitySlider(WHITE, 'intensity', Vec3.multiply(4, perRowOffset)); + var intensity = new entitySlider(WHITE, 'intensity', 4); } if (USE_CUTOFF_SLIDER === true) { - var cutoff = new entitySlider(PURPLE, 'cutoff', Vec3.multiply(5, perRowOffset)); + var cutoff = new entitySlider(PURPLE, 'cutoff', 5); } if (USE_EXPONENT_SLIDER === true) { - var exponent = new entitySlider(PURPLE, 'exponent', Vec3.multiply(6, perRowOffset)); + var exponent = new entitySlider(PURPLE, 'exponent', 6); } }; -makeSliders(light); \ No newline at end of file +function subScribeToNewLights() { + Messages.subscribe('Hifi-Light-Mod-Receiver'); + Messages.messageReceived.connect(handleLightModMessages); +} + +function handleLightModMessages(channel, message, sender) { + if (channel !== 'Hifi-Light-Mod-Receiver') { + return; + } + if (sender !== MyAvatar.sessionUUID) { + return; + } + var parsedMessage = JSON.parse(message); + var light = message.light; + makeSliders(light); +} + +subScribeToNewLights(); + + // diffuseColor: { red: 255, green: 255, blue: 255 }, + // ambientColor: { red: 255, green: 255, blue: 255 }, + // specularColor: { red: 255, green: 255, blue: 255 }, + + // constantAttenuation: 1, + // linearAttenuation: 0, + // quadraticAttenuation: 0, + // exponent: 0, + // cutoff: 180, // in degrees \ No newline at end of file From e43b60f9f54c27b72e2377f32defe489647a415f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 11:40:47 -0800 Subject: [PATCH 055/318] other variations --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 382d5cac7a..cd82db22b9 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1105,7 +1105,7 @@ function MyController(hand) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); } if (USE_OVERLAY_LINES_FOR_MOVING === true) { - this.overlayLineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) From 4d9cb6a6df3f3c07866ca4d6fa2170b939f7196b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 11:41:34 -0800 Subject: [PATCH 056/318] other variations --- .../handControllerGrab-all-overlays.js | 1649 +++++++++++++++++ .../handControllerGrab-particles.js | 1649 +++++++++++++++++ .../handControllerGrab-pointlight.js | 1649 +++++++++++++++++ .../handControllerGrab-spotlight.js | 1649 +++++++++++++++++ 4 files changed, 6596 insertions(+) create mode 100644 examples/controllers/handControllerGrab-all-overlays.js create mode 100644 examples/controllers/handControllerGrab-particles.js create mode 100644 examples/controllers/handControllerGrab-pointlight.js create mode 100644 examples/controllers/handControllerGrab-spotlight.js diff --git a/examples/controllers/handControllerGrab-all-overlays.js b/examples/controllers/handControllerGrab-all-overlays.js new file mode 100644 index 0000000000..acb47b2260 --- /dev/null +++ b/examples/controllers/handControllerGrab-all-overlays.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// 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 */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = false; +var USE_OVERLAY_LINES_FOR_MOVING = true; +var USE_PARTICLE_BEAM_FOR_MOVING = false; + +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = false; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + 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); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + 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; + + // 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; + + // 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; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-particles.js b/examples/controllers/handControllerGrab-particles.js new file mode 100644 index 0000000000..d9ecb18b01 --- /dev/null +++ b/examples/controllers/handControllerGrab-particles.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// 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 */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = false; +var USE_PARTICLE_BEAM_FOR_SEARCHING = true; + +var USE_ENTITY_LINES_FOR_MOVING = false; +var USE_OVERLAY_LINES_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = true; + +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = false; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + 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); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + 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; + + // 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; + + // 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; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-pointlight.js b/examples/controllers/handControllerGrab-pointlight.js new file mode 100644 index 0000000000..fc14e6026e --- /dev/null +++ b/examples/controllers/handControllerGrab-pointlight.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// 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 */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = false; + +var USE_SPOTLIGHT = false; +var USE_POINTLIGHT = true; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + 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); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + 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; + + // 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; + + // 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; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/controllers/handControllerGrab-spotlight.js b/examples/controllers/handControllerGrab-spotlight.js new file mode 100644 index 0000000000..ea05a44f78 --- /dev/null +++ b/examples/controllers/handControllerGrab-spotlight.js @@ -0,0 +1,1649 @@ +// handControllerGrab.js +// +// Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 +// Additions By Seth Alves on 10/20/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// Also supports touch and equipping objects. +// +// 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 */ + +Script.include("../libraries/utils.js"); + +// +// add lines where the hand ray picking is happening +// +var WANT_DEBUG = false; + +// +// these tune time-averaging and "on" value for analog trigger +// + +var TRIGGER_SMOOTH_RATIO = 0.1; // 0.0 disables smoothing of trigger value +var TRIGGER_ON_VALUE = 0.4; +var TRIGGER_OFF_VALUE = 0.15; + +var BUMPER_ON_VALUE = 0.5; + +// +// distant manipulation +// + +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects + +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; + +var LINE_LENGTH = 500; +var PICK_MAX_DISTANCE = 500; // max length of pick-ray + +// +// near grabbing +// + +var GRAB_RADIUS = 0.03; // if the ray misses but an object is this close, it will still be selected +var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position +var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. +var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected +var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things +var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object +var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed + +// +// equip +// + +var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05; +var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position + +// +// other constants +// + +var RIGHT_HAND = 1; +var LEFT_HAND = 0; + +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; + +var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; +var MSEC_PER_SEC = 1000.0; + +// these control how long an abandoned pointer line or action will hang around +var LIFETIME = 10; +var ACTION_TTL = 15; // seconds +var ACTION_TTL_REFRESH = 5; +var PICKS_PER_SECOND_PER_HAND = 5; +var MSECS_PER_SEC = 1000.0; +var GRABBABLE_PROPERTIES = [ + "position", + "rotation", + "gravity", + "ignoreForCollisions", + "collisionsWillMove", + "locked", + "name" +]; + +var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js +var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js + +var DEFAULT_GRABBABLE_DATA = { + grabbable: true, + invertSolidWhileHeld: false +}; + +//we've created various ways of visualizing looking for and moving distant objects +var USE_ENTITY_LINES_FOR_SEARCHING = false; +var USE_OVERLAY_LINES_FOR_SEARCHING = true; +var USE_PARTICLE_BEAM_FOR_SEARCHING = false; + +var USE_ENTITY_LINES_FOR_MOVING = true; +var USE_OVERLAY_LINES_FOR_MOVING = false; +var USE_PARTICLE_BEAM_FOR_MOVING = false; + +var USE_SPOTLIGHT = true; +var USE_POINTLIGHT = false; + +// states for the state machine +var STATE_OFF = 0; +var STATE_SEARCHING = 1; +var STATE_DISTANCE_HOLDING = 2; +var STATE_CONTINUE_DISTANCE_HOLDING = 3; +var STATE_NEAR_GRABBING = 4; +var STATE_CONTINUE_NEAR_GRABBING = 5; +var STATE_NEAR_TRIGGER = 6; +var STATE_CONTINUE_NEAR_TRIGGER = 7; +var STATE_FAR_TRIGGER = 8; +var STATE_CONTINUE_FAR_TRIGGER = 9; +var STATE_RELEASE = 10; +var STATE_EQUIP_SEARCHING = 11; +var STATE_EQUIP = 12 +var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down +var STATE_CONTINUE_EQUIP = 14; +var STATE_WAITING_FOR_BUMPER_RELEASE = 15; +var STATE_EQUIP_SPRING = 16; + + + +function stateToName(state) { + switch (state) { + case STATE_OFF: + return "off"; + case STATE_SEARCHING: + return "searching"; + case STATE_DISTANCE_HOLDING: + return "distance_holding"; + case STATE_CONTINUE_DISTANCE_HOLDING: + return "continue_distance_holding"; + case STATE_NEAR_GRABBING: + return "near_grabbing"; + case STATE_CONTINUE_NEAR_GRABBING: + return "continue_near_grabbing"; + case STATE_NEAR_TRIGGER: + return "near_trigger"; + case STATE_CONTINUE_NEAR_TRIGGER: + return "continue_near_trigger"; + case STATE_FAR_TRIGGER: + return "far_trigger"; + case STATE_CONTINUE_FAR_TRIGGER: + return "continue_far_trigger"; + case STATE_RELEASE: + return "release"; + case STATE_EQUIP_SEARCHING: + return "equip_searching"; + case STATE_EQUIP: + return "equip"; + case STATE_CONTINUE_EQUIP_BD: + return "continue_equip_bd"; + case STATE_CONTINUE_EQUIP: + return "continue_equip"; + case STATE_WAITING_FOR_BUMPER_RELEASE: + return "waiting_for_bumper_release"; + case STATE_EQUIP_SPRING: + return "state_equip_spring"; + } + + return "unknown"; +} + +function getTag() { + return "grab-" + MyAvatar.sessionUUID; +} + +function entityIsGrabbedByOther(entityID) { + // by convention, a distance grab sets the tag of its action to be grab-*owner-session-id*. + var actionIDs = Entities.getActionIDs(entityID); + for (var actionIndex = 0; actionIndex < actionIDs.length; actionIndex++) { + var actionID = actionIDs[actionIndex]; + var actionArguments = Entities.getActionArguments(entityID, actionID); + var tag = actionArguments["tag"]; + if (tag == getTag()) { + // we see a grab-*uuid* shaped tag, but it's our tag, so that's okay. + continue; + } + if (tag.slice(0, 5) == "grab-") { + // we see a grab-*uuid* shaped tag and it's not ours, so someone else is grabbing it. + return true; + } + } + return false; +} + +function getSpatialOffsetPosition(hand, spatialKey) { + var position = Vec3.ZERO; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + position = spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + position = spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + position = spatialKey.relativePosition; + } + + return position; +} + +var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + +function getSpatialOffsetRotation(hand, spatialKey) { + var rotation = Quat.IDENTITY; + + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + rotation = spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + rotation = spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + rotation = spatialKey.relativeRotation; + } + + // Flip left hand + if (hand !== RIGHT_HAND) { + rotation = Quat.multiply(yFlip, rotation); + } + + return rotation; +} + +function MyController(hand) { + this.hand = hand; + if (this.hand === RIGHT_HAND) { + this.getHandPosition = MyAvatar.getRightPalmPosition; + this.getHandRotation = MyAvatar.getRightPalmRotation; + } else { + this.getHandPosition = MyAvatar.getLeftPalmPosition; + this.getHandRotation = MyAvatar.getLeftPalmRotation; + } + + var SPATIAL_CONTROLLERS_PER_PALM = 2; + var TIP_CONTROLLER_OFFSET = 1; + this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand; + this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET; + + this.actionID = null; // action this script created... + this.grabbedEntity = null; // on this entity. + this.state = STATE_OFF; + this.pointer = null; // entity-id of line object + this.triggerValue = 0; // rolling average of trigger value + this.rawTriggerValue = 0; + this.rawBumperValue = 0; + + //for visualizations + this.overlayLine = null; + this.particleBeam = null; + + //for lights + this.spotlight = null; + this.pointlight = null; + + this.ignoreIK = false; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; + + var _this = this; + + this.update = function() { + + this.updateSmoothedTrigger(); + + switch (this.state) { + case STATE_OFF: + this.off(); + this.touchTest(); + break; + case STATE_SEARCHING: + this.search(); + break; + case STATE_EQUIP_SEARCHING: + this.search(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + case STATE_EQUIP: + this.nearGrabbing(); + break; + case STATE_WAITING_FOR_BUMPER_RELEASE: + this.waitingForBumperRelease(); + break; + case STATE_EQUIP_SPRING: + this.pullTowardEquipPosition() + break; + case STATE_CONTINUE_NEAR_GRABBING: + case STATE_CONTINUE_EQUIP_BD: + case STATE_CONTINUE_EQUIP: + this.continueNearGrabbing(); + break; + case STATE_NEAR_TRIGGER: + this.nearTrigger(); + break; + case STATE_CONTINUE_NEAR_TRIGGER: + this.continueNearTrigger(); + break; + case STATE_FAR_TRIGGER: + this.farTrigger(); + break; + case STATE_CONTINUE_FAR_TRIGGER: + this.continueFarTrigger(); + break; + case STATE_RELEASE: + this.release(); + break; + } + }; + + this.setState = function(newState) { + if (WANT_DEBUG) { + print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); + } + this.state = newState; + }; + + this.debugLine = function(closePoint, farPoint, color) { + Entities.addEntity({ + type: "Line", + name: "Grab Debug Entity", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + }; + + this.lineOn = function(closePoint, farPoint, color) { + // draw a line + if (this.pointer === null) { + this.pointer = Entities.addEntity({ + type: "Line", + name: "grab pointer", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: LIFETIME, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } else { + var age = Entities.getEntityProperties(this.pointer, "age").age; + this.pointer = Entities.editEntity(this.pointer, { + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: age + LIFETIME + }); + } + }; + + this.overlayLineOn = function(closePoint, farPoint, color) { + if (this.overlayLine === null) { + var lineProperties = { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + ignoreRayIntersection: true, // always ignore this + visible: true, + alpha: 1 + }; + + this.overlayLine = Overlays.addOverlay("line3d", lineProperties); + + } else { + var success = Overlays.editOverlay(this.overlayLine, { + lineWidth: 5, + start: closePoint, + end: farPoint, + color: color, + visible: true, + ignoreRayIntersection: true, // always ignore this + alpha: 1 + }); + } + }; + + this.handleParticleBeam = function(position, orientation, color) { + + var rotation = Quat.angleAxis(0, { + x: 1, + y: 0, + z: 0 + }); + + var finalRotation = Quat.multiply(orientation, rotation); + + if (this.particleBeam === null) { + this.createParticleBeam(position, finalRotation, color); + } else { + this.updateParticleBeam(position, finalRotation, color); + } + }; + + this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + + var handToObject = Vec3.subtract(objectPosition, handPosition); + var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); + + var distance = Vec3.distance(handPosition, objectPosition); + var speed = distance * 1; + + var lifepsan = distance / speed; + var lifespan = 1; + + if (this.particleBeam === null) { + this.createParticleBeam(objectPosition, finalRotation, color, speed); + } else { + this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + } + }; + + this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + + var particleBeamProperties = { + type: "ParticleEffect", + isEmitting: true, + position: position, + visible: false, + //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), + "name": "Particle Beam", + "color": color, + "maxParticles": 2000, + "lifespan": LINE_LENGTH / 10, + "emitRate": 50, + "emitSpeed": 5, + "speedSpread": 2, + "emitOrientation": { + "x": -1, + "y": 0, + "z": 0, + "w": 1 + }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "emitRadiusStart": 0.5, + "polarStart": 0, + "polarFinish": 0, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + x: 0, + y: 0, + z: 0 + }, + "accelerationSpread": { + "x": 0, + "y": 0, + "z": 0 + }, + "particleRadius": 0.01, + "radiusSpread": 0, + // "radiusStart": 0.01, + // "radiusFinish": 0.01, + // "colorSpread": { + // "red": 0, + // "green": 0, + // "blue": 0 + // }, + // "colorStart": color, + // "colorFinish": color, + "alpha": 1, + "alphaSpread": 0, + "alphaStart": 1, + "alphaFinish": 1, + "additiveBlending": 1, + "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" + } + + this.particleBeam = Entities.addEntity(particleBeamProperties); + }; + + this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { + + Entities.editEntity(this.particleBeam, { + rotation: orientation, + position: position, + visible: true, + color: color, + emitSpeed: speed, + lifepsan: lifepsan + + }) + + }; + + this.evalLightWorldTransform = function(modelPos, modelRot) { + + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + }; + + this.handleSpotlight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var lightProperties = { + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.spotlight === null) { + this.spotlight = Entities.addEntity(lightProperties); + } else { + Entities.editEntity(this.spotlight, { + //without this, this light would maintain rotation with its parent + rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + }) + } + }; + + this.handlePointLight = function(parentID, position) { + var LIFETIME = 100; + + var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']); + var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + + var lightProperties = { + type: "Light", + isSpotlight: false, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: parentID, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + }; + + if (this.pointlight === null) { + this.pointlight = Entities.addEntity(lightProperties); + } else { + + } + }; + + this.lineOff = function() { + if (this.pointer !== null) { + Entities.deleteEntity(this.pointer); + } + this.pointer = null; + }; + + this.overlayLineOff = function() { + if (this.overlayLine !== null) { + Overlays.deleteOverlay(this.overlayLine); + } + this.overlayLine = null; + }; + + this.particleBeamOff = function() { + if (this.particleBeam !== null) { + Entities.editEntity(this.particleBeam, { + visible: false + }) + } + } + + this.turnLightsOff = function() { + if (this.spotlight !== null) { + Entities.deleteEntity(this.spotlight); + this.spotlight = null; + } + + if (this.pointlight !== null) { + Entities.deleteEntity(this.pointlight); + this.pointlight = null; + } + }; + + + this.turnOffVisualizations = function() { + if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOff(); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOff(); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.particleBeamOff(); + } + }; + + this.triggerPress = function(value) { + _this.rawTriggerValue = value; + }; + + this.bumperPress = function(value) { + _this.rawBumperValue = value; + }; + + this.updateSmoothedTrigger = function() { + var triggerValue = this.rawTriggerValue; + // smooth out trigger value + this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); + }; + + this.triggerSmoothedSqueezed = function() { + return this.triggerValue > TRIGGER_ON_VALUE; + }; + + this.triggerSmoothedReleased = function() { + return this.triggerValue < TRIGGER_OFF_VALUE; + }; + + this.triggerSqueezed = function() { + var triggerValue = this.rawTriggerValue; + return triggerValue > TRIGGER_ON_VALUE; + }; + + this.bumperSqueezed = function() { + return _this.rawBumperValue > BUMPER_ON_VALUE; + }; + + this.bumperReleased = function() { + return _this.rawBumperValue < BUMPER_ON_VALUE; + }; + + this.off = function() { + if (this.triggerSmoothedSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_SEARCHING); + return; + } + if (this.bumperSqueezed()) { + this.lastPickTime = 0; + this.setState(STATE_EQUIP_SEARCHING); + return; + } + }; + + this.search = function() { + this.grabbedEntity = null; + + if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { + this.setState(STATE_RELEASE); + return; + } + + // the trigger is being pressed, do a ray test + var handPosition = this.getHandPosition(); + var distantPickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()), + length: PICK_MAX_DISTANCE + }; + + // don't pick 60x per second. + var pickRays = []; + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; + } + + for (var index = 0; index < pickRays.length; ++index) { + var pickRay = pickRays[index]; + var directionNormalized = Vec3.normalize(pickRay.direction); + var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); + var pickRayBacked = { + origin: Vec3.subtract(pickRay.origin, directionBacked), + direction: pickRay.direction + }; + + if (WANT_DEBUG) { + this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { + red: 0, + green: 255, + blue: 0 + }) + } + + var intersection = Entities.findRayIntersection(pickRayBacked, true); + + if (intersection.intersects) { + // the ray is intersecting something we can move. + var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); + + if (intersection.properties.name == "Grab Debug Entity") { + continue; + } + + if (typeof grabbableData.grabbable !== 'undefined' && !grabbableData.grabbable) { + continue; + } + if (intersectionDistance > pickRay.length) { + // too far away for this ray. + continue; + } + if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) { + // the hand is very close to the intersected object. go into close-grabbing mode. + if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!intersection.properties.locked) { + this.grabbedEntity = intersection.entityID; + if (this.state == STATE_SEARCHING) { + this.setState(STATE_NEAR_GRABBING); + } else { // equipping + if (typeof grabbableData.spatialKey !== 'undefined') { + // TODO + // if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch + // to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + } else { + this.setState(STATE_EQUIP); + } + } + return; + } + } else if (!entityIsGrabbedByOther(intersection.entityID)) { + // don't allow two people to distance grab the same object + if (intersection.properties.collisionsWillMove && !intersection.properties.locked) { + // the hand is far from the intersected object. go into distance-holding mode + this.grabbedEntity = intersection.entityID; + if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { + // if a distance pick in equip mode hits something with a spatialKey, equip it + // TODO use STATE_EQUIP_SPRING here once it works right. + // this.setState(STATE_EQUIP_SPRING); + this.setState(STATE_EQUIP); + return; + } else if (this.state == STATE_SEARCHING) { + this.setState(STATE_DISTANCE_HOLDING); + return; + } + } else if (grabbableData.wantsTrigger) { + this.grabbedEntity = intersection.entityID; + this.setState(STATE_FAR_TRIGGER); + return; + } + } + } + } + + // forward ray test failed, try sphere test. + if (WANT_DEBUG) { + Entities.addEntity({ + type: "Sphere", + name: "Grab Debug Entity", + dimensions: { + x: GRAB_RADIUS, + y: GRAB_RADIUS, + z: GRAB_RADIUS + }, + visible: true, + position: handPosition, + color: { + red: 0, + green: 255, + blue: 0 + }, + lifetime: 0.1, + collisionsWillMove: false, + ignoreForCollisions: true, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + }); + } + + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + this.grabbedEntity = null; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (typeof grabbableDataForCandidate.grabbable !== 'undefined' && !grabbableDataForCandidate.grabbable) { + continue; + } + var propsForCandidate = Entities.getEntityProperties(nearbyEntities[i], GRABBABLE_PROPERTIES); + + if (propsForCandidate.type == 'Unknown') { + continue; + } + + if (propsForCandidate.type == 'Light') { + continue; + } + + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'PolyLine') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { + continue; + } + + if (propsForCandidate.name == "Grab Debug Entity") { + continue; + } + + if (propsForCandidate.name == "grab pointer") { + continue; + } + + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance) { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity !== null) { + if (grabbableData.wantsTrigger) { + this.setState(STATE_NEAR_TRIGGER); + return; + } else if (!props.locked && props.collisionsWillMove) { + this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) + return; + } + } + + //search line visualizations + if (USE_ENTITY_LINES_FOR_SEARCHING === true) { + this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + + if (USE_OVERLAY_LINES_FOR_SEARCHING === true) { + this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR); + } + + if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) { + this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR); + } + + }; + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var now = Date.now(); + + // add the action and initialize some variables + 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); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + tag: getTag(), + ttl: ACTION_TTL + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + + if (this.actionID !== null) { + this.setState(STATE_CONTINUE_DISTANCE_HOLDING); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + } + + this.currentAvatarPosition = MyAvatar.position; + this.currentAvatarOrientation = MyAvatar.orientation; + + this.turnOffVisualizations(); + }; + + this.continueDistanceHolding = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + 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); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && + typeof grabbableData.spatialKey !== 'undefined') { + var saveGrabbedID = this.grabbedEntity; + this.release(); + this.setState(STATE_EQUIP); + this.grabbedEntity = saveGrabbedID; + return; + } + + + // the action was set up on a previous call. update the targets. + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + 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; + + // 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; + + // 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; + this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); + + Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + + + //visualizations + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); + } + if (USE_OVERLAY_LINES_FOR_MOVING === true) { + this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); + } + if (USE_PARTICLE_BEAM_FOR_MOVING === true) { + this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + } + if (USE_POINTLIGHT === true) { + this.handlePointLight(this.grabbedEntity); + } + if (USE_SPOTLIGHT === true) { + this.handleSpotlight(this.grabbedEntity); + } + + Entities.updateAction(this.grabbedEntity, this.actionID, { + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + ttl: ACTION_TTL + }); + + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; + + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } + + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; + } else { + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + + } + + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; + + this.currentObjectTime = Date.now(); + }; + + this.continueNearGrabbing = function() { + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } + if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { + this.setState(STATE_CONTINUE_EQUIP); + return; + } + if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { + this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + return; + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { + this.setState(STATE_CONTINUE_EQUIP_BD); + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + return; + } + + // Keep track of the fingertip velocity to impart when we release the object. + // Note that the idea of using a constant 'tip' velocity regardless of the + // object's actual held offset is an idea intended to make it easier to throw things: + // Because we might catch something or transfer it between hands without a good idea + // of it's actual offset, let's try imparting a velocity which is at a fixed radius + // from the palm. + + var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; + var now = Date.now(); + + var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters + var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds + + this.currentHandControllerTipPosition = handControllerPosition; + this.currentObjectTime = now; + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + + if (this.state === STATE_CONTINUE_EQUIP_BD) { + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + + if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { + // if less than a 5 seconds left, refresh the actions ttl + Entities.updateAction(this.grabbedEntity, this.actionID, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK + }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + } + }; + + this.waitingForBumperRelease = function() { + if (this.bumperReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + Entities.callEntityMethod(this.grabbedEntity, "unequip"); + this.endHandGrasp(); + + } + }; + + this.pullTowardEquipPosition = function() { + + this.turnOffVisualizations(); + + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + // use a spring to pull the object to where it will be when equipped + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + var ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + var targetRotation = Quat.multiply(handRotation, relativeRotation); + var offset = Vec3.multiplyQbyV(targetRotation, relativePosition); + var targetPosition = Vec3.sum(handPosition, offset); + + if (typeof this.equipSpringID === 'undefined' || + this.equipSpringID === null || + this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + if (this.equipSpringID === NULL_ACTION_ID) { + this.equipSpringID = null; + this.setState(STATE_OFF); + return; + } + } else { + Entities.updateAction(this.grabbedEntity, this.equipSpringID, { + targetPosition: targetPosition, + linearTimeScale: EQUIP_SPRING_TIMEFRAME, + targetRotation: targetRotation, + angularTimeScale: EQUIP_SPRING_TIMEFRAME, + ttl: ACTION_TTL, + ignoreIK: ignoreIK + }); + } + + if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) { + Entities.deleteAction(this.grabbedEntity, this.equipSpringID); + this.equipSpringID = null; + this.setState(STATE_EQUIP); + } + }; + + this.nearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.setState(STATE_CONTINUE_NEAR_TRIGGER); + }; + + this.farTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.setState(STATE_CONTINUE_FAR_TRIGGER); + }; + + this.continueNearTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + }; + + this.continueFarTrigger = function() { + if (this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + return; + } + + var handPosition = this.getHandPosition(); + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; + + var now = Date.now(); + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + var intersection = Entities.findRayIntersection(pickRay, true); + this.lastPickTime = now; + if (intersection.entityID != this.grabbedEntity) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + return; + } + } + + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + }; + + _this.allTouchedIDs = {}; + + this.touchTest = function() { + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + + if (leftEntities.length !== 0) { + leftEntities.forEach(function(entity) { + ids.push(entity); + }); + + } + + if (rightEntities.length !== 0) { + rightEntities.forEach(function(entity) { + ids.push(entity); + }); + } + + ids.forEach(function(id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id]) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id]) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function(entityID) { + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function(entityID) { + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function(entityID) { + Entities.callEntityMethod(entityID, "stopTouch"); + }; + + this.release = function() { + + this.turnLightsOff(); + this.turnOffVisualizations(); + + if (this.grabbedEntity !== null) { + if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); + } + } + + this.deactivateEntity(this.grabbedEntity); + + this.grabbedEntity = null; + this.actionID = null; + this.setState(STATE_OFF); + }; + + this.cleanup = function() { + this.release(); + this.endHandGrasp(); + Entities.deleteEntity(this.particleBeam); + Entities.deleteEntity(this.spotLight); + Entities.deleteEntity(this.pointLight); + }; + + this.activateEntity = function(entityID, grabbedProperties) { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); + var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + data["activated"] = true; + data["avatarId"] = MyAvatar.sessionUUID; + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done + if (data["refCount"] == 1) { + data["gravity"] = grabbedProperties.gravity; + data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; + var whileHeldProperties = { + gravity: { + x: 0, + y: 0, + z: 0 + } + }; + if (invertSolidWhileHeld) { + whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; + } + Entities.editEntity(entityID, whileHeldProperties); + } + + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + return data; + }; + + this.deactivateEntity = function(entityID) { + var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); + if (data && data["refCount"]) { + data["refCount"] = data["refCount"] - 1; + if (data["refCount"] < 1) { + Entities.editEntity(entityID, { + gravity: data["gravity"], + ignoreForCollisions: data["ignoreForCollisions"], + collisionsWillMove: data["collisionsWillMove"] + }); + data = null; + } + } else { + data = null; + } + setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); + }; + + + //this is our handler, where we do the actual work of changing animation settings + this.graspHand = function(animationProperties) { + var result = {}; + //full alpha on overlay for this hand + //set grab to true + //set idle to false + //full alpha on the blend btw open and grab + if (_this.hand === RIGHT_HAND) { + result['rightHandOverlayAlpha'] = 1.0; + result['isRightHandGrab'] = true; + result['isRightHandIdle'] = false; + result['rightHandGrabBlend'] = 1.0; + } else if (_this.hand === LEFT_HAND) { + result['leftHandOverlayAlpha'] = 1.0; + result['isLeftHandGrab'] = true; + result['isLeftHandIdle'] = false; + result['leftHandGrabBlend'] = 1.0; + } + //return an object with our updated settings + return result; + }; + + this.graspHandler = null + + this.startHandGrasp = function() { + if (this.hand === RIGHT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); + } else if (this.hand === LEFT_HAND) { + this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); + } + }; + + this.endHandGrasp = function() { + // Tell the animation system we don't need any more callbacks. + MyAvatar.removeAnimationStateHandler(this.graspHandler); + }; + +}; + +var rightController = new MyController(RIGHT_HAND); +var leftController = new MyController(LEFT_HAND); + +//preload the particle beams so that they are full length when you start searching +if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) { + rightController.createParticleBeam(); + leftController.createParticleBeam(); +} + +var MAPPING_NAME = "com.highfidelity.handControllerGrab"; + +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from([Controller.Standard.RT]).peek().to(rightController.triggerPress); +mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress); + +mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress); +mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress); + +Controller.enableMapping(MAPPING_NAME); + +//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items +var handToDisable = 'none'; + +function update() { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { + leftController.update(); + } + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { + rightController.update(); + } +} + +Messages.subscribe('Hifi-Hand-Disabler'); + +handleHandDisablerMessages = function(channel, message, sender) { + + if (sender === MyAvatar.sessionUUID) { + if (message === 'left') { + handToDisable = LEFT_HAND; + } + if (message === 'right') { + handToDisable = RIGHT_HAND; + } + if (message === 'both') { + handToDisable = 'both'; + } + if (message === 'none') { + handToDisable = 'none'; + } + } + +} + +Messages.messageReceived.connect(handleHandDisablerMessages); + +function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + Controller.disableMapping(MAPPING_NAME); +} + +Script.scriptEnding.connect(cleanup); +Script.update.connect(update); \ No newline at end of file From 8d691f2132f4acdeb7f98692d1ec97236b77b086 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 14 Dec 2015 11:44:42 -0800 Subject: [PATCH 057/318] light ball --- examples/flowArts/lightBall/lightBall.js | 0 .../flowArts/lightBall/lightBallSpawner.js | 51 +++++++++++++++++++ .../entities/src/ParticleEffectEntityItem.cpp | 4 +- 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 examples/flowArts/lightBall/lightBall.js create mode 100644 examples/flowArts/lightBall/lightBallSpawner.js diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js new file mode 100644 index 0000000000..f758c26bbe --- /dev/null +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -0,0 +1,51 @@ +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); + +var lightBall = Entities.addEntity({ + position: center, + type: "ParticleEffect", + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": {red: 20, green: 20, blue: 255}, + color: {red: 10, green: 0, blue: 255}, + "colorFinish": {red: 250, green: 200, blue:255}, + // "maxParticles": 100000, + "lifespan": 1, + "emitRate": 1000, + "emitSpeed": .1, + "speedSpread": .01, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": 3, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .01, + "y": .01, + "z": .01 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + "additiveBlending": 0, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}) + +function cleanup() { + Entities.deleteEntity(lightBall); +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 5600c85650..f4210f4486 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -52,13 +52,13 @@ const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f; const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000; const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1; -const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000; +const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 100000; const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f; const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f; const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f; -const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f; +const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 100000.0f; const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f; const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3 From 18458a843147f55b4163cac6af1e5dd6b37c2468 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 12:04:44 -0800 Subject: [PATCH 058/318] test scene --- examples/lights/testScene.js | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/lights/testScene.js diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js new file mode 100644 index 0000000000..eeb5f4ffd7 --- /dev/null +++ b/examples/lights/testScene.js @@ -0,0 +1,104 @@ + // These constants define the Spotlight position and orientation relative to the model + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + var basePosition, avatarRot; + avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_RANGE * 3, Quat.getFront(avatarRot))); + + var ground = Entities.addEntity({ + type: "Model", + modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", + dimensions: { + x: 100, + y: 2, + z: 100 + }, + position: basePosition, + shapeType: 'box' + }); + + var light, block; + + basePosition.y += 2; + + function createLight() { + var lightProperties = { + name: 'Hifi-Spotlight' + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: box, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME, + position: lightTransform.p, + rotation: lightTransform.q, + } + light = Entities.addEntity(lightProperties); + + var message = { + light: { + id: light, + type: 'spotlight', + initialProperties:lightProperties + } + }; + Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); + + } + + function createBlock() { + var blockProperties = { + name: 'Hifi-Spotlight-Block', + type: 'Box', + dimensions: { + x: 1, + y: 1, + z: 1 + }, + collisionsWillMove: true, + shapeType: 'Box', + color: { + red: 0, + green: 0 + blue: 255 + }, + position: basePosition + } + + block = Entities.addEntity(block); + } + + function evalLightWorldTransform(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + } + + function cleanup() { + Entities.deleteEntity(ground); + Entities.deleteEntity(light); + } + + createBlock(); + createLight(); \ No newline at end of file From 76487bca7ac69c8fdaa2ec9e8eaaa281871b378e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 13:01:03 -0800 Subject: [PATCH 059/318] updates --- .../handControllerGrab-particles.js | 47 +++++++++++-------- .../handControllerGrab-pointlight.js | 47 +++++++++++-------- .../handControllerGrab-spotlight.js | 47 +++++++++++-------- examples/controllers/handControllerGrab.js | 47 +++++++++++-------- 4 files changed, 108 insertions(+), 80 deletions(-) diff --git a/examples/controllers/handControllerGrab-particles.js b/examples/controllers/handControllerGrab-particles.js index d9ecb18b01..bfe51927d0 100644 --- a/examples/controllers/handControllerGrab-particles.js +++ b/examples/controllers/handControllerGrab-particles.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; diff --git a/examples/controllers/handControllerGrab-pointlight.js b/examples/controllers/handControllerGrab-pointlight.js index fc14e6026e..e7bb4e3e9f 100644 --- a/examples/controllers/handControllerGrab-pointlight.js +++ b/examples/controllers/handControllerGrab-pointlight.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; diff --git a/examples/controllers/handControllerGrab-spotlight.js b/examples/controllers/handControllerGrab-spotlight.js index ea05a44f78..ee6dcfa681 100644 --- a/examples/controllers/handControllerGrab-spotlight.js +++ b/examples/controllers/handControllerGrab-spotlight.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index cd82db22b9..b6f1a82c3f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; From e3e1bc1dc611b0bbb00860807a04018aa04c7105 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 13:01:44 -0800 Subject: [PATCH 060/318] updates --- .../handControllerGrab-all-overlays.js | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/examples/controllers/handControllerGrab-all-overlays.js b/examples/controllers/handControllerGrab-all-overlays.js index acb47b2260..67e2b1f0a7 100644 --- a/examples/controllers/handControllerGrab-all-overlays.js +++ b/examples/controllers/handControllerGrab-all-overlays.js @@ -437,47 +437,49 @@ function MyController(hand) { }); var finalRotation = Quat.multiply(orientation, rotation); - + var lifespan = LINE_LENGTH / 10; + var speed = 5; + var spread = 2; if (this.particleBeam === null) { - this.createParticleBeam(position, finalRotation, color); + this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(position, finalRotation, color); + this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan); } }; - this.handleDistantParticleBeam = function(handPosition, objectPosition, objectRotation, color) { + this.handleDistantParticleBeam = function(handPosition, objectPosition, color) { var handToObject = Vec3.subtract(objectPosition, handPosition); var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject); var distance = Vec3.distance(handPosition, objectPosition); - var speed = distance * 1; + var speed = 5; + var spread = 0; + + var lifespan = distance / speed; - var lifepsan = distance / speed; - var lifespan = 1; if (this.particleBeam === null) { - this.createParticleBeam(objectPosition, finalRotation, color, speed); + this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } else { - this.updateParticleBeam(objectPosition, finalRotation, color, speed, lifepsan); + this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan); } }; - this.createParticleBeam = function(position, orientation, color, speed, lifepsan) { + this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) { var particleBeamProperties = { type: "ParticleEffect", isEmitting: true, position: position, visible: false, - //rotation:Quat.fromPitchYawRollDegrees(-90.0, 0.0, 0.0), "name": "Particle Beam", "color": color, "maxParticles": 2000, - "lifespan": LINE_LENGTH / 10, + "lifespan": lifespan, "emitRate": 50, - "emitSpeed": 5, - "speedSpread": 2, + "emitSpeed": speed, + "speedSpread": spread, "emitOrientation": { "x": -1, "y": 0, @@ -519,22 +521,23 @@ function MyController(hand) { "alphaSpread": 0, "alphaStart": 1, "alphaFinish": 1, - "additiveBlending": 1, + "additiveBlending": 0, "textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png" } this.particleBeam = Entities.addEntity(particleBeamProperties); }; - this.updateParticleBeam = function(position, orientation, color, speed, lifepsan) { - + this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) { + print('lifespan::' + lifespan); Entities.editEntity(this.particleBeam, { rotation: orientation, position: position, visible: true, color: color, emitSpeed: speed, - lifepsan: lifepsan + speedSpread:spread, + lifespan: lifespan }) @@ -1108,7 +1111,8 @@ function MyController(hand) { this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR); } if (USE_PARTICLE_BEAM_FOR_MOVING === true) { - this.handleDistantParticleBeam(handPosition, grabbedProperties.position, this.currentObjectRotation, INTERSECT_COLOR) + this.handleDistantParticleBeam(handPosition,grabbedProperties.position, INTERSECT_COLOR) + // this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR) } if (USE_POINTLIGHT === true) { this.handlePointLight(this.grabbedEntity); @@ -1399,7 +1403,10 @@ function MyController(hand) { } } - this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + if (USE_ENTITY_LINES_FOR_MOVING === true) { + this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); + } + Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); }; From 761dfeaccd72edbd4cd79ce66bb9d9f517b229d1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 14 Dec 2015 14:53:08 -0800 Subject: [PATCH 061/318] 2 balls --- .../flowArts/lightBall/lightBallSpawner.js | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index f758c26bbe..da09829257 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -1,16 +1,80 @@ -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation()))); +var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); + +var containerBall = Entities.addEntity({ + type: "Sphere", + position: center, + dimensions: {x: .1, y: .1, z: .1}, + color: {red: 50, green: 10, blue: 50}, + collisionsWillMove: true, + gravity: {x: 0, y: -.1, z: 0} +}); var lightBall = Entities.addEntity({ position: center, type: "ParticleEffect", + parentID: containerBall, isEmitting: true, "name": "ParticlesTest Emitter", "colorStart": {red: 20, green: 20, blue: 255}, color: {red: 10, green: 0, blue: 255}, "colorFinish": {red: 250, green: 200, blue:255}, - // "maxParticles": 100000, + "maxParticles": 20000, "lifespan": 1, - "emitRate": 1000, + "emitRate": 10000, + "emitSpeed": .1, + "speedSpread": .01, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": 3, + "azimuthStart": -3.1415927410125732, + "azimuthFinish": 3.1415927410125732, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .01, + "y": .01, + "z": .01 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + "additiveBlending": 0, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}) + +var containerBall2 = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), + dimensions: {x: .1, y: .1, z: .1}, + color: {red: 200, green: 10, blue: 50}, + collisionsWillMove: true, + gravity: {x: 0, y: -.1, z: 0} +}); + +var lightBall2 = Entities.addEntity({ + position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), + type: "ParticleEffect", + parentID: containerBall2, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": {red: 200, green: 20, blue: 0}, + color: {red: 255, green: 0, blue: 10}, + "colorFinish": {red: 250, green: 200, blue:255}, + "maxParticles": 100000, + "lifespan": 1, + "emitRate": 10000, "emitSpeed": .1, "speedSpread": .01, "emitDimensions": { @@ -46,6 +110,9 @@ var lightBall = Entities.addEntity({ function cleanup() { Entities.deleteEntity(lightBall); + Entities.deleteEntity(lightBall2); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(containerBall2); } Script.scriptEnding.connect(cleanup); \ No newline at end of file From ea0ffa589930f3528ea347e33709f865e6e645c4 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 16:39:25 -0800 Subject: [PATCH 062/318] support changing values for lights via message --- examples/lights/box.js | 18 ++- examples/lights/light_modifier.js | 197 ++++++++++++++++++++++-------- examples/lights/testScene.js | 38 ++++-- 3 files changed, 183 insertions(+), 70 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index ac3cac7ab3..a8e708b344 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -1,5 +1,11 @@ (function() { + var AXIS_SCALE = 1; + var COLOR_MAX = 255; + var INTENSITY_MAX = 10; + var CUTOFF_MAX = 360; + var EXPONENT_MAX = 1; + function Box() { return this; } @@ -7,6 +13,8 @@ Box.prototype = { preload: function(entityID) { this.entityID = entityID; + var userData = Entities.getEntityProperties(this.entityID, "userData"); + this.userData = JSON.parse(userData); }, startNearGrab: function() { this.setInitialProperties(); @@ -31,7 +39,8 @@ continueDistantGrab: function() { var currentPosition = this.getClampedPosition(); var distance = Vec3.distance(this.initialProperties.position, currentPosition); - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + if () + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); Entities.editEntity(this.entityID) { position: currentPosition, @@ -49,16 +58,17 @@ this.sendValueToSlider(); }, - scaleValueBasedOnDistanceFromStart: function(value, min1, max1, min2, max2) { + scaleValueBasedOnDistanceFromStart: function(value, max2) { var min1 = 0; var max1 = 1; var min2 = 0; - var max2 = 255; + var max2 = max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, sendValueToSlider: function() { var message = { - boxID: this.entityID, + lightID:userData.lightID, + sliderType:userData.sliderType, sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 6ae702bf7f..f1c27b4e4b 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -28,7 +28,7 @@ var PURPLE = { }; var WHITE = { - r: 255 + r: 255, g: 255, b: 255 }; @@ -48,24 +48,48 @@ var PER_ROW_OFFSET = { function entitySlider(light, color, sliderType, row) { this.light = light; - this.lightID = light.id; + this.lightID = light.id.replace(/[{}]/g, ""); this.initialProperties = light.initialProperties; this.color = color; this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - var formattedMessage = { - 'color_red': this.initialProperties.color.r, - 'color_green': this.initialProperties.color.g, - 'color_blue': this.initialProperties.color.b, - 'intensity': this.initialProperties.intensity, - 'exponent': this.initialProperties.exponent, - 'cutoff': this.initialProperties.cutoff, + var message = { + lightID: this.lightID, + sliderType: this.sliderType, + sliderValue: null + }; + + if (this.sliderType === 'color_red') { + message.sliderValue = this.initialProperties.color.red + this.setValueFromMessage(message); + } + if (this.sliderType === 'color_green') { + message.sliderValue = this.initialProperties.color.green + this.setValueFromMessage(message); + } + if (this.sliderType === 'color_blue') { + message.sliderValue = this.initialProperties.color.blue + this.setValueFromMessage(message); } - this.setValueFromMessage(formattedMessage); - this.setInitialSliderPositions(); + if (this.sliderType === 'intensity') { + message.sliderValue = this.initialProperties.intensity + this.setValueFromMessage(message); + } + if (this.sliderType === 'exponent') { + message.sliderValue = this.initialProperties.exponent + this.setValueFromMessage(message); + } + + if (this.sliderType === 'cutoff') { + message.sliderValue = this.initialProperties.cutoff + this.setValueFromMessage(message); + } + + // this.setInitialSliderPositions(); + this.subscribeToBoxMessages(); return this; } @@ -103,31 +127,44 @@ entitySlider.prototype = { dimensions: BOX_DIMENSIONS, color: this.color, position: position, - script: BOX_SCRIPT_URL + script: BOX_SCRIPT_URL, + userData: JSON.stringify({ + lightModifierKey: { + lightID: this.lightID, + sliderType: this.sliderType + } + }) }; this.boxIndicator = Entities.addEntity(properties); }, - handleValueMessages: function(channel, message, sender) { - if (channel !== 'Hifi-Slider-Value-Reciever') { + setValueFromMessage: function(message) { + print('VALUE MESSAGE::'+JSON.stringify(message)) + print('LIGHT ID::'+this.lightID); + + //message is not for our light + if (message.lightID !== this.lightID) { + print('not our light') return; } - //easily protect from other people editing your values, but group editing might be fun so lets try that first. - // if (sender !== MyAvatar.sessionUUID) { - // return; - // } - var parsedMessage = JSON.parse(message); - setValueFromMessage(parsedMessage); - }, - setValueFromMessage: function(message) { + + //message is not our type + if (message.sliderType !== this.sliderType) { + print('not our slider type') + return + } + + print('SHOULD SET SOME VALUE:::' + message.sliderType); + var lightProperties = Entities.getEntityProperties(this.lightID); + // print('LIGHT PROPERTIES::'+JSON.stringify(lightProperties)); if (this.sliderType === 'color_red') { Entities.editEntity(this.lightID, { color: { red: message.sliderValue, - green: lightProperties.color.g, - blue: lightProperties.color.b + green: lightProperties.color.green, + blue: lightProperties.color.blue } }); } @@ -135,9 +172,9 @@ entitySlider.prototype = { if (this.sliderType === 'color_green') { Entities.editEntity(this.lightID, { color: { - red: lightProperties.color.r + red: lightProperties.color.red, green: message.sliderValue, - blue: lightProperties.color.b + blue: lightProperties.color.blue } }); } @@ -145,14 +182,15 @@ entitySlider.prototype = { if (this.sliderType === 'color_blue') { Entities.editEntity(this.lightID, { color: { - red: lightProperties.color.r, - green: lightProperties.color.g, + red: lightProperties.color.red, + green: lightProperties.color.green, blue: message.sliderValue, } }); } if (this.sliderType === 'intensity') { + print('CHANGING INTENSITY TO::' + message.sliderValue) Entities.editEntity(this.lightID, { intensity: message.sliderValue }); @@ -171,17 +209,22 @@ entitySlider.prototype = { } }, subscribeToBoxMessages: function() { + print('subscribing to box messages'); Messages.subscribe('Hifi-Slider-Value-Reciever'); - Messages.messageReceived.connect(this.handleValueMessages); + Messages.messageReceived.connect(handleValueMessages); }, - setInitialSliderPositions:function(){ + setInitialSliderPositions: function() { + var COLOR_MAX = 255; + var INTENSITY_MAX = 10; + var CUTOFF_MAX = 360; + var EXPONENT_MAX = 1; - var distanceRed = (this.initialProperties.color.r / 255) * AXIS_SCALE; - var distanceGreen = (this.initialProperties.color.g / 255) * AXIS_SCALE; - var distanceBlue = (this.initialProperties.color.b / 255) * AXIS_SCALE; - var distanceIntensity = (this.initialProperties.intensity / 255) * AXIS_SCALE; - var distanceCutoff = (this.initialProperties.cutoff / 360) * AXIS_SCALE; - var distanceExponent = (this.initialProperties.exponent / 255) * AXIS_SCALE; + var distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; + var distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; + var distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; + var distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; + var distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; + var distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; }, cleanup: function() { Entities.deleteEntity(this.boxIndicator); @@ -190,8 +233,18 @@ entitySlider.prototype = { } }; -//create them for a given light +var sliders = []; +var slidersRef = { + 'color_red': null, + 'color_green': null, + 'color_blue': null, + intensity: null, + cutoff: null, + exponent: null +} + function makeSliders(light) { + print('light in makesliders:::' + light) if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -205,22 +258,31 @@ function makeSliders(light) { var USE_EXPONENT_SLIDER = false; } if (USE_COLOR_SLIDER === true) { - var r = new entitySlider(RED, 'color_red', 1); - var g = new entitySlider(GREEN, 'color_green', 2); - var b = new entitySlider(BLUE, 'color_blue', 3); + slidersRef.color_red = new entitySlider(light, RED, 'color_red', 1); + slidersRef.color_green = new entitySlider(light, GREEN, 'color_green', 2); + slidersRef.color_blue = new entitySlider(light, BLUE, 'color_blue', 3); + + sliders.push(slidersRef.color_red); + sliders.push(slidersRef.color_green); + sliders.push(slidersRef.color_blue); + } if (USE_INTENSITY_SLIDER === true) { - var intensity = new entitySlider(WHITE, 'intensity', 4); + slidersRef.intensity = new entitySlider(light, WHITE, 'intensity', 4); + sliders.push(slidersRef.intensity); } if (USE_CUTOFF_SLIDER === true) { - var cutoff = new entitySlider(PURPLE, 'cutoff', 5); + slidersRef.cutoff = new entitySlider(light, PURPLE, 'cutoff', 5); + sliders.push(slidersRef.cutoff); } if (USE_EXPONENT_SLIDER === true) { - var exponent = new entitySlider(PURPLE, 'exponent', 6); + slidersRef.exponent = new entitySlider(light, PURPLE, 'exponent', 6); + sliders.push(slidersRef.exponent); } }; function subScribeToNewLights() { + print('subscribing to light messages') Messages.subscribe('Hifi-Light-Mod-Receiver'); Messages.messageReceived.connect(handleLightModMessages); } @@ -233,18 +295,47 @@ function handleLightModMessages(channel, message, sender) { return; } var parsedMessage = JSON.parse(message); - var light = message.light; - makeSliders(light); + + print('MESSAGE LIGHT:::' + message) + makeSliders(parsedMessage.light); } +function handleValueMessages(channel, message, sender) { + + + if (channel !== 'Hifi-Slider-Value-Reciever') { + return; + } + print('HANDLE VALUE MESSAGE') + //easily protect from other people editing your values, but group editing might be fun so lets try that first. + // if (sender !== MyAvatar.sessionUUID) { + // return; + // } + var parsedMessage = JSON.parse(message); + + slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage) + + // this.setValueFromMessage(parsedMessage); +} + +function cleanup() { + while (sliders.length > 0) { + var slider = sliders.pop(); + slider.cleanup(); + } + Messages.messageReceived.disconnect(handleLightModMessages); + delete sliders +} + +Script.scriptEnding.connect(cleanup); subScribeToNewLights(); - // diffuseColor: { red: 255, green: 255, blue: 255 }, - // ambientColor: { red: 255, green: 255, blue: 255 }, - // specularColor: { red: 255, green: 255, blue: 255 }, +// diffuseColor: { red: 255, green: 255, blue: 255 }, +// ambientColor: { red: 255, green: 255, blue: 255 }, +// specularColor: { red: 255, green: 255, blue: 255 }, - // constantAttenuation: 1, - // linearAttenuation: 0, - // quadraticAttenuation: 0, - // exponent: 0, - // cutoff: 180, // in degrees \ No newline at end of file +// constantAttenuation: 1, +// linearAttenuation: 0, +// quadraticAttenuation: 0, +// exponent: 0, +// cutoff: 180, // in degrees \ No newline at end of file diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js index eeb5f4ffd7..4cc0058bea 100644 --- a/examples/lights/testScene.js +++ b/examples/lights/testScene.js @@ -12,7 +12,7 @@ var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_RANGE * 3, Quat.getFront(avatarRot))); + basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); var ground = Entities.addEntity({ type: "Model", @@ -28,11 +28,14 @@ var light, block; - basePosition.y += 2; + // basePosition.y += 2; function createLight() { + print('making light' + block) + var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); + var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); var lightProperties = { - name: 'Hifi-Spotlight' + name: 'Hifi-Spotlight', type: "Light", isSpotlight: true, dimensions: { @@ -40,33 +43,40 @@ y: 2, z: 20 }, - parentID: box, + parentID: block, color: { red: 255, - green: 255, + green: 0, blue: 255 }, intensity: 2, exponent: 0.3, cutoff: 20, - lifetime: LIFETIME, + lifetime: -1, position: lightTransform.p, - rotation: lightTransform.q, - } + rotation: lightTransform.q + }; + light = Entities.addEntity(lightProperties); var message = { light: { id: light, type: 'spotlight', - initialProperties:lightProperties + initialProperties: lightProperties } }; + Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); + print('SENT MESSAGE') } function createBlock() { + print('making block'); + + var position = basePosition; + position.y += 5; var blockProperties = { name: 'Hifi-Spotlight-Block', type: 'Box', @@ -76,16 +86,15 @@ z: 1 }, collisionsWillMove: true, - shapeType: 'Box', color: { red: 0, - green: 0 + green: 0, blue: 255 }, - position: basePosition + position: position } - block = Entities.addEntity(block); + block = Entities.addEntity(blockProperties); } function evalLightWorldTransform(modelPos, modelRot) { @@ -96,9 +105,12 @@ } function cleanup() { + Entities.deleteEntity(block); Entities.deleteEntity(ground); Entities.deleteEntity(light); } + Script.scriptEnding.connect(cleanup); + createBlock(); createLight(); \ No newline at end of file From 8bdced85763a6b8643d8f1b0bf63fa921b4747cd Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 16:51:12 -0800 Subject: [PATCH 063/318] more work --- examples/lights/box.js | 22 +++++++++++++++++----- examples/lights/light_modifier.js | 26 +++++++++++++++----------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index a8e708b344..e43ae22a49 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -26,7 +26,8 @@ this.initialProperties = Entities.getEntityProperties(this.entityID); }, getClampedPosition: function() { - dPosition = Vec3.subtract(MyAvatar.position, previousPosition); + + dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); //convert to localFrame dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); @@ -39,8 +40,19 @@ continueDistantGrab: function() { var currentPosition = this.getClampedPosition(); var distance = Vec3.distance(this.initialProperties.position, currentPosition); - if () - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance); + + if (userData.sliderType === 'color_red' || userData.sliderType === 'color_green' || userData.sliderType === 'color_blue') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); + } + if (userData.sliderType === 'intensity') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); + } + if (userData.sliderType === 'cutoff') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); + } + if (userData.sliderType === 'exponent') { + this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); + } Entities.editEntity(this.entityID) { position: currentPosition, @@ -67,8 +79,8 @@ }, sendValueToSlider: function() { var message = { - lightID:userData.lightID, - sliderType:userData.sliderType, + lightID: userData.lightID, + sliderType: userData.sliderType, sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index f1c27b4e4b..983ea5bcb9 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -1,6 +1,8 @@ // given a selected light, instantiate some entities that represent various values you can dynamically adjust // + + var BOX_SCRIPT_URL = Script.resolvePath('box.js'); var RED = { @@ -54,6 +56,9 @@ function entitySlider(light, color, sliderType, row) { this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(this.avatarRot))); + var message = { lightID: this.lightID, sliderType: this.sliderType, @@ -97,8 +102,14 @@ function entitySlider(light, color, sliderType, row) { entitySlider.prototype = { createAxis: function() { //start of line - var position; - //1 meter along orientationAxis + var position = Vec3.sum(this.basePosition, this.verticalOffset); + + //line starts on left and goes to right + //set the end of the line to the right + var rightVector = Quat.getRight(this.avatarRot); + var extension = Vec3.multiply(AXIS_SCALE, rightVector); + var endOfAxis = Vec3.sum(position, extension); + var endOfAxis; var properties = { type: 'Line', @@ -139,8 +150,6 @@ entitySlider.prototype = { this.boxIndicator = Entities.addEntity(properties); }, setValueFromMessage: function(message) { - print('VALUE MESSAGE::'+JSON.stringify(message)) - print('LIGHT ID::'+this.lightID); //message is not for our light if (message.lightID !== this.lightID) { @@ -154,10 +163,9 @@ entitySlider.prototype = { return } - print('SHOULD SET SOME VALUE:::' + message.sliderType); + print('should set:::' + this.sliderType); var lightProperties = Entities.getEntityProperties(this.lightID); - // print('LIGHT PROPERTIES::'+JSON.stringify(lightProperties)); if (this.sliderType === 'color_red') { Entities.editEntity(this.lightID, { @@ -190,7 +198,6 @@ entitySlider.prototype = { } if (this.sliderType === 'intensity') { - print('CHANGING INTENSITY TO::' + message.sliderValue) Entities.editEntity(this.lightID, { intensity: message.sliderValue }); @@ -209,7 +216,6 @@ entitySlider.prototype = { } }, subscribeToBoxMessages: function() { - print('subscribing to box messages'); Messages.subscribe('Hifi-Slider-Value-Reciever'); Messages.messageReceived.connect(handleValueMessages); }, @@ -296,17 +302,15 @@ function handleLightModMessages(channel, message, sender) { } var parsedMessage = JSON.parse(message); - print('MESSAGE LIGHT:::' + message) makeSliders(parsedMessage.light); } function handleValueMessages(channel, message, sender) { - + if (channel !== 'Hifi-Slider-Value-Reciever') { return; } - print('HANDLE VALUE MESSAGE') //easily protect from other people editing your values, but group editing might be fun so lets try that first. // if (sender !== MyAvatar.sessionUUID) { // return; From 112dd4209b3efa8032c8b5918429c3b633d2a85f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 17:27:01 -0800 Subject: [PATCH 064/318] prep for incoming --- examples/lights/box.js | 2 +- examples/lights/light_modifier.js | 49 ++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index e43ae22a49..806d6be389 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -72,7 +72,7 @@ }, scaleValueBasedOnDistanceFromStart: function(value, max2) { var min1 = 0; - var max1 = 1; + var max1 = AXIS_SCALE; var min2 = 0; var max2 = max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 983ea5bcb9..ac29b65f74 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -93,8 +93,10 @@ function entitySlider(light, color, sliderType, row) { this.setValueFromMessage(message); } - // this.setInitialSliderPositions(); + this.setInitialSliderPositions(); this.subscribeToBoxMessages(); + this.createAxis(); + this.createBoxIndicator(); return this; } @@ -133,11 +135,37 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, createBoxIndicator: function() { + var position = Vec3.sum(this.basePosition, this.verticalOffset); + + //line starts on left and goes to right + //set the end of the line to the right + var rightVector = Quat.getRight(this.avatarRot); + var initialDistance; + if (this.sliderType === 'color_red') { + initialDistance = this.distanceRed; + } + if (this.sliderType === 'color_green') { + initialDistance = this.distanceGreen; + } + if (this.sliderType === 'color_blue') { + initialDistance = this.distanceBlue; + } + if (this.sliderType === 'intensity') { + initialDistance = this.distanceRed; + } + if (this.sliderType === 'cutoff') { + initialDistance = this.distanceCutoff; + } + if (this.sliderType === 'exponent') { + initialDistance = this.distanceExponent; + } + var extension = Vec3.multiply(initialDistance, rightVector); + var endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Box', dimensions: BOX_DIMENSIONS, color: this.color, - position: position, + position: endOfAxis, script: BOX_SCRIPT_URL, userData: JSON.stringify({ lightModifierKey: { @@ -225,12 +253,12 @@ entitySlider.prototype = { var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; - var distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; - var distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; - var distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; - var distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; - var distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; - var distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; + this.distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; + this.distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; + this.distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; + this.distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; + this.distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; + this.distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; }, cleanup: function() { Entities.deleteEntity(this.boxIndicator); @@ -307,7 +335,6 @@ function handleLightModMessages(channel, message, sender) { function handleValueMessages(channel, message, sender) { - if (channel !== 'Hifi-Slider-Value-Reciever') { return; } @@ -318,8 +345,6 @@ function handleValueMessages(channel, message, sender) { var parsedMessage = JSON.parse(message); slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage) - - // this.setValueFromMessage(parsedMessage); } function cleanup() { @@ -334,6 +359,8 @@ function cleanup() { Script.scriptEnding.connect(cleanup); subScribeToNewLights(); + +//other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, // ambientColor: { red: 255, green: 255, blue: 255 }, // specularColor: { red: 255, green: 255, blue: 255 }, From 109aa89619b10fc108c2980a47933d4596a95631 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 14 Dec 2015 18:42:00 -0800 Subject: [PATCH 065/318] end of day --- examples/lights/box.js | 22 +++++++++++----------- examples/lights/light_modifier.js | 3 +++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/lights/box.js b/examples/lights/box.js index 806d6be389..b1f9252073 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -13,8 +13,9 @@ Box.prototype = { preload: function(entityID) { this.entityID = entityID; - var userData = Entities.getEntityProperties(this.entityID, "userData"); - this.userData = JSON.parse(userData); + var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + var parsedUserData = JSON.parse(entityProperties.userData); + var userData = parsedUserData.lightModifierKey; }, startNearGrab: function() { this.setInitialProperties(); @@ -26,10 +27,10 @@ this.initialProperties = Entities.getEntityProperties(this.entityID); }, getClampedPosition: function() { - - dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); + var dPosition; + // dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); //convert to localFrame - dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); + // dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); return dPosition; }, @@ -52,12 +53,12 @@ } if (userData.sliderType === 'exponent') { this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); - } + }; - Entities.editEntity(this.entityID) { + Entities.editEntity(this.entityID, { position: currentPosition, - rotation: this.getClampedRotation() - } + // rotation: this.getClampedRotation() + }); }, releaseGrab: function() { Entities.editEntity(this.entityID, { @@ -84,8 +85,7 @@ sliderValue: this.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); - }; - + } }; return new Box(); diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index ac29b65f74..2e11c5e22e 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -115,6 +115,7 @@ entitySlider.prototype = { var endOfAxis; var properties = { type: 'Line', + name: 'Hifi-Slider-Axis::'+this.sliderType, color: this.color, collisionsWillMove: false, ignoreForCollisions: true, @@ -135,6 +136,7 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, createBoxIndicator: function() { + print('BOX COLOR IS:::'+JSON.stringify(this.color)); var position = Vec3.sum(this.basePosition, this.verticalOffset); //line starts on left and goes to right @@ -163,6 +165,7 @@ entitySlider.prototype = { var endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Box', + name: 'Hifi-Slider::'+this.sliderType, dimensions: BOX_DIMENSIONS, color: this.color, position: endOfAxis, From 2bbd5d86b8f72e092c68aed2a0c7fa8bd88ecb2d Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Dec 2015 09:46:18 -0800 Subject: [PATCH 066/318] cleaning indentation --- .../render-utils/src/RenderDeferredTask.cpp | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index d9b5c1caf6..5f9cb7b575 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -52,25 +52,21 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren RenderDeferredTask::RenderDeferredTask() : Task() { // CPU only, create the list of renderedOpaques items _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", - FetchItems( - [](const RenderContextPointer& context, int count) { - context->_numFeedOpaqueItems = count; - } - ) - ))); + FetchItems([](const RenderContextPointer& context, int count) { + context->_numFeedOpaqueItems = count; + }) + ))); _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput()))); auto& renderedOpaques = _jobs.back().getOutput(); // CPU only, create the list of renderedTransparents items _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", - FetchItems( - ItemFilter::Builder::transparentShape().withoutLayered(), - [](const RenderContextPointer& context, int count) { - context->_numFeedTransparentItems = count; - } - ) - ))); + FetchItems(ItemFilter::Builder::transparentShape().withoutLayered(), + [](const RenderContextPointer& context, int count) { + context->_numFeedTransparentItems = count; + }) + ))); _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); _jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false)))); auto& renderedTransparents = _jobs.back().getOutput(); From c561a53f7c283a7c80e7aa7d921409f73a4971d7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 09:56:28 -0800 Subject: [PATCH 067/318] Going to change additive blending to world position prop --- .../flowArts/lightBall/lightBallSpawner.js | 151 ++++++++++-------- .../RenderableParticleEffectEntityItem.cpp | 4 +- .../entities/src/ParticleEffectEntityItem.cpp | 17 +- 3 files changed, 102 insertions(+), 70 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index da09829257..8f220129b2 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -1,81 +1,101 @@ + +Script.include("../../libraries/utils.js"); + var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); +var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); + +var raveRoom = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: center, + visible:false +}); + +var colorPalette = [{ + red: 250, + green: 137, + blue: 162 +}, { + red: 204, + green: 244, + blue: 249 +}, { + red: 146, + green: 206, + blue: 116 +}, { + red: 240, + green: 87, + blue: 129 +}]; + var containerBall = Entities.addEntity({ type: "Sphere", position: center, dimensions: {x: .1, y: .1, z: .1}, - color: {red: 50, green: 10, blue: 50}, + color: {red: 1500, green: 10, blue: 50}, collisionsWillMove: true, - gravity: {x: 0, y: -.1, z: 0} + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 2, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + // gravity: {x: 0, y: -.1, z: 0} }); +var lightZone = Entities.addEntity({ + type: "Zone", + shapeType: 'box', + keyLightIntensity: 0.2, + keyLightColor: { + red: 50, + green: 0, + blue: 50 + }, + keyLightAmbientIntensity: .2, + position: MyAvatar.position, + dimensions: { + x: 100, + y: 100, + z: 100 + } +}); + +var light = Entities.addEntity({ + type: 'Light', + position: center, + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + var lightBall = Entities.addEntity({ position: center, type: "ParticleEffect", parentID: containerBall, isEmitting: true, "name": "ParticlesTest Emitter", - "colorStart": {red: 20, green: 20, blue: 255}, + "colorStart": {red: 200, green: 20, blue: 40}, color: {red: 10, green: 0, blue: 255}, "colorFinish": {red: 250, green: 200, blue:255}, - "maxParticles": 20000, - "lifespan": 1, - "emitRate": 10000, - "emitSpeed": .1, - "speedSpread": .01, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": 3, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .01, - "y": .01, - "z": .01 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - "additiveBlending": 0, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" -}) - -var containerBall2 = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), - dimensions: {x: .1, y: .1, z: .1}, - color: {red: 200, green: 10, blue: 50}, - collisionsWillMove: true, - gravity: {x: 0, y: -.1, z: 0} -}); - -var lightBall2 = Entities.addEntity({ - position: Vec3.sum(center, {x: 0.5, y: 0, z: 0}), - type: "ParticleEffect", - parentID: containerBall2, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": {red: 200, green: 20, blue: 0}, - color: {red: 255, green: 0, blue: 10}, - "colorFinish": {red: 250, green: 200, blue:255}, "maxParticles": 100000, - "lifespan": 1, + "lifespan": 7, "emitRate": 10000, - "emitSpeed": .1, + "emitSpeed": .02, "speedSpread": .01, "emitDimensions": { "x": 0, @@ -83,9 +103,9 @@ var lightBall2 = Entities.addEntity({ "z": 0 }, "polarStart": 0, - "polarFinish": 3, - "azimuthStart": -3.1415927410125732, - "azimuthFinish": 3.1415927410125732, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, "emitAcceleration": { "x": 0, "y": 0, @@ -108,11 +128,14 @@ var lightBall2 = Entities.addEntity({ "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" }) + + function cleanup() { Entities.deleteEntity(lightBall); - Entities.deleteEntity(lightBall2); Entities.deleteEntity(containerBall); - Entities.deleteEntity(containerBall2); + Entities.deleteEntity(raveRoom); + Entities.deleteEntity(lightZone) + Entities.deleteEntity(light); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 4abd8dbafd..42e9fa446c 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -240,8 +240,8 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { auto position = getPosition(); auto rotation = getRotation(); Transform transform; - transform.setTranslation(position); - transform.setRotation(rotation); + //transform.setTranslation(position); + // transform.setRotation(rotation); render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f4210f4486..8f6f60fa26 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "EntityTree.h" #include "EntityTreeElement.h" @@ -640,12 +642,18 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { Particle particle; - particle.seed = randFloatInRange(0.0f, 1.0f); - + std::random_device rd; + + std::mt19937_64 el(rd()); + std::uniform_real_distribution uniform_dist(-1.0, 1.0); + + particle.seed = randFloatInRange(-1.0f, 1.0f); + particle.position = getPosition(); // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { // Emit along z-axis from position - particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); + + particle.velocity = (_emitSpeed + 0.2f * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } else { @@ -691,10 +699,11 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f )); - particle.position = _emitOrientation * emitPosition; + particle.position += _emitOrientation * emitPosition; } particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); + // particle.velocity = (_emitSpeed + uniform_dist(el) * _speedSpread) * (_emitOrientation * emitDirection); particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } From dca83a054ea3b278e1ca2a8f1c1cb23e1740ff19 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 10:30:57 -0800 Subject: [PATCH 068/318] Changed additiveBlending to emitterShouldTrail --- .../flowArts/lightBall/lightBallSpawner.js | 9 ++++---- .../RenderableParticleEffectEntityItem.cpp | 6 +++-- .../entities/src/EntityItemProperties.cpp | 16 ++++++------- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/EntityPropertyFlags.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 23 ++++++++++++------- .../entities/src/ParticleEffectEntityItem.h | 10 ++++---- 7 files changed, 39 insertions(+), 29 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 8f220129b2..7744c1210e 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -41,7 +41,7 @@ var containerBall = Entities.addEntity({ spatialKey: { relativePosition: { x: 0, - y: 2, + y: 1, z: 0 } }, @@ -93,9 +93,9 @@ var lightBall = Entities.addEntity({ color: {red: 10, green: 0, blue: 255}, "colorFinish": {red: 250, green: 200, blue:255}, "maxParticles": 100000, - "lifespan": 7, + "lifespan": 2, "emitRate": 10000, - "emitSpeed": .02, + "emitSpeed": .2, "speedSpread": .01, "emitDimensions": { "x": 0, @@ -125,7 +125,8 @@ var lightBall = Entities.addEntity({ "alphaStart": 0, "alphaFinish": 0.5, "additiveBlending": 0, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: false }) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 42e9fa446c..91a4811011 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -240,8 +240,10 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { auto position = getPosition(); auto rotation = getRotation(); Transform transform; - //transform.setTranslation(position); - // transform.setRotation(rotation); + if (!getEmitterShouldTrail()) { + transform.setTranslation(position); + transform.setRotation(rotation); + } render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 98a099fcaa..3a2fdf55d4 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -195,7 +195,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish); - CHECK_PROPERTY_CHANGE(PROP_ADDITIVE_BLENDING, additiveBlending); + CHECK_PROPERTY_CHANGE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); @@ -354,7 +354,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); } @@ -515,7 +515,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(additiveBlending, bool, setAdditiveBlending); + COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); @@ -670,7 +670,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float); ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float); ADD_PROPERTY_TO_MAP(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float); - ADD_PROPERTY_TO_MAP(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool); + ADD_PROPERTY_TO_MAP(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool); ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString); ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3); @@ -980,7 +980,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); - APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, properties.getAdditiveBlending()); + APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail()); } if (properties.getType() == EntityTypes::Zone) { @@ -1265,7 +1265,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); } if (properties.getType() == EntityTypes::Zone) { @@ -1608,8 +1608,8 @@ QList EntityItemProperties::listChangedProperties() { if (alphaFinishChanged()) { out += "alphaFinish"; } - if (additiveBlendingChanged()) { - out += "additiveBlending"; + if (emitterShouldTrailChanged()) { + out += "emitterShouldTrail"; } if (modelURLChanged()) { out += "modelURL"; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c13519996a..5420e75aed 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -161,7 +161,7 @@ public: DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD); DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float, ParticleEffectEntityItem::DEFAULT_RADIUS_START); DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH); - DEFINE_PROPERTY(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool, ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING); + DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID); DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup); DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 3bca911a56..2ba86a491e 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -149,7 +149,7 @@ enum EntityPropertyList { PROP_ANIMATION_HOLD, PROP_ANIMATION_START_AUTOMATICALLY, - PROP_ADDITIVE_BLENDING, + PROP_EMITTER_SHOULD_TRAIL, PROP_PARENT_ID, PROP_PARENT_JOINT_INDEX, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 8f6f60fa26..7d9af11862 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -93,7 +93,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; -const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false; +const bool ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL = false; EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -333,7 +333,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(additiveBlending, getAdditiveBlending); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail); return properties; @@ -372,7 +372,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(additiveBlending, setAdditiveBlending); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail); if (somethingChanged) { bool wantDebug = false; @@ -465,7 +465,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch } if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) { - READ_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending); + READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); } return bytesRead; @@ -505,7 +505,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_POLAR_FINISH; requestedProperties += PROP_AZIMUTH_START; requestedProperties += PROP_AZIMUTH_FINISH; - requestedProperties += PROP_ADDITIVE_BLENDING; + requestedProperties += PROP_EMITTER_SHOULD_TRAIL; return requestedProperties; } @@ -548,7 +548,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart()); APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish()); - APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, getAdditiveBlending()); + APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail()); } bool ParticleEffectEntityItem::isEmittingParticles() const { @@ -648,7 +648,9 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { std::uniform_real_distribution uniform_dist(-1.0, 1.0); particle.seed = randFloatInRange(-1.0f, 1.0f); - particle.position = getPosition(); + if (getEmitterShouldTrail()) { + particle.position = getPosition(); + } // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { // Emit along z-axis from position @@ -699,7 +701,12 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f )); - particle.position += _emitOrientation * emitPosition; + if (getEmitterShouldTrail()) { + particle.position += _emitOrientation * emitPosition; + } + else { + particle.position = _emitOrientation * emitPosition; + } } particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index c35a45baeb..7bedbde6d8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -207,10 +207,10 @@ public: } } - static const bool DEFAULT_ADDITIVE_BLENDING; - bool getAdditiveBlending() const { return _additiveBlending; } - void setAdditiveBlending(bool additiveBlending) { - _additiveBlending = additiveBlending; + static const bool DEFAULT_EMITTER_SHOULD_TRAIL; + bool getEmitterShouldTrail() const { return _emitterShouldTrail; } + void setEmitterShouldTrail(bool emitterShouldTrail) { + _emitterShouldTrail = emitterShouldTrail; } virtual bool supportsDetailedRayIntersection() const { return false; } @@ -280,7 +280,7 @@ protected: float _timeUntilNextEmit { 0.0f }; - bool _additiveBlending { DEFAULT_ADDITIVE_BLENDING }; + bool _emitterShouldTrail { DEFAULT_EMITTER_SHOULD_TRAIL }; }; #endif // hifi_ParticleEffectEntityItem_h From 8e7a2ac5362349aab0c0af4a697733b79a6e493e Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Tue, 15 Dec 2015 15:41:36 -0800 Subject: [PATCH 069/318] Exposing emmisive property of the Image3DOverlay --- interface/src/ui/overlays/Image3DOverlay.cpp | 18 ++++++++++++++---- interface/src/ui/overlays/Image3DOverlay.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 11fb647f01..6e4c274943 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -26,14 +26,16 @@ QString const Image3DOverlay::TYPE = "image3d"; Image3DOverlay::Image3DOverlay() { - _isLoaded = false; + _isLoaded = false; + _emmisive = false; } Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : Billboard3DOverlay(image3DOverlay), _url(image3DOverlay->_url), _texture(image3DOverlay->_texture), - _fromImage(image3DOverlay->_fromImage) + _fromImage(image3DOverlay->_fromImage), + _emmisive(image3DOverlay->_emmisive) { } @@ -93,8 +95,8 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - - DependencyManager::get()->bindSimpleProgram(*batch, true, false, false, true); + + DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emmisive, true); DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) @@ -144,6 +146,11 @@ void Image3DOverlay::setProperties(const QScriptValue &properties) { setClipFromSource(subImageRect); } } + + QScriptValue emmisiveValue = properties.property("emmisive"); + if (emmisiveValue.isValid()) { + _emmisive = emmisiveValue.toBool(); + } } QScriptValue Image3DOverlay::getProperty(const QString& property) { @@ -156,6 +163,9 @@ QScriptValue Image3DOverlay::getProperty(const QString& property) { if (property == "offsetPosition") { return vec3toScriptValue(_scriptEngine, getOffsetPosition()); } + if (property == "emmisive") { + return _emmisive; + } return Billboard3DOverlay::getProperty(property); } diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index f848023fbe..0e40c73619 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -46,6 +46,7 @@ public: private: QString _url; NetworkTexturePointer _texture; + bool _emmisive; QRect _fromImage; // where from in the image to sample }; From d4f55ed6d2da961544888a74b22fb45777cbbf8a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 15 Dec 2015 15:55:03 -0800 Subject: [PATCH 070/318] working lsiders --- examples/controllers/handControllerGrab.js | 56 ++++++++++++++++- examples/lights/box.js | 73 +++++++++++++--------- examples/lights/light_modifier.js | 61 ++++++++++-------- examples/lights/testScene.js | 1 + 4 files changed, 135 insertions(+), 56 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 07894b46d1..d9e75c8836 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -816,6 +816,19 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + var defaultConstrainData = { + axisBasePosition:false, + endOfAxis: false, + } + + var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstrainData); + + // var constrainX = constraintData.constrain.x; + // var constrainY = constraintData.constrain.y; + // var constrainZ = constraintData.constrain.z; + + // print('constrainY'+constrainY); + // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); @@ -826,8 +839,21 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } + var clampedVector; + var targetPosition; + if (constraintData.axisBasePosition !== false) { + clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisBasePosition, constraintData.endOfAxis); + targetPosition = clampedVector; + } else { + targetPosition = { + x: this.currentObjectPosition.x, + y: this.currentObjectPosition.y, + z: this.currentObjectPosition.z + } + } + Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, + targetPosition: targetPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, @@ -836,6 +862,34 @@ function MyController(hand) { this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); }; + this.projectVectorAlongAxis = function(position, axisStart, axisEnd) { + + var aPrime = Vec3.subtract(position, axisStart); + + var bPrime = Vec3.subtract(axisEnd, axisStart); + + var bPrimeMagnitude = Vec3.length(bPrime); + + var dotProduct = Vec3.dot(aPrime, bPrime); + + var scalar = dotProduct / bPrimeMagnitude; + + print('SCALAR:::'+scalar); + + if(scalar<0){ + scalar = 0; + } + + if(scalar>1){ + scalar = 1; + } + + var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); + + return projection + + }, + this.nearGrabbing = function() { var now = Date.now(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); diff --git a/examples/lights/box.js b/examples/lights/box.js index b1f9252073..3bcebc64d3 100644 --- a/examples/lights/box.js +++ b/examples/lights/box.js @@ -14,51 +14,64 @@ preload: function(entityID) { this.entityID = entityID; var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + print('USER DATA:::' + entityProperties.userData) var parsedUserData = JSON.parse(entityProperties.userData); - var userData = parsedUserData.lightModifierKey; + this.userData = parsedUserData.lightModifierKey; + this.bPrime = Vec3.subtract(this.userData.endOfAxis, this.userData.axisBasePosition); + this.bPrimeMagnitude = Vec3.length(this.bPrime); + }, startNearGrab: function() { this.setInitialProperties(); }, startDistantGrab: function() { + // Entities.editEntity(this.entityID, { + // parentID: MyAvatar.sessionUUID, + // parentJointIndex: MyAvatar.getJointIndex("LeftHand") + // }); this.setInitialProperties(); }, setInitialProperties: function() { this.initialProperties = Entities.getEntityProperties(this.entityID); }, - getClampedPosition: function() { - var dPosition; - // dPosition = Vec3.subtract(MyAvatar.position, this.previousPosition); - //convert to localFrame - // dPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), dPosition); + clampPosition: function() { + + var currentProperties = Entities.getEntityProperties(this.entityID); + + var aPrime = Vec3.subtract(this.userData.axisBasePosition, currentProperties.position); + + var dotProduct = Vec3.dot(aPrime, this.bPrime); + + var scalar = dotProduct / this.bPrimeMagnitude; + + print('SCALAR:::' + scalar); + + var projection = Vec3.sum(this.userData.axisBasePosition, Vec3.multiply(scalar, Vec3.normalize(this.bPrime))); + + this.currentProjection = projection; - return dPosition; - }, - getClampedRotation: function() { - var rotation = initialProperties.rotation; - return rotation; }, continueDistantGrab: function() { - var currentPosition = this.getClampedPosition(); - var distance = Vec3.distance(this.initialProperties.position, currentPosition); + // this.clampPosition(); + print('distant grab') + var currentPosition = Entities.getEntityProperties(this.entityID, "position").position; - if (userData.sliderType === 'color_red' || userData.sliderType === 'color_green' || userData.sliderType === 'color_blue') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); + var distance = Vec3.distance(this.axisBasePosition, this.currentProjection); + + if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); } - if (userData.sliderType === 'intensity') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); + if (this.userData.sliderType === 'intensity') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); } - if (userData.sliderType === 'cutoff') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); + if (this.userData.sliderType === 'cutoff') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); } - if (userData.sliderType === 'exponent') { - this.sliderValue = scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); + if (this.userData.sliderType === 'exponent') { + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; - Entities.editEntity(this.entityID, { - position: currentPosition, - // rotation: this.getClampedRotation() - }); + }, releaseGrab: function() { Entities.editEntity(this.entityID, { @@ -66,7 +79,8 @@ x: 0, y: 0, z: 0 - } + }, + parentID: null }) this.sendValueToSlider(); @@ -79,10 +93,11 @@ return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, sendValueToSlider: function() { + var _t = this; var message = { - lightID: userData.lightID, - sliderType: userData.sliderType, - sliderValue: this.sliderValue + lightID: _t.userData.lightID, + sliderType: _t.userData.sliderType, + sliderValue: _t.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); } diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index 2e11c5e22e..f54af5b54f 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -3,36 +3,36 @@ -var BOX_SCRIPT_URL = Script.resolvePath('box.js'); +var BOX_SCRIPT_URL = Script.resolvePath('box.js?'+Math.random(0,100)); var RED = { - r: 255, - g: 0, - b: 0 + red: 255, + green: 0, + blue: 0 }; var GREEN = { - r: 0, - g: 255, - b: 0 + red: 0, + green: 255, + blue: 0 }; var BLUE = { - r: 0, - g: 0, - b: 255 + red: 0, + green: 0, + blue: 255 }; var PURPLE = { - r: 255, - g: 0, - b: 255 + red: 255, + green: 0, + blue: 255 }; var WHITE = { - r: 255, - g: 255, - b: 255 + red: 255, + green: 255, + blue: 255 }; var AXIS_SCALE = 1; @@ -44,7 +44,7 @@ var BOX_DIMENSIONS = { }; var PER_ROW_OFFSET = { x: 0, - y: 0.2, + y: -0.2, z: 0 }; @@ -55,6 +55,7 @@ function entitySlider(light, color, sliderType, row) { this.color = color; this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + print('slider : ' + this.sliderType + "should have an offset of : " + this.verticalOffset); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(this.avatarRot))); @@ -111,11 +112,11 @@ entitySlider.prototype = { var rightVector = Quat.getRight(this.avatarRot); var extension = Vec3.multiply(AXIS_SCALE, rightVector); var endOfAxis = Vec3.sum(position, extension); - - var endOfAxis; + this.endOfAxis = endOfAxis; + print('endOfAxis:::' + JSON.stringify(endOfAxis)) var properties = { type: 'Line', - name: 'Hifi-Slider-Axis::'+this.sliderType, + name: 'Hifi-Slider-Axis::' + this.sliderType, color: this.color, collisionsWillMove: false, ignoreForCollisions: true, @@ -129,14 +130,14 @@ entitySlider.prototype = { x: 0, y: 0, z: 0 - }, endOfAxis], + }, extension], lineWidth: 5, }; this.axis = Entities.addEntity(properties); }, createBoxIndicator: function() { - print('BOX COLOR IS:::'+JSON.stringify(this.color)); + print('BOX COLOR IS:::' + JSON.stringify(this.color)); var position = Vec3.sum(this.basePosition, this.verticalOffset); //line starts on left and goes to right @@ -162,18 +163,26 @@ entitySlider.prototype = { initialDistance = this.distanceExponent; } var extension = Vec3.multiply(initialDistance, rightVector); - var endOfAxis = Vec3.sum(position, extension); + var sliderPosition = Vec3.sum(position, extension); var properties = { type: 'Box', - name: 'Hifi-Slider::'+this.sliderType, + name: 'Hifi-Slider::' + this.sliderType, dimensions: BOX_DIMENSIONS, + collisionsWillMove: true, color: this.color, - position: endOfAxis, + position: sliderPosition, script: BOX_SCRIPT_URL, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, - sliderType: this.sliderType + sliderType: this.sliderType, + axisBasePosition: position, + endOfAxis: this.endOfAxis, + }, + constraintKey: { + constrain: { + y: position.y + } } }) }; diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js index 4cc0058bea..0e0a226c0b 100644 --- a/examples/lights/testScene.js +++ b/examples/lights/testScene.js @@ -15,6 +15,7 @@ basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); var ground = Entities.addEntity({ + name:'Hifi-Light-Mod-Floor', type: "Model", modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", dimensions: { From 30480f126bf3d407b40e0f85f70234057bf1d588 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 15 Dec 2015 17:26:17 -0800 Subject: [PATCH 071/318] Improved idle to walk forward transition Hooked up a transition animation from idle to walk in the animation json. Also fixed a bug in the AnimBlendLinearMove which was preventing the interpolation into idle from being correct. --- .../defaultAvatar_full/avatar-animation.json | 35 ++++++++++++++++--- .../animation/src/AnimBlendLinearMove.cpp | 2 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index ae470509be..d63942c510 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -415,10 +415,25 @@ "states": [ { "id": "idle", - "interpTarget": 15, - "interpDuration": 15, + "interpTarget": 10, + "interpDuration": 10, "transitions": [ - { "var": "isMovingForward", "state": "walkFwd" }, + { "var": "isMovingForward", "state": "idleToWalkFwd" }, + { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isAway", "state": "awayIntro" } + ] + }, + { + "id": "idleToWalkFwd", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "idleToWalkFwdOnDone", "state": "walkFwd" }, + { "var": "isNotMoving", "state": "idle" }, { "var": "isMovingBackward", "state": "walkBwd" }, { "var": "isMovingRight", "state": "strafeRight" }, { "var": "isMovingLeft", "state": "strafeLeft" }, @@ -429,7 +444,7 @@ }, { "id": "walkFwd", - "interpTarget": 6, + "interpTarget": 15, "interpDuration": 6, "transitions": [ { "var": "isNotMoving", "state": "idle" }, @@ -638,6 +653,18 @@ } ] }, + { + "id": "idleToWalkFwd", + "type": "clip", + "data": { + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims/idle_to_walk.fbx", + "startFrame": 1.0, + "endFrame": 19.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, { "id": "walkBwd", "type": "blendLinearMove", diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index 3be6a0f1b8..609b464512 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -122,5 +122,5 @@ void AnimBlendLinearMove::setCurrentFrameInternal(float frame) { auto clipNode = std::dynamic_pointer_cast(_children.front()); assert(clipNode); const float NUM_FRAMES = (clipNode->getEndFrame() - clipNode->getStartFrame()) + 1.0f; - _phase = fmodf(frame, NUM_FRAMES); + _phase = fmodf(frame / NUM_FRAMES, 1.0f); } From d9c93130e5a148a2758e9c7016a16467cbd7b5b3 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 18:02:11 -0800 Subject: [PATCH 072/318] In a state where non uniform random vals are clear --- .../flowArts/lightBall/lightBallSpawner.js | 39 +++++++------------ .../entities/src/ParticleEffectEntityItem.cpp | 2 +- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 7744c1210e..dd521b4fd4 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -12,21 +12,9 @@ var raveRoom = Entities.addEntity({ }); var colorPalette = [{ - red: 250, - green: 137, + red: 25, + green: 20, blue: 162 -}, { - red: 204, - green: 244, - blue: 249 -}, { - red: 146, - green: 206, - blue: 116 -}, { - red: 240, - green: 87, - blue: 129 }]; @@ -34,7 +22,7 @@ var containerBall = Entities.addEntity({ type: "Sphere", position: center, dimensions: {x: .1, y: .1, z: .1}, - color: {red: 1500, green: 10, blue: 50}, + color: {red: 15, green: 10, blue: 150}, collisionsWillMove: true, userData: JSON.stringify({ grabbableKey: { @@ -90,13 +78,13 @@ var lightBall = Entities.addEntity({ isEmitting: true, "name": "ParticlesTest Emitter", "colorStart": {red: 200, green: 20, blue: 40}, - color: {red: 10, green: 0, blue: 255}, - "colorFinish": {red: 250, green: 200, blue:255}, + color: {red: 200, green: 200, blue: 255}, + "colorFinish": {red: 25, green: 20, blue:255}, "maxParticles": 100000, - "lifespan": 2, - "emitRate": 10000, - "emitSpeed": .2, - "speedSpread": .01, + "lifespan": 5, + "emitRate": 500, + "emitSpeed": .02, + "speedSpread": .0, "emitDimensions": { "x": 0, "y": 0, @@ -112,9 +100,9 @@ var lightBall = Entities.addEntity({ "z": 0 }, "accelerationSpread": { - "x": .01, - "y": .01, - "z": .01 + "x": .00, + "y": .00, + "z": .00 }, "particleRadius": 0.04, "radiusSpread": 0, @@ -124,9 +112,8 @@ var lightBall = Entities.addEntity({ "alphaSpread": .5, "alphaStart": 0, "alphaFinish": 0.5, - "additiveBlending": 0, "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: false + emitterShouldTrail: true }) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 7d9af11862..954074ec17 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -645,7 +645,7 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { std::random_device rd; std::mt19937_64 el(rd()); - std::uniform_real_distribution uniform_dist(-1.0, 1.0); + std::uniform_real_distribution uniform_dist(0.0, 1.0); particle.seed = randFloatInRange(-1.0f, 1.0f); if (getEmitterShouldTrail()) { From e9f52b12116ea4e67c2c083dae73cb6002e6fdd5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Dec 2015 14:40:30 -0800 Subject: [PATCH 073/318] properly scale avatar collision shape --- interface/src/Application.cpp | 5 +- interface/src/avatar/Avatar.cpp | 76 +++++++++++-------- interface/src/avatar/Avatar.h | 12 +-- interface/src/avatar/AvatarManager.cpp | 26 +++---- interface/src/avatar/AvatarMotionState.h | 2 +- interface/src/avatar/Hand.cpp | 6 +- interface/src/avatar/MyAvatar.cpp | 46 +++++++---- interface/src/avatar/MyAvatar.h | 5 +- .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- 14 files changed, 108 insertions(+), 82 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 930d3b0b8f..c34d2ce649 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1260,15 +1260,14 @@ void Application::paintGL() { hmdOffset.x = -hmdOffset.x; _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + mirrorBodyOrientation * hmdOffset); - } else { _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7a234f2b47..8231d1ebdd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -99,7 +99,8 @@ Avatar::Avatar(RigPointer rig) : // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); - setAvatarScale(1.0f); + setScale(glm::vec3(1.0f)); // avatar scale is uniform + // give the pointer to our head to inherited _headData variable from AvatarData _headData = static_cast(new Head(this)); _handData = static_cast(new Hand(this)); @@ -143,15 +144,28 @@ AABox Avatar::getBounds() const { float Avatar::getLODDistance() const { return DependencyManager::get()->getAvatarLODDistanceMultiplier() * - glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getAvatarScale(); + glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getUniformScale(); +} + +void Avatar::animateScaleChanges(float deltaTime) { + float currentScale = getUniformScale(); + if (currentScale != _targetScale) { + const float SCALE_ANIMATION_TIMESCALE = 1.0f; + float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + const float CLOSE_ENOUGH = 0.05f; + if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + animatedScale = _targetScale; + } + setScale(glm::vec3(animatedScale)); // avatar scale is uniform + rebuildCollisionShape(); + } } void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (getAvatarScale() != _targetScale) { - setAvatarScale(_targetScale); - } + animateScaleChanges(deltaTime); // update the billboard render flag const float BILLBOARD_HYSTERESIS_PROPORTION = 0.1f; @@ -164,7 +178,7 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; qCDebug(interfaceapp) << "Billboarding" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance(); } - + const bool isControllerLogging = DependencyManager::get()->getRenderDistanceControllerIsLogging(); float renderDistance = DependencyManager::get()->getRenderDistance(); const float SKIP_HYSTERESIS_PROPORTION = isControllerLogging ? 0.0f : BILLBOARD_HYSTERESIS_PROPORTION; @@ -210,7 +224,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.getHeadPosition(headPosition); Head* head = getHead(); head->setPosition(headPosition); - head->setScale(getAvatarScale()); + head->setScale(getUniformScale()); head->simulate(deltaTime, false, _shouldRenderBillboard); } } @@ -238,12 +252,12 @@ void Avatar::simulate(float deltaTime) { measureMotionDerivatives(deltaTime); } -bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) { +bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { const float HEAD_SPHERE_RADIUS = 0.1f; glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); glm::vec3 myEyePosition = getHead()->getEyePosition(); - return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getAvatarScale()); + return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getUniformScale()); } void Avatar::slamPosition(const glm::vec3& newPosition) { @@ -423,7 +437,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; const float LIGHT_CUTOFF = glm::radians(80.0f); - float distance = BASE_LIGHT_DISTANCE * getAvatarScale(); + float distance = BASE_LIGHT_DISTANCE * getUniformScale(); glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f); glm::quat orientation = getOrientation(); foreach (const AvatarManager::LocalLight& light, DependencyManager::get()->getLocalLights()) { @@ -479,7 +493,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); position = getHead()->getRightEyePosition(); @@ -489,7 +503,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { eyeDiameter = DEFAULT_EYE_DIAMETER; } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); } @@ -590,9 +604,9 @@ void Avatar::simulateAttachments(float deltaTime) { glm::quat jointRotation; if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && _skeletonModel.getJointRotationInWorldFrame(jointIndex, jointRotation)) { - model->setTranslation(jointPosition + jointRotation * attachment.translation * getAvatarScale()); + model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale()); model->setRotation(jointRotation * attachment.rotation); - model->setScaleToFit(true, getAvatarScale() * attachment.scale, true); // hack to force rescale + model->setScaleToFit(true, getUniformScale() * attachment.scale, true); // hack to force rescale model->setSnapModelToCenter(false); // hack to force resnap model->setSnapModelToCenter(true); model->simulate(deltaTime); @@ -647,7 +661,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } float Avatar::getBillboardSize() const { - return getAvatarScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + return getUniformScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); } #ifdef DEBUG @@ -796,7 +810,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co } void Avatar::setSkeletonOffset(const glm::vec3& offset) { - const float MAX_OFFSET_LENGTH = getAvatarScale() * 0.5f; + const float MAX_OFFSET_LENGTH = getUniformScale() * 0.5f; float offsetLength = glm::length(offset); if (offsetLength > MAX_OFFSET_LENGTH) { _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; @@ -905,7 +919,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const { void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { //Scale a world space vector as if it was relative to the position - positionToScale = getPosition() + getAvatarScale() * (positionToScale - getPosition()); + positionToScale = getPosition() + getUniformScale() * (positionToScale - getPosition()); } void Avatar::setFaceModelURL(const QUrl& faceModelURL) { @@ -945,7 +959,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { for (int i = 0; i < attachmentData.size(); i++) { _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); _attachmentModels[i]->setSnapModelToCenter(true); - _attachmentModels[i]->setScaleToFit(true, getAvatarScale() * _attachmentData.at(i).scale); + _attachmentModels[i]->setScaleToFit(true, getUniformScale() * _attachmentData.at(i).scale); } } @@ -1033,15 +1047,6 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g } } -void Avatar::setAvatarScale(float scale) { - if (_targetScale * (1.0f - RESCALING_TOLERANCE) < scale && - scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { - setScale(glm::vec3(_targetScale)); - } else { - setScale(glm::vec3(scale)); - } -} - float Avatar::getSkeletonHeight() const { Extents extents = _skeletonModel.getBindExtents(); return extents.maximum.y - extents.minimum.y; @@ -1053,7 +1058,7 @@ float Avatar::getHeadHeight() const { // HACK: We have a really odd case when fading out for some models where this value explodes float result = extents.maximum.y - extents.minimum.y; - if (result >= 0.0f && result < 100.0f * getAvatarScale() ) { + if (result >= 0.0f && result < 100.0f * getUniformScale() ) { return result; } } @@ -1096,13 +1101,20 @@ void Avatar::setShowDisplayName(bool showDisplayName) { // virtual void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { - shapeInfo.setCapsuleY(_skeletonModel.getBoundingCapsuleRadius(), 0.5f * _skeletonModel.getBoundingCapsuleHeight()); - shapeInfo.setOffset(_skeletonModel.getBoundingCapsuleOffset()); + float uniformScale = getUniformScale(); + shapeInfo.setCapsuleY(uniformScale * _skeletonModel.getBoundingCapsuleRadius(), + 0.5f * uniformScale * _skeletonModel.getBoundingCapsuleHeight()); + shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset()); } // virtual -void Avatar::rebuildSkeletonBody() { - DependencyManager::get()->updateAvatarPhysicsShape(this); +void Avatar::rebuildCollisionShape() { + if (_motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); + } else { + // adebug TODO: move most of updateAvatarPhysicsShape() to here + DependencyManager::get()->updateAvatarPhysicsShape(this); + } } glm::vec3 Avatar::getLeftPalmPosition() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cdb995efea..379ab8b627 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -36,7 +36,6 @@ namespace render { static const float SCALING_RATIO = .05f; static const float SMOOTHING_RATIO = .05f; // 0 < ratio < 1 -static const float RESCALING_TOLERANCE = .02f; static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees static const float BILLBOARD_DISTANCE = 5.56f; // meters @@ -89,7 +88,7 @@ public: SkeletonModel& getSkeletonModel() { return _skeletonModel; } const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } glm::vec3 getChestPosition() const; - float getAvatarScale() const { return getScale().y; } + float getUniformScale() const { return getScale().y; } const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } Hand* getHand() { return static_cast(_handData); } @@ -154,7 +153,7 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); - virtual void rebuildSkeletonBody(); + virtual void rebuildCollisionShape(); virtual void computeShapeInfo(ShapeInfo& shapeInfo); @@ -199,14 +198,15 @@ protected: float _stringLength; bool _moving; ///< set when position is changing - bool isLookingAtMe(AvatarSharedPointer avatar); - // protected methods... + bool isLookingAtMe(AvatarSharedPointer avatar) const; + + virtual void animateScaleChanges(float deltaTime); + glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; - void setAvatarScale(float scale); void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 7c1a52f1b3..562bea3542 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -203,7 +203,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->startUpdate(); - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); + avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); @@ -375,19 +375,17 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { - AvatarMotionState* motionState = avatar->getMotionState(); - if (motionState) { - motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); - } else { - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); - if (shape) { - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - avatar->setMotionState(motionState); - _motionStatesToAdd.insert(motionState); - _avatarMotionStates.insert(motionState); - } + // adebug TODO: move most of this logic to MyAvatar class + assert(!avatar->getMotionState()); + + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + if (shape) { + AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); + avatar->setMotionState(motionState); + _motionStatesToAdd.insert(motionState); + _avatarMotionStates.insert(motionState); } } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 1c49705f23..b5101d2c70 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -46,7 +46,7 @@ public: virtual float getObjectFriction() const; virtual float getObjectLinearDamping() const; virtual float getObjectAngularDamping() const; - + virtual glm::vec3 getObjectPosition() const; virtual glm::quat getObjectRotation() const; virtual glm::vec3 getObjectLinearVelocity() const; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 4f16449aa2..fe03d22f0b 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -37,7 +37,7 @@ void Hand::simulate(float deltaTime, bool isMine) { void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { float avatarScale = 1.0f; if (_owningAvatar) { - avatarScale = _owningAvatar->getAvatarScale(); + avatarScale = _owningAvatar->getUniformScale(); } const float alpha = 1.0f; @@ -62,7 +62,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { transform.setRotation(palm.getRotation()); transform.postScale(SPHERE_RADIUS); DependencyManager::get()->renderSolidSphereInstance(batch, transform, grayColor); - + // draw a green sphere at the old "finger tip" transform = Transform(); position = palm.getTipPosition(); @@ -72,7 +72,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { DependencyManager::get()->renderSolidSphereInstance(batch, transform, greenColor); } } - + const float AXIS_RADIUS = 0.1f * SPHERE_RADIUS; const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9331682714..926d41f1ca 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -284,13 +284,26 @@ void MyAvatar::update(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); +void MyAvatar::animateScaleChanges(float deltaTime) { + // HACK: override Avatar::animateScaleChanges() until MyAvatar has a MotionState + float currentScale = getUniformScale(); + if (currentScale != _targetScale) { + const float SCALE_ANIMATION_TIMESCALE = 1.0f; + float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + const float CLOSE_ENOUGH = 0.05f; + if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + animatedScale = _targetScale; + } + setScale(glm::vec3(animatedScale)); + rebuildCollisionShape(); + } +} + void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (getAvatarScale() != _targetScale) { - float scale = (1.0f - SMOOTHING_RATIO) * getAvatarScale() + SMOOTHING_RATIO * _targetScale; - setAvatarScale(scale); - } + animateScaleChanges(deltaTime); { PerformanceTimer perfTimer("transform"); @@ -337,7 +350,7 @@ void MyAvatar::simulate(float deltaTime) { headPosition = getPosition(); } head->setPosition(headPosition); - head->setScale(getAvatarScale()); + head->setScale(getUniformScale()); head->simulate(deltaTime, true); } @@ -681,7 +694,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setAvatarScale(getAvatarScale()); + setScale(glm::vec3(getUniformScale())); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); @@ -809,7 +822,7 @@ void MyAvatar::updateLookAtTargetAvatar() { float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition); avatar->setIsLookAtTarget(false); if (!avatar->isMyAvatar() && avatar->isInitialized() && - (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getAvatarScale())) { + (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) { float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition)); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; @@ -1036,14 +1049,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::rebuildSkeletonBody() { +void MyAvatar::rebuildCollisionShape() { // compute localAABox - float radius = _skeletonModel.getBoundingCapsuleRadius(); - float height = _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius; + float scale = getUniformScale(); + float radius = scale * _skeletonModel.getBoundingCapsuleRadius(); + float height = scale * _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius; glm::vec3 corner(-radius, -0.5f * height, -radius); - corner += _skeletonModel.getBoundingCapsuleOffset(); - glm::vec3 scale(2.0f * radius, height, 2.0f * radius); - _characterController.setLocalBoundingBox(corner, scale); + corner += scale * _skeletonModel.getBoundingCapsuleOffset(); + glm::vec3 diagonal(2.0f * radius, height, 2.0f * radius); + _characterController.setLocalBoundingBox(corner, diagonal); } void MyAvatar::prepareForPhysicsSimulation() { @@ -1331,7 +1345,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getAvatarScale()); + return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -1455,11 +1469,11 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe if (isHovering) { // we're flying --> complex acceleration curve with high max speed float motorSpeed = glm::length(_keyboardMotorVelocity); - float finalMaxMotorSpeed = getAvatarScale() * MAX_KEYBOARD_MOTOR_SPEED; + float finalMaxMotorSpeed = getUniformScale() * MAX_KEYBOARD_MOTOR_SPEED; float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - const float maxBoostSpeed = getAvatarScale() * MAX_BOOST_SPEED; + const float maxBoostSpeed = getUniformScale() * MAX_BOOST_SPEED; if (motorSpeed < maxBoostSpeed) { // an active keyboard motor should never be slower than this float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 514261bf16..bce6521c07 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -249,7 +249,7 @@ public slots: Q_INVOKABLE void updateMotionBehaviorFromMenu(); - virtual void rebuildSkeletonBody() override; + virtual void rebuildCollisionShape() override; Q_INVOKABLE QUrl getAnimGraphUrl() const { return _animGraphUrl; } @@ -263,6 +263,9 @@ public slots: glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); +protected: + void animateScaleChanges(float deltaTime); + signals: void audioListenerModeChanged(); void transformChanged(); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 23d601e58e..c7f2945757 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -32,7 +32,7 @@ MyCharacterController::~MyCharacterController() { void MyCharacterController::updateShapeIfNecessary() { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { - _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; + _pendingFlags &= ~PENDING_FLAG_UPDATE_SHAPE; // compute new dimensions from avatar's bounding box float x = _boxScale.x; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 342f8315e1..47c22e9f08 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -69,7 +69,7 @@ void SkeletonModel::initJointStates() { _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); - _owningAvatar->rebuildSkeletonBody(); + _owningAvatar->rebuildCollisionShape(); emit skeletonLoaded(); } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 99285c6558..e5ecdfe217 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -386,7 +386,7 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getAvatarScale(), &t)){ + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getUniformScale(), &t)){ result = position + direction * t; return true; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 9a995263cd..f7ef0c9d56 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -199,7 +199,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); - ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale()); + ui.avatarScaleSpin->setValue(myAvatar->getUniformScale()); ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl().toString()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 1b1c48c3ca..753106fa0a 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -68,7 +68,7 @@ namespace render { glm::vec3 myAvatarPosition = avatar->getPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); - float myAvatarScale = avatar->getAvatarScale(); + float myAvatarScale = avatar->getUniformScale(); Transform transform = Transform(); transform.setTranslation(myAvatarPosition); transform.setRotation(glm::angleAxis(angle, axis)); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d241df7e0e..dce973fb33 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -90,7 +90,7 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - Transform trans; + Transform trans = getTransform(); trans.setTranslation(position); trans.setRotation(orientation); SpatiallyNestable::setTransform(trans); From 33634cdaa16e8faec4fb375f5efcb6ae9e0d27ef Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Dec 2015 18:09:58 -0800 Subject: [PATCH 074/318] properly delete departing avatars --- interface/src/avatar/Avatar.cpp | 21 +++++++++++++-------- interface/src/avatar/Avatar.h | 5 ++++- interface/src/avatar/AvatarManager.cpp | 16 ++++++++-------- interface/src/avatar/AvatarManager.h | 14 +++++++------- libraries/avatars/src/AvatarData.h | 5 +++++ 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8231d1ebdd..a0fa822512 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -150,11 +150,12 @@ float Avatar::getLODDistance() const { void Avatar::animateScaleChanges(float deltaTime) { float currentScale = getUniformScale(); if (currentScale != _targetScale) { - const float SCALE_ANIMATION_TIMESCALE = 1.0f; - float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; - float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; - const float CLOSE_ENOUGH = 0.05f; - if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + const float SCALE_ANIMATION_TIMESCALE = 0.5f; + float scaleVelocity = (_targetScale - currentScale) / SCALE_ANIMATION_TIMESCALE; + float animatedScale = currentScale + deltaTime * scaleVelocity; + const float MIN_SCALE_SPEED = 0.3f; + if (fabsf(scaleVelocity) < MIN_SCALE_SPEED) { + // close enough animatedScale = _targetScale; } setScale(glm::vec3(animatedScale)); // avatar scale is uniform @@ -165,6 +166,9 @@ void Avatar::animateScaleChanges(float deltaTime) { void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); + if (!isDead() && !_motionState) { + DependencyManager::get()->updateAvatarPhysicsShape(this); + } animateScaleChanges(deltaTime); // update the billboard render flag @@ -1107,13 +1111,14 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset()); } +void Avatar::setMotionState(AvatarMotionState* motionState) { + _motionState = motionState; +} + // virtual void Avatar::rebuildCollisionShape() { if (_motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); - } else { - // adebug TODO: move most of updateAvatarPhysicsShape() to here - DependencyManager::get()->updateAvatarPhysicsShape(this); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 379ab8b627..4926212b4d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -157,7 +157,6 @@ public: virtual void computeShapeInfo(ShapeInfo& shapeInfo); - void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } virtual void setPosition(const glm::vec3& position) override; @@ -172,6 +171,10 @@ public slots: glm::quat getRightPalmRotation(); protected: + friend class AvatarManager; + + void setMotionState(AvatarMotionState* motionState); + SkeletonModel _skeletonModel; glm::vec3 _skeletonOffset; QVector _attachmentModels; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 562bea3542..38f191872e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -223,14 +223,14 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { auto newAvatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); auto rawRenderableAvatar = std::static_pointer_cast(newAvatar); - + render::ScenePointer scene = qApp->getMain3DScene(); render::PendingChanges pendingChanges; if (DependencyManager::get()->shouldRenderAvatars()) { rawRenderableAvatar->addToScene(rawRenderableAvatar, scene, pendingChanges); } scene->enqueuePendingChanges(pendingChanges); - + return newAvatar; } @@ -251,7 +251,7 @@ void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { // virtual void AvatarManager::removeAvatar(const QUuid& sessionUUID) { QWriteLocker locker(&_hashLock); - + auto removedAvatar = _avatarHash.take(sessionUUID); if (removedAvatar) { handleRemovedAvatar(removedAvatar); @@ -260,7 +260,8 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(removedAvatar); - + + removedAvatar->die(); removeAvatarMotionState(removedAvatar); _avatarFades.push_back(removedAvatar); } @@ -268,7 +269,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar void AvatarManager::clearOtherAvatars() { // clear any avatars that came from an avatar-mixer QWriteLocker locker(&_hashLock); - + AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { auto avatar = std::static_pointer_cast(avatarIterator.value()); @@ -278,7 +279,7 @@ void AvatarManager::clearOtherAvatars() { } else { auto removedAvatar = avatarIterator.value(); avatarIterator = _avatarHash.erase(avatarIterator); - + handleRemovedAvatar(removedAvatar); } } @@ -375,7 +376,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { - // adebug TODO: move most of this logic to MyAvatar class assert(!avatar->getMotionState()); ShapeInfo shapeInfo; @@ -414,6 +414,6 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) if (sessionID == _myAvatar->getSessionUUID()) { return _myAvatar; } - + return findAvatar(sessionID); } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 84a4bc44b8..d63df9fb76 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -52,7 +52,7 @@ public: glm::vec3 color; glm::vec3 direction; }; - + Q_INVOKABLE void setLocalLights(const QVector& localLights); Q_INVOKABLE QVector getLocalLights() const; // Currently, your own avatar will be included as the null avatar id. @@ -67,7 +67,7 @@ public: void handleCollisionEvents(const CollisionEvents& collisionEvents); void updateAvatarPhysicsShape(Avatar* avatar); - + // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } @@ -80,7 +80,7 @@ public: Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue); - + public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); @@ -90,19 +90,19 @@ private: AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); - + // virtual overrides virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); void removeAvatarMotionState(AvatarSharedPointer avatar); - + virtual void removeAvatar(const QUuid& sessionUUID); virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar); - + QVector _avatarFades; std::shared_ptr _myAvatar; quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. - + QVector _localLights; bool _shouldShowReceiveStats = false; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fa33ff606..cbd15f2ce1 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -342,6 +342,9 @@ public: glm::vec3 getClientGlobalPosition() { return _globalPosition; } + void die() { _isDead = true; } + bool isDead() const { return _isDead; } + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -413,6 +416,8 @@ protected: // updates about one avatar to another. glm::vec3 _globalPosition; + bool _isDead { false }; + private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); static QUrl _defaultFullAvatarModelUrl; From bab07516f032db80e2475b42d90cc94283276a7f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:06:11 -0800 Subject: [PATCH 075/318] fix size of rendered bounding capsule --- interface/src/avatar/Avatar.cpp | 3 ++- interface/src/avatar/SkeletonModel.cpp | 23 +++++++++++++---------- interface/src/avatar/SkeletonModel.h | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a0fa822512..9e881f49ea 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -454,7 +454,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) { PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes"); - _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); + const float BOUNDING_SHAPE_ALPHA = 0.7f; + _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA); } // If this is the avatar being looked at, render a little ball above their head diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 47c22e9f08..e8d952973b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -338,35 +338,38 @@ void SkeletonModel::computeBoundingShape() { return; } - _rig->computeAvatarBoundingCapsule(geometry, - _boundingCapsuleRadius, - _boundingCapsuleHeight, - _boundingCapsuleLocalOffset); + float radius, height; + glm::vec3 offset; + _rig->computeAvatarBoundingCapsule(geometry, radius, height, offset); + float invScale = 1.0f / _owningAvatar->getUniformScale(); + _boundingCapsuleRadius = invScale * radius; + _boundingCapsuleHeight = invScale * height; + _boundingCapsuleLocalOffset = invScale * offset; } -void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { +void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); // draw a blue sphere at the capsule top point - glm::vec3 topPoint = _translation + getRotation() * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 topPoint = _translation + getRotation() * (scale * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * Vectors::UNIT_Y)); deferredLighting->renderSolidSphereInstance(batch, - Transform().setTranslation(topPoint).postScale(_boundingCapsuleRadius), + Transform().setTranslation(topPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule bottom point - glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f); + glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, scale * _boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; deferredLighting->renderSolidSphereInstance(batch, - Transform().setTranslation(bottomPoint).postScale(_boundingCapsuleRadius), + Transform().setTranslation(bottomPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); batch.setModelTransform(Transform().setTranslation(bottomPoint)); deferredLighting->bindSimpleProgram(batch); - Avatar::renderJointConnectingCone(batch, origin, axis, _boundingCapsuleRadius, _boundingCapsuleRadius, + Avatar::renderJointConnectingCone(batch, origin, axis, scale * _boundingCapsuleRadius, scale * _boundingCapsuleRadius, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 9b73119238..7541a002dc 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -89,7 +89,7 @@ public: /// \return whether or not the head was found. glm::vec3 getDefaultEyeModelPosition() const; - void renderBoundingCollisionShapes(gpu::Batch& batch, float alpha); + void renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha); float getBoundingCapsuleRadius() const { return _boundingCapsuleRadius; } float getBoundingCapsuleHeight() const { return _boundingCapsuleHeight; } const glm::vec3 getBoundingCapsuleOffset() const { return _boundingCapsuleLocalOffset; } From cd1e3810ca43c7d3822c7581096f79dd2bd5ac18 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:06:31 -0800 Subject: [PATCH 076/318] set the scale of avatar on login, don't animate --- 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 926d41f1ca..73ff332a37 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -694,7 +694,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setScale(glm::vec3(getUniformScale())); + setScale(glm::vec3(_targetScale)); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); From c3823de353ea40d96501fce20b84c778759991d3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:07:03 -0800 Subject: [PATCH 077/318] setClampedTargetScale()-->setTargetScaleVerbose() --- interface/src/ui/PreferencesDialog.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 5 +---- libraries/avatars/src/AvatarData.h | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index f7ef0c9d56..a38cc13100 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -256,7 +256,7 @@ void PreferencesDialog::savePreferences() { myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum()); myAvatar->setLeanScale(ui.leanScaleSpin->value()); - myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value()); + myAvatar->setTargetScaleVerbose(ui.avatarScaleSpin->value()); if (myAvatar->getAnimGraphUrl() != ui.avatarAnimationEdit->text()) { // If changed, destroy the old and start with the new myAvatar->setAnimGraphUrl(ui.avatarAnimationEdit->text()); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index dce973fb33..645e0ad7fc 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -132,10 +132,7 @@ void AvatarData::setTargetScale(float targetScale) { _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale)); } -void AvatarData::setClampedTargetScale(float targetScale) { - - targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - +void AvatarData::setTargetScaleVerbose(float targetScale) { setTargetScale(targetScale); qCDebug(avatars) << "Changed scale to " << _targetScale; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cbd15f2ce1..64c215cee7 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -172,7 +172,7 @@ public: AvatarData(); virtual ~AvatarData(); - + static const QUrl& defaultFullAvatarModelUrl(); virtual bool isMyAvatar() const { return false; } @@ -237,7 +237,7 @@ public: // Scale float getTargetScale() const; void setTargetScale(float targetScale); - void setClampedTargetScale(float targetScale); + void setTargetScaleVerbose(float targetScale); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } @@ -261,7 +261,7 @@ public: Q_INVOKABLE bool isJointDataValid(const QString& name) const; Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; Q_INVOKABLE glm::vec3 getJointTranslation(const QString& name) const; - + Q_INVOKABLE virtual QVector getJointRotations() const; Q_INVOKABLE virtual void setJointRotations(QVector jointRotations); Q_INVOKABLE virtual void setJointTranslations(QVector jointTranslations); From 9b0c199ed75752d71556adcc27244aacee49aa72 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 15:30:56 -0800 Subject: [PATCH 078/318] updateAvatarPhysicsShape-->addAvatarToSimulation --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 3 ++- interface/src/avatar/AvatarManager.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9e881f49ea..504124c4a7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -167,7 +167,7 @@ void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); if (!isDead() && !_motionState) { - DependencyManager::get()->updateAvatarPhysicsShape(this); + DependencyManager::get()->addAvatarToSimulation(this); } animateScaleChanges(deltaTime); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 38f191872e..312742e778 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -375,13 +375,14 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } -void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { +void AvatarManager::addAvatarToSimulation(Avatar* avatar) { assert(!avatar->getMotionState()); ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); if (shape) { + // we don't add to the simulation now, we put it on a list to be added later AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); avatar->setMotionState(motionState); _motionStatesToAdd.insert(motionState); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index d63df9fb76..1b165495c3 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -66,7 +66,7 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - void updateAvatarPhysicsShape(Avatar* avatar); + void addAvatarToSimulation(Avatar* avatar); // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } From 7baee8c39138e80c05238dd0e93f2671a7cb90dc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 15:34:16 -0800 Subject: [PATCH 079/318] use glm::clamp() instead of std::min() and max() --- libraries/avatars/src/AvatarData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 645e0ad7fc..2ed9a47e02 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -129,7 +129,7 @@ float AvatarData::getTargetScale() const { } void AvatarData::setTargetScale(float targetScale) { - _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale)); + _targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); } void AvatarData::setTargetScaleVerbose(float targetScale) { From 0e1e5db7eb808a71f209e7c219e74a87b29ddf58 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 16:29:39 -0800 Subject: [PATCH 080/318] only need one animateScaleChanges() implementation --- interface/src/avatar/Avatar.cpp | 13 ++++++++----- interface/src/avatar/MyAvatar.cpp | 16 ---------------- interface/src/avatar/MyAvatar.h | 3 --- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 504124c4a7..f8040754d7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -150,14 +150,17 @@ float Avatar::getLODDistance() const { void Avatar::animateScaleChanges(float deltaTime) { float currentScale = getUniformScale(); if (currentScale != _targetScale) { + // use exponential decay toward _targetScale const float SCALE_ANIMATION_TIMESCALE = 0.5f; - float scaleVelocity = (_targetScale - currentScale) / SCALE_ANIMATION_TIMESCALE; - float animatedScale = currentScale + deltaTime * scaleVelocity; - const float MIN_SCALE_SPEED = 0.3f; - if (fabsf(scaleVelocity) < MIN_SCALE_SPEED) { - // close enough + float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f); + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + + // snap to the end when we get close enough + const float MIN_RELATIVE_SCALE_ERROR = 0.03f; + if (fabsf(_targetScale - currentScale) / _targetScale < 0.03f) { animatedScale = _targetScale; } + setScale(glm::vec3(animatedScale)); // avatar scale is uniform rebuildCollisionShape(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 73ff332a37..5c8230bd88 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -284,22 +284,6 @@ void MyAvatar::update(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); -void MyAvatar::animateScaleChanges(float deltaTime) { - // HACK: override Avatar::animateScaleChanges() until MyAvatar has a MotionState - float currentScale = getUniformScale(); - if (currentScale != _targetScale) { - const float SCALE_ANIMATION_TIMESCALE = 1.0f; - float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; - float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; - const float CLOSE_ENOUGH = 0.05f; - if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { - animatedScale = _targetScale; - } - setScale(glm::vec3(animatedScale)); - rebuildCollisionShape(); - } -} - void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index bce6521c07..019ba0f992 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -263,9 +263,6 @@ public slots: glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); -protected: - void animateScaleChanges(float deltaTime); - signals: void audioListenerModeChanged(); void transformChanged(); From d2ebaef69e9c057bcd6cf4c0ba5e60dd688b141b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Dec 2015 18:18:42 -0800 Subject: [PATCH 081/318] Adding a simple manual exposure control to configure the tonemapping and expose it to js. Add a convenient way to access the Job._concept._data with template --- examples/utilities/tools/renderEngineDebug.js | 5 +++ interface/src/Application.cpp | 2 + libraries/gpu/src/gpu/Batch.cpp | 6 +++ libraries/gpu/src/gpu/Batch.h | 4 ++ libraries/gpu/src/gpu/GLBackend.cpp | 1 + libraries/gpu/src/gpu/GLBackend.h | 7 +++- libraries/gpu/src/gpu/GLBackendOutput.cpp | 2 +- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 11 +++++ libraries/gpu/src/gpu/GLBackendTexture.cpp | 37 ++++++++++++++++- .../render-utils/src/DebugDeferredBuffer.cpp | 4 +- .../render-utils/src/FramebufferCache.cpp | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 18 +++++++++ .../render-utils/src/RenderDeferredTask.h | 5 +++ .../render-utils/src/ToneMappingEffect.cpp | 40 ++++++++++++++++--- .../render-utils/src/ToneMappingEffect.h | 8 +++- libraries/render/src/render/DrawTask.h | 17 ++++++++ libraries/render/src/render/Engine.h | 2 + .../src/SceneScriptingInterface.h | 4 ++ 18 files changed, 165 insertions(+), 12 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 60686912e8..2c0dc352b4 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -109,6 +109,11 @@ panel.newCheckbox("Network/Physics status", function(value) { return (value & showNetworkStatusFlag) > 0; } ); +panel.newSlider("Tone Mapping Exposure", -10, 10, + function (value) { Scene.setEngineToneMappingExposure(value); }, + function() { return Scene.getEngineToneMappingExposure(); }, + function (value) { return (value); }); + var tickTackPeriod = 500; function updateCounters() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c26c8330f8..c6fa997eae 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3691,6 +3691,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); renderContext._fxaaStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); + renderContext._toneMappingExposure = sceneInterface->getEngineToneMappingExposure(); + renderArgs->_shouldRender = LODManager::shouldRender; renderContext.args = renderArgs; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 14871aafd1..843eb3d3a5 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -311,6 +311,12 @@ void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport, _params.push_back(dstViewport.w); } +void Batch::generateTextureMipmap(const TexturePointer& texture) { + ADD_COMMAND(generateTextureMipmap); + + _params.push_back(_textures.cache(texture)); +} + void Batch::beginQuery(const QueryPointer& query) { ADD_COMMAND(beginQuery); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 2afcc7caa9..122285f5ea 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -211,6 +211,9 @@ public: // with xy and zw the bounding corners of the rect region. void blit(const FramebufferPointer& src, const Vec4i& srcRect, const FramebufferPointer& dst, const Vec4i& dstRect); + // Generate the mipmap for a texture + void generateTextureMipmap(const TexturePointer& texture); + // Query Section void beginQuery(const QueryPointer& query); void endQuery(const QueryPointer& query); @@ -292,6 +295,7 @@ public: COMMAND_setFramebuffer, COMMAND_clearFramebuffer, COMMAND_blit, + COMMAND_generateTextureMipmap, COMMAND_beginQuery, COMMAND_endQuery, diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index d4f3c5c4b3..ff1b207f7c 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -52,6 +52,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_setFramebuffer), (&::gpu::GLBackend::do_clearFramebuffer), (&::gpu::GLBackend::do_blit), + (&::gpu::GLBackend::do_generateTextureMipmap), (&::gpu::GLBackend::do_beginQuery), (&::gpu::GLBackend::do_endQuery), diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index f44fbe6c0d..4733d81cbf 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -376,12 +376,16 @@ protected: // Resource Stage void do_setResourceTexture(Batch& batch, size_t paramOffset); - + + // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s void releaseResourceTexture(uint32_t slot); + void resetResourceStage(); struct ResourceStageState { Textures _textures; + int findEmptyTextureSlot() const; + ResourceStageState(): _textures(MAX_NUM_RESOURCE_TEXTURES, nullptr) {} @@ -432,6 +436,7 @@ protected: void do_setFramebuffer(Batch& batch, size_t paramOffset); void do_clearFramebuffer(Batch& batch, size_t paramOffset); void do_blit(Batch& batch, size_t paramOffset); + void do_generateTextureMipmap(Batch& batch, size_t paramOffset); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 6d8ce7b2c6..5f226141a8 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -361,4 +361,4 @@ void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, co glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); (void) CHECK_GL_ERROR(); -} \ No newline at end of file +} diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 8601c7512b..8c9647e0f2 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -231,6 +231,7 @@ void GLBackend::releaseResourceTexture(uint32_t slot) { } } + void GLBackend::resetResourceStage() { for (uint32_t i = 0; i < _resource._textures.size(); i++) { releaseResourceTexture(i); @@ -268,3 +269,13 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { } } +int GLBackend::ResourceStageState::findEmptyTextureSlot() const { + // start from the end of the slots, try to find an empty one that can be used + for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) { + if (!_textures[i]) { + return i; + } + } + return -1; +} + diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 73bf02e8c7..eaed50b850 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -404,8 +404,9 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (bytes && texture.isAutogenerateMips()) { glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } else if (texture.isAutogenerateMips()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } - object->_target = GL_TEXTURE_2D; syncSampler(texture.getSampler(), texture.getType(), object); @@ -588,3 +589,37 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); } + + + +void GLBackend::do_generateTextureMipmap(Batch& batch, size_t paramOffset) { + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + if (!resourceTexture) { + return; + } + + GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); + if (!object) { + return; + } + + // IN 4.1 we still need to find an available slot + auto freeSlot = _resource.findEmptyTextureSlot(); + auto bindingSlot = (freeSlot < 0 ? 0 : freeSlot); + glActiveTexture(GL_TEXTURE0 + bindingSlot); + glBindTexture(object->_target, object->_texture); + + glGenerateMipmap(object->_target); + + if (freeSlot < 0) { + // If had to use slot 0 then restore state + GLTexture* boundObject = GLBackend::syncGPUObject(*_resource._textures[0]); + if (boundObject) { + glBindTexture(boundObject->_target, boundObject->_texture); + } + } else { + // clean up + glBindTexture(object->_target, 0); + } + (void)CHECK_GL_ERROR(); +} diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 842729144d..169ae0b58e 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -49,7 +49,7 @@ static const std::string FUNCTIONS_PLACEHOLDER { "/*FUNCTIONS_PLACEHOLDER*/" }; std::string DebugDeferredBuffer::getCode(Modes mode) { switch (mode) { case DiffuseMode: { - QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; + QString code = "return vec4(pow(texture(%1, uv).xyz, vec3(1.0 / 2.2)), 1.0);"; return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString(); } case AlphaMode: { @@ -73,7 +73,7 @@ std::string DebugDeferredBuffer::getCode(Modes mode) { return code.arg(SLOT_NAMES[Depth].c_str()).toStdString(); } case LightingMode: { - QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; + QString code = "return vec4(pow(texture(%1, uv).xyz, vec3(1.0 / 2.2)), 1.0);"; return code.arg(SLOT_NAMES[Lighting].c_str()).toStdString(); } case CustomMode: diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 7b8c0f7f35..e64e245806 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -87,9 +87,11 @@ void FramebufferCache::createPrimaryFramebuffer() { auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); _selfieFramebuffer->setRenderBuffer(0, tex); + auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); + //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler)); //lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); - _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); + _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, smoothSampler)); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 5f9cb7b575..ef95876f11 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -104,6 +104,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // Lighting Buffer ready for tone mapping _jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping"))); + _toneMappingJobIndex = _jobs.size() - 1; // Debugging Deferred buffer job _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); @@ -164,6 +165,8 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setAntialiasingStatus(renderContext->_fxaaStatus); + setToneMappingExposure(renderContext->_toneMappingExposure); + renderContext->args->_context->syncCache(); for (auto job : _jobs) { @@ -390,3 +393,18 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const }); args->_batch = nullptr; } + + +void RenderDeferredTask::setToneMappingExposure(float exposure) { + if (_toneMappingJobIndex >= 0) { + _jobs[_toneMappingJobIndex].edit()._toneMappingEffect.setExposure(exposure); + } +} + +float RenderDeferredTask::getToneMappingExposure() const { + if (_toneMappingJobIndex >= 0) { + _jobs[_toneMappingJobIndex].get()._toneMappingEffect.getExposure(); + } else { + return 0.0f; + } +} diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 009e6f23b2..ea99c9f12e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -129,6 +129,11 @@ public: void setAntialiasingStatus(bool draw) { if (_antialiasingJobIndex >= 0) { _jobs[_antialiasingJobIndex].setEnabled(draw); } } bool doAntialiasingStatus() const { if (_antialiasingJobIndex >= 0) { return _jobs[_antialiasingJobIndex].isEnabled(); } else { return false; } } + int _toneMappingJobIndex = -1; + + void setToneMappingExposure(float exposure); + float getToneMappingExposure() const; + virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 97248a62d0..54794aa4a0 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -20,7 +20,8 @@ ToneMappingEffect::ToneMappingEffect() { - + Parameters parameters; + _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Parameters), (const gpu::Byte*) ¶meters)); } void ToneMappingEffect::init() { @@ -38,6 +39,16 @@ void ToneMappingEffect::init() { // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + struct ToneMappingParams { + vec4 _exp_2powExp_s0_s1; + }; + + uniform toneMappingParamsBuffer { + ToneMappingParams params; + }; + float getTwoPowExposure() { + return params._exp_2powExp_s0_s1.y; + } uniform sampler2D colorMap; @@ -45,16 +56,24 @@ void ToneMappingEffect::init() { out vec4 outFragColor; void main(void) { - vec4 fragColor = texture(colorMap, varTexCoord0); + vec4 fragColorRaw = textureLod(colorMap, varTexCoord0, 0); + vec3 fragColor = fragColorRaw.xyz; + +/* vec4 fragColorAverage = textureLod(colorMap, varTexCoord0, 10); + float averageIntensity = length(fragColorAverage.xyz); + + vec3 fragColor = fragColorRaw.xyz / averageIntensity; +*/ + fragColor *= getTwoPowExposure(); + + // if (gl_FragCoord.x > 1000) { // Manually gamma correct from Ligthing BUffer to color buffer // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); - fragColor *= 2.0; // Hardcoded Exposure Adjustment vec3 x = max(vec3(0.0),fragColor.xyz-0.004); vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); - // fragColor *= 8; // Hardcoded Exposure Adjustment // fragColor = fragColor/(1.0+fragColor); // vec3 retColor = pow(fragColor.xyz,vec3(1/2.2)); @@ -70,12 +89,19 @@ void ToneMappingEffect::init() { auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); - gpu::Shader::makeProgram(*blitProgram); + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), 3)); + gpu::Shader::makeProgram(*blitProgram, slotBindings); auto blitState = std::make_shared(); blitState->setColorWriteMask(true, true, true, true); _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); } +void ToneMappingEffect::setExposure(float exposure) { + _parametersBuffer.edit()._exposure = exposure; + _parametersBuffer.edit()._twoPowExposure = pow(2.0, exposure); +} + void ToneMappingEffect::render(RenderArgs* args) { if (!_blitLightBuffer) { @@ -89,6 +115,9 @@ void ToneMappingEffect::render(RenderArgs* args) { auto lightingBuffer = framebufferCache->getLightingTexture(); auto destFbo = framebufferCache->getPrimaryFramebuffer(); batch.setFramebuffer(destFbo); + + batch.generateTextureMipmap(lightingBuffer); + batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.setViewTransform(Transform()); @@ -104,6 +133,7 @@ void ToneMappingEffect::render(RenderArgs* args) { batch.setModelTransform(model); } + batch.setUniformBuffer(3, _parametersBuffer); batch.setResourceTexture(0, lightingBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); diff --git a/libraries/render-utils/src/ToneMappingEffect.h b/libraries/render-utils/src/ToneMappingEffect.h index 9b07c0f7df..be9664ddd9 100644 --- a/libraries/render-utils/src/ToneMappingEffect.h +++ b/libraries/render-utils/src/ToneMappingEffect.h @@ -27,6 +27,9 @@ public: void render(RenderArgs* args); + void setExposure(float exposure); + float getExposure() const { return _parametersBuffer.get()._exposure; } + private: gpu::PipelinePointer _blitLightBuffer; @@ -34,7 +37,10 @@ private: // Class describing the uniform buffer with all the parameters common to the tone mapping shaders class Parameters { public: - + float _exposure = 0.0f; + float _twoPowExposure = 1.0f; + glm::vec2 spare; + Parameters() {} }; typedef gpu::BufferView UniformBufferView; diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 3f628c3a02..52dc427251 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -84,6 +84,23 @@ public: const Varying getInput() const { return _concept->getInput(); } const Varying getOutput() const { return _concept->getOutput(); } + template T& edit() { + auto theConcept = std::dynamic_pointer_cast(_concept); + if (theConcept) { + return theConcept->_data; + } + assert(false); + return T(); + } + template const T& get() const { + auto theConcept = std::dynamic_pointer_cast(_concept); + if (theConcept) { + return theConcept->_data; + } + assert(false); + return T(); + } + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { PerformanceTimer perfTimer(getName().c_str()); PROFILE_RANGE(getName().c_str()); diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 26bd6f2154..c219b87f40 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -61,6 +61,8 @@ public: bool _occlusionStatus = false; bool _fxaaStatus = false; + float _toneMappingExposure = 0.0; + RenderContext() {} }; typedef std::shared_ptr RenderContextPointer; diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 78261dfdc7..875a2a1b8f 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -118,6 +118,9 @@ public: Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } + Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _engineToneMappingExposure = exposure; } + Q_INVOKABLE float getEngineToneMappingExposure() { return _engineToneMappingExposure; } + signals: void shouldRenderAvatarsChanged(bool shouldRenderAvatars); void shouldRenderEntitiesChanged(bool shouldRenderEntities); @@ -154,6 +157,7 @@ protected: bool _drawHitEffect = false; + float _engineToneMappingExposure = 0.0f; }; #endif // hifi_SceneScriptingInterface_h From 9a2d9997e90c99edd49ce1b7452511c80e1bccb5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Tue, 15 Dec 2015 18:20:12 -0800 Subject: [PATCH 082/318] prep for feedback --- examples/controllers/handControllerGrab.js | 234 ++++++++++--------- examples/lights/light_loader.js | 8 + examples/lights/light_modifier.js | 113 ++++----- examples/lights/light_modifier_test_scene.js | 128 ++++++++++ examples/lights/{box.js => slider.js} | 49 ++-- examples/lights/testScene.js | 117 ---------- 6 files changed, 331 insertions(+), 318 deletions(-) create mode 100644 examples/lights/light_loader.js create mode 100644 examples/lights/light_modifier_test_scene.js rename examples/lights/{box.js => slider.js} (67%) delete mode 100644 examples/lights/testScene.js diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d9e75c8836..c452519522 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -218,6 +218,7 @@ function getSpatialOffsetPosition(hand, spatialKey) { } var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + function getSpatialOffsetRotation(hand, spatialKey) { var rotation = Quat.IDENTITY; @@ -261,9 +262,9 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - + this.overlayLine = null; - + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -816,33 +817,36 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); - var defaultConstrainData = { - axisBasePosition:false, - endOfAxis: false, - } - var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstrainData); - - // var constrainX = constraintData.constrain.x; - // var constrainY = constraintData.constrain.y; - // var constrainZ = constraintData.constrain.z; - - // print('constrainY'+constrainY); // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); - var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); var change = Vec3.subtract(before, after); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } + var defaultConstraintData = { + axisStart: false, + axisEnd: false, + } + + var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstraintData); var clampedVector; var targetPosition; - if (constraintData.axisBasePosition !== false) { - clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisBasePosition, constraintData.endOfAxis); + if (constraintData.startAxis !== false) { + clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd); targetPosition = clampedVector; } else { targetPosition = { @@ -859,121 +863,121 @@ function MyController(hand) { angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, ttl: ACTION_TTL }); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + }; this.projectVectorAlongAxis = function(position, axisStart, axisEnd) { - var aPrime = Vec3.subtract(position, axisStart); + var aPrime = Vec3.subtract(position, axisStart); - var bPrime = Vec3.subtract(axisEnd, axisStart); + var bPrime = Vec3.subtract(axisEnd, axisStart); - var bPrimeMagnitude = Vec3.length(bPrime); + var bPrimeMagnitude = Vec3.length(bPrime); - var dotProduct = Vec3.dot(aPrime, bPrime); + var dotProduct = Vec3.dot(aPrime, bPrime); - var scalar = dotProduct / bPrimeMagnitude; + var scalar = dotProduct / bPrimeMagnitude; - print('SCALAR:::'+scalar); + if (scalar < 0) { + scalar = 0; + } - if(scalar<0){ - scalar = 0; - } + if (scalar > 1) { + scalar = 1; + } - if(scalar>1){ - scalar = 1; - } + var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); - var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); + return projection - return projection + }, - }, + this.nearGrabbing = function() { + var now = Date.now(); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - this.nearGrabbing = function() { - var now = Date.now(); - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + this.setState(STATE_RELEASE); + Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + return; + } - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { - this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - return; - } + this.lineOff(); + this.overlayLineOff(); - this.lineOff(); - this.overlayLineOff(); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + this.activateEntity(this.grabbedEntity, grabbedProperties); + if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + Entities.editEntity(this.grabbedEntity, { + collisionsWillMove: false + }); + } - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { - Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false + var handRotation = this.getHandRotation(); + var handPosition = this.getHandPosition(); + + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + + if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { + // if an object is "equipped" and has a spatialKey, use it. + this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.ignoreIK = false; + + var objectRotation = grabbedProperties.rotation; + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + + this.actionID = NULL_ACTION_ID; + this.actionID = Entities.addAction("hold", this.grabbedEntity, { + hand: this.hand === RIGHT_HAND ? "right" : "left", + timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, + relativePosition: this.offsetPosition, + relativeRotation: this.offsetRotation, + ttl: ACTION_TTL, + kinematic: NEAR_GRABBING_KINEMATIC, + kinematicSetVelocity: true, + ignoreIK: this.ignoreIK }); - } - - var handRotation = this.getHandRotation(); - var handPosition = this.getHandPosition(); - - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); - this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); - } - - this.actionID = NULL_ACTION_ID; - this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand === RIGHT_HAND ? "right" : "left", - timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, - relativePosition: this.offsetPosition, - relativeRotation: this.offsetRotation, - ttl: ACTION_TTL, - kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, - ignoreIK: this.ignoreIK - }); - if (this.actionID === NULL_ACTION_ID) { - this.actionID = null; - } else { - this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); - if (this.state == STATE_NEAR_GRABBING) { - this.setState(STATE_CONTINUE_NEAR_GRABBING); + if (this.actionID === NULL_ACTION_ID) { + this.actionID = null; } else { - // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); + this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); + if (this.state == STATE_NEAR_GRABBING) { + this.setState(STATE_CONTINUE_NEAR_GRABBING); + } else { + // equipping + Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + this.startHandGrasp(); + + this.setState(STATE_CONTINUE_EQUIP_BD); + } + + if (this.hand === RIGHT_HAND) { + Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); + } else { + Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); + } + + Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); + + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - this.setState(STATE_CONTINUE_EQUIP_BD); } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } + this.currentHandControllerTipPosition = + (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - - } - - this.currentHandControllerTipPosition = - (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - - this.currentObjectTime = Date.now(); - }; + this.currentObjectTime = Date.now(); + }; this.continueNearGrabbing = function() { if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { @@ -1358,10 +1362,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND && handToDisable!=='both') { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { rightController.update(); } } @@ -1369,7 +1373,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; @@ -1377,11 +1381,11 @@ handleHandDisablerMessages = function(channel, message, sender) { if (message === 'right') { handToDisable = RIGHT_HAND; } - if(message==='both'){ - handToDisable='both'; + if (message === 'both') { + handToDisable = 'both'; } - if(message==='none'){ - handToDisable='none'; + if (message === 'none') { + handToDisable = 'none'; } } @@ -1396,4 +1400,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/lights/light_loader.js b/examples/lights/light_loader.js new file mode 100644 index 0000000000..8edaa20f57 --- /dev/null +++ b/examples/lights/light_loader.js @@ -0,0 +1,8 @@ +var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); +Script.load(grabScript); +var lightModifier = Script.resolvePath('light_modifier.js'); +Script.load(lightModifier); +Script.setTimeout(function() { + var lightModifierTestScene = Script.resolvePath('light_modifier_test_scene.js'); + Script.load(lightModifierTestScene); +}, 750) \ No newline at end of file diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index f54af5b54f..cbb4e3ff10 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -1,9 +1,22 @@ -// given a selected light, instantiate some entities that represent various values you can dynamically adjust +// +// light_modifier.js +// +// Created byJames Pollack @imgntn on 10/19/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var AXIS_SCALE = 1; +var COLOR_MAX = 255; +var INTENSITY_MAX = 0.05; +var CUTOFF_MAX = 360; +var EXPONENT_MAX = 1; - -var BOX_SCRIPT_URL = Script.resolvePath('box.js?'+Math.random(0,100)); +var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); var RED = { red: 255, @@ -35,13 +48,12 @@ var WHITE = { blue: 255 }; -var AXIS_SCALE = 1; - -var BOX_DIMENSIONS = { - x: 0.05, - y: 0.05, - z: 0.05 +var SLIDER_DIMENSIONS = { + x: 0.075, + y: 0.075, + z: 0.075 }; + var PER_ROW_OFFSET = { x: 0, y: -0.2, @@ -55,10 +67,8 @@ function entitySlider(light, color, sliderType, row) { this.color = color; this.sliderType = sliderType; this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - print('slider : ' + this.sliderType + "should have an offset of : " + this.verticalOffset); - this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(this.avatarRot))); + this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); var message = { lightID: this.lightID, @@ -95,9 +105,8 @@ function entitySlider(light, color, sliderType, row) { } this.setInitialSliderPositions(); - this.subscribeToBoxMessages(); this.createAxis(); - this.createBoxIndicator(); + this.createSliderIndicator(); return this; } @@ -113,7 +122,6 @@ entitySlider.prototype = { var extension = Vec3.multiply(AXIS_SCALE, rightVector); var endOfAxis = Vec3.sum(position, extension); this.endOfAxis = endOfAxis; - print('endOfAxis:::' + JSON.stringify(endOfAxis)) var properties = { type: 'Line', name: 'Hifi-Slider-Axis::' + this.sliderType, @@ -136,10 +144,8 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, - createBoxIndicator: function() { - print('BOX COLOR IS:::' + JSON.stringify(this.color)); + createSliderIndicator: function() { var position = Vec3.sum(this.basePosition, this.verticalOffset); - //line starts on left and goes to right //set the end of the line to the right var rightVector = Quat.getRight(this.avatarRot); @@ -154,7 +160,7 @@ entitySlider.prototype = { initialDistance = this.distanceBlue; } if (this.sliderType === 'intensity') { - initialDistance = this.distanceRed; + initialDistance = this.distanceIntensity; } if (this.sliderType === 'cutoff') { initialDistance = this.distanceCutoff; @@ -165,30 +171,26 @@ entitySlider.prototype = { var extension = Vec3.multiply(initialDistance, rightVector); var sliderPosition = Vec3.sum(position, extension); var properties = { - type: 'Box', + type: 'Sphere', name: 'Hifi-Slider::' + this.sliderType, - dimensions: BOX_DIMENSIONS, + dimensions: SLIDER_DIMENSIONS, collisionsWillMove: true, color: this.color, position: sliderPosition, - script: BOX_SCRIPT_URL, + script: SLIDER_SCRIPT_URL, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, sliderType: this.sliderType, - axisBasePosition: position, - endOfAxis: this.endOfAxis, - }, - constraintKey: { - constrain: { - y: position.y - } + axisStart: position, + axisEnd: this.endOfAxis, } }) }; - this.boxIndicator = Entities.addEntity(properties); + this.sliderIndicator = Entities.addEntity(properties); }, + setValueFromMessage: function(message) { //message is not for our light @@ -203,8 +205,6 @@ entitySlider.prototype = { return } - print('should set:::' + this.sliderType); - var lightProperties = Entities.getEntityProperties(this.lightID); if (this.sliderType === 'color_red') { @@ -255,28 +255,15 @@ entitySlider.prototype = { }); } }, - subscribeToBoxMessages: function() { - Messages.subscribe('Hifi-Slider-Value-Reciever'); - Messages.messageReceived.connect(handleValueMessages); - }, setInitialSliderPositions: function() { - var COLOR_MAX = 255; - var INTENSITY_MAX = 10; - var CUTOFF_MAX = 360; - var EXPONENT_MAX = 1; - this.distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE; this.distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE; this.distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE; this.distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE; this.distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE; this.distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE; - }, - cleanup: function() { - Entities.deleteEntity(this.boxIndicator); - Entities.deleteEntity(this.axis); - Messages.messageReceived.disconnect(this.handleValueMessages); } + }; var sliders = []; @@ -288,9 +275,9 @@ var slidersRef = { cutoff: null, exponent: null } +var light = null; function makeSliders(light) { - print('light in makesliders:::' + light) if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -325,14 +312,19 @@ function makeSliders(light) { slidersRef.exponent = new entitySlider(light, PURPLE, 'exponent', 6); sliders.push(slidersRef.exponent); } + subscribeToSliderMessages(); }; function subScribeToNewLights() { - print('subscribing to light messages') Messages.subscribe('Hifi-Light-Mod-Receiver'); Messages.messageReceived.connect(handleLightModMessages); } +function subscribeToSliderMessages() { + Messages.subscribe('Hifi-Slider-Value-Reciever'); + Messages.messageReceived.connect(handleValueMessages); +} + function handleLightModMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Mod-Receiver') { return; @@ -343,6 +335,7 @@ function handleLightModMessages(channel, message, sender) { var parsedMessage = JSON.parse(message); makeSliders(parsedMessage.light); + light = parsedMessage.light.id } function handleValueMessages(channel, message, sender) { @@ -356,27 +349,39 @@ function handleValueMessages(channel, message, sender) { // } var parsedMessage = JSON.parse(message); - slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage) + slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage); } function cleanup() { - while (sliders.length > 0) { - var slider = sliders.pop(); - slider.cleanup(); + var i; + for (i = 0; i < sliders.length; i++) { + Entities.deleteEntity(sliders[i].axis); + Entities.deleteEntity(sliders[i].sliderIndicator); } + Messages.messageReceived.disconnect(handleLightModMessages); - delete sliders + Messages.messageReceived.disconnect(handleValueMessages); + Entities.deletingEntity.disconnect(deleteEntity); + } Script.scriptEnding.connect(cleanup); subScribeToNewLights(); +function deleteEntity(entityID) { + if (entityID === light) { + // cleanup(); + } +} + + +Entities.deletingEntity.connect(deleteEntity); + //other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, // ambientColor: { red: 255, green: 255, blue: 255 }, // specularColor: { red: 255, green: 255, blue: 255 }, - // constantAttenuation: 1, // linearAttenuation: 0, // quadraticAttenuation: 0, diff --git a/examples/lights/light_modifier_test_scene.js b/examples/lights/light_modifier_test_scene.js new file mode 100644 index 0000000000..d997816957 --- /dev/null +++ b/examples/lights/light_modifier_test_scene.js @@ -0,0 +1,128 @@ +// +// light_modifier_test_scene.js +// +// Created byJames Pollack @imgntn on 10/19/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Given a selected light, instantiate some entities that represent various values you can dynamically adjust. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 +}; +var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 +}); + +var basePosition, avatarRot; +avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); +basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); + +var ground = Entities.addEntity({ + name: 'Hifi-Light-Mod-Floor', + //type: "Model", + type: 'Box', + color: { + red: 100, + green: 100, + blue: 100 + }, + //modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", + dimensions: { + x: 100, + y: 2, + z: 100 + }, + position: basePosition, + shapeType: 'box' +}); + +var light, block; + +function createLight() { + var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); + var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); + var lightProperties = { + name: 'Hifi-Spotlight', + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + parentID: block, + color: { + red: 255, + green: 0, + blue: 255 + }, + intensity: 0.035, + exponent: 1, + cutoff: 30, + lifetime: -1, + position: lightTransform.p, + rotation: lightTransform.q + }; + + light = Entities.addEntity(lightProperties); + + var message = { + light: { + id: light, + type: 'spotlight', + initialProperties: lightProperties + } + }; + + Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); + +} + +function createBlock() { + var position = basePosition; + position.y += 5; + var blockProperties = { + name: 'Hifi-Spotlight-Block', + type: 'Box', + dimensions: { + x: 1, + y: 1, + z: 1 + }, + collisionsWillMove: true, + color: { + red: 0, + green: 0, + blue: 255 + }, + position: position + } + + block = Entities.addEntity(blockProperties); +} + +function evalLightWorldTransform(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; +} + +function cleanup() { + print('CLEANUP TEST SCENE SCRIPT') + Entities.deleteEntity(block); + Entities.deleteEntity(ground); + Entities.deleteEntity(light); +} + +Script.scriptEnding.connect(cleanup); + +createBlock(); +createLight(); \ No newline at end of file diff --git a/examples/lights/box.js b/examples/lights/slider.js similarity index 67% rename from examples/lights/box.js rename to examples/lights/slider.js index 3bcebc64d3..ab90019b9f 100644 --- a/examples/lights/box.js +++ b/examples/lights/slider.js @@ -2,61 +2,40 @@ var AXIS_SCALE = 1; var COLOR_MAX = 255; - var INTENSITY_MAX = 10; + var INTENSITY_MAX = 0.05; var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; - function Box() { + function Slider() { return this; } - Box.prototype = { + Slider.prototype = { preload: function(entityID) { this.entityID = entityID; var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); - print('USER DATA:::' + entityProperties.userData) var parsedUserData = JSON.parse(entityProperties.userData); this.userData = parsedUserData.lightModifierKey; - this.bPrime = Vec3.subtract(this.userData.endOfAxis, this.userData.axisBasePosition); - this.bPrimeMagnitude = Vec3.length(this.bPrime); - }, startNearGrab: function() { this.setInitialProperties(); }, startDistantGrab: function() { - // Entities.editEntity(this.entityID, { - // parentID: MyAvatar.sessionUUID, - // parentJointIndex: MyAvatar.getJointIndex("LeftHand") - // }); this.setInitialProperties(); }, setInitialProperties: function() { this.initialProperties = Entities.getEntityProperties(this.entityID); }, - clampPosition: function() { - - var currentProperties = Entities.getEntityProperties(this.entityID); - - var aPrime = Vec3.subtract(this.userData.axisBasePosition, currentProperties.position); - - var dotProduct = Vec3.dot(aPrime, this.bPrime); - - var scalar = dotProduct / this.bPrimeMagnitude; - - print('SCALAR:::' + scalar); - - var projection = Vec3.sum(this.userData.axisBasePosition, Vec3.multiply(scalar, Vec3.normalize(this.bPrime))); - - this.currentProjection = projection; - + continueNearGrab: function() { + // this.continueDistantGrab(); }, continueDistantGrab: function() { - // this.clampPosition(); - print('distant grab') + this.setSliderValueBasedOnDistance(); + }, + setSliderValueBasedOnDistance: function() { var currentPosition = Entities.getEntityProperties(this.entityID, "position").position; - var distance = Vec3.distance(this.axisBasePosition, this.currentProjection); + var distance = Vec3.distance(this.userData.axisStart, currentPosition); if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') { this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); @@ -71,6 +50,8 @@ this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; + print('SLIDER VALUE:::' + this.sliderValue) + this.sendValueToSlider(); }, releaseGrab: function() { @@ -80,7 +61,11 @@ y: 0, z: 0 }, - parentID: null + angularVelocity: { + x: 0, + y: 0, + z: 0 + } }) this.sendValueToSlider(); @@ -103,5 +88,5 @@ } }; - return new Box(); + return new Slider(); }); \ No newline at end of file diff --git a/examples/lights/testScene.js b/examples/lights/testScene.js deleted file mode 100644 index 0e0a226c0b..0000000000 --- a/examples/lights/testScene.js +++ /dev/null @@ -1,117 +0,0 @@ - // These constants define the Spotlight position and orientation relative to the model - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - var basePosition, avatarRot; - avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); - - var ground = Entities.addEntity({ - name:'Hifi-Light-Mod-Floor', - type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", - dimensions: { - x: 100, - y: 2, - z: 100 - }, - position: basePosition, - shapeType: 'box' - }); - - var light, block; - - // basePosition.y += 2; - - function createLight() { - print('making light' + block) - var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); - var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); - var lightProperties = { - name: 'Hifi-Spotlight', - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - parentID: block, - color: { - red: 255, - green: 0, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: -1, - position: lightTransform.p, - rotation: lightTransform.q - }; - - light = Entities.addEntity(lightProperties); - - var message = { - light: { - id: light, - type: 'spotlight', - initialProperties: lightProperties - } - }; - - Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); - print('SENT MESSAGE') - - } - - function createBlock() { - print('making block'); - - var position = basePosition; - position.y += 5; - var blockProperties = { - name: 'Hifi-Spotlight-Block', - type: 'Box', - dimensions: { - x: 1, - y: 1, - z: 1 - }, - collisionsWillMove: true, - color: { - red: 0, - green: 0, - blue: 255 - }, - position: position - } - - block = Entities.addEntity(blockProperties); - } - - function evalLightWorldTransform(modelPos, modelRot) { - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - } - - function cleanup() { - Entities.deleteEntity(block); - Entities.deleteEntity(ground); - Entities.deleteEntity(light); - } - - Script.scriptEnding.connect(cleanup); - - createBlock(); - createLight(); \ No newline at end of file From c2feec16de17b7f91cdb08d70e0759a43d3624e8 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Dec 2015 18:24:16 -0800 Subject: [PATCH 083/318] Cleaning the code --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 2 -- libraries/render-utils/src/ToneMappingEffect.cpp | 12 +++--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index eaed50b850..18b4065b77 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -404,8 +404,6 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (bytes && texture.isAutogenerateMips()) { glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } else if (texture.isAutogenerateMips()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } object->_target = GL_TEXTURE_2D; diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 54794aa4a0..23d0b3c800 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -25,8 +25,6 @@ ToneMappingEffect::ToneMappingEffect() { } void ToneMappingEffect::init() { - //auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - //auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS(); const char BlitTextureGamma_frag[] = R"SCRIBE(#version 410 core // Generated on Sat Oct 24 09:34:37 2015 // @@ -67,28 +65,24 @@ void ToneMappingEffect::init() { fragColor *= getTwoPowExposure(); - // if (gl_FragCoord.x > 1000) { // Manually gamma correct from Ligthing BUffer to color buffer - // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); + // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); vec3 x = max(vec3(0.0),fragColor.xyz-0.004); vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); - // fragColor = fragColor/(1.0+fragColor); - // vec3 retColor = pow(fragColor.xyz,vec3(1/2.2)); + // fragColor = fragColor/(1.0+fragColor); + // vec3 retColor = pow(fragColor.xyz,vec3(1/2.2)); outFragColor = vec4(retColor, 1.0); - // } } )SCRIBE"; auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(BlitTextureGamma_frag))); - //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); - //auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("toneMappingParamsBuffer"), 3)); gpu::Shader::makeProgram(*blitProgram, slotBindings); From a60ef4fb5ad8dc90f14f041c237b799c89690970 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Dec 2015 18:32:30 -0800 Subject: [PATCH 084/318] Finalize the names --- libraries/gpu/src/gpu/Batch.cpp | 4 ++-- libraries/gpu/src/gpu/Batch.h | 6 +++--- libraries/gpu/src/gpu/GLBackend.cpp | 2 +- libraries/gpu/src/gpu/GLBackend.h | 2 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 2 +- libraries/render-utils/src/ToneMappingEffect.cpp | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 843eb3d3a5..f9c4131a1b 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -311,8 +311,8 @@ void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport, _params.push_back(dstViewport.w); } -void Batch::generateTextureMipmap(const TexturePointer& texture) { - ADD_COMMAND(generateTextureMipmap); +void Batch::generateTextureMips(const TexturePointer& texture) { + ADD_COMMAND(generateTextureMips); _params.push_back(_textures.cache(texture)); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 122285f5ea..88d28f9d10 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -211,8 +211,8 @@ public: // with xy and zw the bounding corners of the rect region. void blit(const FramebufferPointer& src, const Vec4i& srcRect, const FramebufferPointer& dst, const Vec4i& dstRect); - // Generate the mipmap for a texture - void generateTextureMipmap(const TexturePointer& texture); + // Generate the mips for a texture + void generateTextureMips(const TexturePointer& texture); // Query Section void beginQuery(const QueryPointer& query); @@ -295,7 +295,7 @@ public: COMMAND_setFramebuffer, COMMAND_clearFramebuffer, COMMAND_blit, - COMMAND_generateTextureMipmap, + COMMAND_generateTextureMips, COMMAND_beginQuery, COMMAND_endQuery, diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index ff1b207f7c..a730c06bd9 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -52,7 +52,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_setFramebuffer), (&::gpu::GLBackend::do_clearFramebuffer), (&::gpu::GLBackend::do_blit), - (&::gpu::GLBackend::do_generateTextureMipmap), + (&::gpu::GLBackend::do_generateTextureMips), (&::gpu::GLBackend::do_beginQuery), (&::gpu::GLBackend::do_endQuery), diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 4733d81cbf..400c9f08f8 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -436,7 +436,7 @@ protected: void do_setFramebuffer(Batch& batch, size_t paramOffset); void do_clearFramebuffer(Batch& batch, size_t paramOffset); void do_blit(Batch& batch, size_t paramOffset); - void do_generateTextureMipmap(Batch& batch, size_t paramOffset); + void do_generateTextureMips(Batch& batch, size_t paramOffset); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 18b4065b77..17802ae6ed 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -590,7 +590,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur -void GLBackend::do_generateTextureMipmap(Batch& batch, size_t paramOffset) { +void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) { TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); if (!resourceTexture) { return; diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 23d0b3c800..22c31a2459 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -110,7 +110,7 @@ void ToneMappingEffect::render(RenderArgs* args) { auto destFbo = framebufferCache->getPrimaryFramebuffer(); batch.setFramebuffer(destFbo); - batch.generateTextureMipmap(lightingBuffer); + batch.generateTextureMips(lightingBuffer); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); From 61bad36d5c1b0a0ad40747724372c121040e60d5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 15 Dec 2015 18:49:04 -0800 Subject: [PATCH 085/318] tweaks --- examples/flowArts/lightBall/lightBallSpawner.js | 5 +++-- libraries/entities/src/ParticleEffectEntityItem.cpp | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index dd521b4fd4..505df7d83b 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -24,6 +24,7 @@ var containerBall = Entities.addEntity({ dimensions: {x: .1, y: .1, z: .1}, color: {red: 15, green: 10, blue: 150}, collisionsWillMove: true, + visible: false, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -82,8 +83,8 @@ var lightBall = Entities.addEntity({ "colorFinish": {red: 25, green: 20, blue:255}, "maxParticles": 100000, "lifespan": 5, - "emitRate": 500, - "emitSpeed": .02, + "emitRate": 5000, + "emitSpeed": .1, "speedSpread": .0, "emitDimensions": { "x": 0, diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 954074ec17..4d46439554 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -666,13 +666,14 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); - float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); + // float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); + float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * uniform_dist(el)); float azimuth; if (_azimuthFinish >= _azimuthStart) { - azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); + azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * uniform_dist(el); } else { - azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); + azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * uniform_dist(el); } glm::vec3 emitDirection; From 1364329886c27afb05d713c7571b652670dcee8a Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 15 Dec 2015 22:07:06 -0800 Subject: [PATCH 086/318] FIxing the compil bug by checking security of the call with assert and avoiding the compilation error --- libraries/render/src/render/DrawTask.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 52dc427251..ab102e32a7 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -86,19 +86,13 @@ public: template T& edit() { auto theConcept = std::dynamic_pointer_cast(_concept); - if (theConcept) { - return theConcept->_data; - } - assert(false); - return T(); + assert(theConcept); + return theConcept->_data; } template const T& get() const { auto theConcept = std::dynamic_pointer_cast(_concept); - if (theConcept) { - return theConcept->_data; - } - assert(false); - return T(); + assert(theConcept); + return theConcept->_data; } void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { From adf6cf8aa3f3d41ad79013ae8d2ee724de3b738c Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 16 Dec 2015 00:58:00 -0800 Subject: [PATCH 087/318] vary colors --- examples/lights/light_modifier.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index cbb4e3ff10..ed11b9c618 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -48,6 +48,12 @@ var WHITE = { blue: 255 }; +var ORANGE={ + red:255, + green:0, + blue:128 +} + var SLIDER_DIMENSIONS = { x: 0.075, y: 0.075, @@ -309,7 +315,7 @@ function makeSliders(light) { sliders.push(slidersRef.cutoff); } if (USE_EXPONENT_SLIDER === true) { - slidersRef.exponent = new entitySlider(light, PURPLE, 'exponent', 6); + slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 6); sliders.push(slidersRef.exponent); } subscribeToSliderMessages(); From 5a9549a2d951442bdc0b3fbf269f7984d126599b Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 16 Dec 2015 01:21:22 -0800 Subject: [PATCH 088/318] headers --- examples/lights/light_modifier.js | 2 +- examples/lights/light_modifier_test_scene.js | 2 +- examples/lights/slider.js | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/lights/light_modifier.js b/examples/lights/light_modifier.js index ed11b9c618..132934f5d2 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/light_modifier.js @@ -1,7 +1,7 @@ // // light_modifier.js // -// Created byJames Pollack @imgntn on 10/19/2015 +// Created byJames Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving. diff --git a/examples/lights/light_modifier_test_scene.js b/examples/lights/light_modifier_test_scene.js index d997816957..e70812cb45 100644 --- a/examples/lights/light_modifier_test_scene.js +++ b/examples/lights/light_modifier_test_scene.js @@ -1,7 +1,7 @@ // // light_modifier_test_scene.js // -// Created byJames Pollack @imgntn on 10/19/2015 +// Created byJames Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust. diff --git a/examples/lights/slider.js b/examples/lights/slider.js index ab90019b9f..ab59b6eed1 100644 --- a/examples/lights/slider.js +++ b/examples/lights/slider.js @@ -1,3 +1,13 @@ +// +// slider.js +// +// Created byJames Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. +// +// 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 AXIS_SCALE = 1; From 28a5dba2d32a0a2a96ff161fff58a4647a07f07e Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 16 Dec 2015 01:31:24 -0800 Subject: [PATCH 089/318] rename files --- examples/lights/lightLoader.js | 20 +++++++++++++++++++ .../{light_modifier.js => lightModifier.js} | 8 ++++---- ...est_scene.js => lightModifierTestScene.js} | 5 ++--- examples/lights/light_loader.js | 8 -------- examples/lights/slider.js | 5 +++-- 5 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 examples/lights/lightLoader.js rename examples/lights/{light_modifier.js => lightModifier.js} (98%) rename examples/lights/{light_modifier_test_scene.js => lightModifierTestScene.js} (95%) delete mode 100644 examples/lights/light_loader.js diff --git a/examples/lights/lightLoader.js b/examples/lights/lightLoader.js new file mode 100644 index 0000000000..e4022e7bc1 --- /dev/null +++ b/examples/lights/lightLoader.js @@ -0,0 +1,20 @@ +// +// lightLoader.js +// +// Created by James Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Loads a test scene showing sliders that you can grab and move to change entity properties. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); +Script.load(grabScript); +var lightModifier = Script.resolvePath('lightModifier.js'); +Script.load(lightModifier); +Script.setTimeout(function() { + var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js'); + Script.load(lightModifierTestScene); +}, 750) \ No newline at end of file diff --git a/examples/lights/light_modifier.js b/examples/lights/lightModifier.js similarity index 98% rename from examples/lights/light_modifier.js rename to examples/lights/lightModifier.js index 132934f5d2..ffd1469a4a 100644 --- a/examples/lights/light_modifier.js +++ b/examples/lights/lightModifier.js @@ -1,7 +1,7 @@ // -// light_modifier.js +// lightModifier.js // -// Created byJames Pollack @imgntn on 12/15/2015 +// Created by James Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving. @@ -201,13 +201,13 @@ entitySlider.prototype = { //message is not for our light if (message.lightID !== this.lightID) { - print('not our light') + // print('not our light') return; } //message is not our type if (message.sliderType !== this.sliderType) { - print('not our slider type') + // print('not our slider type') return } diff --git a/examples/lights/light_modifier_test_scene.js b/examples/lights/lightModifierTestScene.js similarity index 95% rename from examples/lights/light_modifier_test_scene.js rename to examples/lights/lightModifierTestScene.js index e70812cb45..214d900130 100644 --- a/examples/lights/light_modifier_test_scene.js +++ b/examples/lights/lightModifierTestScene.js @@ -1,7 +1,7 @@ // -// light_modifier_test_scene.js +// lightModifierTestScene.js // -// Created byJames Pollack @imgntn on 12/15/2015 +// Created by James Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Given a selected light, instantiate some entities that represent various values you can dynamically adjust. @@ -116,7 +116,6 @@ function evalLightWorldTransform(modelPos, modelRot) { } function cleanup() { - print('CLEANUP TEST SCENE SCRIPT') Entities.deleteEntity(block); Entities.deleteEntity(ground); Entities.deleteEntity(light); diff --git a/examples/lights/light_loader.js b/examples/lights/light_loader.js deleted file mode 100644 index 8edaa20f57..0000000000 --- a/examples/lights/light_loader.js +++ /dev/null @@ -1,8 +0,0 @@ -var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); -Script.load(grabScript); -var lightModifier = Script.resolvePath('light_modifier.js'); -Script.load(lightModifier); -Script.setTimeout(function() { - var lightModifierTestScene = Script.resolvePath('light_modifier_test_scene.js'); - Script.load(lightModifierTestScene); -}, 750) \ No newline at end of file diff --git a/examples/lights/slider.js b/examples/lights/slider.js index ab59b6eed1..c17704b0db 100644 --- a/examples/lights/slider.js +++ b/examples/lights/slider.js @@ -1,13 +1,14 @@ // // slider.js // -// Created byJames Pollack @imgntn on 12/15/2015 +// Created by James Pollack @imgntn on 12/15/2015 // Copyright 2015 High Fidelity, Inc. // // Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. // // 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 AXIS_SCALE = 1; @@ -60,7 +61,7 @@ this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; - print('SLIDER VALUE:::' + this.sliderValue) + //print('SLIDER VALUE:::' + this.sliderValue) this.sendValueToSlider(); }, From 08f75917876e1e50f7a7c1a4c9f051a12355b117 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Wed, 16 Dec 2015 10:02:47 -0800 Subject: [PATCH 090/318] Fix misspelling --- interface/src/ui/overlays/Image3DOverlay.cpp | 16 ++++++++-------- interface/src/ui/overlays/Image3DOverlay.h | 2 +- .../render-utils/src/DeferredLightingEffect.cpp | 4 ++-- .../render-utils/src/DeferredLightingEffect.h | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 6e4c274943..7d105a6ccf 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -27,7 +27,7 @@ QString const Image3DOverlay::TYPE = "image3d"; Image3DOverlay::Image3DOverlay() { _isLoaded = false; - _emmisive = false; + _emissive = false; } Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : @@ -35,7 +35,7 @@ Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : _url(image3DOverlay->_url), _texture(image3DOverlay->_texture), _fromImage(image3DOverlay->_fromImage), - _emmisive(image3DOverlay->_emmisive) + _emissive(image3DOverlay->_emissive) { } @@ -96,7 +96,7 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emmisive, true); + DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emissive, true); DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) @@ -147,9 +147,9 @@ void Image3DOverlay::setProperties(const QScriptValue &properties) { } } - QScriptValue emmisiveValue = properties.property("emmisive"); - if (emmisiveValue.isValid()) { - _emmisive = emmisiveValue.toBool(); + QScriptValue emissiveValue = properties.property("emissive"); + if (emissiveValue.isValid()) { + _emissive = emissiveValue.toBool(); } } @@ -163,8 +163,8 @@ QScriptValue Image3DOverlay::getProperty(const QString& property) { if (property == "offsetPosition") { return vec3toScriptValue(_scriptEngine, getOffsetPosition()); } - if (property == "emmisive") { - return _emmisive; + if (property == "emissive") { + return _emissive; } return Billboard3DOverlay::getProperty(property); diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index 0e40c73619..f2cc3789ee 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -46,7 +46,7 @@ public: private: QString _url; NetworkTexturePointer _texture; - bool _emmisive; + bool _emissive; QRect _fromImage; // where from in the image to sample }; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 10b58b156b..dcadaa5177 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -169,8 +169,8 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, - bool emmisive, bool depthBias) { - SimpleProgramKey config{textured, culled, emmisive, depthBias}; + bool emissive, bool depthBias) { + SimpleProgramKey config{textured, culled, emissive, depthBias}; gpu::PipelinePointer pipeline = getPipeline(config); batch.setPipeline(pipeline); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9c4809a82e..eee5993c29 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -38,7 +38,7 @@ public: /// Sets up the state necessary to render static untextured geometry with the simple program. gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, - bool emmisive = false, bool depthBias = false); + bool emissive = false, bool depthBias = false); void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { From b0bcbb03f2bee5fa5c299c9f20774fd0d7ddea04 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 11:57:54 -0800 Subject: [PATCH 091/318] remove floor and move sliders up a bit --- examples/lights/lightModifier.js | 84 +++++++++++++++++++++-- examples/lights/lightModifierTestScene.js | 46 ++++--------- examples/lights/slider.js | 3 +- 3 files changed, 92 insertions(+), 41 deletions(-) diff --git a/examples/lights/lightModifier.js b/examples/lights/lightModifier.js index ffd1469a4a..0a584b127c 100644 --- a/examples/lights/lightModifier.js +++ b/examples/lights/lightModifier.js @@ -10,6 +10,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +// Script.include('../libraries/lightOverlayManager.js'); +// var lightOverlayManager = new LightOverlayManager(); +// lightOverlayManager.setVisible(true); + + // var pickRay = Camera.computePickRay(event.x, event.y); + // var lightResult = lightOverlayManager.findRayIntersection(pickRay) + + +var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' +var SHOULD_STAY_WITH_AVATAR = false; +var VERTICAL_SLIDERS = false; + var AXIS_SCALE = 1; var COLOR_MAX = 255; var INTENSITY_MAX = 0.05; @@ -48,10 +61,10 @@ var WHITE = { blue: 255 }; -var ORANGE={ - red:255, - green:0, - blue:128 +var ORANGE = { + red: 255, + green: 0, + blue: 128 } var SLIDER_DIMENSIONS = { @@ -75,6 +88,7 @@ function entitySlider(light, color, sliderType, row) { this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); + this.basePosition.y +=1; var message = { lightID: this.lightID, @@ -190,6 +204,10 @@ entitySlider.prototype = { sliderType: this.sliderType, axisStart: position, axisEnd: this.endOfAxis, + }, + releaseVelocityKey: { + disableReleaseVelocity: true, + customReleaseVelocity: false } }) }; @@ -201,13 +219,13 @@ entitySlider.prototype = { //message is not for our light if (message.lightID !== this.lightID) { - // print('not our light') + // print('not our light') return; } //message is not our type if (message.sliderType !== this.sliderType) { - // print('not our slider type') + // print('not our slider type') return } @@ -381,8 +399,62 @@ function deleteEntity(entityID) { } + Entities.deletingEntity.connect(deleteEntity); +// search for lights to make grabbable + +// var USE_DEBOUNCE = true; +// var sinceLastUpdate = 0; + +// function searchForLightsToVisualize() { + +// var deltaTime = interval(); + +// if (USE_DEBOUNCE === true) { +// sinceLastUpdate = sinceLastUpdate + deltaTime; + +// if (sinceLastUpdate > 60) { +// sinceLastUpdate = 0; +// } else { +// return; +// } +// } + +// print('SEARCHING FOR LIGHTS'); + +// var entitites = Entities.findEntities(MyAvatar.position, 50); +// for (i = 0; i < entities.length; i++) { +// var entityProperties = Entities.getEntityProperties(entities[i], ['type', 'parentID']) +// var parentID = entityProperties.parentID; +// var type = entityProperties.type; + +// if (type !== 'Light') { +// return; +// } + +// if (type === "Light" && parentID !== DEFAULT_PARENT_ID && parentID !== null) { +// var light = entities[i]; +// //do something with the light. +// } + +// } + +// } + +// function interval() { +// var lastTime = new Date().getTime(); + +// return function getInterval() { +// var newTime = new Date().getTime(); +// var delta = newTime - lastTime; +// lastTime = newTime; +// return delta; +// }; +// } + + + //other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, diff --git a/examples/lights/lightModifierTestScene.js b/examples/lights/lightModifierTestScene.js index 214d900130..5748f0d4ed 100644 --- a/examples/lights/lightModifierTestScene.js +++ b/examples/lights/lightModifierTestScene.js @@ -9,39 +9,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 -}; -var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 -}); var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); -basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(-3, Quat.getUp(avatarRot))); - -var ground = Entities.addEntity({ - name: 'Hifi-Light-Mod-Floor', - //type: "Model", - type: 'Box', - color: { - red: 100, - green: 100, - blue: 100 - }, - //modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/woodFloor.fbx", - dimensions: { - x: 100, - y: 2, - z: 100 - }, - position: basePosition, - shapeType: 'box' -}); +basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot))); var light, block; @@ -87,7 +58,7 @@ function createLight() { function createBlock() { var position = basePosition; - position.y += 5; + position.y += 3; var blockProperties = { name: 'Hifi-Spotlight-Block', type: 'Box', @@ -103,12 +74,22 @@ function createBlock() { blue: 255 }, position: position - } + }; block = Entities.addEntity(blockProperties); } function evalLightWorldTransform(modelPos, modelRot) { + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); return { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) @@ -117,7 +98,6 @@ function evalLightWorldTransform(modelPos, modelRot) { function cleanup() { Entities.deleteEntity(block); - Entities.deleteEntity(ground); Entities.deleteEntity(light); } diff --git a/examples/lights/slider.js b/examples/lights/slider.js index c17704b0db..dc02e0bdba 100644 --- a/examples/lights/slider.js +++ b/examples/lights/slider.js @@ -9,6 +9,7 @@ // 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 AXIS_SCALE = 1; @@ -61,9 +62,7 @@ this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); }; - //print('SLIDER VALUE:::' + this.sliderValue) this.sendValueToSlider(); - }, releaseGrab: function() { Entities.editEntity(this.entityID, { From 6cd86e8a6bf2371079416dfa3b5c387eddc05696 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 12:23:10 -0800 Subject: [PATCH 092/318] midday --- examples/lights/lightModifier.js | 68 +++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/examples/lights/lightModifier.js b/examples/lights/lightModifier.js index 0a584b127c..e928679f08 100644 --- a/examples/lights/lightModifier.js +++ b/examples/lights/lightModifier.js @@ -11,17 +11,20 @@ // +//some experimental options +var ONLY_I_CAN_EDIT = false; +var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; +var VERTICAL_SLIDERS = false; + // Script.include('../libraries/lightOverlayManager.js'); // var lightOverlayManager = new LightOverlayManager(); // lightOverlayManager.setVisible(true); - // var pickRay = Camera.computePickRay(event.x, event.y); - // var lightResult = lightOverlayManager.findRayIntersection(pickRay) - +// var pickRay = Camera.computePickRay(event.x, event.y); +// var lightResult = lightOverlayManager.findRayIntersection(pickRay) var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' -var SHOULD_STAY_WITH_AVATAR = false; -var VERTICAL_SLIDERS = false; + var AXIS_SCALE = 1; var COLOR_MAX = 255; @@ -88,7 +91,7 @@ function entitySlider(light, color, sliderType, row) { this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); - this.basePosition.y +=1; + this.basePosition.y += 1; var message = { lightID: this.lightID, @@ -134,14 +137,23 @@ function entitySlider(light, color, sliderType, row) { entitySlider.prototype = { createAxis: function() { //start of line - var position = Vec3.sum(this.basePosition, this.verticalOffset); + var position; + var extension; - //line starts on left and goes to right - //set the end of the line to the right - var rightVector = Quat.getRight(this.avatarRot); - var extension = Vec3.multiply(AXIS_SCALE, rightVector); - var endOfAxis = Vec3.sum(position, extension); - this.endOfAxis = endOfAxis; + if (VERTICAL_SLIDERS == true) { + position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot))))); + //line starts on bottom and goes up + var upVector = Quat.getUp(this.avatarRot); + extension = Vec3.multiply(AXIS_SCALE, upVector); + } else { + position = Vec3.sum(this.basePosition, this.verticalOffset); + //line starts on left and goes to right + //set the end of the line to the right + var rightVector = Quat.getRight(this.avatarRot); + extension = Vec3.multiply(AXIS_SCALE, rightVector); + } + + this.endOfAxis = Vec3.sum(position, extension); var properties = { type: 'Line', name: 'Hifi-Slider-Axis::' + this.sliderType, @@ -165,10 +177,18 @@ entitySlider.prototype = { this.axis = Entities.addEntity(properties); }, createSliderIndicator: function() { - var position = Vec3.sum(this.basePosition, this.verticalOffset); - //line starts on left and goes to right - //set the end of the line to the right - var rightVector = Quat.getRight(this.avatarRot); + var extensionVector; + var position; + if (VERTICAL_SLIDERS == true) { + position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot))))); + extensionVector = Quat.getUp(this.avatarRot); + + } else { + position = Vec3.sum(this.basePosition, this.verticalOffset); + extensionVector = Quat.getRight(this.avatarRot); + + } + var initialDistance; if (this.sliderType === 'color_red') { initialDistance = this.distanceRed; @@ -188,11 +208,13 @@ entitySlider.prototype = { if (this.sliderType === 'exponent') { initialDistance = this.distanceExponent; } - var extension = Vec3.multiply(initialDistance, rightVector); + + var extension = Vec3.multiply(initialDistance, extensionVector); var sliderPosition = Vec3.sum(position, extension); + var properties = { type: 'Sphere', - name: 'Hifi-Slider::' + this.sliderType, + name: 'Hifi-Slider-' + this.sliderType, dimensions: SLIDER_DIMENSIONS, collisionsWillMove: true, color: this.color, @@ -367,10 +389,9 @@ function handleValueMessages(channel, message, sender) { if (channel !== 'Hifi-Slider-Value-Reciever') { return; } - //easily protect from other people editing your values, but group editing might be fun so lets try that first. - // if (sender !== MyAvatar.sessionUUID) { - // return; - // } + if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) { + return; + } var parsedMessage = JSON.parse(message); slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage); @@ -455,7 +476,6 @@ Entities.deletingEntity.connect(deleteEntity); - //other light properties // diffuseColor: { red: 255, green: 255, blue: 255 }, // ambientColor: { red: 255, green: 255, blue: 255 }, From 711d02ba2f44d7bef93c36e8079642d35e72e105 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 14:26:24 -0600 Subject: [PATCH 093/318] Consolidating installer checkpoint --- CMakeLists.txt | 42 ++--- cmake/macros/ConsolidateStackComponents.cmake | 37 ++-- cmake/modules/FindOpenSSL.cmake | 1 - tools/nsis/release.nsi | 176 ++++++++++++++++++ 4 files changed, 207 insertions(+), 49 deletions(-) create mode 100644 tools/nsis/release.nsi diff --git a/CMakeLists.txt b/CMakeLists.txt index a8271abd8e..836b808a4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12.2) +cmake_minimum_required(VERSION 3.3.2) if (USE_ANDROID_TOOLCHAIN) set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake") @@ -230,32 +230,14 @@ endif () include_application_version() if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - message(STATUS "+++++ Package for deployment will be generated on this build +++++") - - file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/full-stack-deployment) - - set(ICONPATH_INTERFACE "$INSTDIR/${PATH_INSTALL_DATA}/interface.ico") - set(ICONPATH_STACK_MANAGER "$INSTDIR/${PATH_INSTALL_DATA}/stack-manager.ico") - string(REPLACE "/" "\\\\" ICONPATH_INTERFACE ${ICONPATH_INTERFACE}) - string(REPLACE "/" "\\\\" ICONPATH_STACK_MANAGER ${ICONPATH_STACK_MANAGER}) - - set(CPACK_PACKAGE_NAME "High Fidelity") - set(CPACK_PACKAGE_VENDOR "High Fidelity, Inc") - set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "High Fidelity Interface and Stack") - set(CPACK_PACKAGE_VERSION "${BUILD_SEQ}") - set(CPACK_PACKAGE_VERSION_MAJOR "${BUILD_SEQ}") - set(CPACK_PACKAGE_VERSION_MINOR "0") - set(CPACK_PACKAGE_VERSION_PATCH "0") - set(CPACK_PACKAGE_INSTALL_DIRECTORY "High Fidelity-${BUILD_SEQ}") - set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - set(CPACK_PACKAGE_EXECUTABLES - stack-manager "Stack Manager" - interface "Interface" - ) - - if (WIN32) - install(DIRECTORY ${CMAKE_BINARY_DIR}/full-stack-deployment/ DESTINATION "./") - endif (WIN32) - - include(CPack) -endif () + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment") + find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) + if (NOT MAKENSIS_COMMAND) + message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") + endif () + add_custom_target( + build-package ALL + DEPENDS interface assignment-client domain-server stack-manager + COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" + ) +endif () \ No newline at end of file diff --git a/cmake/macros/ConsolidateStackComponents.cmake b/cmake/macros/ConsolidateStackComponents.cmake index 4bcc777751..ca272f6485 100644 --- a/cmake/macros/ConsolidateStackComponents.cmake +++ b/cmake/macros/ConsolidateStackComponents.cmake @@ -1,26 +1,27 @@ macro(CONSOLIDATE_STACK_COMPONENTS) - if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE AND WIN32) - - # Copy all the output for this target into the common deployment location - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory $ ${CMAKE_BINARY_DIR}/full-stack-deployment - ) - - # Copy icon files for interface and stack manager - if (TARGET_NAME STREQUAL "interface" OR TARGET_NAME STREQUAL "stack-manager") - if (TARGET_NAME STREQUAL "interface") - set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/interface.ico") - set (ICON_DESTINATION_NAME "interface.ico") - elseif (TARGET_NAME STREQUAL "stack-manager") - set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/assets/icon.ico") - set (ICON_DESTINATION_NAME "stack-manager.ico") - endif () + if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) + if (WIN32) + # Copy all the output for this target into the common deployment location add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/full-stack-deployment/${ICON_DESTINATION_NAME} + COMMAND "${CMAKE_COMMAND}" -E copy_directory $ ${CMAKE_BINARY_DIR}/full-stack-deployment ) + + # Copy icon files for interface and stack manager + if (TARGET_NAME STREQUAL "interface" OR TARGET_NAME STREQUAL "stack-manager") + if (TARGET_NAME STREQUAL "interface") + set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/interface.ico") + set (ICON_DESTINATION_NAME "interface.ico") + elseif (TARGET_NAME STREQUAL "stack-manager") + set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/assets/icon.ico") + set (ICON_DESTINATION_NAME "stack-manager.ico") + endif () + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/full-stack-deployment/${ICON_DESTINATION_NAME} + ) + endif () endif () endif () diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 6893948d01..9d9557ad9e 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -256,7 +256,6 @@ if (WIN32) # For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this # but for now resorting to the following interm solution if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - message(STATUS "*********** Copying SSL DLL from ${OPENSSL_DLL_PATH}/ssleay32.dll") add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/full-stack-deployment/ diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi new file mode 100644 index 0000000000..5b2cce5c61 --- /dev/null +++ b/tools/nsis/release.nsi @@ -0,0 +1,176 @@ +!include LogicLib.nsh +!include x64.nsh + +!define srcdir "E:\development\md-hifi\build\full-stack-deployment" ;$%INSTALLER_SOURCE_DIR% +!define setup "E:\development\md-hifi\build\installer-test.exe" ;$%INSTALLER_NAME% +!define scriptsdir "E:\development\md-hifi\examples" ;$%INSTALLER_SCRIPTS_DIR% +!define company "High Fidelity" +!define prodname "Interface" +!define exec "interface.exe" +!define icon "${srcdir}\interface.ico" +!define regkey "Software\${company}\${prodname}" +!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prodname}" +!define install_dir_company "$PROGRAMFILES64\${company}" +!define install_dir_product "${install_dir_company}\${prodname}" +!define startmenu_company "$SMPROGRAMS\${company}" +!define startmenu_product "${startmenu_company}\${prodname}" +!define uninstaller "uninstall.exe" + +;-------------------------------- + +XPStyle on +ShowInstDetails hide +ShowUninstDetails hide + +Name "${prodname}" +Caption "${prodname}" + +!ifdef icon + Icon "${icon}" +!endif + +OutFile "${setup}" + +SetDateSave on +SetDatablockOptimize on +CRCCheck on +SilentInstall normal + +InstallDir "${install_dir_product}" +InstallDirRegKey HKLM "${regkey}" "" + +; Page components +Page directory +Page components +Page instfiles + +UninstPage uninstConfirm +UninstPage instfiles + +;-------------------------------- + +AutoCloseWindow true +ShowInstDetails show + + +!ifdef screenimage + + ; set up background image + ; uses BgImage plugin + + Function .onGUIInit + ; extract background BMP into temp plugin directory + InitPluginsDir + File /oname=$PLUGINSDIR\1.bmp "${screenimage}" + + BgImage::SetBg /NOUNLOAD /FILLSCREEN $PLUGINSDIR\1.bmp + BgImage::Redraw /NOUNLOAD + FunctionEnd + + Function .onGUIEnd + ; Destroy must not have /NOUNLOAD so NSIS will be able to unload and delete BgImage before it exits + BgImage::Destroy + FunctionEnd + +!endif + +; Optional Component Selection +Section /o "DDE Face Recognition" SEC01 + SetOutPath "$INSTDIR" + CreateDirectory $INSTDIR\dde + NSISdl::download "https://s3-us-west-1.amazonaws.com/hifi-production/optionals/dde-installer.exe" "$INSTDIR\dde-installer.exe" + ExecWait '"$INSTDIR\dde-installer.exe" /q:a /t:"$INSTDIR\dde"' +SectionEnd + +; beginning (invisible) section +Section "Registry Entries and Procotol Handler" SEC02 + + SectionIn RO + + WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" + WriteRegStr HKLM "${uninstkey}" "DisplayName" "${prodname} (remove only)" + WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"' + WriteRegStr HKCR "${prodname}\Shell\open\command\" "" '"$INSTDIR\${exec} "%1"' + + !ifdef icon + WriteRegStr HKCR "${prodname}\DefaultIcon" "" "$INSTDIR\${icon}" + !endif + + ; hifi:// protocol handler registry entries + WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' + WriteRegStr HKCR 'hifi' 'URL Protocol' '' + WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${icon},1' + WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${exec} --url "%1"' + + SetOutPath $INSTDIR + + ; package all files, recursively, preserving attributes + ; assume files are in the correct places + File /r "${srcdir}\" + !ifdef icon + File /a "${icon}" + !endif + ; any application-specific files + !ifdef files + !include "${files}" + !endif + SetOutPath "$DOCUMENTS\${company}\Scripts" + File /r "${scriptsdir}\" + SetOutPath $INSTDIR + WriteUninstaller "${uninstaller}" + Exec '"$INSTDIR\2013_vcredist_x64.exe" /q /norestart' + Exec '"$INSTDIR\2010_vcredist_x86.exe" /q /norestart' +SectionEnd + +; create shortcuts +Section "Start Menu Shortcuts" SEC03 + + SectionIn RO + + ; This should install the shortcuts for "All Users" + SetShellVarContext all + CreateDirectory "${startmenu_product}" + SetOutPath $INSTDIR ; for working directory + !ifdef icon + CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\${icon}" + !else + CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" + !endif + + CreateShortCut "${startmenu_product}\Uninstall ${prodname}.lnk" "$INSTDIR\${uninstaller}" +SectionEnd + +; Uninstaller +; All section names prefixed by "Un" will be in the uninstaller + +UninstallText "This will uninstall ${prodname}." + +!ifdef icon + UninstallIcon "${icon}" +!endif + +Section "Uninstall" SEC04 + + SectionIn RO + + ; Explicitly remove all added shortcuts + SetShellVarContext all + DELETE "${startmenu_product}\${prodname}.lnk" + DELETE "${startmenu_product}\Uninstall ${prodname}.lnk" + + RMDIR "${startmenu_product}" + ; This should remove the High Fidelity folder in Start Menu if it's empty + RMDIR "${startmenu_company}" + + RMDIR /r "$INSTDIR" + ; This should remove the High Fidelity folder in Program Files if it's empty + RMDIR "${install_dir_company}" + + !ifdef unfiles + !include "${unfiles}" + !endif + ; It's good practice to put the registry key removal at the very end + DeleteRegKey HKLM "${uninstkey}" + DeleteRegKey HKLM "${regkey}" + DeleteRegKey HKCR 'hifi' +SectionEnd \ No newline at end of file From 56ef52022dd17d9defc3fe25c144337b0826eb33 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 14:28:05 -0600 Subject: [PATCH 094/318] Removing unwanted changes --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 7741445842..a2eb058ae6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -### TESTING BUILD - DO NOT MERGE ### - High Fidelity (hifi) is an early-stage technology lab experimenting with Virtual Worlds and VR. In this repository you'll find the source to many of the components in our From 5ed422e3a19687a941fb5476212a30d854ccaaec Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 14:28:49 -0600 Subject: [PATCH 095/318] Removing unwanted changes --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 836b808a4c..b2ed36a8c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,9 +67,9 @@ if ((NOT MSVC12) AND (NOT MSVC14)) CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) if (COMPILER_SUPPORTS_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") elseif(COMPILER_SUPPORTS_CXX0X) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") else() message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") endif() @@ -235,9 +235,9 @@ if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) if (NOT MAKENSIS_COMMAND) message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") endif () - add_custom_target( - build-package ALL - DEPENDS interface assignment-client domain-server stack-manager + add_custom_target( + build-package ALL + DEPENDS interface assignment-client domain-server stack-manager COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" - ) + ) endif () \ No newline at end of file From cbed8bf35a8001c309b8a136fbd5c04650e96251 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 15:12:14 -0600 Subject: [PATCH 096/318] NSIS Changes --- CMakeLists.txt | 3 ++ tools/nsis/release.nsi | 71 +++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2ed36a8c5..69e6365c8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,6 +238,9 @@ if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) add_custom_target( build-package ALL DEPENDS interface assignment-client domain-server stack-manager + COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment + COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/this-is-a-test.exe + COMMANE set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" ) endif () \ No newline at end of file diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi index 5b2cce5c61..86ea055e6b 100644 --- a/tools/nsis/release.nsi +++ b/tools/nsis/release.nsi @@ -1,19 +1,18 @@ !include LogicLib.nsh !include x64.nsh -!define srcdir "E:\development\md-hifi\build\full-stack-deployment" ;$%INSTALLER_SOURCE_DIR% -!define setup "E:\development\md-hifi\build\installer-test.exe" ;$%INSTALLER_NAME% -!define scriptsdir "E:\development\md-hifi\examples" ;$%INSTALLER_SCRIPTS_DIR% -!define company "High Fidelity" -!define prodname "Interface" -!define exec "interface.exe" -!define icon "${srcdir}\interface.ico" -!define regkey "Software\${company}\${prodname}" -!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prodname}" +!define srcdir $%INSTALLER_SOURCE_DIR% +!define setup $%INSTALLER_NAME% +!define scriptsdir $%INSTALLER_SCRIPTS_DIR% +!define company $%INSTALLER_COMPANY% +!define interface_exec "interface.exe" +!define stack_manager_exec "stack-manager.exe" +!define interface_icon "interface.ico" +!define stack_manager_icon "stack-manager.ico" +!define regkey "Software\${company}" +!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${company}" !define install_dir_company "$PROGRAMFILES64\${company}" -!define install_dir_product "${install_dir_company}\${prodname}" !define startmenu_company "$SMPROGRAMS\${company}" -!define startmenu_product "${startmenu_company}\${prodname}" !define uninstaller "uninstall.exe" ;-------------------------------- @@ -22,8 +21,8 @@ XPStyle on ShowInstDetails hide ShowUninstDetails hide -Name "${prodname}" -Caption "${prodname}" +Name "${company}" +Caption "${company}" !ifdef icon Icon "${icon}" @@ -36,7 +35,7 @@ SetDatablockOptimize on CRCCheck on SilentInstall normal -InstallDir "${install_dir_product}" +InstallDir "${install_dir_company}" InstallDirRegKey HKLM "${regkey}" "" ; Page components @@ -88,35 +87,28 @@ Section "Registry Entries and Procotol Handler" SEC02 SectionIn RO WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" - WriteRegStr HKLM "${uninstkey}" "DisplayName" "${prodname} (remove only)" + WriteRegStr HKLM "${uninstkey}" "DisplayName" "${company} (remove only)" WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"' - WriteRegStr HKCR "${prodname}\Shell\open\command\" "" '"$INSTDIR\${exec} "%1"' - - !ifdef icon - WriteRegStr HKCR "${prodname}\DefaultIcon" "" "$INSTDIR\${icon}" - !endif + WriteRegStr HKCR "${company}\Shell\open\command\" "" '"$INSTDIR\${interface_exec} "%1"' + WriteRegStr HKCR "${company}\DefaultIcon" "" "$INSTDIR\${interface_icon}" ; hifi:// protocol handler registry entries WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' WriteRegStr HKCR 'hifi' 'URL Protocol' '' - WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${icon},1' - WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${exec} --url "%1"' + WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${interface_icon},1' + WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${interface_exec} --url "%1"' SetOutPath $INSTDIR ; package all files, recursively, preserving attributes ; assume files are in the correct places File /r "${srcdir}\" - !ifdef icon - File /a "${icon}" - !endif + File /a "${srcdir}\${interface_icon}" + File /a "${srcdir}\${stack_manager_icon}" ; any application-specific files !ifdef files !include "${files}" !endif - SetOutPath "$DOCUMENTS\${company}\Scripts" - File /r "${scriptsdir}\" - SetOutPath $INSTDIR WriteUninstaller "${uninstaller}" Exec '"$INSTDIR\2013_vcredist_x64.exe" /q /norestart' Exec '"$INSTDIR\2010_vcredist_x86.exe" /q /norestart' @@ -129,24 +121,20 @@ Section "Start Menu Shortcuts" SEC03 ; This should install the shortcuts for "All Users" SetShellVarContext all - CreateDirectory "${startmenu_product}" + CreateDirectory "${startmenu_company}" SetOutPath $INSTDIR ; for working directory - !ifdef icon - CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\${icon}" - !else - CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" - !endif - - CreateShortCut "${startmenu_product}\Uninstall ${prodname}.lnk" "$INSTDIR\${uninstaller}" + CreateShortCut "${startmenu_company}\Interface.lnk" "$INSTDIR\${interface_exec}" "" "$INSTDIR\${interface_icon}" + CreateShortCut "${startmenu_company}\Stack Manager.lnk" "$INSTDIR\${stack_manager_exec}" "" "$INSTDIR\${stack_manager_icon}" + CreateShortCut "${startmenu_company}\Uninstall ${company}.lnk" "$INSTDIR\${uninstaller}" SectionEnd ; Uninstaller ; All section names prefixed by "Un" will be in the uninstaller -UninstallText "This will uninstall ${prodname}." +UninstallText "This will uninstall ${company}." !ifdef icon - UninstallIcon "${icon}" + UninstallIcon "${interface_icon}" !endif Section "Uninstall" SEC04 @@ -155,11 +143,10 @@ Section "Uninstall" SEC04 ; Explicitly remove all added shortcuts SetShellVarContext all - DELETE "${startmenu_product}\${prodname}.lnk" - DELETE "${startmenu_product}\Uninstall ${prodname}.lnk" + DELETE "${startmenu_company}\Interface.lnk" + DELETE "${startmenu_company}\Stack Manager.lnk" + DELETE "${startmenu_company}\Uninstall ${company}.lnk" - RMDIR "${startmenu_product}" - ; This should remove the High Fidelity folder in Start Menu if it's empty RMDIR "${startmenu_company}" RMDIR /r "$INSTDIR" From e37d68449bb3b344936bc5ad0845098c878cc57f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 13:57:40 -0800 Subject: [PATCH 097/318] rename folder --- examples/controllers/handControllerGrab.js | 4 ++-- examples/{lights => light_modifier}/lightLoader.js | 0 examples/{lights => light_modifier}/lightModifier.js | 0 examples/{lights => light_modifier}/lightModifierTestScene.js | 0 examples/{lights => light_modifier}/slider.js | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename examples/{lights => light_modifier}/lightLoader.js (100%) rename examples/{lights => light_modifier}/lightModifier.js (100%) rename examples/{lights => light_modifier}/lightModifierTestScene.js (100%) rename examples/{lights => light_modifier}/slider.js (100%) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index c452519522..e7d1b5f84b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -944,7 +944,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, + kinematicSetVelocity: false, ignoreIK: this.ignoreIK }); if (this.actionID === NULL_ACTION_ID) { @@ -1029,7 +1029,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: true, + kinematicSetVelocity: false, ignoreIK: this.ignoreIK }); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); diff --git a/examples/lights/lightLoader.js b/examples/light_modifier/lightLoader.js similarity index 100% rename from examples/lights/lightLoader.js rename to examples/light_modifier/lightLoader.js diff --git a/examples/lights/lightModifier.js b/examples/light_modifier/lightModifier.js similarity index 100% rename from examples/lights/lightModifier.js rename to examples/light_modifier/lightModifier.js diff --git a/examples/lights/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js similarity index 100% rename from examples/lights/lightModifierTestScene.js rename to examples/light_modifier/lightModifierTestScene.js diff --git a/examples/lights/slider.js b/examples/light_modifier/slider.js similarity index 100% rename from examples/lights/slider.js rename to examples/light_modifier/slider.js From fcfa3969125e956b983401983a5964a86721968a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 13:58:55 -0800 Subject: [PATCH 098/318] syntax tweak --- examples/flowArts/lightBall/lightBallSpawner.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 505df7d83b..20a9c312fc 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -24,7 +24,6 @@ var containerBall = Entities.addEntity({ dimensions: {x: .1, y: .1, z: .1}, color: {red: 15, green: 10, blue: 150}, collisionsWillMove: true, - visible: false, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -85,7 +84,7 @@ var lightBall = Entities.addEntity({ "lifespan": 5, "emitRate": 5000, "emitSpeed": .1, - "speedSpread": .0, + "speedSpread": 0.0, "emitDimensions": { "x": 0, "y": 0, From d3c57821c0338b70e068b01f2b5f6c9721609773 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Dec 2015 14:00:04 -0800 Subject: [PATCH 099/318] call a method on actions before each physics simulation step. use this to attempt to dejitter held objects --- interface/src/Application.cpp | 3 + interface/src/avatar/AvatarActionHold.cpp | 70 ++++++++++++++++++- interface/src/avatar/AvatarActionHold.h | 14 ++-- .../entities/src/EntityActionInterface.h | 2 + libraries/physics/src/CharacterController.cpp | 13 ++++ libraries/physics/src/CharacterController.h | 2 + libraries/physics/src/ObjectAction.h | 34 ++++----- libraries/physics/src/ObjectActionOffset.h | 10 +-- libraries/physics/src/ObjectActionSpring.h | 10 +-- libraries/physics/src/PhysicsEngine.cpp | 8 +++ libraries/physics/src/PhysicsEngine.h | 1 + 11 files changed, 134 insertions(+), 33 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f3291469cb..e28d1b2eac 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2989,6 +2989,9 @@ void Application::update(float deltaTime) { _physicsEngine->changeObjects(motionStates); myAvatar->prepareForPhysicsSimulation(); + _physicsEngine->forEachAction([&](EntityActionPointer action) { + action->prepareForPhysicsSimulation(); + }); getEntities()->getTree()->withWriteLock([&] { _physicsEngine->stepSimulation(); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index fab838aa68..87cf53143c 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -14,6 +14,7 @@ #include #include "avatar/AvatarManager.h" +#include "CharacterController.h" const uint16_t AvatarActionHold::holdVersion = 1; @@ -32,6 +33,57 @@ AvatarActionHold::~AvatarActionHold() { #endif } +void AvatarActionHold::prepareForPhysicsSimulation() { + auto avatarManager = DependencyManager::get(); + auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); + + if (!holdingAvatar) { + return; + } + + withTryReadLock([&]{ + bool isRightHand = (_hand == "right"); + + if (_ignoreIK && holdingAvatar->isMyAvatar()) { + return; + } + + if (holdingAvatar->isMyAvatar()) { + glm::vec3 palmPosition { Vectors::ZERO }; + glm::quat palmRotation { Quaternions::IDENTITY }; + if (isRightHand) { + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); + } else { + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); + } + + // XXX dup code + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; + if (!controller) { + qDebug() << "AvatarActionHold::prepareForPhysicsSimulation failed to get character controller"; + return; + } + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + + + if (isRightHand) { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + + _palmOffsetFromRigidBody = palmPosition - avatarRigidBodyPosition; + } + }); +} + std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) { auto avatarManager = DependencyManager::get(); auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); @@ -44,7 +96,7 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve bool isRightHand = (_hand == "right"); glm::vec3 palmPosition { Vectors::ZERO }; glm::quat palmRotation { Quaternions::IDENTITY }; - + if (_ignoreIK && holdingAvatar->isMyAvatar()) { // We cannot ignore other avatars IK and this is not the point of this option // This is meant to make the grabbing behavior more reactive. @@ -55,6 +107,22 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } + } else if (holdingAvatar->isMyAvatar()) { + // XXX dup code + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; + if (!controller) { + qDebug() << "AvatarActionHold::prepareForPhysicsSimulation failed to get character controller"; + return; + } + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + + + + palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; + palmRotation = holdingAvatar->getRightPalmRotation(); // XXX } else { if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 63f30a75d9..2746c817ca 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -25,18 +25,20 @@ public: AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity); virtual ~AvatarActionHold(); - virtual bool updateArguments(QVariantMap arguments); - virtual QVariantMap getArguments(); + virtual bool updateArguments(QVariantMap arguments) override; + virtual QVariantMap getArguments() override; - virtual void updateActionWorker(float deltaTimeStep); + virtual void updateActionWorker(float deltaTimeStep) override; QByteArray serialize() const; - virtual void deserialize(QByteArray serializedArguments); + virtual void deserialize(QByteArray serializedArguments) override; - virtual bool shouldSuppressLocationEdits() { return _active && !_ownerEntity.expired(); } + virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } std::shared_ptr getTarget(glm::quat& rotation, glm::vec3& position); + virtual void prepareForPhysicsSimulation() override; + private: void doKinematicUpdate(float deltaTimeStep); @@ -56,6 +58,8 @@ private: float _previousDeltaTimeStep = 0.0f; glm::vec3 _previousPositionalDelta; + + glm::vec3 _palmOffsetFromRigidBody; }; #endif // hifi_AvatarActionHold_h diff --git a/libraries/entities/src/EntityActionInterface.h b/libraries/entities/src/EntityActionInterface.h index a192661e52..ba59d66cf4 100644 --- a/libraries/entities/src/EntityActionInterface.h +++ b/libraries/entities/src/EntityActionInterface.h @@ -58,6 +58,8 @@ public: virtual bool shouldSuppressLocationEdits() { return false; } + virtual void prepareForPhysicsSimulation() { } + // these look in the arguments map for a named argument. if it's not found or isn't well formed, // ok will be set to false (note that it's never set to true -- set it to true before calling these). // if required is true, failure to extract an argument will cause a warning to be printed. diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 44d4269e0e..86d57b7ee9 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -15,6 +15,7 @@ #include "BulletUtil.h" #include "PhysicsCollisionGroups.h" +#include "ObjectMotionState.h" const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const float JUMP_SPEED = 3.5f; @@ -379,3 +380,15 @@ void CharacterController::preSimulation() { void CharacterController::postSimulation() { // postSimulation() exists for symmetry and just in case we need to do something here later } + + +bool CharacterController::getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation) { + if (!_rigidBody) { + return false; + } + + const btTransform& worldTrans = _rigidBody->getCenterOfMassTransform(); + avatarRigidBodyPosition = bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(); + avatarRigidBodyRotation = bulletToGLM(worldTrans.getRotation()); + return true; +} diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 88c02d0940..7bdc35fc0b 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -79,6 +79,8 @@ public: void setEnabled(bool enabled); bool isEnabled() const { return _enabled && _dynamicsWorld; } + bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); + protected: void updateUpAxis(const glm::quat& rotation); diff --git a/libraries/physics/src/ObjectAction.h b/libraries/physics/src/ObjectAction.h index e44036eadc..4ca13f2fbf 100644 --- a/libraries/physics/src/ObjectAction.h +++ b/libraries/physics/src/ObjectAction.h @@ -29,12 +29,12 @@ public: ObjectAction(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity); virtual ~ObjectAction(); - virtual void removeFromSimulation(EntitySimulation* simulation) const; - virtual EntityItemWeakPointer getOwnerEntity() const { return _ownerEntity; } - virtual void setOwnerEntity(const EntityItemPointer ownerEntity) { _ownerEntity = ownerEntity; } + virtual void removeFromSimulation(EntitySimulation* simulation) const override; + virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; } + virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override { _ownerEntity = ownerEntity; } - virtual bool updateArguments(QVariantMap arguments); - virtual QVariantMap getArguments(); + virtual bool updateArguments(QVariantMap arguments) override; + virtual QVariantMap getArguments() override; // this is called from updateAction and should be overridden by subclasses virtual void updateActionWorker(float deltaTimeStep) = 0; @@ -43,25 +43,25 @@ public: virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep); virtual void debugDraw(btIDebugDraw* debugDrawer); - virtual QByteArray serialize() const = 0; - virtual void deserialize(QByteArray serializedArguments) = 0; + virtual QByteArray serialize() const override = 0; + virtual void deserialize(QByteArray serializedArguments) override = 0; - virtual bool lifetimeIsOver(); - virtual quint64 getExpires() { return _expires; } + virtual bool lifetimeIsOver() override; + virtual quint64 getExpires() override { return _expires; } protected: quint64 localTimeToServerTime(quint64 timeValue) const; quint64 serverTimeToLocalTime(quint64 timeValue) const; virtual btRigidBody* getRigidBody(); - virtual glm::vec3 getPosition(); - virtual void setPosition(glm::vec3 position); - virtual glm::quat getRotation(); - virtual void setRotation(glm::quat rotation); - virtual glm::vec3 getLinearVelocity(); - virtual void setLinearVelocity(glm::vec3 linearVelocity); - virtual glm::vec3 getAngularVelocity(); - virtual void setAngularVelocity(glm::vec3 angularVelocity); + virtual glm::vec3 getPosition() override; + virtual void setPosition(glm::vec3 position) override; + virtual glm::quat getRotation() override; + virtual void setRotation(glm::quat rotation) override; + virtual glm::vec3 getLinearVelocity() override; + virtual void setLinearVelocity(glm::vec3 linearVelocity) override; + virtual glm::vec3 getAngularVelocity() override; + virtual void setAngularVelocity(glm::vec3 angularVelocity) override; virtual void activateBody(); virtual void forceBodyNonStatic(); diff --git a/libraries/physics/src/ObjectActionOffset.h b/libraries/physics/src/ObjectActionOffset.h index 1918da6996..ea01b10d33 100644 --- a/libraries/physics/src/ObjectActionOffset.h +++ b/libraries/physics/src/ObjectActionOffset.h @@ -22,13 +22,13 @@ public: ObjectActionOffset(const QUuid& id, EntityItemPointer ownerEntity); virtual ~ObjectActionOffset(); - virtual bool updateArguments(QVariantMap arguments); - virtual QVariantMap getArguments(); + virtual bool updateArguments(QVariantMap arguments) override; + virtual QVariantMap getArguments() override; - virtual void updateActionWorker(float deltaTimeStep); + virtual void updateActionWorker(float deltaTimeStep) override; - virtual QByteArray serialize() const; - virtual void deserialize(QByteArray serializedArguments); + virtual QByteArray serialize() const override; + virtual void deserialize(QByteArray serializedArguments) override; private: static const uint16_t offsetVersion; diff --git a/libraries/physics/src/ObjectActionSpring.h b/libraries/physics/src/ObjectActionSpring.h index caa64c3d3a..96bb900bf6 100644 --- a/libraries/physics/src/ObjectActionSpring.h +++ b/libraries/physics/src/ObjectActionSpring.h @@ -19,13 +19,13 @@ public: ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity); virtual ~ObjectActionSpring(); - virtual bool updateArguments(QVariantMap arguments); - virtual QVariantMap getArguments(); + virtual bool updateArguments(QVariantMap arguments) override; + virtual QVariantMap getArguments() override; - virtual void updateActionWorker(float deltaTimeStep); + virtual void updateActionWorker(float deltaTimeStep) override; - virtual QByteArray serialize() const; - virtual void deserialize(QByteArray serializedArguments); + virtual QByteArray serialize() const override; + virtual void deserialize(QByteArray serializedArguments) override; protected: static const uint16_t springVersion; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 10e285186c..22695a1b66 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -497,3 +497,11 @@ void PhysicsEngine::removeAction(const QUuid actionID) { _objectActions.remove(actionID); } } + +void PhysicsEngine::forEachAction(std::function actor) { + QHashIterator iter(_objectActions); + while (iter.hasNext()) { + iter.next(); + actor(iter.value()); + } +} diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index e7b5fd79d4..05032ccae2 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -97,6 +97,7 @@ public: EntityActionPointer getActionByID(const QUuid& actionID) const; void addAction(EntityActionPointer action); void removeAction(const QUuid actionID); + void forEachAction(std::function actor); private: void removeContacts(ObjectMotionState* motionState); From 40e6e4b13389fb57d5ef627113beda458eabcf76 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:01:50 -0800 Subject: [PATCH 100/318] add readme --- examples/light_modifier/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 examples/light_modifier/README.md diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md new file mode 100644 index 0000000000..d978c73b5b --- /dev/null +++ b/examples/light_modifier/README.md @@ -0,0 +1,24 @@ +This PR demonstrates one way in-world editing of objects might work. We start with a spotlight. When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. + +To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js +To reset, I recommend stopping all scripts then re-loading lightLoader.js + +When you run the lightLoader.js script, 4 scripts will be loaded: +- handControllerGrab.js (custom) +- lightModifier.js (listens for message to create sliders for a given light) +- lightModifierTestScene.js (creates a light and parents it to a block, then sends a message ^^) +- slider.js (attached to each slider entity) + + + +Current sliders are (top to bottom): +red +green +blue +intensity +cutoff +exponent + +To-Do: Determine how to enter / exit edit mode , support near grab, add other input types (checkbox, etc), prevent velocity drift on slider release,button to hide entity + +![capture](https://cloud.githubusercontent.com/assets/843228/11830366/2f2dfe70-a359-11e5-84f0-33a380ebeac7.PNG) From 66770cc907c654d03b01dd6dc3b5a294467955b8 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 16:11:35 -0600 Subject: [PATCH 101/318] Finishing touches --- CMakeLists.txt | 6 ++++-- cmake/macros/IncludeApplicationVersion.cmake | 17 +++++++++++++---- tools/nsis/release.nsi | 13 +++++++------ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69e6365c8c..ca3e381405 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,8 +239,10 @@ if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) build-package ALL DEPENDS interface assignment-client domain-server stack-manager COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment - COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/this-is-a-test.exe - COMMANE set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} + COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} + COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" ) endif () \ No newline at end of file diff --git a/cmake/macros/IncludeApplicationVersion.cmake b/cmake/macros/IncludeApplicationVersion.cmake index a91aad6acc..753a12a01c 100644 --- a/cmake/macros/IncludeApplicationVersion.cmake +++ b/cmake/macros/IncludeApplicationVersion.cmake @@ -14,13 +14,22 @@ macro(INCLUDE_APPLICATION_VERSION) # We are relying on Jenkins defined environment variables to determine the origin of this build # and will only package if this is a PR or Release build if (DEFINED ENV{JOB_ID}) - set (DEPLOY_PACKAGE 1) - set (BUILD_SEQ $ENV{JOB_ID}) + set(DEPLOY_PACKAGE 1) + set(BUILD_SEQ $ENV{JOB_ID}) + set(INSTALLER_COMPANY "High Fidelity") + set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") + set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") elseif (DEFINED ENV{ghprbPullId}) - set (DEPLOY_PACKAGE 1) - set (BUILD_SEQ "PR-$ENV{ghprbPullId}") + set(DEPLOY_PACKAGE 1) + set(BUILD_SEQ "PR-$ENV{ghprbPullId}") + set(INSTALLER_COMPANY "High Fidelity - PR") + set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") + set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe") else () set(BUILD_SEQ "dev") + set(INSTALLER_COMPANY "High Fidelity - Dev") + set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") + set(INSTALLER_NAME "dev-interface-win64.exe") endif () configure_file("${MACRO_DIR}/ApplicationVersion.h.in" "${PROJECT_BINARY_DIR}/includes/ApplicationVersion.h") include_directories("${PROJECT_BINARY_DIR}/includes") diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi index 86ea055e6b..9bc75e5274 100644 --- a/tools/nsis/release.nsi +++ b/tools/nsis/release.nsi @@ -1,18 +1,19 @@ !include LogicLib.nsh !include x64.nsh -!define srcdir $%INSTALLER_SOURCE_DIR% -!define setup $%INSTALLER_NAME% -!define scriptsdir $%INSTALLER_SCRIPTS_DIR% -!define company $%INSTALLER_COMPANY% +!define srcdir "$%INSTALLER_SOURCE_DIR%" +!define setup "$%INSTALLER_NAME%" +!define scriptsdir "$%INSTALLER_SCRIPTS_DIR%" +!define company "$%INSTALLER_COMPANY%" +!define install_directory "$%INSTALLER_DIRECTORY%" !define interface_exec "interface.exe" !define stack_manager_exec "stack-manager.exe" !define interface_icon "interface.ico" !define stack_manager_icon "stack-manager.ico" !define regkey "Software\${company}" !define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${company}" -!define install_dir_company "$PROGRAMFILES64\${company}" -!define startmenu_company "$SMPROGRAMS\${company}" +!define install_dir_company "$PROGRAMFILES64\${install_directory}" +!define startmenu_company "$SMPROGRAMS\${install_directory}" !define uninstaller "uninstall.exe" ;-------------------------------- From 8bfbb69316712d5573aa435dc089c816de7f7c27 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Dec 2015 14:21:56 -0800 Subject: [PATCH 102/318] clean up code, change try-locks to locks --- interface/src/avatar/AvatarActionHold.cpp | 89 ++++++++--------------- interface/src/avatar/AvatarActionHold.h | 1 + 2 files changed, 31 insertions(+), 59 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 87cf53143c..32d35e3f8f 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -33,6 +33,19 @@ AvatarActionHold::~AvatarActionHold() { #endif } +glm::vec3 AvatarActionHold::getAvatarRigidBodyPosition() { + MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; + if (!controller) { + qDebug() << "AvatarActionHold::getAvatarRigidBodyPosition failed to get character controller"; + return glm::vec3(0.0f); + } + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + return avatarRigidBodyPosition; +} + void AvatarActionHold::prepareForPhysicsSimulation() { auto avatarManager = DependencyManager::get(); auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); @@ -41,45 +54,14 @@ void AvatarActionHold::prepareForPhysicsSimulation() { return; } - withTryReadLock([&]{ - bool isRightHand = (_hand == "right"); - + withReadLock([&]{ if (_ignoreIK && holdingAvatar->isMyAvatar()) { return; } - if (holdingAvatar->isMyAvatar()) { - glm::vec3 palmPosition { Vectors::ZERO }; - glm::quat palmRotation { Quaternions::IDENTITY }; - if (isRightHand) { - palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); - palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); - } else { - palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); - palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); - } - - // XXX dup code - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; - if (!controller) { - qDebug() << "AvatarActionHold::prepareForPhysicsSimulation failed to get character controller"; - return; - } - glm::vec3 avatarRigidBodyPosition; - glm::quat avatarRigidBodyRotation; - controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); - - - if (isRightHand) { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } - - _palmOffsetFromRigidBody = palmPosition - avatarRigidBodyPosition; + glm::vec3 palmPosition = (_hand == "right") ? + holdingAvatar->getRightPalmPosition() : holdingAvatar->getLeftPalmPosition(); + _palmOffsetFromRigidBody = palmPosition - getAvatarRigidBodyPosition(); } }); } @@ -92,7 +74,7 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve return holdingAvatar; } - withTryReadLock([&]{ + withReadLock([&]{ bool isRightHand = (_hand == "right"); glm::vec3 palmPosition { Vectors::ZERO }; glm::quat palmRotation { Quaternions::IDENTITY }; @@ -108,21 +90,12 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } } else if (holdingAvatar->isMyAvatar()) { - // XXX dup code - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; - if (!controller) { - qDebug() << "AvatarActionHold::prepareForPhysicsSimulation failed to get character controller"; - return; + palmPosition = getAvatarRigidBodyPosition() + _palmOffsetFromRigidBody; + if (isRightHand) { + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmRotation = holdingAvatar->getLeftPalmRotation(); } - glm::vec3 avatarRigidBodyPosition; - glm::quat avatarRigidBodyRotation; - controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); - - - - palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; - palmRotation = holdingAvatar->getRightPalmRotation(); // XXX } else { if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); @@ -171,21 +144,19 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { if (valid && holdCount > 0) { position /= holdCount; - bool gotLock = withTryWriteLock([&]{ + withWriteLock([&]{ _positionalTarget = position; _rotationalTarget = rotation; _positionalTargetSet = true; _rotationalTargetSet = true; _active = true; }); - if (gotLock) { - if (_kinematic) { - doKinematicUpdate(deltaTimeStep); - } else { - activateBody(); - forceBodyNonStatic(); - ObjectActionSpring::updateActionWorker(deltaTimeStep); - } + if (_kinematic) { + doKinematicUpdate(deltaTimeStep); + } else { + activateBody(); + forceBodyNonStatic(); + ObjectActionSpring::updateActionWorker(deltaTimeStep); } } } diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 2746c817ca..36a9aa3049 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -35,6 +35,7 @@ public: virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } + glm::vec3 getAvatarRigidBodyPosition(); std::shared_ptr getTarget(glm::quat& rotation, glm::vec3& position); virtual void prepareForPhysicsSimulation() override; From e0b8c6b48b46e1f380a5940a16c6dcb702ae3c89 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:24:31 -0800 Subject: [PATCH 103/318] show light volumes --- examples/light_modifier/lightModifier.js | 32 +++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index e928679f08..b33b6fc0f1 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -10,22 +10,37 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - //some experimental options var ONLY_I_CAN_EDIT = false; var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; var VERTICAL_SLIDERS = false; +var SHOW_OVERLAYS = true; +var SHOW_LIGHT_VOLUME = true; -// Script.include('../libraries/lightOverlayManager.js'); -// var lightOverlayManager = new LightOverlayManager(); -// lightOverlayManager.setVisible(true); +//variables for managing overlays +var selectionDisplay; +var selectionManager; +var lightOverlayManager; +if (SHOW_OVERLAYS === true) { + Script.include('../libraries/entitySelectionTool.js'); + + selectionDisplay = SelectionDisplay; + selectionManager = SelectionManager; + Script.include('../libraries/lightOverlayManager.js'); + lightOverlayManager = new LightOverlayManager(); + selectionManager.addEventListener(function() { + selectionDisplay.updateHandles(); + lightOverlayManager.updatePositions(); + }); + + lightOverlayManager.setVisible(true); +} // var pickRay = Camera.computePickRay(event.x, event.y); // var lightResult = lightOverlayManager.findRayIntersection(pickRay) var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' - var AXIS_SCALE = 1; var COLOR_MAX = 255; var INTENSITY_MAX = 0.05; @@ -323,7 +338,9 @@ var slidersRef = { } var light = null; -function makeSliders(light) { +function makeSliders(light) { // selectionManager.setSelections([entityID]); + + if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -382,6 +399,9 @@ function handleLightModMessages(channel, message, sender) { makeSliders(parsedMessage.light); light = parsedMessage.light.id + if (SHOW_LIGHT_VOLUME === true) { + selectionManager.setSelections([parsedMessage.light.id]); + } } function handleValueMessages(channel, message, sender) { From bd7fa266cffb2cf142b9da521b21d6bd99ee874a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 14 Dec 2015 11:57:52 -0800 Subject: [PATCH 104/318] Bit of cleanup --- .../src/octree/OctreeQueryNode.cpp | 32 +------------- .../src/octree/OctreeQueryNode.h | 43 ++++++++++--------- .../src/octree/OctreeSendThread.cpp | 8 ++-- .../src/octree/OctreeSendThread.h | 16 +++---- assignment-client/src/octree/OctreeServer.cpp | 1 + 5 files changed, 37 insertions(+), 63 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index ffe2e24ca0..58fd39f73f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -20,39 +20,11 @@ #include "OctreeSendThread.h" -OctreeQueryNode::OctreeQueryNode() : - _viewSent(false), - _octreePacket(), - _octreePacketWaiting(false), - _lastOctreePayload(new char[udt::MAX_PACKET_SIZE]), - _lastOctreePacketLength(0), - _duplicatePacketCount(0), - _firstSuppressedPacket(usecTimestampNow()), - _maxSearchLevel(1), - _maxLevelReachedInLastSearch(1), - _lastTimeBagEmpty(0), - _viewFrustumChanging(false), - _viewFrustumJustStoppedChanging(true), - _octreeSendThread(NULL), - _lastClientBoundaryLevelAdjust(0), - _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), - _lodChanged(false), - _lodInitialized(false), - _sequenceNumber(0), - _lastRootTimestamp(0), - _myPacketType(PacketType::Unknown), - _isShuttingDown(false), - _sentPacketHistory() -{ -} - OctreeQueryNode::~OctreeQueryNode() { _isShuttingDown = true; if (_octreeSendThread) { forceNodeShutdown(); } - - delete[] _lastOctreePayload; } void OctreeQueryNode::nodeKilled() { @@ -105,7 +77,7 @@ bool OctreeQueryNode::packetIsDuplicate() const { // of the entire packet, we need to compare only the packet content... if (_lastOctreePacketLength == _octreePacket->getPayloadSize()) { - if (memcmp(_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE, + if (memcmp(&_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getPayload() + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getPayloadSize() - OCTREE_PACKET_EXTRA_HEADERS_SIZE) == 0) { return true; @@ -173,7 +145,7 @@ void OctreeQueryNode::resetOctreePacket() { // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing // packet send rate. _lastOctreePacketLength = _octreePacket->getPayloadSize(); - memcpy(_lastOctreePayload, _octreePacket->getPayload(), _lastOctreePacketLength); + memcpy(&_lastOctreePayload, _octreePacket->getPayload(), _lastOctreePacketLength); // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 89583492e0..130e7031d1 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -29,7 +29,7 @@ class OctreeServer; class OctreeQueryNode : public OctreeQuery { Q_OBJECT public: - OctreeQueryNode(); + OctreeQueryNode() {} virtual ~OctreeQueryNode(); void init(); // called after creation to set up some virtual items @@ -110,43 +110,44 @@ private slots: private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); - - bool _viewSent; + + bool _viewSent { false }; std::unique_ptr _octreePacket; bool _octreePacketWaiting; - char* _lastOctreePayload = nullptr; - unsigned int _lastOctreePacketLength; - int _duplicatePacketCount; - quint64 _firstSuppressedPacket; + unsigned int _lastOctreePacketLength { 0 }; + int _duplicatePacketCount { 0 }; + quint64 _firstSuppressedPacket { usecTimestampNow() }; - int _maxSearchLevel; - int _maxLevelReachedInLastSearch; + int _maxSearchLevel { 1 }; + int _maxLevelReachedInLastSearch { 1 }; ViewFrustum _currentViewFrustum; ViewFrustum _lastKnownViewFrustum; - quint64 _lastTimeBagEmpty; - bool _viewFrustumChanging; - bool _viewFrustumJustStoppedChanging; + quint64 _lastTimeBagEmpty { 0 }; + bool _viewFrustumChanging { false }; + bool _viewFrustumJustStoppedChanging { true }; - OctreeSendThread* _octreeSendThread; + OctreeSendThread* _octreeSendThread { nullptr }; // watch for LOD changes - int _lastClientBoundaryLevelAdjust; - float _lastClientOctreeSizeScale; - bool _lodChanged; - bool _lodInitialized; + int _lastClientBoundaryLevelAdjust { 0 }; + float _lastClientOctreeSizeScale { DEFAULT_OCTREE_SIZE_SCALE }; + bool _lodChanged { false }; + bool _lodInitialized { false }; - OCTREE_PACKET_SEQUENCE _sequenceNumber; + OCTREE_PACKET_SEQUENCE _sequenceNumber { 0 }; - quint64 _lastRootTimestamp; + quint64 _lastRootTimestamp { 0 }; - PacketType _myPacketType; - bool _isShuttingDown; + PacketType _myPacketType { PacketType::Unknown }; + bool _isShuttingDown { false }; SentPacketHistory _sentPacketHistory; QQueue _nackedSequenceNumbers; quint64 _sceneSendStartTime = 0; + + std::array _lastOctreePayload; }; #endif // hifi_OctreeQueryNode_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index b4eb75ede9..dbd6d117dc 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -14,6 +14,7 @@ #include #include +#include "OctreeQueryNode.h" #include "OctreeSendThread.h" #include "OctreeServer.h" #include "OctreeServerConsts.h" @@ -25,10 +26,7 @@ quint64 endSceneSleepTime = 0; OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : _myServer(myServer), _node(node), - _nodeUUID(node->getUUID()), - _packetData(), - _nodeMissingCount(0), - _isShuttingDown(false) + _nodeUUID(node->getUUID()) { QString safeServerName("Octree"); @@ -46,6 +44,8 @@ OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePoint } OctreeSendThread::~OctreeSendThread() { + setIsShuttingDown(); + QString safeServerName("Octree"); if (_myServer) { safeServerName = _myServer->getMyServerName(); diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 6775e56820..64a9c59465 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -18,8 +18,7 @@ #include -#include "OctreeQueryNode.h" - +class OctreeQueryNode; class OctreeServer; using AtomicUIntStat = std::atomic; @@ -48,17 +47,18 @@ protected: virtual bool process(); private: - OctreeServer* _myServer; + int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); + int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged); + + + OctreeServer* _myServer { nullptr }; SharedNodePointer _node; QUuid _nodeUUID; - int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); - int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged); - OctreePacketData _packetData; - int _nodeMissingCount; - bool _isShuttingDown; + int _nodeMissingCount { 0 }; + bool _isShuttingDown { false }; }; #endif // hifi_OctreeSendThread_h diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index ec34ad4410..d32968596a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -25,6 +25,7 @@ #include "../AssignmentClient.h" +#include "OctreeQueryNode.h" #include "OctreeServerConsts.h" OctreeServer* OctreeServer::_instance = NULL; From b65cdd286524e806283898bd54af32c6b5e5def7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 14 Dec 2015 15:26:50 -0800 Subject: [PATCH 105/318] Add logging categories to assignment client. --- assignment-client/src/AssignmentClient.cpp | 37 ++++++++++--------- .../src/AssignmentClientLogging.cpp | 14 +++++++ .../src/AssignmentClientLogging.h | 19 ++++++++++ 3 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 assignment-client/src/AssignmentClientLogging.cpp create mode 100644 assignment-client/src/AssignmentClientLogging.h diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index fc0cfe1abb..bbee597797 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -35,6 +35,7 @@ #include "AssignmentActionFactory.h" #include "AssignmentClient.h" +#include "AssignmentClientLogging.h" #include "avatars/ScriptableAvatar.h" const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client"; @@ -84,7 +85,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri // check for a wallet UUID on the command line or in the config // this would represent where the user running AC wants funds sent to if (!walletUUID.isNull()) { - qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); + qCDebug(assigmnentclient) << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); _requestAssignment.setWalletUUID(walletUUID); } @@ -98,13 +99,13 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri _assignmentServerSocket.setObjectName("AssigmentServer"); nodeList->setAssignmentServerSocket(_assignmentServerSocket); - qDebug() << "Assignment server socket is" << _assignmentServerSocket; + qCDebug(assigmnentclient) << "Assignment server socket is" << _assignmentServerSocket; // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required - qDebug() << "Waiting for assignment -" << _requestAssignment; + qCDebug(assigmnentclient) << "Waiting for assignment -" << _requestAssignment; if (_assignmentServerHostname != "localhost") { - qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); + qCDebug(assigmnentclient) << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); } connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); @@ -122,7 +123,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri _assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort); _assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor"); - qDebug() << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket; + qCDebug(assigmnentclient) << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket; // Hook up a timer to send this child's status to the Monitor once per second setUpStatusToMonitor(); @@ -133,7 +134,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri } void AssignmentClient::stopAssignmentClient() { - qDebug() << "Forced stop of assignment-client."; + qCDebug(assigmnentclient) << "Forced stop of assignment-client."; _requestTimer.stop(); _statsTimerACM.stop(); @@ -209,14 +210,14 @@ void AssignmentClient::sendAssignmentRequest() { quint16 localAssignmentServerPort; if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) { if (localAssignmentServerPort != _assignmentServerSocket.getPort()) { - qDebug() << "Port for local assignment server read from shared memory is" + qCDebug(assigmnentclient) << "Port for local assignment server read from shared memory is" << localAssignmentServerPort; _assignmentServerSocket.setPort(localAssignmentServerPort); nodeList->setAssignmentServerSocket(_assignmentServerSocket); } } else { - qDebug() << "Failed to read local assignment server port from shared memory" + qCWarning(assigmnentclient) << "Failed to read local assignment server port from shared memory" << "- will send assignment request to previous assignment server socket."; } } @@ -226,13 +227,13 @@ void AssignmentClient::sendAssignmentRequest() { } void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { - qDebug() << "Received a PacketType::CreateAssignment - attempting to unpack."; + qCDebug(assigmnentclient) << "Received a PacketType::CreateAssignment - attempting to unpack."; // construct the deployed assignment from the packet data _currentAssignment = AssignmentFactory::unpackAssignment(*message); if (_currentAssignment && !_isAssigned) { - qDebug() << "Received an assignment -" << *_currentAssignment; + qDebug(assigmnentclient) << "Received an assignment -" << *_currentAssignment; _isAssigned = true; auto nodeList = DependencyManager::get(); @@ -242,7 +243,7 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointergetDomainHandler().setSockAddr(message->getSenderSockAddr(), _assignmentServerHostname); nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID()); - qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString(); + qCDebug(assigmnentclient) << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString(); // start the deployed assignment QThread* workerThread = new QThread; @@ -270,7 +271,7 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointerstarted() workerThread->start(); } else { - qDebug() << "Received an assignment that could not be unpacked. Re-requesting."; + qCWarning(assigmnentclient) << "Received an assignment that could not be unpacked. Re-requesting."; } } @@ -278,12 +279,12 @@ void AssignmentClient::handleStopNodePacket(QSharedPointer mess const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); if (senderSockAddr.getAddress() == QHostAddress::LocalHost || - senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { - qDebug() << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode."; - + senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { + + qCDebug(assigmnentclient) << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode."; QCoreApplication::quit(); } else { - qDebug() << "Got a stop packet from other than localhost."; + qCWarning(assigmnentclient) << "Got a stop packet from other than localhost."; } } @@ -303,7 +304,7 @@ void AssignmentClient::handleAuthenticationRequest() { // ask the account manager to log us in from the env variables accountManager.requestAccessToken(username, password); } else { - qDebug() << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString()) + qCWarning(assigmnentclient) << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString()) << "but both or one of" << qPrintable(DATA_SERVER_USERNAME_ENV) << "/" << qPrintable(DATA_SERVER_PASSWORD_ENV) << "are not set. Unable to authenticate."; @@ -321,7 +322,7 @@ void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); - qDebug() << "Assignment finished or never started - waiting for new assignment."; + qCDebug(assigmnentclient) << "Assignment finished or never started - waiting for new assignment."; auto nodeList = DependencyManager::get(); diff --git a/assignment-client/src/AssignmentClientLogging.cpp b/assignment-client/src/AssignmentClientLogging.cpp new file mode 100644 index 0000000000..3e9dbdc53c --- /dev/null +++ b/assignment-client/src/AssignmentClientLogging.cpp @@ -0,0 +1,14 @@ +// +// AssignmentClientLogging.cpp +// assignment-client/src +// +// Created by Clement on 12/14/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AssignmentClientLogging.h" + +Q_LOGGING_CATEGORY(assigmnentclient, "hifi.assignmentclient") \ No newline at end of file diff --git a/assignment-client/src/AssignmentClientLogging.h b/assignment-client/src/AssignmentClientLogging.h new file mode 100644 index 0000000000..d6b5ee90e0 --- /dev/null +++ b/assignment-client/src/AssignmentClientLogging.h @@ -0,0 +1,19 @@ +// +// AssignmentClientLogging.h +// assignment-client/src +// +// Created by Clement on 12/14/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AssignmentClientLogging_h +#define hifi_AssignmentClientLogging_h + +#include + +Q_DECLARE_LOGGING_CATEGORY(assigmnentclient) + +#endif // hifi_AssignmentClientLogging_h \ No newline at end of file From 09701fdcf1cebe6d17249c4653bf4ad27499737d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Dec 2015 14:14:20 -0800 Subject: [PATCH 106/318] deadlock 101 --- assignment-client/src/octree/OctreeServer.cpp | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index d32968596a..9f0e7919e4 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1460,15 +1460,22 @@ void OctreeServer::didCallWriteDatagram(OctreeSendThread* thread) { void OctreeServer::stopTrackingThread(OctreeSendThread* thread) { - QMutexLocker lockerA(&_threadsDidProcessMutex); - QMutexLocker lockerB(&_threadsDidPacketDistributorMutex); - QMutexLocker lockerC(&_threadsDidHandlePacketSendMutex); - QMutexLocker lockerD(&_threadsDidCallWriteDatagramMutex); - - _threadsDidProcess.remove(thread); - _threadsDidPacketDistributor.remove(thread); - _threadsDidHandlePacketSend.remove(thread); - _threadsDidCallWriteDatagram.remove(thread); + { + QMutexLocker locker(&_threadsDidProcessMutex); + _threadsDidProcess.remove(thread); + } + { + QMutexLocker locker(&_threadsDidPacketDistributorMutex); + _threadsDidPacketDistributor.remove(thread); + } + { + QMutexLocker locker(&_threadsDidHandlePacketSendMutex); + _threadsDidHandlePacketSend.remove(thread); + } + { + QMutexLocker locker(&_threadsDidCallWriteDatagramMutex); + _threadsDidCallWriteDatagram.remove(thread); + } } int howManyThreadsDidSomething(QMutex& mutex, QMap& something, quint64 since) { From 346c28f9e21e231a89e6af8c7f65df4044c8f61e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 15:02:04 -0800 Subject: [PATCH 107/318] Remove OctreeServer's static instance --- assignment-client/src/octree/OctreeServer.cpp | 15 ++------------- assignment-client/src/octree/OctreeServer.h | 2 -- libraries/networking/src/LimitedNodeList.h | 2 +- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9f0e7919e4..4f572760b1 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -28,7 +28,6 @@ #include "OctreeQueryNode.h" #include "OctreeServerConsts.h" -OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; @@ -232,13 +231,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) : _started(time(0)), _startedUSecs(usecTimestampNow()) { - if (_instance) { - qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]"; - } - - qDebug() << "Octree Server starting... setting _instance to=[" << this << "]"; - _instance = this; - _averageLoopTime.updateAverage(0); qDebug() << "Octree server starting... [" << this << "]"; @@ -282,9 +274,6 @@ OctreeServer::~OctreeServer() { _tree.reset(); qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]"; - if (_instance == this) { - _instance = NULL; // we are gone - } qDebug() << qPrintable(_safeServerName) << "server DONE shutting down... [" << this << "]"; } @@ -1118,8 +1107,8 @@ void OctreeServer::domainSettingsRequestComplete() { setvbuf(stdout, NULL, _IOLBF, 0); #endif - nodeList->linkedDataCreateCallback = [] (Node* node) { - auto queryNodeData = _instance->createOctreeQueryNode(); + nodeList->linkedDataCreateCallback = [this](Node* node) { + auto queryNodeData = createOctreeQueryNode(); queryNodeData->init(); node->setLinkedData(std::move(queryNodeData)); }; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 80668f841c..51fe6d46c3 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -187,8 +187,6 @@ protected: int _backupInterval; int _maxBackupVersions; - static OctreeServer* _instance; - time_t _started; quint64 _startedUSecs; QString _safeServerName; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index c89949b9fd..87ed12ac66 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -129,7 +129,7 @@ public: qint64 sendPacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr); qint64 sendPacketList(std::unique_ptr packetList, const Node& destinationNode); - void (*linkedDataCreateCallback)(Node *); + std::function linkedDataCreateCallback; size_t size() const { return _nodeHash.size(); } From 562d9ac2de4507f1250096992b0611e9280b497a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:30:31 -0800 Subject: [PATCH 108/318] Forward QThread's finished signal in GenericThread --- libraries/shared/src/GenericThread.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 66af2e01c8..4fdd2eb1d2 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -38,9 +38,10 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { _thread->setObjectName(objectName()); // when the worker thread is started, call our engine's run.. - connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine())); + connect(_thread, &QThread::started, this, &GenericThread::threadRoutine); + connect(_thread, &QThread::finished, this, &GenericThread::finished); - this->moveToThread(_thread); + moveToThread(_thread); // Starts an event loop, and emits _thread->started() _thread->start(); @@ -82,5 +83,4 @@ void GenericThread::threadRoutine() { if (_isThreaded && _thread) { _thread->quit(); } - emit finished(); } From 95da71b19c9812b6ff020cbc741b11c39bcfd279 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:33:40 -0800 Subject: [PATCH 109/318] Assignment don't inherit from NodeData This is an artefact from an old design that stuck around --- libraries/networking/src/Assignment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 399deaa314..97caedcfb3 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -23,7 +23,7 @@ const int MAX_PAYLOAD_BYTES = 1024; const QString emptyPool = QString(); /// Holds information used for request, creation, and deployment of assignments -class Assignment : public NodeData { +class Assignment : public QObject { Q_OBJECT public: From 3cd1eea1dc67f1b22c5f4cee610a473765909bfe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:35:22 -0800 Subject: [PATCH 110/318] Use weak pointer to the Node instead of strong ownership --- .../src/octree/OctreeSendThread.cpp | 44 +++++++++---------- .../src/octree/OctreeSendThread.h | 7 ++- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index dbd6d117dc..6215712c6c 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -25,8 +25,7 @@ quint64 endSceneSleepTime = 0; OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : _myServer(myServer), - _node(node), - _nodeUUID(node->getUUID()) + _node(node) { QString safeServerName("Octree"); @@ -56,8 +55,6 @@ OctreeSendThread::~OctreeSendThread() { OctreeServer::clientDisconnected(); OctreeServer::stopTrackingThread(this); - - _node.clear(); } void OctreeSendThread::setIsShuttingDown() { @@ -79,15 +76,17 @@ bool OctreeSendThread::process() { // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { - if (_node) { + if (auto node = _node.lock()) { _nodeMissingCount = 0; - OctreeQueryNode* nodeData = static_cast(_node->getLinkedData()); + OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - packetDistributor(nodeData, viewFrustumChanged); + packetDistributor(node, nodeData, viewFrustumChanged); } + } else { + return false; // exit early if we're shutting down } } @@ -123,7 +122,8 @@ AtomicUIntStat OctreeSendThread::_totalSpecialBytes { 0 }; AtomicUIntStat OctreeSendThread::_totalSpecialPackets { 0 }; -int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) { +int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, int& trueBytesSent, + int& truePacketsSent) { OctreeServer::didHandlePacketSend(this); // if we're shutting down, then exit early @@ -183,12 +183,12 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // actually send it OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(statsPacket, *_node); + DependencyManager::get()->sendUnreliablePacket(statsPacket, *node); packetSent = true; } else { // not enough room in the packet, send two packets OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(statsPacket, *_node); + DependencyManager::get()->sendUnreliablePacket(statsPacket, *node); // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since // there was nothing else to send. @@ -219,7 +219,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes packetsSent++; OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *_node); + DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *node); packetSent = true; int packetSizeWithHeader = nodeData->getPacket().getDataSize(); @@ -251,7 +251,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) { // just send the octree packet OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *_node); + DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *node); packetSent = true; int packetSizeWithHeader = nodeData->getPacket().getDataSize(); @@ -293,7 +293,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes } /// Version of octree element distributor that sends the deepest LOD level at once -int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) { +int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged) { OctreeServer::didPacketDistributor(this); @@ -322,7 +322,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. if (nodeData->isPacketWaiting()) { - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { nodeData->resetOctreePacket(); } @@ -355,7 +355,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus //unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); //unsigned long elapsedTime = nodeData->stats.getElapsedTime(); - int packetsJustSent = handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += packetsJustSent; // If we're starting a full scene, then definitely we want to empty the elementBag @@ -431,8 +431,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // Our trackSend() function is implemented by the server subclass, and will be called back // during the encodeTreeBitstream() as new entities/data elements are sent - params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { - _myServer->trackSend(dataID, dataEdited, _nodeUUID); + params.trackSend = [this, node](const QUuid& dataID, quint64 dataEdited) { + _myServer->trackSend(dataID, dataEdited, node->getUUID()); }; // TODO: should this include the lock time or not? This stat is sent down to the client, @@ -481,7 +481,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus unsigned int writtenSize = _packetData.getFinalizedSize() + sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); if (writtenSize > nodeData->getAvailable()) { - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); @@ -501,7 +501,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (sendNow) { quint64 packetSendingStart = usecTimestampNow(); - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); @@ -538,9 +538,9 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // Here's where we can/should allow the server to send other data... // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets - if (_myServer->hasSpecialPacketsToSend(_node) && !nodeData->isShuttingDown()) { + if (_myServer->hasSpecialPacketsToSend(node) && !nodeData->isShuttingDown()) { int specialPacketsSent = 0; - trueBytesSent += _myServer->sendSpecialPackets(_node, nodeData, specialPacketsSent); + trueBytesSent += _myServer->sendSpecialPackets(node, nodeData, specialPacketsSent); nodeData->resetOctreePacket(); // because nodeData's _sequenceNumber has changed truePacketsSent += specialPacketsSent; packetsSentThisInterval += specialPacketsSent; @@ -556,7 +556,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus while (nodeData->hasNextNackedPacket() && packetsSentThisInterval < maxPacketsPerInterval) { const NLPacket* packet = nodeData->getNextNackedPacket(); if (packet) { - DependencyManager::get()->sendUnreliablePacket(*packet, *_node); + DependencyManager::get()->sendUnreliablePacket(*packet, *node); truePacketsSent++; packetsSentThisInterval++; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 64a9c59465..e3c47343b0 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -47,13 +47,12 @@ protected: virtual bool process(); private: - int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); - int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged); + int handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); + int packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged); OctreeServer* _myServer { nullptr }; - SharedNodePointer _node; - QUuid _nodeUUID; + QWeakPointer _node; OctreePacketData _packetData; From 51ec7ae2edbce416fd4c0bf477deec94eff46c28 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:51:28 -0800 Subject: [PATCH 111/318] Keep UUID of node in send thread --- assignment-client/src/octree/OctreeSendThread.cpp | 5 +++-- assignment-client/src/octree/OctreeSendThread.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 6215712c6c..2ff06c7439 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -25,12 +25,13 @@ quint64 endSceneSleepTime = 0; OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : _myServer(myServer), - _node(node) + _node(node), + _nodeUuid(node->getUUID()) { QString safeServerName("Octree"); // set our QThread object name so we can identify this thread while debugging - setObjectName(QString("Octree Send Thread (%1)").arg(uuidStringWithoutCurlyBraces(node->getUUID()))); + setObjectName(QString("Octree Send Thread (%1)").arg(uuidStringWithoutCurlyBraces(_nodeUuid))); if (_myServer) { safeServerName = _myServer->getMyServerName(); diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index e3c47343b0..c77a327e70 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -31,6 +31,7 @@ public: virtual ~OctreeSendThread(); void setIsShuttingDown(); + QUuid getNodeUuid() const { return _nodeUuid; } static AtomicUIntStat _totalBytes; static AtomicUIntStat _totalWastedBytes; @@ -53,6 +54,7 @@ private: OctreeServer* _myServer { nullptr }; QWeakPointer _node; + QUuid _nodeUuid; OctreePacketData _packetData; From a541fdd2df445d864dfa7b4435dee65b0317694c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 10:04:20 -0800 Subject: [PATCH 112/318] Move OctreeSendThread to the OctreeServer --- .../src/octree/OctreeQueryNode.cpp | 44 ------------ .../src/octree/OctreeQueryNode.h | 11 +-- .../src/octree/OctreeSendThread.h | 2 + assignment-client/src/octree/OctreeServer.cpp | 72 +++++++++---------- assignment-client/src/octree/OctreeServer.h | 5 +- libraries/shared/src/GenericThread.cpp | 1 - 6 files changed, 40 insertions(+), 95 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 58fd39f73f..044b44a165 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -20,52 +20,8 @@ #include "OctreeSendThread.h" -OctreeQueryNode::~OctreeQueryNode() { - _isShuttingDown = true; - if (_octreeSendThread) { - forceNodeShutdown(); - } -} - void OctreeQueryNode::nodeKilled() { _isShuttingDown = true; - if (_octreeSendThread) { - // just tell our thread we want to shutdown, this is asynchronous, and fast, we don't need or want it to block - // while the thread actually shuts down - _octreeSendThread->setIsShuttingDown(); - } -} - -void OctreeQueryNode::forceNodeShutdown() { - _isShuttingDown = true; - if (_octreeSendThread) { - // we really need to force our thread to shutdown, this is synchronous, we will block while the thread actually - // shuts down because we really need it to shutdown, and it's ok if we wait for it to complete - OctreeSendThread* sendThread = _octreeSendThread; - _octreeSendThread = NULL; - sendThread->setIsShuttingDown(); - sendThread->terminate(); - delete sendThread; - } -} - -void OctreeQueryNode::sendThreadFinished() { - // We've been notified by our thread that it is shutting down. So we can clean up our reference to it, and - // delete the actual thread object. Cleaning up our thread will correctly unroll all refereces to shared - // pointers to our node as well as the octree server assignment - if (_octreeSendThread) { - OctreeSendThread* sendThread = _octreeSendThread; - _octreeSendThread = NULL; - delete sendThread; - } -} - -void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) { - _octreeSendThread = new OctreeSendThread(myServer, node); - - // we want to be notified when the thread finishes - connect(_octreeSendThread, &GenericThread::finished, this, &OctreeQueryNode::sendThreadFinished); - _octreeSendThread->initialize(true); } bool OctreeQueryNode::packetIsDuplicate() const { diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 130e7031d1..4313d101fd 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -29,8 +29,8 @@ class OctreeServer; class OctreeQueryNode : public OctreeQuery { Q_OBJECT public: - OctreeQueryNode() {} - virtual ~OctreeQueryNode(); + OctreeQueryNode() = default; + virtual ~OctreeQueryNode() = default; void init(); // called after creation to set up some virtual items virtual PacketType getMyPacketType() const = 0; @@ -79,9 +79,6 @@ public: OctreeSceneStats stats; - void initializeOctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node); - bool isOctreeSendThreadInitalized() { return _octreeSendThread; } - void dumpOutOfView(); quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } @@ -92,7 +89,6 @@ public: void sceneStart(quint64 sceneSendStartTime) { _sceneSendStartTime = sceneSendStartTime; } void nodeKilled(); - void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } void octreePacketSent() { packetSent(*_octreePacket); } @@ -104,9 +100,6 @@ public: bool hasNextNackedPacket() const; const NLPacket* getNextNackedPacket(); -private slots: - void sendThreadFinished(); - private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index c77a327e70..38f5de722f 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -31,6 +31,8 @@ public: virtual ~OctreeSendThread(); void setIsShuttingDown(); + bool isShuttingDown() { return _isShuttingDown; } + QUuid getNodeUuid() const { return _nodeUuid; } static AtomicUIntStat _totalBytes; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 4f572760b1..f42431589e 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -868,16 +868,28 @@ void OctreeServer::parsePayload() { } } +void OctreeServer::removeSendThread() { + auto sendThread = static_cast(sender()); + + // This deletes the unique_ptr, so sendThread is destructed after that line + _sendThreads.erase(sendThread->getNodeUuid()); +} + void OctreeServer::handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode) { - if (!_isFinished) { + if (!_isFinished && !_isShuttingDown) { // If we got a query packet, then we're talking to an agent, and we // need to make sure we have it in our nodeList. auto nodeList = DependencyManager::get(); nodeList->updateNodeWithDataFromPacket(message, senderNode); - OctreeQueryNode* nodeData = dynamic_cast(senderNode->getLinkedData()); - if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { - nodeData->initializeOctreeSendThread(this, senderNode); + auto it = _sendThreads.find(senderNode->getUUID()); + if (it == _sendThreads.end() || it->second->isShuttingDown()) { + auto sendThread = std::unique_ptr(new OctreeSendThread(this, senderNode)); + + // we want to be notified when the thread finishes + connect(sendThread.get(), &GenericThread::finished, this, &OctreeServer::removeSendThread); + sendThread->initialize(true); + _sendThreads.emplace(senderNode->getUUID(), std::move(sendThread)); } } } @@ -1157,6 +1169,12 @@ void OctreeServer::nodeAdded(SharedNodePointer node) { void OctreeServer::nodeKilled(SharedNodePointer node) { quint64 start = usecTimestampNow(); + + // Shutdown send thread + auto it = _sendThreads.find(node->getUUID()); + if (it != _sendThreads.end()) { + it->second->setIsShuttingDown(); + } // calling this here since nodeKilled slot in ReceivedPacketProcessor can't be triggered by signals yet!! _octreeInboundPacketProcessor->nodeKilled(node); @@ -1178,24 +1196,6 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { trackViewerGone(node->getUUID()); } -void OctreeServer::forceNodeShutdown(SharedNodePointer node) { - quint64 start = usecTimestampNow(); - - qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node; - OctreeQueryNode* nodeData = dynamic_cast(node->getLinkedData()); - if (nodeData) { - nodeData->forceNodeShutdown(); // tell our node data and sending threads that we'd like to shut down - } else { - qDebug() << qPrintable(_safeServerName) << "server node missing linked data node:" << *node; - } - - quint64 end = usecTimestampNow(); - quint64 usecsElapsed = (end - start); - qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " - << usecsElapsed << " usecs for node:" << *node; -} - - void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; @@ -1204,9 +1204,8 @@ void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down..."; // we're going down - set the NodeList linkedDataCallback to NULL so we do not create any more OctreeQueryNode objects. - // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes - auto nodeList = DependencyManager::get(); - nodeList->linkedDataCreateCallback = NULL; + // This ensures that we don't get any more newly connecting nodes + DependencyManager::get()->linkedDataCreateCallback = NULL; if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); @@ -1216,27 +1215,20 @@ void OctreeServer::aboutToFinish() { _jurisdictionSender->terminating(); } - QSet nodesToShutdown; - - // Force a shutdown of all of our OctreeSendThreads. - // At this point it has to be impossible for a linkedDataCreateCallback to be called for a new node - nodeList->eachNode([&nodesToShutdown](const SharedNodePointer& node) { - nodesToShutdown << node; - }); - - // What follows is a hack to force OctreeSendThreads to cleanup before the OctreeServer is gone. - // I would prefer to allow the SharedNodePointer ref count drop to zero to do this automatically - // but that isn't possible as long as the OctreeSendThread has an OctreeServer* that it uses. - for (auto& node : nodesToShutdown) { - qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; - forceNodeShutdown(node); + // Shut down all the send threads + for (auto it = _sendThreads.begin(); it != _sendThreads.end(); ++it) { + it->second->disconnect(this); // Disconnect so that removeSendThread doesn't get called later + it->second->setIsShuttingDown(); } + + // Wait on all send threads to be done before continuing + _sendThreads.clear(); if (_persistThread) { _persistThread->aboutToFinish(); _persistThread->terminating(); } - + qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 51fe6d46c3..98f6c79893 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -124,7 +124,6 @@ public: bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler); virtual void aboutToFinish(); - void forceNodeShutdown(SharedNodePointer node); public slots: /// runs the octree server assignment @@ -138,6 +137,7 @@ private slots: void handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode); void handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode); + void removeSendThread(); protected: virtual OctreePointer createTree() = 0; @@ -190,6 +190,9 @@ protected: time_t _started; quint64 _startedUSecs; QString _safeServerName; + + using SendThreads = std::unordered_map>; + SendThreads _sendThreads; static int _clientCount; static SimpleMovingAverage _averageLoopTime; diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 4fdd2eb1d2..c1c31ab50a 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -15,7 +15,6 @@ GenericThread::GenericThread() : - QObject(), _stopThread(false), _isThreaded(false) // assume non-threaded, must call initialize() { From b4dc3b1b472f1fc5dc8cbedd1691ebca0d746f42 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:07:19 -0800 Subject: [PATCH 113/318] Fix windows compile error. --- assignment-client/src/octree/OctreeServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f42431589e..75252ddf8c 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1205,7 +1205,7 @@ void OctreeServer::aboutToFinish() { // we're going down - set the NodeList linkedDataCallback to NULL so we do not create any more OctreeQueryNode objects. // This ensures that we don't get any more newly connecting nodes - DependencyManager::get()->linkedDataCreateCallback = NULL; + DependencyManager::get()->linkedDataCreateCallback = nullptr; if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 4419ba882a..0b194b017e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -40,7 +40,6 @@ const char SOLO_NODE_TYPES[2] = { }; LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) : - linkedDataCreateCallback(NULL), _sessionUUID(), _nodeHash(), _nodeMutex(QReadWriteLock::Recursive), From a655557af0249cb9ed15d6321f51533d42896fa6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:11:34 -0800 Subject: [PATCH 114/318] Make variable name more obvious --- assignment-client/src/octree/OctreeServer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 75252ddf8c..acc9537a56 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1173,7 +1173,8 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { // Shutdown send thread auto it = _sendThreads.find(node->getUUID()); if (it != _sendThreads.end()) { - it->second->setIsShuttingDown(); + auto& sendThread = *it->second; + sendThread.setIsShuttingDown(); } // calling this here since nodeKilled slot in ReceivedPacketProcessor can't be triggered by signals yet!! @@ -1217,8 +1218,9 @@ void OctreeServer::aboutToFinish() { // Shut down all the send threads for (auto it = _sendThreads.begin(); it != _sendThreads.end(); ++it) { - it->second->disconnect(this); // Disconnect so that removeSendThread doesn't get called later - it->second->setIsShuttingDown(); + auto& sendThread = *it->second; + sendThread.disconnect(this); // Disconnect so that removeSendThread doesn't get called later + sendThread.setIsShuttingDown(); } // Wait on all send threads to be done before continuing From df24fafe49c2ae3563ab9a54b513a680baf41165 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:28:26 -0800 Subject: [PATCH 115/318] CR feedback --- assignment-client/src/octree/OctreeServer.cpp | 17 +++++++++++------ assignment-client/src/octree/OctreeServer.h | 6 +++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index acc9537a56..9cb809f48f 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -868,6 +868,16 @@ void OctreeServer::parsePayload() { } } +OctreeServer::UniqueSendThread OctreeServer::createSendThread(const SharedNodePointer& node) { + auto sendThread = std::unique_ptr(new OctreeSendThread(this, node)); + + // we want to be notified when the thread finishes + connect(sendThread.get(), &GenericThread::finished, this, &OctreeServer::removeSendThread); + sendThread->initialize(true); + + return sendThread; +} + void OctreeServer::removeSendThread() { auto sendThread = static_cast(sender()); @@ -884,12 +894,7 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer messa auto it = _sendThreads.find(senderNode->getUUID()); if (it == _sendThreads.end() || it->second->isShuttingDown()) { - auto sendThread = std::unique_ptr(new OctreeSendThread(this, senderNode)); - - // we want to be notified when the thread finishes - connect(sendThread.get(), &GenericThread::finished, this, &OctreeServer::removeSendThread); - sendThread->initialize(true); - _sendThreads.emplace(senderNode->getUUID(), std::move(sendThread)); + _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); } } } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 98f6c79893..2aabb97428 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -140,6 +140,9 @@ private slots: void removeSendThread(); protected: + using UniqueSendThread = std::unique_ptr; + using SendThreads = std::unordered_map; + virtual OctreePointer createTree() = 0; bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result); bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result); @@ -153,6 +156,8 @@ protected: QString getFileLoadTime(); QString getConfiguration(); QString getStatusLink(); + + UniqueSendThread createSendThread(const SharedNodePointer& node); int _argc; const char** _argv; @@ -191,7 +196,6 @@ protected: quint64 _startedUSecs; QString _safeServerName; - using SendThreads = std::unordered_map>; SendThreads _sendThreads; static int _clientCount; From 0f7093bed7b259211f29d06bb1a38752c9ce47f6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:35:12 -0800 Subject: [PATCH 116/318] Whitespace --- assignment-client/src/octree/OctreeQueryNode.h | 2 +- assignment-client/src/octree/OctreeServer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 4313d101fd..0ec876e674 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -103,7 +103,7 @@ public: private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); - + bool _viewSent { false }; std::unique_ptr _octreePacket; bool _octreePacketWaiting; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9cb809f48f..9961b5d688 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1235,7 +1235,7 @@ void OctreeServer::aboutToFinish() { _persistThread->aboutToFinish(); _persistThread->terminating(); } - + qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } From b55d8f750fed1368ab84e1af2ebb992b8c53fde0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:47:40 -0800 Subject: [PATCH 117/318] CR --- assignment-client/src/octree/OctreeServer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9961b5d688..937998f28a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1222,14 +1222,15 @@ void OctreeServer::aboutToFinish() { } // Shut down all the send threads - for (auto it = _sendThreads.begin(); it != _sendThreads.end(); ++it) { - auto& sendThread = *it->second; + for (auto& it : _sendThreads) { + auto& sendThread = *it.second; sendThread.disconnect(this); // Disconnect so that removeSendThread doesn't get called later sendThread.setIsShuttingDown(); } - // Wait on all send threads to be done before continuing - _sendThreads.clear(); + // Clear will destruct all the unique_ptr to OctreeSendThreads which will call the GenericThread's dtor + // which waits on the thread to be done before returning + _sendThreads.clear(); // Cleans up all the send threads. if (_persistThread) { _persistThread->aboutToFinish(); From 6bda8d3f18fb32a252e35ba0234965b97c567513 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:48:23 -0800 Subject: [PATCH 118/318] CR logging category --- assignment-client/src/AssignmentClientLogging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientLogging.cpp b/assignment-client/src/AssignmentClientLogging.cpp index 3e9dbdc53c..890187ecaa 100644 --- a/assignment-client/src/AssignmentClientLogging.cpp +++ b/assignment-client/src/AssignmentClientLogging.cpp @@ -11,4 +11,4 @@ #include "AssignmentClientLogging.h" -Q_LOGGING_CATEGORY(assigmnentclient, "hifi.assignmentclient") \ No newline at end of file +Q_LOGGING_CATEGORY(assigmnentclient, "hifi.assignment-client") \ No newline at end of file From b709c8162c71a05a099273c60db01fba66a5010d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 14:24:52 -0800 Subject: [PATCH 119/318] Fix node flapping race --- assignment-client/src/octree/OctreeServer.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 937998f28a..04b6845ad8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -879,10 +879,11 @@ OctreeServer::UniqueSendThread OctreeServer::createSendThread(const SharedNodePo } void OctreeServer::removeSendThread() { - auto sendThread = static_cast(sender()); - - // This deletes the unique_ptr, so sendThread is destructed after that line - _sendThreads.erase(sendThread->getNodeUuid()); + // If the object has been deleted since the event was queued, sender() will return nullptr + if (auto sendThread = qobject_cast(sender())) { + // This deletes the unique_ptr, so sendThread is destructed after that line + _sendThreads.erase(sendThread->getNodeUuid()); + } } void OctreeServer::handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -893,7 +894,13 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer messa nodeList->updateNodeWithDataFromPacket(message, senderNode); auto it = _sendThreads.find(senderNode->getUUID()); - if (it == _sendThreads.end() || it->second->isShuttingDown()) { + if (it == _sendThreads.end()) { + _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); + } else if (it->second->isShuttingDown()) { + auto& sendThread = *it->second; + sendThread.setIsShuttingDown(); + _sendThreads.erase(it); // Remove right away and wait on thread to be + _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); } } @@ -1224,7 +1231,6 @@ void OctreeServer::aboutToFinish() { // Shut down all the send threads for (auto& it : _sendThreads) { auto& sendThread = *it.second; - sendThread.disconnect(this); // Disconnect so that removeSendThread doesn't get called later sendThread.setIsShuttingDown(); } From 40a096ca8d9c2e1166387531b154da2d263c3759 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:34:01 -0800 Subject: [PATCH 120/318] kinematic grab things --- examples/controllers/handControllerGrab.js | 25 ++++++++++++++++--- examples/light_modifier/lightModifier.js | 3 +-- .../light_modifier/lightModifierTestScene.js | 8 +++++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e7d1b5f84b..ce519880af 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -944,7 +944,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: false, + kinematicSetVelocity: true, ignoreIK: this.ignoreIK }); if (this.actionID === NULL_ACTION_ID) { @@ -1029,7 +1029,7 @@ function MyController(hand) { relativeRotation: this.offsetRotation, ttl: ACTION_TTL, kinematic: NEAR_GRABBING_KINEMATIC, - kinematicSetVelocity: false, + kinematicSetVelocity: true, ignoreIK: this.ignoreIK }); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); @@ -1243,7 +1243,26 @@ function MyController(hand) { this.overlayLineOff(); if (this.grabbedEntity !== null) { if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); + //add velocity whatnot + var defaultReleaseVelocityData = { + disableReleaseVelocity: false + }; + + var releaseVelocityData = getEntityCustomData('releaseVelocityKey', this.grabbedEntity, defaultReleaseVelocityData); + if (releaseVelocityData.disableReleaseVelocity === true) { + Entities.updateAction(this.grabbedEntity, this.actionID, { + ttl: 1, + kinematic: false, + kinematicSetVelocity: false, + + }); + // Entities.deleteAction(this.grabbedEntity, this.actionID); + + } else { + //don't make adjustments + Entities.deleteAction(this.grabbedEntity, this.actionID); + + } } } diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index b33b6fc0f1..b79c00da92 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -243,8 +243,7 @@ entitySlider.prototype = { axisEnd: this.endOfAxis, }, releaseVelocityKey: { - disableReleaseVelocity: true, - customReleaseVelocity: false + disableReleaseVelocity: true } }) }; diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 5748f0d4ed..e939353b8c 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -73,7 +73,13 @@ function createBlock() { green: 0, blue: 255 }, - position: position + position: position, + userData: JSON.stringify({ + + releaseVelocityKey: { + disableReleaseVelocity: true + } + }) }; block = Entities.addEntity(blockProperties); From a7b61cf791387695126b9da9a56233ab06ab170a Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 16:39:09 -0600 Subject: [PATCH 121/318] Couple of fixes --- CMakeLists.txt | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca3e381405..13d5b2bc79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3.2) +cmake_minimum_required(VERSION 3.2) if (USE_ANDROID_TOOLCHAIN) set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake") @@ -228,21 +228,4 @@ if (HIFI_MEMORY_DEBUGGING) endif () include_application_version() - -if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment") - find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) - if (NOT MAKENSIS_COMMAND) - message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") - endif () - add_custom_target( - build-package ALL - DEPENDS interface assignment-client domain-server stack-manager - COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment - COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} - COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples - COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} - COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} - COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" - ) -endif () \ No newline at end of file +generate_installers() \ No newline at end of file From bbe444ffc1a4833f7b4bab49d81d02a02494782c Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 16:40:51 -0600 Subject: [PATCH 122/318] Forgot to add file --- cmake/macros/GenerateInstallers.cmake | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 cmake/macros/GenerateInstallers.cmake diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake new file mode 100644 index 0000000000..570e24332b --- /dev/null +++ b/cmake/macros/GenerateInstallers.cmake @@ -0,0 +1,30 @@ +# +# GenerateInstallers.cmake +# cmake/macros +# +# Created by Leonardo Murillo on 12/16/2015. +# Copyright 2015 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(GENERATE_INSTALLERS) + if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE AND WIN32) + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment") + find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) + if (NOT MAKENSIS_COMMAND) + message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") + endif () + add_custom_target( + build-package ALL + DEPENDS interface assignment-client domain-server stack-manager + COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment + COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} + COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} + COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} + COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" + ) + endif () +endmacro() \ No newline at end of file From b29a6b16a954f4e5427fdbe96517c65153d355ed Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 14:40:56 -0800 Subject: [PATCH 123/318] modularizing flow art tools --- examples/flowArts/flowArtsHutSpawner.js | 77 ++++++ .../flowArts/lightBall/lightBallSpawner.js | 239 +++++++++--------- 2 files changed, 194 insertions(+), 122 deletions(-) create mode 100644 examples/flowArts/flowArtsHutSpawner.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js new file mode 100644 index 0000000000..d3c60548ea --- /dev/null +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -0,0 +1,77 @@ +// +// flowArtsHutSpawner.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creates a special flow arts hut with a numch of flow art toys people can go in and play with +// +// +// 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"); +Script.include("lightBall/lightBallSpawner.js"); + +var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); +basePosition.y = MyAvatar.position.y + 1 +var lightBall = LightBallSpawner(basePosition); +var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); + +var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; + +var raveRoom = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: basePosition, + dimensions:roomDimensions, + visible: true +}); + +var floor = Entities.addEntity({ + type: "Box", + position: Vec3.sum(basePosition, {x: 0, y: -1.5, z: 0}), + dimensions: {x: roomDimensions.x, y: 0.6, z: roomDimensions.z}, + color: {red: 50, green: 10, blue: 100}, + shapeType: 'box' +}); + + + + + +var lightZone = Entities.addEntity({ + type: "Zone", + shapeType: 'box', + keyLightIntensity: 0.2, + keyLightColor: { + red: 50, + green: 0, + blue: 50 + }, + keyLightAmbientIntensity: .2, + position: MyAvatar.position, + dimensions: { + x: 100, + y: 100, + z: 100 + } +}); + + + + + + +function cleanup() { + + Entities.deleteEntity(raveRoom); + Entities.deleteEntity(lightZone) + Entities.deleteEntity(floor); + lightBall.cleanup(); +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js index 20a9c312fc..7325f16a64 100644 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ b/examples/flowArts/lightBall/lightBallSpawner.js @@ -1,129 +1,124 @@ + Script.include("../../libraries/utils.js"); -Script.include("../../libraries/utils.js"); + LightBallSpawner = function(basePosition) { -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); -var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); - -var raveRoom = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - position: center, - visible:false -}); - -var colorPalette = [{ - red: 25, - green: 20, - blue: 162 -}]; + var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; -var containerBall = Entities.addEntity({ - type: "Sphere", - position: center, - dimensions: {x: .1, y: .1, z: .1}, - color: {red: 15, green: 10, blue: 150}, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 1, - z: 0 - } + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(basePosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 }, - invertSolidWhileHeld: true + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 20, + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 5, + "emitRate": 5000, + "emitSpeed": .1, + "speedSpread": 0.0, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); } - }) - // gravity: {x: 0, y: -.1, z: 0} -}); -var lightZone = Entities.addEntity({ - type: "Zone", - shapeType: 'box', - keyLightIntensity: 0.2, - keyLightColor: { - red: 50, - green: 0, - blue: 50 - }, - keyLightAmbientIntensity: .2, - position: MyAvatar.position, - dimensions: { - x: 100, - y: 100, - z: 100 - } -}); - -var light = Entities.addEntity({ - type: 'Light', - position: center, - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - -var lightBall = Entities.addEntity({ - position: center, - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": {red: 200, green: 20, blue: 40}, - color: {red: 200, green: 200, blue: 255}, - "colorFinish": {red: 25, green: 20, blue:255}, - "maxParticles": 100000, - "lifespan": 5, - "emitRate": 5000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: true -}) - - - -function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(raveRoom); - Entities.deleteEntity(lightZone) - Entities.deleteEntity(light); -} - -Script.scriptEnding.connect(cleanup); \ No newline at end of file + this.cleanup = cleanup; + } \ No newline at end of file From f1ec28e169896581a1eb5788d9e89453d6c93378 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 14:55:01 -0800 Subject: [PATCH 124/318] visualize volumes --- examples/libraries/lightOverlayManager.js | 19 +++++++++++++------ examples/light_modifier/lightModifier.js | 2 ++ .../light_modifier/lightModifierTestScene.js | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/libraries/lightOverlayManager.js b/examples/libraries/lightOverlayManager.js index 0942fae723..2d3618096b 100644 --- a/examples/libraries/lightOverlayManager.js +++ b/examples/libraries/lightOverlayManager.js @@ -53,7 +53,9 @@ LightOverlayManager = function() { if (visible != isVisible) { visible = isVisible; for (var id in entityOverlays) { - Overlays.editOverlay(entityOverlays[id], { visible: visible }); + Overlays.editOverlay(entityOverlays[id], { + visible: visible + }); } } }; @@ -61,8 +63,7 @@ LightOverlayManager = function() { // Allocate or get an unused overlay function getOverlay() { if (unusedOverlays.length == 0) { - var overlay = Overlays.addOverlay("image3d", { - }); + var overlay = Overlays.addOverlay("image3d", {}); allOverlays.push(overlay); } else { var overlay = unusedOverlays.pop(); @@ -72,7 +73,9 @@ LightOverlayManager = function() { function releaseOverlay(overlay) { unusedOverlays.push(overlay); - Overlays.editOverlay(overlay, { visible: false }); + Overlays.editOverlay(overlay, { + visible: false + }); } function addEntity(entityID) { @@ -88,7 +91,11 @@ LightOverlayManager = function() { visible: visible, alpha: 0.9, scale: 0.5, - color: { red: 255, green: 255, blue: 255 } + color: { + red: 255, + green: 255, + blue: 255 + } }); } } @@ -123,4 +130,4 @@ LightOverlayManager = function() { Overlays.deleteOverlay(allOverlays[i]); } }); -}; +}; \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index b79c00da92..4d5a326cae 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -36,6 +36,7 @@ if (SHOW_OVERLAYS === true) { lightOverlayManager.setVisible(true); } +// var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking // var pickRay = Camera.computePickRay(event.x, event.y); // var lightResult = lightOverlayManager.findRayIntersection(pickRay) @@ -427,6 +428,7 @@ function cleanup() { Messages.messageReceived.disconnect(handleValueMessages); Entities.deletingEntity.disconnect(deleteEntity); + lightOverlayManager.setVisible(false); } Script.scriptEnding.connect(cleanup); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index e939353b8c..84fb779469 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -26,7 +26,7 @@ function createLight() { dimensions: { x: 2, y: 2, - z: 20 + z: 8 }, parentID: block, color: { From f55994b99317472a9b39e4ddeee619700899b96f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 16 Dec 2015 15:07:31 -0800 Subject: [PATCH 125/318] cleanup --- examples/light_modifier/lightModifier.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 4d5a326cae..7cd442e9ed 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -23,19 +23,27 @@ var selectionManager; var lightOverlayManager; if (SHOW_OVERLAYS === true) { + + Script.include('../libraries/gridTool.js'); Script.include('../libraries/entitySelectionTool.js'); + Script.include('../libraries/lightOverlayManager.js'); + + var grid = Grid(); + gridTool = GridTool({ + horizontalGrid: grid + }); + gridTool.setVisible(false); selectionDisplay = SelectionDisplay; selectionManager = SelectionManager; - Script.include('../libraries/lightOverlayManager.js'); lightOverlayManager = new LightOverlayManager(); selectionManager.addEventListener(function() { selectionDisplay.updateHandles(); lightOverlayManager.updatePositions(); }); - lightOverlayManager.setVisible(true); } + // var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking // var pickRay = Camera.computePickRay(event.x, event.y); // var lightResult = lightOverlayManager.findRayIntersection(pickRay) From c14433979b1911a51afbbf6cdcfddf30be4379ed Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 16 Dec 2015 15:09:37 -0800 Subject: [PATCH 126/318] fix crash mode when model late to get collision URL --- .../src/RenderableModelEntityItem.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b5203ea460..83bfbf7f05 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -385,7 +385,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { _needsInitialSimulation = true; } } - + return result; } @@ -398,14 +398,14 @@ void RenderableModelEntityItem::update(const quint64& now) { EntityItemProperties properties; auto extents = _model->getMeshExtents(); properties.setDimensions(extents.maximum - extents.minimum); - + qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); QMetaObject::invokeMethod(DependencyManager::get().data(), "editEntity", Qt::QueuedConnection, Q_ARG(QUuid, getEntityItemID()), Q_ARG(EntityItemProperties, properties)); } - + ModelEntityItem::update(now); } @@ -427,7 +427,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori // << precisionPicking; QString extraInfo; - return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, + return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo, precisionPicking); } @@ -447,24 +447,22 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { ShapeType type = getShapeType(); if (type == SHAPE_TYPE_COMPOUND) { - if (!_model) { + if (!_model || _model->getCollisionURL().isEmpty()) { EntityTreePointer tree = getTree(); if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); } - return false; // hmm... + return false; } - assert(!_model->getCollisionURL().isEmpty()); - if (_model->getURL().isEmpty()) { // we need a render geometry with a scale to proceed, so give up. return false; } - + const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); const QSharedPointer renderNetworkGeometry = _model->getGeometry(); - + if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) && (renderNetworkGeometry && renderNetworkGeometry->isLoaded())) { // we have both URLs AND both geometries AND they are both fully loaded. From ff83f8fc37081bfb115cb8878ff224235eed4563 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 16 Dec 2015 15:10:30 -0800 Subject: [PATCH 127/318] fix crash mode when leaving domain with handgun --- libraries/physics/src/PhysicalEntitySimulation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 40366257df..5a12627abd 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -44,7 +44,7 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { assert(entity); - if (entity->shouldBePhysical()) { + if (entity->shouldBePhysical()) { EntityMotionState* motionState = static_cast(entity->getPhysicsInfo()); if (!motionState) { _pendingAdds.insert(entity); @@ -117,6 +117,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { _pendingRemoves.clear(); _pendingAdds.clear(); _pendingChanges.clear(); + _outgoingChanges.clear(); } // end EntitySimulation overrides From c0faf978f84f4e8b5957234ac35fcd28bf89a735 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 16 Dec 2015 15:21:09 -0800 Subject: [PATCH 128/318] Introducing a setting for the tone curve --- .../render-utils/src/ToneMappingEffect.cpp | 48 ++++++++++++------- .../render-utils/src/ToneMappingEffect.h | 14 +++++- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 22c31a2459..29e5da6e2a 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -36,18 +36,28 @@ void ToneMappingEffect::init() { // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - + struct ToneMappingParams { vec4 _exp_2powExp_s0_s1; + ivec4 _toneCurve_s0_s1_s2; }; + const float INV_GAMMA_22 = 1.0 / 2.2; + const int ToneCurveNone = 0; + const int ToneCurveGamma22 = 1; + const int ToneCurveReinhard = 2; + const int ToneCurveFilmic = 3; + uniform toneMappingParamsBuffer { ToneMappingParams params; }; float getTwoPowExposure() { return params._exp_2powExp_s0_s1.y; } - + int getToneCurve() { + return params._toneCurve_s0_s1_s2.x; + } + uniform sampler2D colorMap; in vec2 varTexCoord0; @@ -56,25 +66,26 @@ void ToneMappingEffect::init() { void main(void) { vec4 fragColorRaw = textureLod(colorMap, varTexCoord0, 0); vec3 fragColor = fragColorRaw.xyz; - -/* vec4 fragColorAverage = textureLod(colorMap, varTexCoord0, 10); +/* + vec4 fragColorAverage = textureLod(colorMap, varTexCoord0, 10); float averageIntensity = length(fragColorAverage.xyz); - - vec3 fragColor = fragColorRaw.xyz / averageIntensity; + fragColor /= averageIntensity; */ - fragColor *= getTwoPowExposure(); + vec3 srcColor = fragColor * getTwoPowExposure(); + int toneCurve = getToneCurve(); + vec3 tonedColor = srcColor; + if (toneCurve == ToneCurveFilmic) { + vec3 x = max(vec3(0.0), srcColor-0.004); + tonedColor = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); + } else if (toneCurve == ToneCurveReinhard) { + tonedColor = srcColor/(1.0 + srcColor); + tonedColor = pow(tonedColor, vec3(INV_GAMMA_22)); + } else if (toneCurve == ToneCurveGamma22) { + tonedColor = pow(srcColor, vec3(INV_GAMMA_22)); + } // else None toned = src - // Manually gamma correct from Ligthing BUffer to color buffer - // outFragColor.xyz = pow( fragColor.xyz , vec3(1.0 / 2.2) ); - - vec3 x = max(vec3(0.0),fragColor.xyz-0.004); - vec3 retColor = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06); - - // fragColor = fragColor/(1.0+fragColor); - // vec3 retColor = pow(fragColor.xyz,vec3(1/2.2)); - - outFragColor = vec4(retColor, 1.0); + outFragColor = vec4(tonedColor, 1.0); } )SCRIBE"; @@ -96,6 +107,9 @@ void ToneMappingEffect::setExposure(float exposure) { _parametersBuffer.edit()._twoPowExposure = pow(2.0, exposure); } +void ToneMappingEffect::setToneCurve(ToneCurve curve) { + _parametersBuffer.edit()._toneCurve = curve; +} void ToneMappingEffect::render(RenderArgs* args) { if (!_blitLightBuffer) { diff --git a/libraries/render-utils/src/ToneMappingEffect.h b/libraries/render-utils/src/ToneMappingEffect.h index be9664ddd9..20ee9024cf 100644 --- a/libraries/render-utils/src/ToneMappingEffect.h +++ b/libraries/render-utils/src/ToneMappingEffect.h @@ -30,6 +30,16 @@ public: void setExposure(float exposure); float getExposure() const { return _parametersBuffer.get()._exposure; } + // Different tone curve available + enum ToneCurve { + None = 0, + Gamma22, + Reinhard, + Filmic, + }; + void setToneCurve(ToneCurve curve); + ToneCurve getToneCurve() const { return (ToneCurve)_parametersBuffer.get()._toneCurve; } + private: gpu::PipelinePointer _blitLightBuffer; @@ -39,7 +49,9 @@ private: public: float _exposure = 0.0f; float _twoPowExposure = 1.0f; - glm::vec2 spare; + glm::vec2 spareA; + int _toneCurve = Filmic; + glm::vec3 spareB; Parameters() {} }; From 489d4099a7dbd76f59fa2d7b62092de402ba5748 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Dec 2015 15:21:20 -0800 Subject: [PATCH 129/318] add locationChanged to model entities --- interface/src/avatar/AvatarActionHold.cpp | 2 ++ .../entities-renderer/src/RenderableModelEntityItem.cpp | 8 ++++++++ .../entities-renderer/src/RenderableModelEntityItem.h | 1 + 3 files changed, 11 insertions(+) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 32d35e3f8f..160a437f44 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -199,6 +199,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { motionState->dirtyInternalKinematicChanges(); + ownerEntity->setPosition(_positionalTarget); + _previousPositionalTarget = _positionalTarget; _previousRotationalTarget = _rotationalTarget; _previousSet = true; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b5203ea460..14e89b59fd 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -625,3 +625,11 @@ glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(in } return glm::vec3(0.0f); } + +void RenderableModelEntityItem::locationChanged() { + EntityItem::locationChanged(); + if (_model && _model->isActive()) { + _model->setRotation(getRotation()); + _model->setTranslation(getPosition()); + } +} diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 143113146e..cf948bd7a0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -73,6 +73,7 @@ public: virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; virtual void loader() override; + virtual void locationChanged() override; private: void remapTextures(); From 4155e3af71a9efc3bc79772364e475864d2187d6 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 15:22:56 -0800 Subject: [PATCH 130/318] refactoring --- examples/flowArts/flowArtsHutSpawner.js | 8 +- examples/flowArts/lightBall/lightBall.js | 124 ++++++++++++++++++ .../flowArts/lightBall/lightBallSpawner.js | 124 ------------------ .../flowArts/raveStick/createRaveStick.js | 0 4 files changed, 126 insertions(+), 130 deletions(-) delete mode 100644 examples/flowArts/lightBall/lightBallSpawner.js create mode 100644 examples/flowArts/raveStick/createRaveStick.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index d3c60548ea..c8f7dbed78 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -14,11 +14,11 @@ Script.include("../../libraries/utils.js"); -Script.include("lightBall/lightBallSpawner.js"); +Script.include("lightBall/LightBall.js"); var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); basePosition.y = MyAvatar.position.y + 1 -var lightBall = LightBallSpawner(basePosition); +var lightBall = LightBall(basePosition); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; @@ -62,10 +62,6 @@ var lightZone = Entities.addEntity({ }); - - - - function cleanup() { Entities.deleteEntity(raveRoom); diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index e69de29bb2..6f44ed6d74 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -0,0 +1,124 @@ + Script.include("../../libraries/utils.js"); + + LightBall = function(basePosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(basePosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 20, + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 5, + "emitRate": 5000, + "emitSpeed": .1, + "speedSpread": 0.0, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "particleRadius": 0.04, + "radiusSpread": 0, + "radiusStart": 0.05, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; + } \ No newline at end of file diff --git a/examples/flowArts/lightBall/lightBallSpawner.js b/examples/flowArts/lightBall/lightBallSpawner.js deleted file mode 100644 index 7325f16a64..0000000000 --- a/examples/flowArts/lightBall/lightBallSpawner.js +++ /dev/null @@ -1,124 +0,0 @@ - Script.include("../../libraries/utils.js"); - - LightBallSpawner = function(basePosition) { - - var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); - var colorPalette = [{ - red: 25, - green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(basePosition, { - x: 0, - y: .5, - z: 0 - }), - dimensions: { - x: .1, - y: .1, - z: .1 - }, - color: { - red: 15, - green: 10, - blue: 150 - }, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 1, - z: 0 - } - }, - invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var lightBall = Entities.addEntity({ - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - "colorFinish": { - red: 25, - green: 20, - blue: 255 - }, - "maxParticles": 100000, - "lifespan": 5, - "emitRate": 5000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: true - }) - - - - function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } - - this.cleanup = cleanup; - } \ No newline at end of file diff --git a/examples/flowArts/raveStick/createRaveStick.js b/examples/flowArts/raveStick/createRaveStick.js new file mode 100644 index 0000000000..e69de29bb2 From 45e31ca4422359e6af92ba257fdb20bbaa1469b6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 16 Dec 2015 15:35:23 -0800 Subject: [PATCH 131/318] fix warning about unused variable --- 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 f8040754d7..6094a0b9fe 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -157,7 +157,7 @@ void Avatar::animateScaleChanges(float deltaTime) { // snap to the end when we get close enough const float MIN_RELATIVE_SCALE_ERROR = 0.03f; - if (fabsf(_targetScale - currentScale) / _targetScale < 0.03f) { + if (fabsf(_targetScale - currentScale) / _targetScale < MIN_RELATIVE_SCALE_ERROR) { animatedScale = _targetScale; } From d7affcf811a8e5a46d5f201336effbeeec1584e3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Dec 2015 15:41:27 -0800 Subject: [PATCH 132/318] keep track of palm rotation vs avatar as well as palm translation --- interface/src/avatar/AvatarActionHold.cpp | 49 +++++++++++++++++------ interface/src/avatar/AvatarActionHold.h | 3 +- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 160a437f44..5a4dbfa4d1 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -33,17 +33,15 @@ AvatarActionHold::~AvatarActionHold() { #endif } -glm::vec3 AvatarActionHold::getAvatarRigidBodyPosition() { +bool AvatarActionHold::getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation) { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; if (!controller) { - qDebug() << "AvatarActionHold::getAvatarRigidBodyPosition failed to get character controller"; - return glm::vec3(0.0f); + qDebug() << "AvatarActionHold::getAvatarRigidBodyLocation failed to get character controller"; + return false; } - glm::vec3 avatarRigidBodyPosition; - glm::quat avatarRigidBodyRotation; controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); - return avatarRigidBodyPosition; + return true; } void AvatarActionHold::prepareForPhysicsSimulation() { @@ -59,9 +57,28 @@ void AvatarActionHold::prepareForPhysicsSimulation() { return; } if (holdingAvatar->isMyAvatar()) { - glm::vec3 palmPosition = (_hand == "right") ? - holdingAvatar->getRightPalmPosition() : holdingAvatar->getLeftPalmPosition(); - _palmOffsetFromRigidBody = palmPosition - getAvatarRigidBodyPosition(); + glm::vec3 palmPosition; + glm::quat palmRotation; + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + + // determine the difference in translation and rotation between the avatar's + // rigid body and the palm position. The avatar's rigid body will be moved by bullet + // between this call and the call to getTarget, below. A call to get*PalmPosition in + // getTarget would get the palm position of the previous location of the avatar (because + // bullet has moved the av's rigid body but the rigid body's location has not yet been + // copied out into the Avatar class. + _palmOffsetFromRigidBody = palmPosition - avatarRigidBodyPosition; + _palmRotationFromRigidBody = glm::inverse(avatarRigidBodyRotation) * palmRotation; } }); } @@ -90,7 +107,17 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } } else if (holdingAvatar->isMyAvatar()) { - palmPosition = getAvatarRigidBodyPosition() + _palmOffsetFromRigidBody; + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + + // the offset and rotation between the avatar's rigid body and the palm were determined earlier + // in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet + // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will + // be stale. Instead, determine the current palm position with the current avatar's rigid body + // location and the saved offsets. + palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; + palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; if (isRightHand) { palmRotation = holdingAvatar->getRightPalmRotation(); } else { @@ -199,8 +226,6 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { motionState->dirtyInternalKinematicChanges(); - ownerEntity->setPosition(_positionalTarget); - _previousPositionalTarget = _positionalTarget; _previousRotationalTarget = _rotationalTarget; _previousSet = true; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 36a9aa3049..fc8baf6dcc 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -35,7 +35,7 @@ public: virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } - glm::vec3 getAvatarRigidBodyPosition(); + bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); std::shared_ptr getTarget(glm::quat& rotation, glm::vec3& position); virtual void prepareForPhysicsSimulation() override; @@ -61,6 +61,7 @@ private: glm::vec3 _previousPositionalDelta; glm::vec3 _palmOffsetFromRigidBody; + glm::quat _palmRotationFromRigidBody; }; #endif // hifi_AvatarActionHold_h From 364a70bb46106143a66a9d2f5da038c04c0b2ce0 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Wed, 16 Dec 2015 15:39:45 -0800 Subject: [PATCH 133/318] Fix to avoid MVS warning --- interface/src/ui/overlays/Image3DOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 7d105a6ccf..f1e0f08a3a 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -34,8 +34,8 @@ Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : Billboard3DOverlay(image3DOverlay), _url(image3DOverlay->_url), _texture(image3DOverlay->_texture), - _fromImage(image3DOverlay->_fromImage), - _emissive(image3DOverlay->_emissive) + _emissive(image3DOverlay->_emissive), + _fromImage(image3DOverlay->_fromImage) { } From 6a77ae5db2cbead0c901ca40e788a73929ad8bc5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 15:47:34 -0800 Subject: [PATCH 134/318] adding rave stick --- examples/flowArts/flowArtsHutSpawner.js | 9 +- examples/flowArts/lightBall/lightBall.js | 232 +++++++++--------- examples/flowArts/raveStick/RaveStick.js | 24 ++ .../flowArts/raveStick/createRaveStick.js | 0 4 files changed, 145 insertions(+), 120 deletions(-) create mode 100644 examples/flowArts/raveStick/RaveStick.js delete mode 100644 examples/flowArts/raveStick/createRaveStick.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index c8f7dbed78..ffd73dbdca 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -15,10 +15,12 @@ Script.include("../../libraries/utils.js"); Script.include("lightBall/LightBall.js"); +Script.include("raveStick/RaveStick.js"); var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); -basePosition.y = MyAvatar.position.y + 1 -var lightBall = LightBall(basePosition); +basePosition.y = MyAvatar.position.y + 1; +var lightBall = new LightBall(basePosition); +var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 1, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; @@ -41,8 +43,6 @@ var floor = Entities.addEntity({ - - var lightZone = Entities.addEntity({ type: "Zone", shapeType: 'box', @@ -68,6 +68,7 @@ function cleanup() { Entities.deleteEntity(lightZone) Entities.deleteEntity(floor); lightBall.cleanup(); + raveStick.cleanup(); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index 6f44ed6d74..e2d65874fa 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -1,124 +1,124 @@ - Script.include("../../libraries/utils.js"); +Script.include("../../libraries/utils.js"); - LightBall = function(basePosition) { +LightBall = function(spawnPosition) { - var colorPalette = [{ + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(spawnPosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: .7, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { red: 25, green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(basePosition, { - x: 0, - y: .5, - z: 0 - }), - dimensions: { - x: .1, - y: .1, - z: .1 - }, - color: { - red: 15, - green: 10, - blue: 150 - }, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 1, - z: 0 - } - }, - invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var lightBall = Entities.addEntity({ - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - "colorFinish": { - red: 25, - green: 20, - blue: 255 - }, - "maxParticles": 100000, - "lifespan": 5, - "emitRate": 5000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 - }, - "particleRadius": 0.04, - "radiusSpread": 0, - "radiusStart": 0.05, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), - emitterShouldTrail: true - }) + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 10000, + "emitSpeed": .1, + "speedSpread": 0.0, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, + "polarStart": 0, + "polarFinish": Math.PI, + "azimuthStart": -Math.PI, + "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "particleRadius": 0.02, + "radiusSpread": 0, + "radiusStart": 0.03, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + emitterShouldTrail: true + }) - function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } - this.cleanup = cleanup; - } \ No newline at end of file + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js new file mode 100644 index 0000000000..2703436bec --- /dev/null +++ b/examples/flowArts/raveStick/RaveStick.js @@ -0,0 +1,24 @@ +Script.include("../../libraries/utils.js"); +var modelURL = "file:///C:/Users/Eric/Desktop/raveStick.fbx?v1" + Math.random(); + +RaveStick = function(spawnPosition) { + + var stick = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: spawnPosition, + shapeType: 'box', + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) + }); + + + function cleanup() { + Entities.deleteEntity(stick); + } + + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/raveStick/createRaveStick.js b/examples/flowArts/raveStick/createRaveStick.js deleted file mode 100644 index e69de29bb2..0000000000 From 5f9bdcb2aa6ba705ac3173cdebf9fbb171e03b90 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 16 Dec 2015 15:52:20 -0800 Subject: [PATCH 135/318] fix lock type --- interface/src/avatar/AvatarActionHold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5a4dbfa4d1..34b959575d 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -52,7 +52,7 @@ void AvatarActionHold::prepareForPhysicsSimulation() { return; } - withReadLock([&]{ + withWriteLock([&]{ if (_ignoreIK && holdingAvatar->isMyAvatar()) { return; } From 2c8be15e6671df5e74f0241d1185d119a504df16 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 15:56:22 -0800 Subject: [PATCH 136/318] Unnecessary shutdown (Already shutting down) --- assignment-client/src/octree/OctreeServer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 04b6845ad8..410aa922dc 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -897,8 +897,6 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer messa if (it == _sendThreads.end()) { _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); } else if (it->second->isShuttingDown()) { - auto& sendThread = *it->second; - sendThread.setIsShuttingDown(); _sendThreads.erase(it); // Remove right away and wait on thread to be _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); From 263557cc1ac008e5ae98ed1c5ea977cc20aae6fa Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 16:18:57 -0800 Subject: [PATCH 137/318] setting dimensions for rave stick --- examples/flowArts/lightBall/lightBall.js | 3 ++- examples/flowArts/raveStick/RaveStick.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index e2d65874fa..698c62a71d 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -27,12 +27,13 @@ LightBall = function(spawnPosition) { blue: 150 }, collisionsWillMove: true, + gravity: {x: 0, y: -.5, z: 0}, userData: JSON.stringify({ grabbableKey: { spatialKey: { relativePosition: { x: 0, - y: .7, + y: .1, z: 0 } }, diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index 2703436bec..bee5c995f9 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -8,6 +8,7 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', + dimensions: {x: 0.17, y: 0.48, z: 0.17}, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true From fa5bab08b15effee1ff91cc5cc6a4934c4f2bbbf Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 16 Dec 2015 16:03:30 -0800 Subject: [PATCH 138/318] Support web content inside QML --- .../PackageLibrariesForDeployment.cmake | 2 +- examples/html/eventBridgeLoader.js | 59 ++ examples/html/qmlWebTest.html | 31 + examples/tests/qmlWebTest.js | 32 + interface/CMakeLists.txt | 18 +- interface/resources/qml/Browser.qml | 28 +- interface/resources/qml/InfoView.qml | 16 +- interface/resources/qml/MarketplaceDialog.qml | 37 +- interface/resources/qml/QmlWebWindow.qml | 45 ++ interface/resources/qml/TestMenu.qml | 109 --- interface/resources/qml/WebEntity.qml | 6 +- interface/resources/qml/qwebchannel.js | 413 ++++++++++++ interface/src/Application.cpp | 18 + libraries/gl/src/gl/OffscreenQmlSurface.cpp | 13 +- libraries/gl/src/gl/OffscreenQmlSurface.h | 4 +- libraries/ui/CMakeLists.txt | 2 +- libraries/ui/src/QmlWebWindowClass.cpp | 344 ++++++++++ libraries/ui/src/QmlWebWindowClass.h | 92 +++ .../ui/src/impl/websocketclientwrapper.cpp | 72 ++ .../ui/src/impl/websocketclientwrapper.h | 63 ++ libraries/ui/src/impl/websockettransport.cpp | 100 +++ libraries/ui/src/impl/websockettransport.h | 60 ++ tests/ui/CMakeLists.txt | 19 +- tests/ui/src/main.cpp | 622 +++++++++++++----- 24 files changed, 1878 insertions(+), 327 deletions(-) create mode 100644 examples/html/eventBridgeLoader.js create mode 100644 examples/html/qmlWebTest.html create mode 100644 examples/tests/qmlWebTest.js create mode 100644 interface/resources/qml/QmlWebWindow.qml create mode 100644 interface/resources/qml/qwebchannel.js create mode 100644 libraries/ui/src/QmlWebWindowClass.cpp create mode 100644 libraries/ui/src/QmlWebWindowClass.h create mode 100644 libraries/ui/src/impl/websocketclientwrapper.cpp create mode 100644 libraries/ui/src/impl/websocketclientwrapper.h create mode 100644 libraries/ui/src/impl/websockettransport.cpp create mode 100644 libraries/ui/src/impl/websockettransport.h diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index bb0b268dd4..17b5d5f49d 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -40,7 +40,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} $<$,$,$>:--release> $" + COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release> $" ) elseif (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE) find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH) diff --git a/examples/html/eventBridgeLoader.js b/examples/html/eventBridgeLoader.js new file mode 100644 index 0000000000..b62e7d9384 --- /dev/null +++ b/examples/html/eventBridgeLoader.js @@ -0,0 +1,59 @@ + +//public slots: +// void emitWebEvent(const QString& data); +// void emitScriptEvent(const QString& data); +// +//signals: +// void webEventReceived(const QString& data); +// void scriptEventReceived(const QString& data); +// + +EventBridgeConnectionProxy = function(parent) { + this.parent = parent; + this.realSignal = this.parent.realBridge.scriptEventReceived + this.webWindowId = this.parent.webWindow.windowId; +} + +EventBridgeConnectionProxy.prototype.connect = function(callback) { + var that = this; + this.realSignal.connect(function(id, message) { + if (id === that.webWindowId) { callback(message); } + }); +} + +EventBridgeProxy = function(webWindow) { + this.webWindow = webWindow; + this.realBridge = this.webWindow.eventBridge; + this.scriptEventReceived = new EventBridgeConnectionProxy(this); +} + +EventBridgeProxy.prototype.emitWebEvent = function(data) { + this.realBridge.emitWebEvent(data); +} + +openEventBridge = function(callback) { + EVENT_BRIDGE_URI = "ws://localhost:51016"; + socket = new WebSocket(this.EVENT_BRIDGE_URI); + + socket.onclose = function() { + console.error("web channel closed"); + }; + + socket.onerror = function(error) { + console.error("web channel error: " + error); + }; + + socket.onopen = function() { + channel = new QWebChannel(socket, function(channel) { + console.log("Document url is " + document.URL); + for(var key in channel.objects){ + console.log("registered object: " + key); + } + var webWindow = channel.objects[document.URL.toLowerCase()]; + console.log("WebWindow is " + webWindow) + eventBridgeProxy = new EventBridgeProxy(webWindow); + if (callback) { callback(eventBridgeProxy); } + }); + } +} + diff --git a/examples/html/qmlWebTest.html b/examples/html/qmlWebTest.html new file mode 100644 index 0000000000..e59535701d --- /dev/null +++ b/examples/html/qmlWebTest.html @@ -0,0 +1,31 @@ + + +Properties + + + + + + + + + + + + + diff --git a/examples/tests/qmlWebTest.js b/examples/tests/qmlWebTest.js new file mode 100644 index 0000000000..250852abe7 --- /dev/null +++ b/examples/tests/qmlWebTest.js @@ -0,0 +1,32 @@ +print("Launching web window"); + +webWindow = new QmlWebWindow('Test Event Bridge', "file:///C:/Users/bdavis/Git/hifi/examples/html/qmlWebTest.html", 320, 240, false); +print("JS Side window: " + webWindow); +print("JS Side bridge: " + webWindow.eventBridge); +webWindow.eventBridge.webEventReceived.connect(function(data) { + print("JS Side event received: " + data); +}); + +var titles = ["A", "B", "C"]; +var titleIndex = 0; + +Script.setInterval(function() { + webWindow.eventBridge.emitScriptEvent("JS Event sent"); + var size = webWindow.size; + var position = webWindow.position; + print("Window url: " + webWindow.url) + print("Window visible: " + webWindow.visible) + print("Window size: " + size.x + "x" + size.y) + print("Window pos: " + position.x + "x" + position.y) + webWindow.setVisible(!webWindow.visible); + webWindow.setTitle(titles[titleIndex]); + webWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100); + titleIndex += 1; + titleIndex %= titles.length; +}, 2 * 1000); + +Script.setTimeout(function() { + print("Closing script"); + webWindow.close(); + Script.stop(); +}, 15 * 1000) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 87cf1a384c..1d9557a835 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -45,7 +45,9 @@ else () list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) endif () -find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets WebSockets) +find_package(Qt5 COMPONENTS + Gui Multimedia Network OpenGL Qml Quick Script Svg + WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) @@ -175,9 +177,17 @@ include_directories("${PROJECT_SOURCE_DIR}/src") target_link_libraries( ${TARGET_NAME} - Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets + Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL + Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg + Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets ) +# Issue causes build failure unless we add this directory. +# See https://bugreports.qt.io/browse/QTBUG-43351 +if (WIN32) + add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) +endif() + # assume we are using a Qt build without bearer management add_definitions(-DQT_NO_BEARERMANAGEMENT) @@ -209,5 +219,9 @@ else (APPLE) endif() endif (APPLE) +if (WIN32) + set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") +endif() + package_libraries_for_deployment() consolidate_stack_components() diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 947bf739fc..8f3cd0e1e7 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,6 +1,6 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtWebKit 3.0 +import QtWebEngine 1.1 import "controls" import "styles" @@ -39,9 +39,10 @@ VrDialog { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.bottom: scrollView.top + anchors.bottom: webview.top color: "white" } + Row { id: buttons spacing: 4 @@ -112,26 +113,22 @@ VrDialog { } } - ScrollView { - id: scrollView + WebEngineView { + id: webview + url: "http://highfidelity.com" anchors.top: buttons.bottom anchors.topMargin: 8 anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - WebView { - id: webview - url: "http://highfidelity.com" - anchors.fill: parent - onLoadingChanged: { - if (loadRequest.status == WebView.LoadSucceededStarted) { - addressBar.text = loadRequest.url - } - } - onIconChanged: { - barIcon.source = icon + onLoadingChanged: { + if (loadRequest.status == WebEngineView.LoadSucceededStatus) { + addressBar.text = loadRequest.url } } + onIconChanged: { + console.log("New icon: " + icon) + } } } // item @@ -146,5 +143,4 @@ VrDialog { break; } } - } // dialog diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 012f04f1fd..75b82342ca 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -2,7 +2,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -import QtWebKit 3.0 +import QtWebEngine 1.1 import "controls" VrDialog { @@ -18,15 +18,11 @@ VrDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - ScrollView { + WebEngineView { + id: webview + objectName: "WebView" anchors.fill: parent - WebView { - objectName: "WebView" - id: webview - url: infoView.url - anchors.fill: parent - } - } - + url: infoView.url + } } } diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml index 946f32e84a..3a66c5340f 100644 --- a/interface/resources/qml/MarketplaceDialog.qml +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -2,7 +2,7 @@ import Hifi 1.0 import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -import QtWebKit 3.0 +import QtWebEngine 1.1 import "controls" VrDialog { @@ -24,27 +24,22 @@ VrDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - - ScrollView { + WebEngineView { + objectName: "WebView" + id: webview + url: "https://metaverse.highfidelity.com/marketplace" anchors.fill: parent - WebView { - objectName: "WebView" - id: webview - url: "https://metaverse.highfidelity.com/marketplace" - anchors.fill: parent - onNavigationRequested: { - console.log(request.url) - if (!marketplaceDialog.navigationRequested(request.url)) { - console.log("Application absorbed the request") - request.action = WebView.IgnoreRequest; - return; - } - console.log("Application passed on the request") - request.action = WebView.AcceptRequest; + onNavigationRequested: { + console.log(request.url) + if (!marketplaceDialog.navigationRequested(request.url)) { + console.log("Application absorbed the request") + request.action = WebView.IgnoreRequest; return; - } + } + console.log("Application passed on the request") + request.action = WebView.AcceptRequest; + return; } - } - - } + } + } } diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml new file mode 100644 index 0000000000..d59ef4955e --- /dev/null +++ b/interface/resources/qml/QmlWebWindow.qml @@ -0,0 +1,45 @@ + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtWebEngine 1.1 +import QtWebChannel 1.0 +import QtWebSockets 1.0 + +import "qwebchannel.js" as WebChannel +import "controls" +import "styles" + +VrDialog { + id: root + HifiConstants { id: hifi } + title: "WebWindow" + resizable: true + contentImplicitWidth: clientArea.implicitWidth + contentImplicitHeight: clientArea.implicitHeight + backgroundColor: "#7f000000" + property url source: "about:blank" + + Component.onCompleted: { + enabled = true + console.log("Web Window Created " + root); + webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); + }); + } + + Item { + id: clientArea + implicitHeight: 600 + implicitWidth: 800 + x: root.clientX + y: root.clientY + width: root.clientWidth + height: root.clientHeight + + WebEngineView { + id: webview + url: root.source + anchors.fill: parent + } + } // item +} // dialog diff --git a/interface/resources/qml/TestMenu.qml b/interface/resources/qml/TestMenu.qml index 4d109e6298..fe8a26e234 100644 --- a/interface/resources/qml/TestMenu.qml +++ b/interface/resources/qml/TestMenu.qml @@ -4,116 +4,7 @@ import Hifi 1.0 // Currently for testing a pure QML replacement menu Item { - Item { - objectName: "AllActions" - Action { - id: aboutApp - objectName: "HifiAction_" + MenuConstants.AboutApp - text: qsTr("About Interface") - } - - // - // File Menu - // - Action { - id: login - objectName: "HifiAction_" + MenuConstants.Login - text: qsTr("Login") - } - Action { - id: quit - objectName: "HifiAction_" + MenuConstants.Quit - text: qsTr("Quit") - //shortcut: StandardKey.Quit - shortcut: "Ctrl+Q" - } - - - // - // Edit menu - // - Action { - id: undo - text: "Undo" - shortcut: StandardKey.Undo - } - - Action { - id: redo - text: "Redo" - shortcut: StandardKey.Redo - } - - Action { - id: animations - objectName: "HifiAction_" + MenuConstants.Animations - text: qsTr("Animations...") - } - Action { - id: attachments - text: qsTr("Attachments...") - } - Action { - id: explode - text: qsTr("Explode on quit") - checkable: true - checked: true - } - Action { - id: freeze - text: qsTr("Freeze on quit") - checkable: true - checked: false - } - ExclusiveGroup { - Action { - id: visibleToEveryone - objectName: "HifiAction_" + MenuConstants.VisibleToEveryone - text: qsTr("Everyone") - checkable: true - checked: true - } - Action { - id: visibleToFriends - objectName: "HifiAction_" + MenuConstants.VisibleToFriends - text: qsTr("Friends") - checkable: true - } - Action { - id: visibleToNoOne - objectName: "HifiAction_" + MenuConstants.VisibleToNoOne - text: qsTr("No one") - checkable: true - } - } - } - Menu { objectName: "rootMenu"; - Menu { - title: "File" - MenuItem { action: login } - MenuItem { action: explode } - MenuItem { action: freeze } - MenuItem { action: quit } - } - Menu { - title: "Tools" - Menu { - title: "I Am Visible To" - MenuItem { action: visibleToEveryone } - MenuItem { action: visibleToFriends } - MenuItem { action: visibleToNoOne } - } - MenuItem { action: animations } - } - Menu { - title: "Long menu name top menu" - MenuItem { action: aboutApp } - } - Menu { - title: "Help" - MenuItem { action: aboutApp } - } } } diff --git a/interface/resources/qml/WebEntity.qml b/interface/resources/qml/WebEntity.qml index 0eb943cac7..ae94105672 100644 --- a/interface/resources/qml/WebEntity.qml +++ b/interface/resources/qml/WebEntity.qml @@ -1,10 +1,10 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtWebKit 3.0 +import QtWebEngine 1.1 -WebView { +WebEngineView { id: root - objectName: "webview" anchors.fill: parent + objectName: "webview" url: "about:blank" } diff --git a/interface/resources/qml/qwebchannel.js b/interface/resources/qml/qwebchannel.js new file mode 100644 index 0000000000..d8c28bc663 --- /dev/null +++ b/interface/resources/qml/qwebchannel.js @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +"use strict"; + +var QWebChannelMessageTypes = { + signal: 1, + propertyUpdate: 2, + init: 3, + idle: 4, + debug: 5, + invokeMethod: 6, + connectToSignal: 7, + disconnectFromSignal: 8, + setProperty: 9, + response: 10, +}; + +var QWebChannel = function(transport, initCallback) +{ + if (typeof transport !== "object" || typeof transport.send !== "function") { + console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." + + " Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send)); + return; + } + + var channel = this; + this.transport = transport; + + this.send = function(data) + { + if (typeof(data) !== "string") { + data = JSON.stringify(data); + } + channel.transport.send(data); + } + + this.transport.onmessage = function(message) + { + var data = message.data; + if (typeof data === "string") { + data = JSON.parse(data); + } + switch (data.type) { + case QWebChannelMessageTypes.signal: + channel.handleSignal(data); + break; + case QWebChannelMessageTypes.response: + channel.handleResponse(data); + break; + case QWebChannelMessageTypes.propertyUpdate: + channel.handlePropertyUpdate(data); + break; + default: + console.error("invalid message received:", message.data); + break; + } + } + + this.execCallbacks = {}; + this.execId = 0; + this.exec = function(data, callback) + { + if (!callback) { + // if no callback is given, send directly + channel.send(data); + return; + } + if (channel.execId === Number.MAX_VALUE) { + // wrap + channel.execId = Number.MIN_VALUE; + } + if (data.hasOwnProperty("id")) { + console.error("Cannot exec message with property id: " + JSON.stringify(data)); + return; + } + data.id = channel.execId++; + channel.execCallbacks[data.id] = callback; + channel.send(data); + }; + + this.objects = {}; + + this.handleSignal = function(message) + { + var object = channel.objects[message.object]; + if (object) { + object.signalEmitted(message.signal, message.args); + } else { + console.warn("Unhandled signal: " + message.object + "::" + message.signal); + } + } + + this.handleResponse = function(message) + { + if (!message.hasOwnProperty("id")) { + console.error("Invalid response message received: ", JSON.stringify(message)); + return; + } + channel.execCallbacks[message.id](message.data); + delete channel.execCallbacks[message.id]; + } + + this.handlePropertyUpdate = function(message) + { + for (var i in message.data) { + var data = message.data[i]; + var object = channel.objects[data.object]; + if (object) { + object.propertyUpdate(data.signals, data.properties); + } else { + console.warn("Unhandled property update: " + data.object + "::" + data.signal); + } + } + channel.exec({type: QWebChannelMessageTypes.idle}); + } + + this.debug = function(message) + { + channel.send({type: QWebChannelMessageTypes.debug, data: message}); + }; + + channel.exec({type: QWebChannelMessageTypes.init}, function(data) { + for (var objectName in data) { + var object = new QObject(objectName, data[objectName], channel); + } + // now unwrap properties, which might reference other registered objects + for (var objectName in channel.objects) { + channel.objects[objectName].unwrapProperties(); + } + if (initCallback) { + initCallback(channel); + } + channel.exec({type: QWebChannelMessageTypes.idle}); + }); +}; + +function QObject(name, data, webChannel) +{ + this.__id__ = name; + webChannel.objects[name] = this; + + // List of callbacks that get invoked upon signal emission + this.__objectSignals__ = {}; + + // Cache of all properties, updated when a notify signal is emitted + this.__propertyCache__ = {}; + + var object = this; + + // ---------------------------------------------------------------------- + + this.unwrapQObject = function(response) + { + if (response instanceof Array) { + // support list of objects + var ret = new Array(response.length); + for (var i = 0; i < response.length; ++i) { + ret[i] = object.unwrapQObject(response[i]); + } + return ret; + } + if (!response + || !response["__QObject*__"] + || response.id === undefined) { + return response; + } + + var objectId = response.id; + if (webChannel.objects[objectId]) + return webChannel.objects[objectId]; + + if (!response.data) { + console.error("Cannot unwrap unknown QObject " + objectId + " without data."); + return; + } + + var qObject = new QObject( objectId, response.data, webChannel ); + qObject.destroyed.connect(function() { + if (webChannel.objects[objectId] === qObject) { + delete webChannel.objects[objectId]; + // reset the now deleted QObject to an empty {} object + // just assigning {} though would not have the desired effect, but the + // below also ensures all external references will see the empty map + // NOTE: this detour is necessary to workaround QTBUG-40021 + var propertyNames = []; + for (var propertyName in qObject) { + propertyNames.push(propertyName); + } + for (var idx in propertyNames) { + delete qObject[propertyNames[idx]]; + } + } + }); + // here we are already initialized, and thus must directly unwrap the properties + qObject.unwrapProperties(); + return qObject; + } + + this.unwrapProperties = function() + { + for (var propertyIdx in object.__propertyCache__) { + object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]); + } + } + + function addSignal(signalData, isPropertyNotifySignal) + { + var signalName = signalData[0]; + var signalIndex = signalData[1]; + object[signalName] = { + connect: function(callback) { + if (typeof(callback) !== "function") { + console.error("Bad callback given to connect to signal " + signalName); + return; + } + + object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; + object.__objectSignals__[signalIndex].push(callback); + + if (!isPropertyNotifySignal && signalName !== "destroyed") { + // only required for "pure" signals, handled separately for properties in propertyUpdate + // also note that we always get notified about the destroyed signal + webChannel.exec({ + type: QWebChannelMessageTypes.connectToSignal, + object: object.__id__, + signal: signalIndex + }); + } + }, + disconnect: function(callback) { + if (typeof(callback) !== "function") { + console.error("Bad callback given to disconnect from signal " + signalName); + return; + } + object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; + var idx = object.__objectSignals__[signalIndex].indexOf(callback); + if (idx === -1) { + console.error("Cannot find connection of signal " + signalName + " to " + callback.name); + return; + } + object.__objectSignals__[signalIndex].splice(idx, 1); + if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) { + // only required for "pure" signals, handled separately for properties in propertyUpdate + webChannel.exec({ + type: QWebChannelMessageTypes.disconnectFromSignal, + object: object.__id__, + signal: signalIndex + }); + } + } + }; + } + + /** + * Invokes all callbacks for the given signalname. Also works for property notify callbacks. + */ + function invokeSignalCallbacks(signalName, signalArgs) + { + var connections = object.__objectSignals__[signalName]; + if (connections) { + connections.forEach(function(callback) { + callback.apply(callback, signalArgs); + }); + } + } + + this.propertyUpdate = function(signals, propertyMap) + { + // update property cache + for (var propertyIndex in propertyMap) { + var propertyValue = propertyMap[propertyIndex]; + object.__propertyCache__[propertyIndex] = propertyValue; + } + + for (var signalName in signals) { + // Invoke all callbacks, as signalEmitted() does not. This ensures the + // property cache is updated before the callbacks are invoked. + invokeSignalCallbacks(signalName, signals[signalName]); + } + } + + this.signalEmitted = function(signalName, signalArgs) + { + invokeSignalCallbacks(signalName, signalArgs); + } + + function addMethod(methodData) + { + var methodName = methodData[0]; + var methodIdx = methodData[1]; + object[methodName] = function() { + var args = []; + var callback; + for (var i = 0; i < arguments.length; ++i) { + if (typeof arguments[i] === "function") + callback = arguments[i]; + else + args.push(arguments[i]); + } + + webChannel.exec({ + "type": QWebChannelMessageTypes.invokeMethod, + "object": object.__id__, + "method": methodIdx, + "args": args + }, function(response) { + if (response !== undefined) { + var result = object.unwrapQObject(response); + if (callback) { + (callback)(result); + } + } + }); + }; + } + + function bindGetterSetter(propertyInfo) + { + var propertyIndex = propertyInfo[0]; + var propertyName = propertyInfo[1]; + var notifySignalData = propertyInfo[2]; + // initialize property cache with current value + // NOTE: if this is an object, it is not directly unwrapped as it might + // reference other QObject that we do not know yet + object.__propertyCache__[propertyIndex] = propertyInfo[3]; + + if (notifySignalData) { + if (notifySignalData[0] === 1) { + // signal name is optimized away, reconstruct the actual name + notifySignalData[0] = propertyName + "Changed"; + } + addSignal(notifySignalData, true); + } + + Object.defineProperty(object, propertyName, { + configurable: true, + get: function () { + var propertyValue = object.__propertyCache__[propertyIndex]; + if (propertyValue === undefined) { + // This shouldn't happen + console.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__); + } + + return propertyValue; + }, + set: function(value) { + if (value === undefined) { + console.warn("Property setter for " + propertyName + " called with undefined value!"); + return; + } + object.__propertyCache__[propertyIndex] = value; + webChannel.exec({ + "type": QWebChannelMessageTypes.setProperty, + "object": object.__id__, + "property": propertyIndex, + "value": value + }); + } + }); + + } + + // ---------------------------------------------------------------------- + + data.methods.forEach(addMethod); + + data.properties.forEach(bindGetterSetter); + + data.signals.forEach(function(signal) { addSignal(signal, false); }); + + for (var name in data.enums) { + object[name] = data.enums[name]; + } +} + +//required for use with nodejs +if (typeof module === 'object') { + module.exports = { + QWebChannel: QWebChannel + }; +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 67b1be9c4d..f0d41f0426 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -101,6 +101,7 @@ #include #include #include +#include #include "AnimDebugDraw.h" #include "AudioClient.h" @@ -362,6 +363,17 @@ Cube3DOverlay* _keyboardFocusHighlight{ nullptr }; int _keyboardFocusHighlightID{ -1 }; PluginContainer* _pluginContainer; + +// FIXME hack access to the internal share context for the Chromium helper +// Normally we'd want to use QWebEngine::initialize(), but we can't because +// our primary context is a QGLWidget, which can't easily be initialized to share +// from a QOpenGLContext. +// +// So instead we create a new offscreen context to share with the QGLWidget, +// and manually set THAT to be the shared context for the Chromium helper +OffscreenGLCanvas* _chromiumShareContext { nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); + Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), @@ -623,6 +635,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _glWidget->makeCurrent(); _glWidget->initializeGL(); + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->create(_glWidget->context()->contextHandle()); + _chromiumShareContext->makeCurrent(); + qt_gl_set_global_share_context(_chromiumShareContext->getContext()); + _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->makeCurrent(); @@ -4138,6 +4155,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); + scriptEngine->registerFunction("QmlWebWindow", QmlWebWindowClass::constructor); scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index bddc7d19ae..26a564e20b 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -320,10 +320,13 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { void OffscreenQmlSurface::resize(const QSize& newSize) { if (!_renderer || !_renderer->_quickWindow) { - QSize currentSize = _renderer->_quickWindow->geometry().size(); - if (newSize == currentSize) { - return; - } + return; + } + + + QSize currentSize = _renderer->_quickWindow->geometry().size(); + if (newSize == currentSize) { + return; } _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize); @@ -437,7 +440,9 @@ void OffscreenQmlSurface::updateQuick() { } if (_render) { + QMutexLocker lock(&(_renderer->_mutex)); _renderer->post(RENDER); + _renderer->_cond.wait(&(_renderer->_mutex)); _render = false; } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h index 67315b0783..d66cbeb285 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.h +++ b/libraries/gl/src/gl/OffscreenQmlSurface.h @@ -40,8 +40,8 @@ public: void create(QOpenGLContext* context); void resize(const QSize& size); QSize size() const; - QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { + Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { return load(QUrl(qmlSourceFile), f); } diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 140ca87d0d..cc2382926f 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME ui) -setup_hifi_library(OpenGL Network Qml Quick Script XmlPatterns) +setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebSockets XmlPatterns) link_hifi_libraries(shared networking gl) diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp new file mode 100644 index 0000000000..3797034e79 --- /dev/null +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -0,0 +1,344 @@ +// +// Created by Bradley Austin Davis on 2015-12-15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QmlWebWindowClass.h" + +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include "impl/websocketclientwrapper.h" +#include "impl/websockettransport.h" +#include "OffscreenUi.h" + +static QWebSocketServer * webChannelServer { nullptr }; +static WebSocketClientWrapper * webChannelClientWrapper { nullptr }; +static QWebChannel webChannel; +static std::once_flag webChannelSetup; +static const uint16_t WEB_CHANNEL_PORT = 51016; +static std::atomic nextWindowId; + +void initWebChannelServer() { + std::call_once(webChannelSetup, [] { + webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); + webChannelClientWrapper = new WebSocketClientWrapper(webChannelServer); + if (!webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { + qFatal("Failed to open web socket server."); + } + QObject::connect(webChannelClientWrapper, &WebSocketClientWrapper::clientConnected, &webChannel, &QWebChannel::connectTo); + }); +} + +void QmlScriptEventBridge::emitWebEvent(const QString& data) { + QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); +} + +void QmlScriptEventBridge::emitScriptEvent(const QString& data) { + QMetaObject::invokeMethod(this, "scriptEventReceived", Qt::QueuedConnection, + Q_ARG(int, _webWindow->getWindowId()), + Q_ARG(QString, data) + ); +} + +QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { + QmlWebWindowClass* retVal { nullptr }; + const QString title = context->argument(0).toString(); + QString url = context->argument(1).toString(); + if (!url.startsWith("http") && !url.startsWith("file://")) { + url = QUrl::fromLocalFile(url).toString(); + } + const int width = std::max(100, std::min(1280, context->argument(2).toInt32()));; + const int height = std::max(100, std::min(720, context->argument(3).toInt32()));; + + // Build the event bridge and wrapper on the main thread + QMetaObject::invokeMethod(DependencyManager::get().data(), "load", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, "QmlWebWindow.qml"), + Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { + initWebChannelServer(); + retVal = new QmlWebWindowClass(object); + webChannel.registerObject(url.toLower(), retVal); + retVal->setTitle(title); + retVal->setURL(url); + retVal->setSize(width, height); + }) + ); + connect(engine, &QScriptEngine::destroyed, retVal, &QmlWebWindowClass::deleteLater); + return engine->newQObject(retVal); +} + +QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) + : _isToolWindow(false), _windowId(++nextWindowId), _eventBridge(new QmlScriptEventBridge(this)), _qmlWindow(qmlWindow) +{ + qDebug() << "Created window with ID " << _windowId; + Q_ASSERT(_qmlWindow); + Q_ASSERT(dynamic_cast(_qmlWindow)); +} + +void QmlWebWindowClass::setVisible(bool visible) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); + return; + } + + auto qmlWindow = (QQuickItem*)_qmlWindow; + if (qmlWindow->isEnabled() != visible) { + qmlWindow->setEnabled(visible); + emit visibilityChanged(visible); + } +} + +bool QmlWebWindowClass::isVisible() const { + if (QThread::currentThread() != thread()) { + bool result; + QMetaObject::invokeMethod(const_cast(this), "isVisible", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); + return result; + } + + return ((QQuickItem*)_qmlWindow)->isEnabled(); +} + + +glm::vec2 QmlWebWindowClass::getPosition() const { + if (QThread::currentThread() != thread()) { + glm::vec2 result; + QMetaObject::invokeMethod(const_cast(this), "getPosition", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); + return result; + } + + return glm::vec2(((QQuickItem*)_qmlWindow)->x(), ((QQuickItem*)_qmlWindow)->y()); +} + + +void QmlWebWindowClass::setPosition(const glm::vec2& position) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setPosition", Qt::QueuedConnection, Q_ARG(glm::vec2, position)); + return; + } + + ((QQuickItem*)_qmlWindow)->setPosition(QPointF(position.x, position.y)); +} + +void QmlWebWindowClass::setPosition(int x, int y) { + setPosition(glm::vec2(x, y)); +} + +glm::vec2 QmlWebWindowClass::getSize() const { + if (QThread::currentThread() != thread()) { + glm::vec2 result; + QMetaObject::invokeMethod(const_cast(this), "getSize", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); + return result; + } + + return glm::vec2(((QQuickItem*)_qmlWindow)->width(), ((QQuickItem*)_qmlWindow)->height()); +} + +void QmlWebWindowClass::setSize(const glm::vec2& size) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setSize", Qt::QueuedConnection, Q_ARG(glm::vec2, size)); + } + + ((QQuickItem*)_qmlWindow)->setSize(QSizeF(size.x, size.y)); +} + +void QmlWebWindowClass::setSize(int width, int height) { + setSize(glm::vec2(width, height)); +} + +static const char* const URL_PROPERTY = "source"; + +QString QmlWebWindowClass::getURL() const { + if (QThread::currentThread() != thread()) { + QString result; + QMetaObject::invokeMethod(const_cast(this), "getURL", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, result)); + return result; + } + return _qmlWindow->property(URL_PROPERTY).toString(); +} + +void QmlWebWindowClass::setURL(const QString& urlString) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setURL", Qt::QueuedConnection, Q_ARG(QString, urlString)); + } + _qmlWindow->setProperty(URL_PROPERTY, urlString); +} + +static const char* const TITLE_PROPERTY = "title"; + +void QmlWebWindowClass::setTitle(const QString& title) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setTitle", Qt::QueuedConnection, Q_ARG(QString, title)); + } + + _qmlWindow->setProperty(TITLE_PROPERTY, title); +} + +void QmlWebWindowClass::close() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); + } + _qmlWindow->setProperty("destroyOnInvisible", true); + _qmlWindow->setProperty("visible", false); + _qmlWindow->deleteLater(); +} + +void QmlWebWindowClass::hasClosed() { +} + +void QmlWebWindowClass::raise() { +} + +#if 0 + +#include + +#include + +WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow) + : QObject(NULL), _eventBridge(new ScriptEventBridge(this)), _isToolWindow(isToolWindow) { + /* + if (_isToolWindow) { + ToolWindow* toolWindow = qApp->getToolWindow(); + + auto dockWidget = new QDockWidget(title, toolWindow); + dockWidget->setFeatures(QDockWidget::DockWidgetMovable); + connect(dockWidget, &QDockWidget::visibilityChanged, this, &WebWindowClass::visibilityChanged); + + _webView = new QWebView(dockWidget); + addEventBridgeToWindowObject(); + + dockWidget->setWidget(_webView); + + auto titleWidget = new QWidget(dockWidget); + dockWidget->setTitleBarWidget(titleWidget); + + toolWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget, Qt::Horizontal); + + _windowWidget = dockWidget; + } else { + auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window); + dialogWidget->setWindowTitle(title); + dialogWidget->resize(width, height); + dialogWidget->installEventFilter(this); + connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed); + + auto layout = new QVBoxLayout(dialogWidget); + layout->setContentsMargins(0, 0, 0, 0); + dialogWidget->setLayout(layout); + + _webView = new QWebView(dialogWidget); + + layout->addWidget(_webView); + + addEventBridgeToWindowObject(); + + _windowWidget = dialogWidget; + } + + auto style = QStyleFactory::create("fusion"); + if (style) { + _webView->setStyle(style); + } + + _webView->setPage(new DataWebPage()); + if (!url.startsWith("http") && !url.startsWith("file://")) { + _webView->setUrl(QUrl::fromLocalFile(url)); + } else { + _webView->setUrl(url); + } + connect(this, &WebWindowClass::destroyed, _windowWidget, &QWidget::deleteLater); + connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, + this, &WebWindowClass::addEventBridgeToWindowObject); + */ +} + +void WebWindowClass::hasClosed() { + emit closed(); +} + + +void WebWindowClass::setVisible(bool visible) { +} + +QString WebWindowClass::getURL() const { + return QString(); +} + +void WebWindowClass::setURL(const QString& url) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url)); + return; + } +} + +QSizeF WebWindowClass::getSize() const { + QSizeF size; + return size; +} + +void WebWindowClass::setSize(const QSizeF& size) { + setSize(size.width(), size.height()); +} + +void WebWindowClass::setSize(int width, int height) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setSize", Qt::AutoConnection, Q_ARG(int, width), Q_ARG(int, height)); + return; + } +} + +glm::vec2 WebWindowClass::getPosition() const { + return glm::vec2(); +} + +void WebWindowClass::setPosition(const glm::vec2& position) { + setPosition(position.x, position.y); +} + +void WebWindowClass::setPosition(int x, int y) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setPosition", Qt::AutoConnection, Q_ARG(int, x), Q_ARG(int, y)); + return; + } +} + +void WebWindowClass::raise() { +} + +QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { + WebWindowClass* retVal { nullptr }; + //QString file = context->argument(0).toString(); + //QMetaObject::invokeMethod(DependencyManager::get().data(), "doCreateWebWindow", Qt::BlockingQueuedConnection, + // Q_RETURN_ARG(WebWindowClass*, retVal), + // Q_ARG(const QString&, file), + // Q_ARG(QString, context->argument(1).toString()), + // Q_ARG(int, context->argument(2).toInteger()), + // Q_ARG(int, context->argument(3).toInteger()), + // Q_ARG(bool, context->argument(4).toBool())); + + //connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater); + + return engine->newQObject(retVal); +} + +void WebWindowClass::setTitle(const QString& title) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setTitle", Qt::AutoConnection, Q_ARG(QString, title)); + return; + } +} + +#endif \ No newline at end of file diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h new file mode 100644 index 0000000000..c166fd2c20 --- /dev/null +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -0,0 +1,92 @@ +// +// Created by Bradley Austin Davis on 2015-12-15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ui_QmlWebWindowClass_h +#define hifi_ui_QmlWebWindowClass_h + +#include +#include +#include +#include + +class QScriptEngine; +class QScriptContext; +class QmlWebWindowClass; + +class QmlScriptEventBridge : public QObject { + Q_OBJECT +public: + QmlScriptEventBridge(const QmlWebWindowClass* webWindow) : _webWindow(webWindow) {} + +public slots : + void emitWebEvent(const QString& data); + void emitScriptEvent(const QString& data); + +signals: + void webEventReceived(const QString& data); + void scriptEventReceived(int windowId, const QString& data); + +private: + const QmlWebWindowClass* _webWindow { nullptr }; +}; + +// FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping +class QmlWebWindowClass : public QObject { + Q_OBJECT + Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) + Q_PROPERTY(int windowId READ getWindowId CONSTANT) + Q_PROPERTY(QString url READ getURL CONSTANT) + Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) + +public: + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + QmlWebWindowClass(QObject* qmlWindow); + +public slots: + bool isVisible() const; + void setVisible(bool visible); + + glm::vec2 getPosition() const; + void setPosition(const glm::vec2& position); + void setPosition(int x, int y); + + glm::vec2 getSize() const; + void setSize(const glm::vec2& size); + void setSize(int width, int height); + + QString getURL() const; + void setURL(const QString& url); + + void setTitle(const QString& title); + + // Ugh.... do not want to do + Q_INVOKABLE void raise(); + Q_INVOKABLE void close(); + Q_INVOKABLE int getWindowId() const { return _windowId; }; + Q_INVOKABLE QmlScriptEventBridge* getEventBridge() const { return _eventBridge; }; + +signals: + void visibilityChanged(bool visible); // Tool window + void urlChanged(); + void moved(glm::vec2 position); + void resized(QSizeF size); + void closed(); + +private slots: + void hasClosed(); + +private: + QmlScriptEventBridge* _eventBridge; + bool _isToolWindow { false }; + QObject* _qmlWindow; + const int _windowId; +}; + +#endif diff --git a/libraries/ui/src/impl/websocketclientwrapper.cpp b/libraries/ui/src/impl/websocketclientwrapper.cpp new file mode 100644 index 0000000000..00ddd6e009 --- /dev/null +++ b/libraries/ui/src/impl/websocketclientwrapper.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "websocketclientwrapper.h" + +#include + +#include "websockettransport.h" + +/*! + \brief Wrapps connected QWebSockets clients in WebSocketTransport objects. + + This code is all that is required to connect incoming WebSockets to the WebChannel. Any kind + of remote JavaScript client that supports WebSockets can thus receive messages and access the + published objects. +*/ + +QT_BEGIN_NAMESPACE + +/*! + Construct the client wrapper with the given parent. + + All clients connecting to the QWebSocketServer will be automatically wrapped + in WebSocketTransport objects. +*/ +WebSocketClientWrapper::WebSocketClientWrapper(QWebSocketServer *server, QObject *parent) + : QObject(parent) + , m_server(server) +{ + connect(server, &QWebSocketServer::newConnection, + this, &WebSocketClientWrapper::handleNewConnection); +} + +/*! + Wrap an incoming WebSocket connection in a WebSocketTransport object. +*/ +void WebSocketClientWrapper::handleNewConnection() +{ + emit clientConnected(new WebSocketTransport(m_server->nextPendingConnection())); +} + +QT_END_NAMESPACE diff --git a/libraries/ui/src/impl/websocketclientwrapper.h b/libraries/ui/src/impl/websocketclientwrapper.h new file mode 100644 index 0000000000..edb0a1b1a3 --- /dev/null +++ b/libraries/ui/src/impl/websocketclientwrapper.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WEBSOCKETTRANSPORTSERVER_H +#define WEBSOCKETTRANSPORTSERVER_H + +#include + +QT_BEGIN_NAMESPACE + +class QWebSocketServer; +class WebSocketTransport; + +class WebSocketClientWrapper : public QObject +{ + Q_OBJECT + +public: + WebSocketClientWrapper(QWebSocketServer *server, QObject *parent = 0); + +Q_SIGNALS: + void clientConnected(WebSocketTransport* client); + +private Q_SLOTS: + void handleNewConnection(); + +private: + QWebSocketServer *m_server; +}; + +QT_END_NAMESPACE + +#endif // WEBSOCKETTRANSPORTSERVER_H diff --git a/libraries/ui/src/impl/websockettransport.cpp b/libraries/ui/src/impl/websockettransport.cpp new file mode 100644 index 0000000000..8ed330c72d --- /dev/null +++ b/libraries/ui/src/impl/websockettransport.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "websockettransport.h" + +#include +#include +#include + +#include + +/*! + \brief QWebChannelAbstractSocket implementation that uses a QWebSocket internally. + + The transport delegates all messages received over the QWebSocket over its + textMessageReceived signal. Analogously, all calls to sendTextMessage will + be send over the QWebSocket to the remote client. +*/ + +QT_BEGIN_NAMESPACE + +/*! + Construct the transport object and wrap the given socket. + + The socket is also set as the parent of the transport object. +*/ +WebSocketTransport::WebSocketTransport(QWebSocket *socket) +: QWebChannelAbstractTransport(socket) +, m_socket(socket) +{ + connect(socket, &QWebSocket::textMessageReceived, + this, &WebSocketTransport::textMessageReceived); +} + +/*! + Destroys the WebSocketTransport. +*/ +WebSocketTransport::~WebSocketTransport() +{ + +} + +/*! + Serialize the JSON message and send it as a text message via the WebSocket to the client. +*/ +void WebSocketTransport::sendMessage(const QJsonObject &message) +{ + QJsonDocument doc(message); + m_socket->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact))); +} + +/*! + Deserialize the stringified JSON messageData and emit messageReceived. +*/ +void WebSocketTransport::textMessageReceived(const QString &messageData) +{ + QJsonParseError error; + QJsonDocument message = QJsonDocument::fromJson(messageData.toUtf8(), &error); + if (error.error) { + qWarning() << "Failed to parse text message as JSON object:" << messageData + << "Error is:" << error.errorString(); + return; + } else if (!message.isObject()) { + qWarning() << "Received JSON message that is not an object: " << messageData; + return; + } + emit messageReceived(message.object(), this); +} + +QT_END_NAMESPACE diff --git a/libraries/ui/src/impl/websockettransport.h b/libraries/ui/src/impl/websockettransport.h new file mode 100644 index 0000000000..a1fdd3553a --- /dev/null +++ b/libraries/ui/src/impl/websockettransport.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WEBSOCKETTRANSPORT_H +#define WEBSOCKETTRANSPORT_H + +#include + +QT_BEGIN_NAMESPACE + +class QWebSocket; +class WebSocketTransport : public QWebChannelAbstractTransport +{ + Q_OBJECT +public: + explicit WebSocketTransport(QWebSocket *socket); + virtual ~WebSocketTransport(); + + void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void textMessageReceived(const QString &message); + +private: + QWebSocket *m_socket; +}; + +QT_END_NAMESPACE + +#endif // WEBSOCKETTRANSPORT_H diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt index 8fda001e14..f94a0b85c0 100644 --- a/tests/ui/CMakeLists.txt +++ b/tests/ui/CMakeLists.txt @@ -2,15 +2,32 @@ set(TARGET_NAME "ui-test") # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Widgets OpenGL Network Qml Quick Script) +setup_hifi_project(Network OpenGL Qml Quick Script WebChannel WebEngine WebSockets) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") if (WIN32) target_link_libraries(${TARGET_NAME} wsock32.lib opengl32.lib Winmm.lib) + # Issue causes build failure unless we add this directory. + # See https://bugreports.qt.io/browse/QTBUG-43351 + add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) endif() # link in the shared libraries link_hifi_libraries(shared networking gl gpu ui) +# copy the resources files beside the executable +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory + "${PROJECT_SOURCE_DIR}/qml" + $/qml +) + + +target_glew() + +if (WIN32) + set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/../../interface/resources/qml") +endif() + package_libraries_for_deployment() diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 18f62dc016..75397ad95f 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -1,41 +1,92 @@ // -// main.cpp -// tests/render-utils/src -// -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015-04-22 +// Copyright 2013-2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "OffscreenUi.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include #include -#include -#include "MessageDialog.h" -#include "VrMenu.h" -#include "InfoView.h" -#include +#include +#include +#include +#include +#include +#include + +const QString& getResourcesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; +} + +const QString& getExamplesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; +} + +const QString& getInterfaceQmlDir() { + static QString dir; + if (dir.isEmpty()) { + dir = getResourcesDir() + "qml/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} + +const QString& getTestQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Qml Test Path: " << dir; + } + return dir; +} + class RateCounter { std::vector times; @@ -74,54 +125,302 @@ public: }; -class MenuConstants : public QObject{ - Q_OBJECT - Q_ENUMS(Item) -public: - enum Item { - RenderLookAtTargets, - }; -public: - MenuConstants(QObject* parent = nullptr) : QObject(parent) { +extern QOpenGLContext* qt_gl_global_share_context(); + +static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { + if (engine.hasUncaughtException()) { + const auto backtrace = engine.uncaughtExceptionBacktrace(); + const auto exception = engine.uncaughtException().toString(); + const auto line = QString::number(engine.uncaughtExceptionLineNumber()); + engine.clearExceptions(); + + auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); + if (!backtrace.empty()) { + static const auto lineSeparator = "\n "; + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); + } + qWarning() << qPrintable(message); + return true; } + return false; +} + +const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); + +static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { + QString message = ""; + for (int i = 0; i < context->argumentCount(); i++) { + if (i > 0) { + message += " "; + } + message += context->argument(i).toString(); + } + qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline + + message = message.replace("\\", "\\\\") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("'", "\\'"); + engine->evaluate("Script.print('" + message + "')"); + + return QScriptValue(); +} + +class ScriptEngine : public QScriptEngine { + Q_OBJECT + +public: + void loadFile(const QString& scriptPath) { + if (_isRunning) { + return; + } + qDebug() << "Loading script from " << scriptPath; + _fileNameString = scriptPath; + + QFile file(scriptPath); + if (file.exists()) { + file.open(QIODevice::ReadOnly); + _scriptContents = file.readAll(); + } else { + qFatal("Missing file "); + } + runInThread(); + } + + Q_INVOKABLE void stop() { + if (!_isFinished) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "stop"); + return; + } + _isFinished = true; + if (_wantSignals) { + emit runningStateChanged(); + } + } + } + + Q_INVOKABLE void print(const QString& message) { + if (_wantSignals) { + emit printedMessage(message); + } + } + + Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { + // create the timer, add it to the map, and start it + QTimer* newTimer = new QTimer(this); + newTimer->setSingleShot(isSingleShot); + + connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); + + // make sure the timer stops when the script does + connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); + + _timerFunctionMap.insert(newTimer, function); + + newTimer->start(intervalMS); + return newTimer; + } + + Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) { + return setupTimerWithInterval(function, intervalMS, false); + } + + Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) { + return setupTimerWithInterval(function, timeoutMS, true); + } +private: + + void runInThread() { + QThread* workerThread = new QThread(); + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + connect(workerThread, &QThread::started, this, &ScriptEngine::run); + connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); + connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); + moveToThread(workerThread); + workerThread->start(); + } + + void init() { + _isInitialized = true; + registerMetaTypes(this); + registerGlobalObject("Script", this); + qScriptRegisterSequenceMetaType>(this); + qScriptRegisterSequenceMetaType>(this); + globalObject().setProperty("QmlWebWindow", newFunction(QmlWebWindowClass::constructor)); + QScriptValue printConstructorValue = newFunction(debugPrint); + globalObject().setProperty("print", printConstructorValue); + } + + void timerFired() { + QTimer* callingTimer = reinterpret_cast(sender()); + QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); + + if (!callingTimer->isActive()) { + // this timer is done, we can kill it + _timerFunctionMap.remove(callingTimer); + delete callingTimer; + } + + // call the associated JS function, if it exists + if (timerFunction.isValid()) { + timerFunction.call(); + } + } + + + void run() { + if (!_isInitialized) { + init(); + } + + _isRunning = true; + if (_wantSignals) { + emit runningStateChanged(); + } + + QScriptValue result = evaluate(_scriptContents, _fileNameString); + QElapsedTimer startTime; + startTime.start(); + + int thisFrame = 0; + + qint64 lastUpdate = usecTimestampNow(); + + while (!_isFinished) { + int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec + if (usecToSleep > 0) { + usleep(usecToSleep); + } + + if (_isFinished) { + break; + } + + QCoreApplication::processEvents(); + if (_isFinished) { + break; + } + + qint64 now = usecTimestampNow(); + float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND; + if (!_isFinished) { + if (_wantSignals) { + emit update(deltaTime); + } + } + lastUpdate = now; + + // Debug and clear exceptions + hadUncaughtExceptions(*this, _fileNameString); + } + + if (_wantSignals) { + emit scriptEnding(); + } + + if (_wantSignals) { + emit finished(_fileNameString, this); + } + + _isRunning = false; + + if (_wantSignals) { + emit runningStateChanged(); + emit doneRunning(); + } + } + + void registerGlobalObject(const QString& name, QObject* object) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerGlobalObject", + Q_ARG(const QString&, name), + Q_ARG(QObject*, object)); + return; + } + if (!globalObject().property(name).isValid()) { + if (object) { + QScriptValue value = newQObject(object); + globalObject().setProperty(name, value); + } else { + globalObject().setProperty(name, QScriptValue()); + } + } + } + + void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } + QScriptValue scriptFun = newFunction(functionSignature, numArguments); + globalObject().setProperty(name, scriptFun); + } + + void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } + + QScriptValue object = globalObject().property(parent); + if (object.isValid()) { + QScriptValue scriptFun = newFunction(functionSignature, numArguments); + object.setProperty(name, scriptFun); + } + } + +signals: + void scriptLoaded(const QString& scriptFilename); + void errorLoadingScript(const QString& scriptFilename); + void update(float deltaTime); + void scriptEnding(); + void finished(const QString& fileNameString, ScriptEngine* engine); + void cleanupMenuItem(const QString& menuItemString); + void printedMessage(const QString& message); + void errorMessage(const QString& message); + void runningStateChanged(); + void evaluationFinished(QScriptValue result, bool isException); + void loadScript(const QString& scriptName, bool isUserLoaded); + void reloadScript(const QString& scriptName, bool isUserLoaded); + void doneRunning(); + + +private: + QString _scriptContents; + QString _fileNameString; + QString _parentURL; + bool _isInitialized { false }; + std::atomic _isFinished { false }; + std::atomic _isRunning { false }; + bool _wantSignals { true }; + bool _isThreaded { false }; + QHash _timerFunctionMap; }; -const QString& getResourcesDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; - qDebug() << "Resources Path: " << dir; - } - return dir; + + +ScriptEngine* loadScript(const QString& scriptFilename) { + ScriptEngine* scriptEngine = new ScriptEngine(); + scriptEngine->loadFile(scriptFilename); + return scriptEngine; } -const QString& getQmlDir() { - static QString dir; - if (dir.isEmpty()) { - dir = getResourcesDir() + "qml/"; - qDebug() << "Qml Path: " << dir; - } - return dir; -} +OffscreenGLCanvas* _chromiumShareContext { nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); -const QString& getTestQmlDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; - qDebug() << "Qml Test Path: " << dir; - } - return dir; -} // Create a simple OpenGL window that renders text in various ways -class QTestWindow : public QWindow, private QOpenGLFunctions { +class QTestWindow : public QWindow { Q_OBJECT QOpenGLContext* _context{ nullptr }; @@ -130,86 +429,103 @@ class QTestWindow : public QWindow, private QOpenGLFunctions { RateCounter fps; QTimer _timer; int testQmlTexture{ 0 }; + ProgramPtr _program; + ShapeWrapperPtr _plane; + QScriptEngine* _scriptEngine { nullptr }; public: QObject* rootMenu; QTestWindow() { + _scriptEngine = new ScriptEngine(); _timer.setInterval(1); - connect(&_timer, &QTimer::timeout, [=] { - draw(); - }); + QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw); - DependencyManager::set(); - setSurfaceType(QSurface::OpenGLSurface); + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->create(); + _chromiumShareContext->makeCurrent(); + qt_gl_set_global_share_context(_chromiumShareContext->getContext()); - QSurfaceFormat format; - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setVersion(4, 1); - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - format.setOption(QSurfaceFormat::DebugContext); + { + setSurfaceType(QSurface::OpenGLSurface); + QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); + setFormat(format); + _context = new QOpenGLContext; + _context->setFormat(format); + _context->setShareContext(_chromiumShareContext->getContext()); + } - setFormat(format); - _context = new QOpenGLContext; - _context->setFormat(format); if (!_context->create()) { qFatal("Could not create OpenGL context"); } show(); + makeCurrent(); - initializeOpenGLFunctions(); + { + qDebug() << (const char*)glGetString(GL_VERSION); QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); logger->initialize(); // initializes in the current context, i.e. ctx logger->enableMessages(); connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { qDebug() << debugMessage; }); - // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); + //logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); } - qDebug() << (const char*)this->glGetString(GL_VERSION); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glClearColor(0.2f, 0.2f, 0.2f, 1); - glDisable(GL_DEPTH_TEST); + glewExperimental = true; + glewInit(); + glGetError(); + + using namespace oglplus; + Context::Enable(Capability::Blend); + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); + Context::Disable(Capability::DepthTest); + Context::Disable(Capability::CullFace); + Context::ClearColor(0.2f, 0.2f, 0.2f, 1); MessageDialog::registerType(); - VrMenu::registerType(); InfoView::registerType(); + auto offscreenUi = DependencyManager::set(); + { + offscreenUi->create(_context); + offscreenUi->setProxyWindow(this); - auto offscreenUi = DependencyManager::get(); - offscreenUi->create(_context); - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { - testQmlTexture = textureId; - }); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + testQmlTexture = textureId; + }); - makeCurrent(); + makeCurrent(); + } - offscreenUi->setProxyWindow(this); - QDesktopWidget* desktop = QApplication::desktop(); - QRect rect = desktop->availableGeometry(desktop->screenCount() - 1); - int height = rect.height(); - //rect.setHeight(height / 2); - rect.setY(rect.y() + height / 2); + + auto primaryScreen = QGuiApplication::primaryScreen(); + auto targetScreen = primaryScreen; + auto screens = QGuiApplication::screens(); + if (screens.size() > 1) { + for (auto screen : screens) { + if (screen != targetScreen) { + targetScreen = screen; + break; + } + } + } + auto rect = targetScreen->availableGeometry(); + rect.setWidth(rect.width() * 0.8f); + rect.setHeight(rect.height() * 0.8f); + rect.moveTo(QPoint(20, 20)); setGeometry(rect); -// setFramePosition(QPoint(-1000, 0)); -// resize(QSize(800, 600)); #ifdef QML_CONTROL_GALLERY offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); offscreenUi->load(QUrl("main.qml")); #else - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->load(QUrl("TestMenu.qml")); - // Requires a root menu to have been loaded before it can load - VrMenu::load(); #endif installEventFilter(offscreenUi.data()); offscreenUi->resume(); @@ -227,16 +543,35 @@ private: } makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); + auto error = glGetError(); + if (error != GL_NO_ERROR) { + qDebug() << "GL error in entering draw " << error; + } - renderQml(); + using namespace oglplus; + Context::Clear().ColorBuffer().DepthBuffer(); + ivec2 size(_size.width(), _size.height()); + size *= devicePixelRatio(); + size = glm::max(size, ivec2(100, 100)); + Context::Viewport(size.x, size.y); + if (!_program) { + _program = loadDefaultShader(); + _plane = loadPlane(_program); + } + if (testQmlTexture > 0) { + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + _program->Bind(); + _plane->Use(); + _plane->Draw(); _context->swapBuffers(this); - glFinish(); fps.increment(); - if (fps.elapsed() >= 2.0f) { + if (fps.elapsed() >= 10.0f) { qDebug() << "FPS: " << fps.rate(); fps.reset(); } @@ -246,8 +581,6 @@ private: _context->makeCurrent(this); } - void renderQml(); - void resizeWindow(const QSize & size) { _size = size; DependencyManager::get()->resize(_size); @@ -269,11 +602,13 @@ protected: offscreenUi->load("Browser.qml"); } break; - case Qt::Key_L: + + case Qt::Key_J: if (event->modifiers() & Qt::CTRL) { - InfoView::show(getResourcesDir() + "html/interface-welcome.html", true); + loadScript(getExamplesDir() + "tests/qmlWebTest.js"); } break; + case Qt::Key_K: if (event->modifiers() & Qt::CTRL) { OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ @@ -281,22 +616,9 @@ protected: }); } break; - case Qt::Key_J: - if (event->modifiers() & Qt::CTRL) { - auto offscreenUi = DependencyManager::get(); - rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); - QMetaObject::invokeMethod(rootMenu, "popup"); - } - break; } QWindow::keyPressEvent(event); } - QQmlContext* menuContext{ nullptr }; - void keyReleaseEvent(QKeyEvent *event) override { - if (_altPressed && Qt::Key_Alt == event->key()) { - VrMenu::toggle(); - } - } void moveEvent(QMoveEvent* event) override { static qreal oldPixelRatio = 0.0; @@ -308,40 +630,26 @@ protected: } }; -void QTestWindow::renderQml() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (testQmlTexture > 0) { - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, testQmlTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - glBegin(GL_QUADS); - { - glTexCoord2f(0, 0); - glVertex2f(-1, -1); - glTexCoord2f(0, 1); - glVertex2f(-1, 1); - glTexCoord2f(1, 1); - glVertex2f(1, 1); - glTexCoord2f(1, 0); - glVertex2f(1, -1); - } - glEnd(); -} - - const char * LOG_FILTER_RULES = R"V0G0N( hifi.offscreen.focus.debug=false qt.quick.mouse.debug=false )V0G0N"; +void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + QString logMessage = message; + +#ifdef Q_OS_WIN + if (!logMessage.isEmpty()) { + OutputDebugStringA(logMessage.toLocal8Bit().constData()); + OutputDebugStringA("\n"); + } +#endif +} + + int main(int argc, char** argv) { - QApplication app(argc, argv); + QGuiApplication app(argc, argv); + qInstallMessageHandler(messageHandler); QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow window; app.exec(); From 1b1365fd403bb661e39606df0d2d5930611b7127 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 16 Dec 2015 16:32:53 -0800 Subject: [PATCH 139/318] Exposing the tone curve in the js api --- interface/src/Application.cpp | 1 + .../render-utils/src/RenderDeferredTask.cpp | 18 ++++++++++++- .../render-utils/src/RenderDeferredTask.h | 3 +++ libraries/render/src/render/Engine.h | 1 + .../src/SceneScriptingInterface.cpp | 27 +++++++++++++++++++ .../src/SceneScriptingInterface.h | 7 ++++- 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9a8373282b..aa0c0fa8c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3703,6 +3703,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._fxaaStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); renderContext._toneMappingExposure = sceneInterface->getEngineToneMappingExposure(); + renderContext._toneMappingToneCurve = sceneInterface->getEngineToneMappingToneCurveValue(); renderArgs->_shouldRender = LODManager::shouldRender; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ef95876f11..5423d928a7 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -166,6 +166,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setAntialiasingStatus(renderContext->_fxaaStatus); setToneMappingExposure(renderContext->_toneMappingExposure); + setToneMappingToneCurve(renderContext->_toneMappingToneCurve); renderContext->args->_context->syncCache(); @@ -403,8 +404,23 @@ void RenderDeferredTask::setToneMappingExposure(float exposure) { float RenderDeferredTask::getToneMappingExposure() const { if (_toneMappingJobIndex >= 0) { - _jobs[_toneMappingJobIndex].get()._toneMappingEffect.getExposure(); + return _jobs[_toneMappingJobIndex].get()._toneMappingEffect.getExposure(); } else { return 0.0f; } } + +void RenderDeferredTask::setToneMappingToneCurve(int toneCurve) { + if (_toneMappingJobIndex >= 0) { + _jobs[_toneMappingJobIndex].edit()._toneMappingEffect.setToneCurve((ToneMappingEffect::ToneCurve)toneCurve); + } +} + +int RenderDeferredTask::getToneMappingToneCurve() const { + if (_toneMappingJobIndex >= 0) { + return _jobs[_toneMappingJobIndex].get()._toneMappingEffect.getToneCurve(); + } else { + return 0.0f; + } +} + diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index ea99c9f12e..b84db31a26 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -134,6 +134,9 @@ public: void setToneMappingExposure(float exposure); float getToneMappingExposure() const; + void setToneMappingToneCurve(int toneCurve); + int getToneMappingToneCurve() const; + virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index c219b87f40..abfef03039 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -62,6 +62,7 @@ public: bool _fxaaStatus = false; float _toneMappingExposure = 0.0; + int _toneMappingToneCurve = 3; RenderContext() {} }; diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 59d2765659..3e22a9e929 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -167,3 +167,30 @@ void SceneScriptingInterface::clearEngineCounters() { _numFeedOverlay3DItems = 0; _numDrawnOverlay3DItems = 0; } + + +void SceneScriptingInterface::setEngineToneMappingToneCurve(const QString& toneCurve) { + if (toneCurve == QString("None")) { + _engineToneMappingToneCurve = 0; + } else if (toneCurve == QString("Gamma22")) { + _engineToneMappingToneCurve = 1; + } else if (toneCurve == QString("Reinhard")) { + _engineToneMappingToneCurve = 2; + } else if (toneCurve == QString("Filmic")) { + _engineToneMappingToneCurve = 3; + } +} +QString SceneScriptingInterface::getEngineToneMappingToneCurve() const { + switch (_engineToneMappingToneCurve) { + case 0: + return QString("None"); + case 1: + return QString("Gamma22"); + case 2: + return QString("Reinhard"); + case 3: + return QString("Filmic"); + default: + return QString("Filmic"); + }; +} \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 875a2a1b8f..246f624b08 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -119,7 +119,11 @@ public: Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _engineToneMappingExposure = exposure; } - Q_INVOKABLE float getEngineToneMappingExposure() { return _engineToneMappingExposure; } + Q_INVOKABLE float getEngineToneMappingExposure() const { return _engineToneMappingExposure; } + + Q_INVOKABLE void setEngineToneMappingToneCurve(const QString& curve); + Q_INVOKABLE QString getEngineToneMappingToneCurve() const; + int getEngineToneMappingToneCurveValue() const { return _engineToneMappingToneCurve; } signals: void shouldRenderAvatarsChanged(bool shouldRenderAvatars); @@ -158,6 +162,7 @@ protected: bool _drawHitEffect = false; float _engineToneMappingExposure = 0.0f; + int _engineToneMappingToneCurve = 3; }; #endif // hifi_SceneScriptingInterface_h From d8c877831664a37949932217b75be6937236c468 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 16:50:27 -0800 Subject: [PATCH 140/318] rave stick in right orientation --- examples/flowArts/flowArtsHutSpawner.js | 6 +- examples/flowArts/raveStick/RaveStick.js | 16 +++- .../raveStick/raveStickEntityScript.js | 81 +++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 examples/flowArts/raveStick/raveStickEntityScript.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index ffd73dbdca..8e39a4b1d8 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -19,8 +19,12 @@ Script.include("raveStick/RaveStick.js"); var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); basePosition.y = MyAvatar.position.y + 1; + +// RAVE ITEMS var lightBall = new LightBall(basePosition); -var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 1, z: 1})); +var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); + + var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index bee5c995f9..046932c473 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -1,6 +1,6 @@ Script.include("../../libraries/utils.js"); var modelURL = "file:///C:/Users/Eric/Desktop/raveStick.fbx?v1" + Math.random(); - +var scriptURL = Script.resolvePath("raveStickEntityScript.js"); RaveStick = function(spawnPosition) { var stick = Entities.addEntity({ @@ -8,9 +8,21 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', - dimensions: {x: 0.17, y: 0.48, z: 0.17}, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.8 + }, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.4 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, invertSolidWhileHeld: true } }) diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js new file mode 100644 index 0000000000..cfe1e3a2fd --- /dev/null +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -0,0 +1,81 @@ +// raveStickEntityScript.js +// +// Script Type: Entity +// Created by Eric Levin on 9/21/15. +// Additions by James B. Pollack @imgntn on 9/24/15 +// Copyright 2015 High Fidelity, Inc. +// +// This entity script create light trails on a given object as it moves. +// 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 _this; + // this is the "constructor" for the entity as a JS object we don't do much here + var Doll = function() { + _this = this; + this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; + }; + + Doll.prototype = { + audioInjector: null, + isGrabbed: false, + setLeftHand: function() { + this.hand = 'left'; + }, + + setRightHand: function() { + this.hand = 'right'; + }, + + startNearGrab: function() { + Entities.editEntity(this.entityID, { + animation: { + url: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx", + running: true + } + }); + + var position = Entities.getEntityProperties(this.entityID, "position").position; + this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], { + position: position, + volume: 0.1 + }); + + this.isGrabbed = true; + this.initialHand = this.hand; + }, + + continueNearGrab: function() { + var props = Entities.getEntityProperties(this.entityID, ["position"]); + var audioOptions = { + position: props.position + }; + this.audioInjector.options = audioOptions; + }, + + releaseGrab: function() { + if (this.isGrabbed === true && this.hand === this.initialHand) { + this.audioInjector.stop(); + Entities.editEntity(this.entityID, { + animation: { + // Providing actual model fbx for animation used to work, now contorts doll into a weird ball + // See bug: https://app.asana.com/0/26225263936266/70097355490098 + // url: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", + running: false, + } + }); + + this.isGrabbed = false; + } + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + }; + // entity scripts always need to return a newly constructed object of our type + return new Doll(); +}); From 1b0856307976ab348027491b795997b0368551f9 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 16 Dec 2015 16:56:49 -0800 Subject: [PATCH 141/318] ParticleEffectEntityItem: fix for invalid iterator increment Was causing an assert in debug, due to calling ++ on an invalid iterator. In release this might lead to memory corruption. --- libraries/entities/src/ParticleEffectEntityItem.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 5600c85650..533b077a9c 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -595,19 +595,24 @@ void ParticleEffectEntityItem::integrateParticle(Particle& particle, float delta void ParticleEffectEntityItem::stepSimulation(float deltaTime) { // update particles between head and tail + int popCount = 0; for (Particle& particle : _particles) { particle.lifetime += deltaTime; // if particle has died. if (particle.lifetime >= _lifespan) { // move head forward - _particles.pop_front(); + popCount++; } else { // Otherwise update it integrateParticle(particle, deltaTime); } } + for (int i = 0; i < popCount; i++) { + _particles.pop_front(); + } + // emit new particles, but only if we are emmitting if (getIsEmitting() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) { From 3b1ba67a889cf44a5349b955bf1d2e95072d8603 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 16 Dec 2015 17:08:22 -0800 Subject: [PATCH 142/318] ModelEntityItem: Fix for incorrect animations with preTranslations ModelEntities that were playing animations on models with local pivot offsets were not working correctly. Specifically, the windmill animation in the demo domain. We now compose a matrix containing all of the FBX's preTranslation, preRotation and postTranformations. --- libraries/animation/src/AnimSkeleton.cpp | 32 ++++++++++++---------- libraries/entities/src/ModelEntityItem.cpp | 20 ++++++++++---- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index c9c6e43a02..8e3d716aac 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -140,6 +140,7 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector& joints) } #ifndef NDEBUG +#define DUMP_FBX_JOINTS void AnimSkeleton::dump() const { qCDebug(animation) << "["; for (int i = 0; i < getNumJoints(); i++) { @@ -151,21 +152,22 @@ void AnimSkeleton::dump() const { qCDebug(animation) << " absDefaultPose =" << getAbsoluteDefaultPose(i); qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i); #ifdef DUMP_FBX_JOINTS - qCDebug(animation) << " isFree =" << _joints[i].isFree; - qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage; - qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex; - qCDebug(animation) << " translation =" << _joints[i].translation; - qCDebug(animation) << " preTransform =" << _joints[i].preTransform; - qCDebug(animation) << " preRotation =" << _joints[i].preRotation; - qCDebug(animation) << " rotation =" << _joints[i].rotation; - qCDebug(animation) << " postRotation =" << _joints[i].postRotation; - qCDebug(animation) << " postTransform =" << _joints[i].postTransform; - qCDebug(animation) << " transform =" << _joints[i].transform; - qCDebug(animation) << " rotationMin =" << _joints[i].rotationMin << ", rotationMax =" << _joints[i].rotationMax; - qCDebug(animation) << " inverseDefaultRotation" << _joints[i].inverseDefaultRotation; - qCDebug(animation) << " inverseBindRotation" << _joints[i].inverseBindRotation; - qCDebug(animation) << " bindTransform" << _joints[i].bindTransform; - qCDebug(animation) << " isSkeletonJoint" << _joints[i].isSkeletonJoint; + qCDebug(animation) << " fbxJoint ="; + qCDebug(animation) << " isFree =" << _joints[i].isFree; + qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage; + qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex; + qCDebug(animation) << " translation =" << _joints[i].translation; + qCDebug(animation) << " preTransform =" << _joints[i].preTransform; + qCDebug(animation) << " preRotation =" << _joints[i].preRotation; + qCDebug(animation) << " rotation =" << _joints[i].rotation; + qCDebug(animation) << " postRotation =" << _joints[i].postRotation; + qCDebug(animation) << " postTransform =" << _joints[i].postTransform; + qCDebug(animation) << " transform =" << _joints[i].transform; + qCDebug(animation) << " rotationMin =" << _joints[i].rotationMin << ", rotationMax =" << _joints[i].rotationMax; + qCDebug(animation) << " inverseDefaultRotation" << _joints[i].inverseDefaultRotation; + qCDebug(animation) << " inverseBindRotation" << _joints[i].inverseBindRotation; + qCDebug(animation) << " bindTransform" << _joints[i].bindTransform; + qCDebug(animation) << " isSkeletonJoint" << _joints[i].isSkeletonJoint; #endif if (getParentIndex(i) >= 0) { qCDebug(animation) << " parent =" << getJointName(getParentIndex(i)); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 352ab4d701..a1f16ee251 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "EntitiesLogging.h" #include "EntityItemProperties.h" @@ -243,13 +244,22 @@ void ModelEntityItem::getAnimationFrame(bool& newFrame, _lastKnownFrameDataRotations.resize(_jointMapping.size()); _lastKnownFrameDataTranslations.resize(_jointMapping.size()); + for (int j = 0; j < _jointMapping.size(); j++) { int index = _jointMapping[j]; - if (index != -1 && index < rotations.size()) { - _lastKnownFrameDataRotations[j] = fbxJoints[index].preRotation * rotations[index]; - } - if (index != -1 && index < translations.size()) { - _lastKnownFrameDataTranslations[j] = translations[index]; + if (index >= 0) { + glm::mat4 translationMat; + if (index < translations.size()) { + translationMat = glm::translate(translations[index]); + } + glm::mat4 rotationMat; + if (index < rotations.size()) { + rotationMat = glm::mat4_cast(rotations[index]); + } + glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform * + rotationMat * fbxJoints[index].postTransform); + _lastKnownFrameDataTranslations[j] = extractTranslation(finalMat); + _lastKnownFrameDataRotations[j] = glmExtractRotation(finalMat); } } } From f9f496ef5ab2d0e65e9d20500fb6f6fe521492d2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 17:32:30 -0800 Subject: [PATCH 143/318] adding beam effect --- examples/flowArts/flowArtsHutSpawner.js | 2 +- examples/flowArts/raveStick/RaveStick.js | 5 +- .../raveStick/raveStickEntityScript.js | 128 +++++++++++------- 3 files changed, 85 insertions(+), 50 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 8e39a4b1d8..aa87ddbd10 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -50,7 +50,7 @@ var floor = Entities.addEntity({ var lightZone = Entities.addEntity({ type: "Zone", shapeType: 'box', - keyLightIntensity: 0.2, + keyLightIntensity: 0.4, keyLightColor: { red: 50, green: 0, diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index 046932c473..5151b528cc 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -8,10 +8,11 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', + script: scriptURL, dimensions: { x: 0.06, y: 0.06, - z: 0.8 + z: 0.31 }, userData: JSON.stringify({ grabbableKey: { @@ -19,7 +20,7 @@ RaveStick = function(spawnPosition) { relativePosition: { x: 0, y: 0, - z: -0.4 + z: -0.1 }, relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) }, diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index cfe1e3a2fd..67571e49fa 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -1,8 +1,7 @@ // raveStickEntityScript.js // // Script Type: Entity -// Created by Eric Levin on 9/21/15. -// Additions by James B. Pollack @imgntn on 9/24/15 +// Created by Eric Levin on 12/16/15. // Copyright 2015 High Fidelity, Inc. // // This entity script create light trails on a given object as it moves. @@ -14,68 +13,103 @@ Script.include("../../libraries/utils.js"); var _this; // this is the "constructor" for the entity as a JS object we don't do much here - var Doll = function() { + var RaveStick = function() { _this = this; - this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; }; - Doll.prototype = { - audioInjector: null, + RaveStick.prototype = { isGrabbed: false, - setLeftHand: function() { - this.hand = 'left'; - }, - - setRightHand: function() { - this.hand = 'right'; - }, startNearGrab: function() { - Entities.editEntity(this.entityID, { - animation: { - url: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx", - running: true - } - }); - - var position = Entities.getEntityProperties(this.entityID, "position").position; - this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], { - position: position, - volume: 0.1 - }); - - this.isGrabbed = true; - this.initialHand = this.hand; + // this.createBeam(); }, continueNearGrab: function() { - var props = Entities.getEntityProperties(this.entityID, ["position"]); - var audioOptions = { - position: props.position - }; - this.audioInjector.options = audioOptions; + }, releaseGrab: function() { - if (this.isGrabbed === true && this.hand === this.initialHand) { - this.audioInjector.stop(); - Entities.editEntity(this.entityID, { - animation: { - // Providing actual model fbx for animation used to work, now contorts doll into a weird ball - // See bug: https://app.asana.com/0/26225263936266/70097355490098 - // url: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", - running: false, - } - }); - this.isGrabbed = false; - } }, preload: function(entityID) { this.entityID = entityID; + this.createBeam(); }, + + unload: function() { + Entities.deleteEntity(this.beam); + }, + + createBeam: function() { + + var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var props = { + type: "ParticleEffect", + position: position, + parentID: this.entityID, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 0, + green: 200, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 200, + blue: 5 + }, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 1000, + emitOrientation: forwardQuat, + "emitSpeed": .4, + "speedSpread": 0.0, + // "emitDimensions": { + // "x": .1, + // "y": .1, + // "z": .1 + // }, + "polarStart": 0, + "polarFinish": .0, + "azimuthStart": .1, + "azimuthFinish": .01, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "radiusStart": 0.03, + radiusFinish: 0.025, + "alpha": 0.7, + "alphaSpread": .1, + "alphaStart": 0.5, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + emitterShouldTrail: false + } + this.beam = Entities.addEntity(props); + + } }; // entity scripts always need to return a newly constructed object of our type - return new Doll(); -}); + return new RaveStick(); +}); \ No newline at end of file From bb67ca87e238a4db2b613e15c3de787d93544955 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 16 Dec 2015 17:52:39 -0800 Subject: [PATCH 144/318] lightsabers --- examples/flowArts/flowArtsHutSpawner.js | 2 ++ .../raveStick/raveStickEntityScript.js | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index aa87ddbd10..b9d89859df 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -23,6 +23,7 @@ basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); +var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); @@ -73,6 +74,7 @@ function cleanup() { Entities.deleteEntity(floor); lightBall.cleanup(); raveStick.cleanup(); + raveStick2.cleanup(); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 67571e49fa..0372fd388f 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -15,6 +15,15 @@ // this is the "constructor" for the entity as a JS object we don't do much here var RaveStick = function() { _this = this; + this.colorPalette = [{ + red: 0, + green: 200, + blue: 40 + }, { + red: 200, + green: 10, + blue: 40 + }]; }; RaveStick.prototype = { @@ -39,6 +48,7 @@ unload: function() { Entities.deleteEntity(this.beam); + // Entities.deleteEntity(this.beamTrail); }, createBeam: function() { @@ -50,27 +60,20 @@ var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", position: position, parentID: this.entityID, isEmitting: true, "name": "ParticlesTest Emitter", - "colorStart": { - red: 0, - green: 200, - blue: 40 - }, + "colorStart": color, color: { red: 200, green: 200, blue: 255 }, - "colorFinish": { - red: 25, - green: 200, - blue: 5 - }, + "colorFinish": color, "maxParticles": 100000, "lifespan": 2, "emitRate": 1000, @@ -108,6 +111,9 @@ } this.beam = Entities.addEntity(props); + // props.emitterShouldTrail = true; + // this.beamTrail = Entities.addEntity(props); + } }; // entity scripts always need to return a newly constructed object of our type From 7bc815448e025d677c94a750fb6c184ca9fe94c6 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 16 Dec 2015 18:14:43 -0800 Subject: [PATCH 145/318] The material colors for diffuse and emissive are now gamma corrected by default --- libraries/model/src/model/Material.cpp | 8 ++++---- libraries/model/src/model/Material.h | 27 ++++++++++++++------------ libraries/shared/src/ColorUtils.h | 16 +++++++++++++++ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index c2ff828af3..1d0f6ee5d9 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) { +void Material::setDiffuse(const Color& diffuse, bool isSRGB) { _key.setDiffuse(glm::any(glm::greaterThan(diffuse, Color(0.0f)))); - _schemaBuffer.edit()._diffuse = diffuse; + _schemaBuffer.edit()._diffuse = (isSRGB ? ColorUtils::toLinearVec3(diffuse) : diffuse); } void Material::setMetallic(float metallic) { @@ -54,9 +54,9 @@ void Material::setMetallic(float metallic) { _schemaBuffer.edit()._metallic = glm::vec3(metallic); } -void Material::setEmissive(const Color& emissive) { +void Material::setEmissive(const Color& emissive, bool isSRGB) { _key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f)))); - _schemaBuffer.edit()._emissive = emissive; + _schemaBuffer.edit()._emissive = (isSRGB ? ColorUtils::toLinearVec3(emissive) : emissive); } void Material::setGloss(float gloss) { diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index b0725d9908..bd1d45c7ed 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include @@ -219,28 +219,31 @@ public: virtual ~Material(); const MaterialKey& getKey() const { return _key; } - - const Color& getEmissive() const { return _schemaBuffer.get()._emissive; } - const Color& getDiffuse() const { return _schemaBuffer.get()._diffuse; } - float getMetallic() const { return _schemaBuffer.get()._metallic.x; } - float getGloss() const { return _schemaBuffer.get()._gloss; } - float getOpacity() const { return _schemaBuffer.get()._opacity; } - void setEmissive(const Color& emissive); - void setDiffuse(const Color& diffuse); + void setEmissive(const Color& emissive, bool isSRGB = true); + const Color& getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._emissive) : _schemaBuffer.get()._emissive); } + + void setDiffuse(const Color& diffuse, bool isSRGB = true); + const Color& getDiffuse(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._diffuse) : _schemaBuffer.get()._diffuse); } + void setMetallic(float metallic); + float getMetallic() const { return _schemaBuffer.get()._metallic.x; } + void setGloss(float gloss); + float getGloss() const { return _schemaBuffer.get()._gloss; } + void setOpacity(float opacity); + float getOpacity() const { return _schemaBuffer.get()._opacity; } // Schema to access the attribute values of the material class Schema { public: - Color _diffuse{0.5f}; + glm::vec3 _diffuse{ 0.5f }; float _opacity{1.f}; - Color _metallic{0.03f}; + glm::vec3 _metallic{ 0.03f }; float _gloss{0.1f}; - Color _emissive{0.0f}; + glm::vec3 _emissive{ 0.0f }; float _spare0{0.0f}; glm::vec4 _spareVec4{0.0f}; // for alignment beauty, Material size == Mat4x4 diff --git a/libraries/shared/src/ColorUtils.h b/libraries/shared/src/ColorUtils.h index 1ef8420cd7..b47e7c3a98 100644 --- a/libraries/shared/src/ColorUtils.h +++ b/libraries/shared/src/ColorUtils.h @@ -20,6 +20,10 @@ class ColorUtils { public: inline static glm::vec3 toVec3(const xColor& color); + + // Convert from gamma 2.2 space to linear + inline static glm::vec3 toLinearVec3(const glm::vec3& srgb); + inline static glm::vec3 toGamma22Vec3(const glm::vec3& linear); }; inline glm::vec3 ColorUtils::toVec3(const xColor& color) { @@ -27,4 +31,16 @@ inline glm::vec3 ColorUtils::toVec3(const xColor& color) { return glm::vec3(color.red * ONE_OVER_255, color.green * ONE_OVER_255, color.blue * ONE_OVER_255); } +inline glm::vec3 ColorUtils::toLinearVec3(const glm::vec3& srgb) { + const float GAMMA_22 = 2.2f; + // Couldn't find glm::pow(vec3, vec3) ? so did it myself... + return glm::vec3(glm::pow(srgb.x, GAMMA_22), glm::pow(srgb.y, GAMMA_22), glm::pow(srgb.z, GAMMA_22)); +} + +inline glm::vec3 ColorUtils::toGamma22Vec3(const glm::vec3& linear) { + const float INV_GAMMA_22 = 1.0f / 2.2f; + // Couldn't find glm::pow(vec3, vec3) ? so did it myself... + return glm::vec3(glm::pow(linear.x, INV_GAMMA_22), glm::pow(linear.y, INV_GAMMA_22), glm::pow(linear.z, INV_GAMMA_22)); +} + #endif // hifi_ColorUtils_h \ No newline at end of file From 2eecb61da5a5c9f130522e0cf3cd6907fc5ef95b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 16 Dec 2015 19:08:31 -0800 Subject: [PATCH 146/318] Prefer erase over repeated pop_front calls --- libraries/entities/src/ParticleEffectEntityItem.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 533b077a9c..165afd1536 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -608,10 +608,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { integrateParticle(particle, deltaTime); } } - - for (int i = 0; i < popCount; i++) { - _particles.pop_front(); - } + _particles.erase(_particles.begin(), _particles.begin() + popCount); // emit new particles, but only if we are emmitting if (getIsEmitting() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) { From 0b9bd858a7c1fedecca7b32190155b5038ba6491 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 16 Dec 2015 21:28:27 -0800 Subject: [PATCH 147/318] implement support for pose ScriptEndpoints --- examples/controllers/reticleTests.js | 42 +++++++++++++++++ .../controllers/src/controllers/Pose.cpp | 18 +++++++- .../impl/endpoints/ScriptEndpoint.cpp | 46 ++++++++++++++++++- .../impl/endpoints/ScriptEndpoint.h | 13 ++++++ 4 files changed, 117 insertions(+), 2 deletions(-) diff --git a/examples/controllers/reticleTests.js b/examples/controllers/reticleTests.js index 4c805c8b1c..3392d1b7d9 100644 --- a/examples/controllers/reticleTests.js +++ b/examples/controllers/reticleTests.js @@ -34,6 +34,48 @@ var mappingJSON = { mapping = Controller.parseMapping(JSON.stringify(mappingJSON)); mapping.enable(); + +var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand"; +var mapping2 = Controller.newMapping(MAPPING_NAME); +//mapping2.from(Controller.Standard.RightHand).debug(true).to(Controller.Actions.LeftHand); + +/* +mapping2.from(Controller.Standard.RightHand).peek().to(function(pose) { + print("Controller.Standard.RightHand value:" + JSON.stringify(pose)); + }); +*/ + +var translation = { x: 0, y: 0.1, z: 0 }; +var translationDx = 0.01; +var translationDy = 0.01; +var translationDz = 0.01; +var TRANSLATION_LIMIT = 0.5; +var rotation = Quat.fromPitchYawRollDegrees(45, 0, 45); +mapping2.from(function() { + translation.x = translation.x + translationDx; + translation.y = translation.y + translationDy; + translation.z = translation.z + translationDz; + if ((translation.x > TRANSLATION_LIMIT) || (translation.x < (-1 *TRANSLATION_LIMIT))) { + translationDx = translationDx * -1; + } + if ((translation.y > TRANSLATION_LIMIT) || (translation.y < (-1 *TRANSLATION_LIMIT))) { + translationDy = translationDy * -1; + } + if ((translation.z > TRANSLATION_LIMIT) || (translation.z < (-1 *TRANSLATION_LIMIT))) { + translationDz = translationDz * -1; + } + var pose = { + translation: translation, + rotation: rotation, + velocity: { x: 0, y: 0, z: 0 }, + angularVelocity: { x: 0, y: 0, z: 0, w: 1 } + }; + return pose; +}).debug(true).to(Controller.Standard.LeftHand); + +Controller.enableMapping(MAPPING_NAME); + + Script.scriptEnding.connect(function(){ mapping.disable(); }); diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index 2281fc98ff..2e1d30cff2 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -42,7 +42,23 @@ namespace controller { } void Pose::fromScriptValue(const QScriptValue& object, Pose& pose) { - // nothing for now... + bool isValid = true; + auto translation = object.property("translation"); + auto rotation = object.property("rotation"); + auto velocity = object.property("velocity"); + auto angularVelocity = object.property("angularVelocity"); + if (translation.isValid() && + rotation.isValid() && + velocity.isValid() && + angularVelocity.isValid()) { + vec3FromScriptValue(translation, pose.translation); + quatFromScriptValue(rotation, pose.rotation); + vec3FromScriptValue(velocity, pose.velocity); + quatFromScriptValue(angularVelocity, pose.angularVelocity); + pose.valid = true; + } else { + pose.valid = false; + } } } diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp index bb9517b136..3e7fde347e 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp @@ -10,6 +10,8 @@ #include +#include + using namespace controller; float ScriptEndpoint::peek() const { @@ -23,7 +25,16 @@ void ScriptEndpoint::updateValue() { return; } - _lastValueRead = (float)_callable.call().toNumber(); + QScriptValue result = _callable.call(); + + // If the callable ever returns a non-number, we assume it's a pose + // and start reporting ourselves as a pose. + if (result.isNumber()) { + _lastValueRead = (float)_callable.call().toNumber(); + } else { + Pose::fromScriptValue(result, _lastPoseRead); + _returnPose = true; + } } void ScriptEndpoint::apply(float value, const Pointer& source) { @@ -44,3 +55,36 @@ void ScriptEndpoint::internalApply(float value, int sourceID) { _callable.call(QScriptValue(), QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) })); } + +Pose ScriptEndpoint::peekPose() const { + const_cast(this)->updatePose(); + return _lastPoseRead; +} + +void ScriptEndpoint::updatePose() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "updatePose", Qt::QueuedConnection); + return; + } + QScriptValue result = _callable.call(); + Pose::fromScriptValue(result, _lastPoseRead); +} + +void ScriptEndpoint::apply(const Pose& newPose, const Pointer& source) { + if (newPose == _lastPoseWritten) { + return; + } + internalApply(newPose, source->getInput().getID()); +} + +void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) { + _lastPoseWritten = newPose; + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection, + Q_ARG(const Pose&, newPose), + Q_ARG(int, sourceID)); + return; + } + _callable.call(QScriptValue(), + QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) })); +} diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h index 836af721f6..00439f5560 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.h @@ -27,13 +27,26 @@ public: virtual float peek() const override; virtual void apply(float newValue, const Pointer& source) override; + + virtual Pose peekPose() const override; + virtual void apply(const Pose& newValue, const Pointer& source) override; + + virtual bool isPose() const override { return _returnPose; } + protected: Q_INVOKABLE void updateValue(); Q_INVOKABLE virtual void internalApply(float newValue, int sourceID); + + Q_INVOKABLE void updatePose(); + Q_INVOKABLE virtual void internalApply(const Pose& newValue, int sourceID); private: QScriptValue _callable; float _lastValueRead { 0.0f }; float _lastValueWritten { 0.0f }; + + bool _returnPose { false }; + Pose _lastPoseRead; + Pose _lastPoseWritten; }; } From b127b6a9e887874b0cfa253c9dcb447a2e91f7d4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 08:55:57 -0800 Subject: [PATCH 148/318] separating out rave stick --- examples/flowArts/flowArtsHutSpawner.js | 5 + examples/flowArts/lightSaber/LightSaber.js | 38 ++++++ .../lightSaber/lightSaberEntityScript.js | 121 ++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 examples/flowArts/lightSaber/LightSaber.js create mode 100644 examples/flowArts/lightSaber/lightSaberEntityScript.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index b9d89859df..920fcc90ea 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -16,6 +16,9 @@ Script.include("../../libraries/utils.js"); Script.include("lightBall/LightBall.js"); Script.include("raveStick/RaveStick.js"); +Script.include("lightSaber/LightSaber.js"); + + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); basePosition.y = MyAvatar.position.y + 1; @@ -24,6 +27,7 @@ basePosition.y = MyAvatar.position.y + 1; var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); +var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); @@ -75,6 +79,7 @@ function cleanup() { lightBall.cleanup(); raveStick.cleanup(); raveStick2.cleanup(); + lightSaber.cleanup(); } Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/LightSaber.js new file mode 100644 index 0000000000..12ac3f3b60 --- /dev/null +++ b/examples/flowArts/lightSaber/LightSaber.js @@ -0,0 +1,38 @@ +Script.include("../../libraries/utils.js"); +var modelURL = "file:///C:/Users/Eric/Desktop/lightSaber.fbx?v1" + Math.random(); +var scriptURL = Script.resolvePath("lightSaberEntityScript.js"); +LightSaber = function(spawnPosition) { + + var stick = Entities.addEntity({ + type: "Model", + modelURL: modelURL, + position: spawnPosition, + shapeType: 'box', + script: scriptURL, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.31 + }, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.1 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, + invertSolidWhileHeld: true + } + }) + }); + + + function cleanup() { + Entities.deleteEntity(stick); + } + + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js new file mode 100644 index 0000000000..5ff3c65afd --- /dev/null +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -0,0 +1,121 @@ +// lightSaberEntityScript.js +// +// Script Type: Entity +// Created by Eric Levin on 12/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// This entity script creates a lightsaber. +// 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 _this; + // this is the "constructor" for the entity as a JS object we don't do much here + var LightSaber = function() { + _this = this; + this.colorPalette = [{ + red: 0, + green: 200, + blue: 40 + }, { + red: 200, + green: 10, + blue: 40 + }]; + }; + + LightSaber.prototype = { + isGrabbed: false, + + startNearGrab: function() { + // this.createBeam(); + this.createBeam(); + }, + + continueNearGrab: function() { + + }, + + releaseGrab: function() { + + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + + unload: function() { + Entities.deleteEntity(this.beam); + // Entities.deleteEntity(this.beamTrail); + }, + + createBeam: function() { + + var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var props = { + type: "ParticleEffect", + position: position, + parentID: this.entityID, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": color, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": color, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 1000, + emitOrientation: forwardQuat, + "emitSpeed": .4, + "speedSpread": 0.0, + // "emitDimensions": { + // "x": .1, + // "y": .1, + // "z": .1 + // }, + "polarStart": 0, + "polarFinish": .0, + "azimuthStart": .1, + "azimuthFinish": .01, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .00, + "z": .00 + }, + "radiusStart": 0.03, + radiusFinish: 0.025, + "alpha": 0.7, + "alphaSpread": .1, + "alphaStart": 0.5, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + emitterShouldTrail: false + } + this.beam = Entities.addEntity(props); + + // props.emitterShouldTrail = true; + // this.beamTrail = Entities.addEntity(props); + + } + }; + // entity scripts always need to return a newly constructed object of our type + return new LightSaber(); +}); \ No newline at end of file From 064c05e98cb3f421e36ed3c827af4b643d86996a Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:04:51 -0800 Subject: [PATCH 149/318] light trails --- examples/flowArts/flowArtsHutSpawner.js | 2 +- examples/flowArts/lightBall/particles.js | 129 ++++++++++++++++++ .../lightSaber/lightSaberEntityScript.js | 21 +-- .../raveStick/raveStickEntityScript.js | 49 ++++++- 4 files changed, 189 insertions(+), 12 deletions(-) create mode 100644 examples/flowArts/lightBall/particles.js diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 920fcc90ea..1ed3325b9c 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -27,7 +27,7 @@ basePosition.y = MyAvatar.position.y + 1; var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); -var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); +// var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); diff --git a/examples/flowArts/lightBall/particles.js b/examples/flowArts/lightBall/particles.js new file mode 100644 index 0000000000..86616d5099 --- /dev/null +++ b/examples/flowArts/lightBall/particles.js @@ -0,0 +1,129 @@ +Script.include("../../libraries/utils.js"); + +LightBall = function(spawnPosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + position: Vec3.sum(spawnPosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + collisionsWillMove: true, + gravity: {x: 0, y: -.5, z: 0}, + visible: false, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: .1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var lightBall = Entities.addEntity({ + type: "ParticleEffect", + position: spawnPosition, + // parentID: containerBall, + isEmitting: true, + "name": "ParticlesTest Emitter", + "colorStart": { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + "colorFinish": { + red: 25, + green: 20, + blue: 255 + }, + "maxParticles": 100000, + "lifespan": 2, + "emitRate": 10000, + "emitSpeed": .0, + "speedSpread": 0.0, + "emitDimensions": { + "x": 5, + "y":0 , + "z": 0 + }, + // "polarStart": 0, + // "polarFinish": Math.PI, + // "azimuthStart": -Math.PI, + // "azimuthFinish": Math.PI, + "emitAcceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "accelerationSpread": { + "x": .00, + "y": .0, + "z": .00 + }, + "particleRadius": 0.02, + "radiusSpread": 0, + "radiusStart": 0.03, + "radiusFinish": 0.0003, + "alpha": 0, + "alphaSpread": .5, + "alphaStart": 0, + "alphaFinish": 0.5, + // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(lightBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; +} + +LightBall(); \ No newline at end of file diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 5ff3c65afd..ea1f408abd 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -31,7 +31,7 @@ startNearGrab: function() { // this.createBeam(); - this.createBeam(); + }, continueNearGrab: function() { @@ -44,6 +44,7 @@ preload: function(entityID) { this.entityID = entityID; + this.createBeam(); }, unload: function() { @@ -53,11 +54,12 @@ createBeam: function() { - var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); - var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + + this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); forwardVec = Vec3.normalize(forwardVec); var forwardQuat = orientationOf(forwardVec); - var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); + var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; var color = this.colorPalette[randInt(0, this.colorPalette.length)]; @@ -66,7 +68,6 @@ position: position, parentID: this.entityID, isEmitting: true, - "name": "ParticlesTest Emitter", "colorStart": color, color: { red: 200, @@ -80,11 +81,11 @@ emitOrientation: forwardQuat, "emitSpeed": .4, "speedSpread": 0.0, - // "emitDimensions": { - // "x": .1, - // "y": .1, - // "z": .1 - // }, + "emitDimensions": { + "x": 0, + "y": 0, + "z": 0 + }, "polarStart": 0, "polarFinish": .0, "azimuthStart": .1, diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 0372fd388f..95e37ee79b 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -13,6 +13,11 @@ Script.include("../../libraries/utils.js"); var _this; // this is the "constructor" for the entity as a JS object we don't do much here + var LIFETIME = 6000; + var DRAWING_DEPTH = 0.8; + var LINE_DIMENSIONS = 100; + var MAX_POINTS_PER_LINE = 50; + var MIN_POINT_DISTANCE = 0.02; var RaveStick = function() { _this = this; this.colorPalette = [{ @@ -24,6 +29,21 @@ green: 10, blue: 40 }]; + var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; + this.trail = Entities.addEntity({ + type: "PolyLine", + dimensions: {x: LINE_DIMENSIONS, y: LINE_DIMENSIONS, z: LINE_DIMENSIONS}, + color: { + red: 255, + green: 255, + blue: 255 + }, + textures: texture, + lifetime: LIFETIME + }) + this.points = []; + this.normals = []; + this.strokeWidths = []; }; RaveStick.prototype = { @@ -31,9 +51,31 @@ startNearGrab: function() { // this.createBeam(); + this.trailBasePosition = Entities.getEntityProperties(this.entityID, "position").position; + Entities.editEntity(this.trail, { + position: this.trailBasePosition + }); + this.points = []; + this.normals = []; + this.strokeWidths = []; }, continueNearGrab: function() { + var position = Entities.getEntityProperties(this.entityID, "position").position; + var localPoint = Vec3.subtract(position, this.trailBasePosition); + if (this.points.length >=1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + this.points.push(localPoint); + var normal = computeNormal(position, Camera.getPosition()); + this.normals.push(normal); + this.strokeWidths.push(0.04); + Entities.editEntity(this.trail, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths + }) }, @@ -48,6 +90,7 @@ unload: function() { Entities.deleteEntity(this.beam); + Entities.deleteEntity(this.trail); // Entities.deleteEntity(this.beamTrail); }, @@ -60,7 +103,7 @@ var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", position: position, @@ -118,4 +161,8 @@ }; // entity scripts always need to return a newly constructed object of our type return new RaveStick(); + + function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); + } }); \ No newline at end of file From 8d4d0d4e9a849f50109d8cb670bed3d2195994c4 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 17 Dec 2015 10:08:40 -0800 Subject: [PATCH 150/318] FIxing the bad returned value per reference --- libraries/model/src/model/Material.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index bd1d45c7ed..cb5a285dba 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -221,10 +221,10 @@ public: const MaterialKey& getKey() const { return _key; } void setEmissive(const Color& emissive, bool isSRGB = true); - const Color& getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._emissive) : _schemaBuffer.get()._emissive); } + Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._emissive) : _schemaBuffer.get()._emissive); } void setDiffuse(const Color& diffuse, bool isSRGB = true); - const Color& getDiffuse(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._diffuse) : _schemaBuffer.get()._diffuse); } + Color getDiffuse(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get()._diffuse) : _schemaBuffer.get()._diffuse); } void setMetallic(float metallic); float getMetallic() const { return _schemaBuffer.get()._metallic.x; } From f7811cf5dc5bc33af18788a21b8c46d9ad8d8fe7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:25:51 -0800 Subject: [PATCH 151/318] light trails from rave stick --- .../raveStick/raveStickEntityScript.js | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 95e37ee79b..7b84f473ea 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -18,6 +18,8 @@ var LINE_DIMENSIONS = 100; var MAX_POINTS_PER_LINE = 50; var MIN_POINT_DISTANCE = 0.02; + var STROKE_WIDTH = 0.05 + var ugLSD = 25; var RaveStick = function() { _this = this; this.colorPalette = [{ @@ -32,7 +34,11 @@ var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png"; this.trail = Entities.addEntity({ type: "PolyLine", - dimensions: {x: LINE_DIMENSIONS, y: LINE_DIMENSIONS, z: LINE_DIMENSIONS}, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, color: { red: 255, green: 255, @@ -58,29 +64,58 @@ this.points = []; this.normals = []; this.strokeWidths = []; + this.setupEraseInterval(); }, continueNearGrab: function() { - var position = Entities.getEntityProperties(this.entityID, "position").position; + var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); + var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.2)); + // position.z += 0.1; + // position.x += -0.035; var localPoint = Vec3.subtract(position, this.trailBasePosition); - if (this.points.length >=1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + if (this.points.length >= 1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { //Need a minimum distance to avoid binormal NANs return; } + if (this.points.length === MAX_POINTS_PER_LINE) { + this.points.shift(); + this.normals.shift(); + this.strokeWidths.shift(); + } + this.points.push(localPoint); - var normal = computeNormal(position, Camera.getPosition()); + var normal = Quat.getUp(props.rotation); this.normals.push(normal); - this.strokeWidths.push(0.04); + this.strokeWidths.push(STROKE_WIDTH); Entities.editEntity(this.trail, { linePoints: this.points, normals: this.normals, strokeWidths: this.strokeWidths - }) + }); + }, - releaseGrab: function() { + setupEraseInterval: function() { + this.trailEraseInterval = Script.setInterval(function() { + if (_this.points.length > 0) { + _this.points.shift(); + _this.normals.shift(); + _this.strokeWidths.shift(); + Entities.editEntity(_this.trail, { + linePoints: _this.points, + strokeWidths: _this.strokeWidths, + normals: _this.normals + }); + } + }, ugLSD); + }, + releaseGrab: function() { + Script.clearInterval(this.trailEraseInterval); }, preload: function(entityID) { @@ -91,7 +126,7 @@ unload: function() { Entities.deleteEntity(this.beam); Entities.deleteEntity(this.trail); - // Entities.deleteEntity(this.beamTrail); + Script.clearInterval(this.trailEraseInterval); }, createBeam: function() { @@ -111,6 +146,7 @@ isEmitting: true, "name": "ParticlesTest Emitter", "colorStart": color, + colorSpread: {red: 200, green : 10, blue: 10}, color: { red: 200, green: 200, @@ -118,16 +154,11 @@ }, "colorFinish": color, "maxParticles": 100000, - "lifespan": 2, + "lifespan": 1, "emitRate": 1000, emitOrientation: forwardQuat, - "emitSpeed": .4, + "emitSpeed": .2, "speedSpread": 0.0, - // "emitDimensions": { - // "x": .1, - // "y": .1, - // "z": .1 - // }, "polarStart": 0, "polarFinish": .0, "azimuthStart": .1, From cd911b31d29413a56ae1d54e215e70b4ef895ea5 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 10:26:54 -0800 Subject: [PATCH 152/318] dont accidentally constrain all objects --- examples/controllers/handControllerGrab.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ce519880af..9efbff7c58 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -845,7 +845,8 @@ function MyController(hand) { var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstraintData); var clampedVector; var targetPosition; - if (constraintData.startAxis !== false) { + if (constraintData.axisStart !== false) { + print('CONSTRAINING OBJECT') clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd); targetPosition = clampedVector; } else { From 57e51afd46c661db3545cef4345327137abc2338 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:35:20 -0800 Subject: [PATCH 153/318] light stick --- examples/flowArts/flowArtsHutSpawner.js | 4 +--- examples/flowArts/lightSaber/lightSaberEntityScript.js | 6 +++--- examples/flowArts/raveStick/raveStickEntityScript.js | 5 ++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 1ed3325b9c..2f9b2052d1 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -26,8 +26,7 @@ basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS var lightBall = new LightBall(basePosition); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); -var raveStick2 = new RaveStick(Vec3.sum(basePosition, {x: 2, y: 0.5, z: 1})); -// var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); +var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); @@ -78,7 +77,6 @@ function cleanup() { Entities.deleteEntity(floor); lightBall.cleanup(); raveStick.cleanup(); - raveStick2.cleanup(); lightSaber.cleanup(); } diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index ea1f408abd..5175de25bb 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -31,7 +31,7 @@ startNearGrab: function() { // this.createBeam(); - + }, continueNearGrab: function() { @@ -44,7 +44,7 @@ preload: function(entityID) { this.entityID = entityID; - this.createBeam(); + this.createBeam(); }, unload: function() { @@ -62,7 +62,7 @@ var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", position: position, diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 7b84f473ea..20c21d3a79 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -116,6 +116,7 @@ releaseGrab: function() { Script.clearInterval(this.trailEraseInterval); + this.trailEraseInterval = null; }, preload: function(entityID) { @@ -126,7 +127,9 @@ unload: function() { Entities.deleteEntity(this.beam); Entities.deleteEntity(this.trail); - Script.clearInterval(this.trailEraseInterval); + if(this.trailEraseInterval) { + Script.clearInterval(this.trailEraseInterval); + } }, createBeam: function() { From 286b984d6fd0cb693b8465123ede179476c84893 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Dec 2015 10:48:33 -0800 Subject: [PATCH 154/318] serve SHTML files with HTML MIME type --- libraries/embedded-webserver/src/HTTPManager.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 1f1dfa1735..0b98d52cb1 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -145,9 +145,14 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, localFileData = localFileString.toLocal8Bit(); } - - connection->respond(HTTPConnection::StatusCode200, localFileData, - qPrintable(mimeDatabase.mimeTypeForFile(filePath).name())); + + // if this is an shtml file just make the MIME type match HTML so browsers aren't confused + auto mimeType = QString { "text/html" }; + if (localFileInfo.suffix() != "shtml") { + mimeType = mimeDatabase.mimeTypeForFile(filePath).name(); + } + + connection->respond(HTTPConnection::StatusCode200, localFileData, qPrintable(mimeType)); return true; } From d4481818b2e991512afb6e8819ed5c910d7cf801 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 10:50:58 -0800 Subject: [PATCH 155/318] lightsaber oriented right --- .../flowArts/lightSaber/lightSaberEntityScript.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 5175de25bb..2faf0abff9 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -30,8 +30,9 @@ isGrabbed: false, startNearGrab: function() { - // this.createBeam(); - + Entities.editEntity(this.beam, { + isEmitting: true + }); }, continueNearGrab: function() { @@ -39,7 +40,9 @@ }, releaseGrab: function() { - + Entities.editEntity(this.beam, { + isEmitting: false + }); }, preload: function(entityID) { @@ -57,7 +60,7 @@ this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - forwardVec = Vec3.normalize(forwardVec); + // forwardVec = Vec3.normalize(forwardVec); var forwardQuat = orientationOf(forwardVec); var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; @@ -67,7 +70,7 @@ type: "ParticleEffect", position: position, parentID: this.entityID, - isEmitting: true, + isEmitting: false, "colorStart": color, color: { red: 200, From 08f42c08d9e5286ee4483b3f40654c3adf4258c7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Dec 2015 10:54:32 -0800 Subject: [PATCH 156/318] use a ternary for single assignment --- libraries/embedded-webserver/src/HTTPManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index 0b98d52cb1..4c804f2e7b 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -147,10 +147,10 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, } // if this is an shtml file just make the MIME type match HTML so browsers aren't confused - auto mimeType = QString { "text/html" }; - if (localFileInfo.suffix() != "shtml") { - mimeType = mimeDatabase.mimeTypeForFile(filePath).name(); - } + // otherwise use the mimeDatabase to look it up + auto mimeType = localFileInfo.suffix() == "shtml" + ? QString { "text/html" } + : mimeDatabase.mimeTypeForFile(filePath).name(); connection->respond(HTTPConnection::StatusCode200, localFileData, qPrintable(mimeType)); From 5cc5a2ab33aa2df0edfb622849d17b220c3c1a00 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 10:58:14 -0800 Subject: [PATCH 157/318] working non kinematic release --- examples/controllers/handControllerGrab.js | 71 ++++++++++++------- examples/light_modifier/lightLoader.js | 6 +- examples/light_modifier/lightModifier.js | 8 +-- .../light_modifier/lightModifierTestScene.js | 3 +- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 9efbff7c58..f21df807b4 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -817,26 +817,35 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + var defaultMoveWithHeadData = { + disableMoveWithHead: false + }; + var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData); - // mix in head motion - if (MOVE_WITH_HEAD) { - var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var after = Vec3.multiplyQbyV(Camera.orientation, { - x: 0.0, - y: 0.0, - z: objDistance - }); - var change = Vec3.subtract(before, after); - this.currentCameraOrientation = Camera.orientation; - this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + if (handControllerData.disableMoveWithHead !== true) { + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + } else { + print('should not head move!'); } + var defaultConstraintData = { axisStart: false, axisEnd: false, @@ -846,7 +855,6 @@ function MyController(hand) { var clampedVector; var targetPosition; if (constraintData.axisStart !== false) { - print('CONSTRAINING OBJECT') clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd); targetPosition = clampedVector; } else { @@ -1249,15 +1257,29 @@ function MyController(hand) { disableReleaseVelocity: false }; - var releaseVelocityData = getEntityCustomData('releaseVelocityKey', this.grabbedEntity, defaultReleaseVelocityData); + var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData); if (releaseVelocityData.disableReleaseVelocity === true) { - Entities.updateAction(this.grabbedEntity, this.actionID, { - ttl: 1, - kinematic: false, - kinematicSetVelocity: false, + print('SHOULD NOT BE KINEMATIC AT RELEASE') + // Entities.updateAction(this.grabbedEntity, this.actionID, { + // ttl: 1, + // kinematic: false, + // kinematicSetVelocity: false, + // }); + Entities.deleteAction(this.grabbedEntity, this.actionID); - }); - // Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.editEntity(this.grabbedEntity,{ + velocity:{ + x:0, + y:0, + z:0 + }, + angularVelocity:{ + x:0, + y:0, + z:0 + } + }) + Entities.deleteAction(this.grabbedEntity, this.actionID); } else { //don't make adjustments @@ -1266,7 +1288,6 @@ function MyController(hand) { } } } - this.deactivateEntity(this.grabbedEntity); this.grabbedEntity = null; diff --git a/examples/light_modifier/lightLoader.js b/examples/light_modifier/lightLoader.js index e4022e7bc1..83618f85c2 100644 --- a/examples/light_modifier/lightLoader.js +++ b/examples/light_modifier/lightLoader.js @@ -10,11 +10,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var grabScript = Script.resolvePath('../controllers/handControllerGrab.js'); +var grabScript = Script.resolvePath('../controllers/handControllerGrab.js?' + Math.random(0 - 100)); Script.load(grabScript); -var lightModifier = Script.resolvePath('lightModifier.js'); +var lightModifier = Script.resolvePath('lightModifier.js?' + Math.random(0 - 100)); Script.load(lightModifier); Script.setTimeout(function() { - var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js'); + var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js?' + Math.random(0 - 100)); Script.load(lightModifierTestScene); }, 750) \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 7cd442e9ed..8eae5cc2a4 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -251,15 +251,15 @@ entitySlider.prototype = { axisStart: position, axisEnd: this.endOfAxis, }, - releaseVelocityKey: { - disableReleaseVelocity: true + handControllerKey: { + disableReleaseVelocity: true, + disableMoveWithHead: true } - }) + }), }; this.sliderIndicator = Entities.addEntity(properties); }, - setValueFromMessage: function(message) { //message is not for our light diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 84fb779469..761eb4786d 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -75,8 +75,7 @@ function createBlock() { }, position: position, userData: JSON.stringify({ - - releaseVelocityKey: { + handControllerKey: { disableReleaseVelocity: true } }) From 06e9731fe4f626366f1120b2a85a727b79200ff1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Dec 2015 11:07:36 -0800 Subject: [PATCH 158/318] don't attempt to read an empty or malformed packet --- libraries/networking/src/udt/Socket.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 11f1b043c8..8fb5db3853 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -236,8 +236,14 @@ void Socket::readPendingDatagrams() { auto buffer = std::unique_ptr(new char[packetSizeWithHeader]); // pull the datagram - _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, - senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, + senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + + if (sizeRead <= 0) { + // we either didn't pull anything for this packet or there was an error reading (this seems to trigger + // on windows even if there's not a packet available) + continue; + } auto it = _unfilteredHandlers.find(senderSockAddr); @@ -248,7 +254,7 @@ void Socket::readPendingDatagrams() { it->second(std::move(basePacket)); } - return; + continue; } // check if this was a control packet or a data packet @@ -276,7 +282,7 @@ void Socket::readPendingDatagrams() { packet->getDataSize(), packet->getPayloadSize())) { // the connection indicated that we should not continue processing this packet - return; + continue; } } From 63a63152a48afe98be231bfd653b3c17c3f7cc02 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Dec 2015 11:10:49 -0800 Subject: [PATCH 159/318] add procedural hand pose example --- .../controllers/proceduralHandPoseExample.js | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 examples/controllers/proceduralHandPoseExample.js diff --git a/examples/controllers/proceduralHandPoseExample.js b/examples/controllers/proceduralHandPoseExample.js new file mode 100644 index 0000000000..5d0b10c46a --- /dev/null +++ b/examples/controllers/proceduralHandPoseExample.js @@ -0,0 +1,76 @@ +// +// proceduralHandPoseExample.js +// examples/controllers +// +// Created by Brad Hefta-Gaub on 2015/12/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +var MAPPING_NAME = "com.highfidelity.examples.proceduralHandPose"; +var mapping = Controller.newMapping(MAPPING_NAME); +var translation = { x: 0, y: 0.1, z: 0 }; +var translationDx = 0.01; +var translationDy = 0.01; +var translationDz = -0.01; +var TRANSLATION_LIMIT = 0.5; + +var pitch = 45; +var yaw = 0; +var roll = 45; +var pitchDelta = 1; +var yawDelta = -1; +var rollDelta = 1; +var ROTATION_MIN = -90; +var ROTATION_MAX = 90; + +mapping.from(function() { + + // adjust the hand translation in a periodic back and forth motion for each of the 3 axes + translation.x = translation.x + translationDx; + translation.y = translation.y + translationDy; + translation.z = translation.z + translationDz; + if ((translation.x > TRANSLATION_LIMIT) || (translation.x < (-1 * TRANSLATION_LIMIT))) { + translationDx = translationDx * -1; + } + if ((translation.y > TRANSLATION_LIMIT) || (translation.y < (-1 * TRANSLATION_LIMIT))) { + translationDy = translationDy * -1; + } + if ((translation.z > TRANSLATION_LIMIT) || (translation.z < (-1 * TRANSLATION_LIMIT))) { + translationDz = translationDz * -1; + } + + // adjust the hand rotation in a periodic back and forth motion for each of pitch/yaw/roll + pitch = pitch + pitchDelta; + yaw = yaw + yawDelta; + roll = roll + rollDelta; + if ((pitch > ROTATION_MAX) || (pitch < ROTATION_MIN)) { + pitchDelta = pitchDelta * -1; + } + if ((yaw > ROTATION_MAX) || (yaw < ROTATION_MIN)) { + yawDelta = yawDelta * -1; + } + if ((roll > ROTATION_MAX) || (roll < ROTATION_MIN)) { + rollDelta = rollDelta * -1; + } + + var rotation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll); + + var pose = { + translation: translation, + rotation: rotation, + velocity: { x: 0, y: 0, z: 0 }, + angularVelocity: { x: 0, y: 0, z: 0, w: 1 } + }; + return pose; +}).debug(true).to(Controller.Standard.LeftHand); + +Controller.enableMapping(MAPPING_NAME); + + +Script.scriptEnding.connect(function(){ + mapping.disable(); +}); From f3adb8a2f70264af4eb50b93b314065ce88d059b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 17 Dec 2015 11:16:59 -0800 Subject: [PATCH 160/318] fix offset math in hold action --- interface/src/avatar/AvatarActionHold.cpp | 55 +++++++++++------------ 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 34b959575d..b2343c8bce 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -48,38 +48,38 @@ void AvatarActionHold::prepareForPhysicsSimulation() { auto avatarManager = DependencyManager::get(); auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); - if (!holdingAvatar) { + if (!holdingAvatar || !holdingAvatar->isMyAvatar()) { return; } withWriteLock([&]{ - if (_ignoreIK && holdingAvatar->isMyAvatar()) { + if (_ignoreIK) { return; } - if (holdingAvatar->isMyAvatar()) { - glm::vec3 palmPosition; - glm::quat palmRotation; - if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } - glm::vec3 avatarRigidBodyPosition; - glm::quat avatarRigidBodyRotation; - getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); - - // determine the difference in translation and rotation between the avatar's - // rigid body and the palm position. The avatar's rigid body will be moved by bullet - // between this call and the call to getTarget, below. A call to get*PalmPosition in - // getTarget would get the palm position of the previous location of the avatar (because - // bullet has moved the av's rigid body but the rigid body's location has not yet been - // copied out into the Avatar class. - _palmOffsetFromRigidBody = palmPosition - avatarRigidBodyPosition; - _palmRotationFromRigidBody = glm::inverse(avatarRigidBodyRotation) * palmRotation; + glm::vec3 palmPosition; + glm::quat palmRotation; + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); } + + glm::vec3 avatarRigidBodyPosition; + glm::quat avatarRigidBodyRotation; + getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); + + // determine the difference in translation and rotation between the avatar's + // rigid body and the palm position. The avatar's rigid body will be moved by bullet + // between this call and the call to getTarget, below. A call to get*PalmPosition in + // getTarget would get the palm position of the previous location of the avatar (because + // bullet has moved the av's rigid body but the rigid body's location has not yet been + // copied out into the Avatar class. + glm::quat avatarRotationInverse = glm::inverse(avatarRigidBodyRotation); + _palmOffsetFromRigidBody = avatarRotationInverse * (palmPosition - avatarRigidBodyPosition); + _palmRotationFromRigidBody = avatarRotationInverse * palmRotation; }); } @@ -116,13 +116,8 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will // be stale. Instead, determine the current palm position with the current avatar's rigid body // location and the saved offsets. - palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; + palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; - if (isRightHand) { - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmRotation = holdingAvatar->getLeftPalmRotation(); - } } else { if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); From 2aaefbcfcbbcc0d6e3ed7d4cfbb932467131d4a4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 11:32:48 -0800 Subject: [PATCH 161/318] refactoring, adding headers --- examples/flowArts/flowArtsHutSpawner.js | 13 +-- examples/flowArts/lightBall/lightBall.js | 90 +++++++++++-------- examples/flowArts/lightSaber/LightSaber.js | 21 ++++- .../lightSaber/lightSaberEntityScript.js | 74 +++++++-------- examples/flowArts/lightTrails.js | 23 +---- examples/flowArts/raveStick/RaveStick.js | 41 ++++++++- .../raveStick/raveStickEntityScript.js | 67 +++++++------- .../RenderableParticleEffectEntityItem.cpp | 1 + .../entities/src/ParticleEffectEntityItem.cpp | 11 +-- 9 files changed, 195 insertions(+), 146 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 2f9b2052d1..03c0ca112f 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -1,11 +1,11 @@ // // flowArtsHutSpawner.js -// examples +// examples/flowArts // -// Created by Eric Levin on 5/14/15. +// Created by Eric Levin on 12/17/15. // Copyright 2014 High Fidelity, Inc. // -// This script creates a special flow arts hut with a numch of flow art toys people can go in and play with +// This script creates a special flow arts hut with a bunch of flow art toys people can go in and play with // // // Distributed under the Apache License, Version 2.0. @@ -29,12 +29,13 @@ var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); -var modelURL = "file:///C:/Users/Eric/Desktop/RaveRoom.fbx?v1" + Math.random(); +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/RaveRoom.fbx"; var roomDimensions = {x: 30.58, y: 15.29, z: 30.58}; var raveRoom = Entities.addEntity({ type: "Model", + name: "Rave Hut Room", modelURL: modelURL, position: basePosition, dimensions:roomDimensions, @@ -43,7 +44,8 @@ var raveRoom = Entities.addEntity({ var floor = Entities.addEntity({ type: "Box", - position: Vec3.sum(basePosition, {x: 0, y: -1.5, z: 0}), + name: "Rave Floor", + position: Vec3.sum(basePosition, {x: 0, y: -1.2, z: 0}), dimensions: {x: roomDimensions.x, y: 0.6, z: roomDimensions.z}, color: {red: 50, green: 10, blue: 100}, shapeType: 'box' @@ -53,6 +55,7 @@ var floor = Entities.addEntity({ var lightZone = Entities.addEntity({ type: "Zone", + name: "Rave Hut Zone", shapeType: 'box', keyLightIntensity: 0.4, keyLightColor: { diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index 698c62a71d..a8cdf894d1 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -1,3 +1,17 @@ +// +// LightBall.js +// examples/lightBall +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creats a particle light ball which makes particle trails as you move it. +// +// +// 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"); LightBall = function(spawnPosition) { @@ -11,6 +25,7 @@ LightBall = function(spawnPosition) { var containerBall = Entities.addEntity({ type: "Sphere", + name: "containerBall", position: Vec3.sum(spawnPosition, { x: 0, y: .5, @@ -27,7 +42,11 @@ LightBall = function(spawnPosition) { blue: 150 }, collisionsWillMove: true, - gravity: {x: 0, y: -.5, z: 0}, + gravity: { + x: 0, + y: -.5, + z: 0 + }, userData: JSON.stringify({ grabbableKey: { spatialKey: { @@ -45,6 +64,7 @@ LightBall = function(spawnPosition) { var light = Entities.addEntity({ type: 'Light', + name: "ballLight", parentID: containerBall, dimensions: { x: 30, @@ -60,8 +80,8 @@ LightBall = function(spawnPosition) { type: "ParticleEffect", parentID: containerBall, isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { + name: "particleBall", + colorStart: { red: 200, green: 20, blue: 40 @@ -71,45 +91,45 @@ LightBall = function(spawnPosition) { green: 200, blue: 255 }, - "colorFinish": { + colorFinish: { red: 25, green: 20, blue: 255 }, - "maxParticles": 100000, - "lifespan": 2, - "emitRate": 10000, - "emitSpeed": .1, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 + maxParticles: 100000, + lifespan: 2, + emitRate: 10000, + emitSpeed: .1, + lifetime: -1, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 }, - "polarStart": 0, - "polarFinish": Math.PI, - "azimuthStart": -Math.PI, - "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 + polarStart: 0, + polarFinish: Math.PI, + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, - "particleRadius": 0.02, - "radiusSpread": 0, - "radiusStart": 0.03, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), + particleRadius: 0.02, + radiusSpread: 0, + radiusStart: 0.03, + radiusFinish: 0.0003, + alpha: 0, + alphaSpread: .5, + alphaStart: 0, + alphaFinish: 0.5, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", emitterShouldTrail: true }) diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/LightSaber.js index 12ac3f3b60..8a4f3f2902 100644 --- a/examples/flowArts/lightSaber/LightSaber.js +++ b/examples/flowArts/lightSaber/LightSaber.js @@ -1,10 +1,25 @@ +// +// LightSaber.js +// examples +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creates a lightsaber which activates on grab +// +// +// 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 modelURL = "file:///C:/Users/Eric/Desktop/lightSaber.fbx?v1" + Math.random(); +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/lightSaber.fbx"; var scriptURL = Script.resolvePath("lightSaberEntityScript.js"); LightSaber = function(spawnPosition) { - var stick = Entities.addEntity({ + var saberHandle = Entities.addEntity({ type: "Model", + name: "LightSaber Handle", modelURL: modelURL, position: spawnPosition, shapeType: 'box', @@ -31,7 +46,7 @@ LightSaber = function(spawnPosition) { function cleanup() { - Entities.deleteEntity(stick); + Entities.deleteEntity(saberHandle); } this.cleanup = cleanup; diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 2faf0abff9..6f396bf6e3 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -1,10 +1,10 @@ // lightSaberEntityScript.js // // Script Type: Entity -// Created by Eric Levin on 12/16/15. +// Created by Eric Levin on 12/17/15. // Copyright 2015 High Fidelity, Inc. // -// This entity script creates a lightsaber. +// This entity script creates the logic for displaying the lightsaber beam. // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // @@ -35,10 +35,6 @@ }); }, - continueNearGrab: function() { - - }, - releaseGrab: function() { Entities.editEntity(this.beam, { isEmitting: false @@ -52,7 +48,6 @@ unload: function() { Entities.deleteEntity(this.beam); - // Entities.deleteEntity(this.beamTrail); }, createBeam: function() { @@ -68,56 +63,53 @@ var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", + name: "LightSaber Beam", position: position, parentID: this.entityID, isEmitting: false, - "colorStart": color, + colorStart: color, color: { red: 200, green: 200, blue: 255 }, - "colorFinish": color, - "maxParticles": 100000, - "lifespan": 2, - "emitRate": 1000, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 1000, emitOrientation: forwardQuat, - "emitSpeed": .4, - "speedSpread": 0.0, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 + emitSpeed: .4, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 }, - "polarStart": 0, - "polarFinish": .0, - "azimuthStart": .1, - "azimuthFinish": .01, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, - "radiusStart": 0.03, - radiusFinish: 0.025, - "alpha": 0.7, - "alphaSpread": .1, - "alphaStart": 0.5, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + radiusStart: 0.03, + adiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: false } this.beam = Entities.addEntity(props); - // props.emitterShouldTrail = true; - // this.beamTrail = Entities.addEntity(props); - } }; // entity scripts always need to return a newly constructed object of our type diff --git a/examples/flowArts/lightTrails.js b/examples/flowArts/lightTrails.js index 8e0dc98bbb..522ecce851 100644 --- a/examples/flowArts/lightTrails.js +++ b/examples/flowArts/lightTrails.js @@ -1,11 +1,11 @@ // -// hydraPaint.js +// lightTrails.js // examples // // Created by Eric Levin on 5/14/15. // Copyright 2014 High Fidelity, Inc. // -// This script allows you to paint with the hydra! +// This script creates light trails as you move your hydra hands // // // Distributed under the Apache License, Version 2.0. @@ -25,24 +25,6 @@ var LIFETIME = 6000; var DRAWING_DEPTH = 0.8; var LINE_DIMENSIONS = 100; -var lightZone = Entities.addEntity({ - type: "Zone", - shapeType: 'box', - keyLightIntensity: 0.02, - keyLightColor: { - red: 5, - green: 0, - blue: 5 - }, - keyLightAmbientIntensity: .05, - position: MyAvatar.position, - dimensions: { - x: 100, - y: 100, - z: 100 - } -}); - var MIN_POINT_DISTANCE = 0.02; @@ -192,7 +174,6 @@ function update(deltaTime) { function scriptEnding() { leftController.cleanup(); rightController.cleanup(); - Entities.deleteEntity(lightZone); } function vectorIsZero(v) { diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index 5151b528cc..fd3c98b6e5 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -1,10 +1,32 @@ +// +// RaveStick.js +// examples/flowArats/raveStick +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creates a rave stick which makes pretty light trails as you paint +// +// 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 modelURL = "file:///C:/Users/Eric/Desktop/raveStick.fbx?v1" + Math.random(); +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; var scriptURL = Script.resolvePath("raveStickEntityScript.js"); RaveStick = function(spawnPosition) { - + var colorPalette = [{ + red: 0, + green: 200, + blue: 40 + }, { + red: 200, + green: 10, + blue: 40 + }]; var stick = Entities.addEntity({ type: "Model", + name: "raveStick", modelURL: modelURL, position: spawnPosition, shapeType: 'box', @@ -29,9 +51,24 @@ RaveStick = function(spawnPosition) { }) }); + var light = Entities.addEntity({ + type: 'Light', + name: "raveLight", + parentID: stick, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + function cleanup() { Entities.deleteEntity(stick); + Entities.deleteEntity(light); } this.cleanup = cleanup; diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 20c21d3a79..2c484e601d 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -46,7 +46,9 @@ }, textures: texture, lifetime: LIFETIME - }) + }); + + this.points = []; this.normals = []; this.strokeWidths = []; @@ -127,8 +129,8 @@ unload: function() { Entities.deleteEntity(this.beam); Entities.deleteEntity(this.trail); - if(this.trailEraseInterval) { - Script.clearInterval(this.trailEraseInterval); + if (this.trailEraseInterval) { + Script.clearInterval(this.trailEraseInterval); } }, @@ -147,43 +149,46 @@ position: position, parentID: this.entityID, isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": color, - colorSpread: {red: 200, green : 10, blue: 10}, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, color: { red: 200, green: 200, blue: 255 }, - "colorFinish": color, - "maxParticles": 100000, - "lifespan": 1, - "emitRate": 1000, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, emitOrientation: forwardQuat, - "emitSpeed": .2, - "speedSpread": 0.0, - "polarStart": 0, - "polarFinish": .0, - "azimuthStart": .1, - "azimuthFinish": .01, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - "accelerationSpread": { - "x": .00, - "y": .00, - "z": .00 + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, - "radiusStart": 0.03, + radiusStart: 0.03, radiusFinish: 0.025, - "alpha": 0.7, - "alphaSpread": .1, - "alphaStart": 0.5, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/beamParticle.png?v1" + Math.random(), + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: false } this.beam = Entities.addEntity(props); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 91a4811011..43b9ae7870 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -245,6 +245,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { transform.setRotation(rotation); } + render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { payload.setVisibleFlag(true); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 4d46439554..413604dbdf 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -641,11 +641,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { Particle particle; - - std::random_device rd; - std::mt19937_64 el(rd()); - std::uniform_real_distribution uniform_dist(0.0, 1.0); particle.seed = randFloatInRange(-1.0f, 1.0f); if (getEmitterShouldTrail()) { @@ -667,13 +663,13 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); // float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); - float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * uniform_dist(el)); + float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) *randFloat()); float azimuth; if (_azimuthFinish >= _azimuthStart) { - azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * uniform_dist(el); + azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); } else { - azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * uniform_dist(el); + azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); } glm::vec3 emitDirection; @@ -711,7 +707,6 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { } particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); - // particle.velocity = (_emitSpeed + uniform_dist(el) * _speedSpread) * (_emitOrientation * emitDirection); particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } From 8d25a666d11dd6e3498e55fcae021f9c886edc4c Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 11:40:06 -0800 Subject: [PATCH 162/318] fixed bug where trail would remain after user released rave stick --- examples/flowArts/flowArtsHutSpawner.js | 1 - examples/flowArts/lightBall/lightBall.js | 2 +- .../flowArts/raveStick/raveStickEntityScript.js | 13 +++++-------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 03c0ca112f..3762c67fe4 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -72,7 +72,6 @@ var lightZone = Entities.addEntity({ } }); - function cleanup() { Entities.deleteEntity(raveRoom); diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index a8cdf894d1..1898f86eef 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -44,7 +44,7 @@ LightBall = function(spawnPosition) { collisionsWillMove: true, gravity: { x: 0, - y: -.5, + y: -0.5, z: 0 }, userData: JSON.stringify({ diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 2c484e601d..171b53e0cf 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -19,7 +19,7 @@ var MAX_POINTS_PER_LINE = 50; var MIN_POINT_DISTANCE = 0.02; var STROKE_WIDTH = 0.05 - var ugLSD = 25; + var ugLSD = 35; var RaveStick = function() { _this = this; this.colorPalette = [{ @@ -117,8 +117,10 @@ }, releaseGrab: function() { - Script.clearInterval(this.trailEraseInterval); - this.trailEraseInterval = null; + Script.setTimeout(function() { + Script.clearInterval(_this.trailEraseInterval); + _this.trailEraseInterval = null; + }, 3000); }, preload: function(entityID) { @@ -192,13 +194,8 @@ emitterShouldTrail: false } this.beam = Entities.addEntity(props); - - // props.emitterShouldTrail = true; - // this.beamTrail = Entities.addEntity(props); - } }; - // entity scripts always need to return a newly constructed object of our type return new RaveStick(); function computeNormal(p1, p2) { From b80fa1c8064c23bb3709593dafcef968cb7e1aa3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 17 Dec 2015 11:46:41 -0800 Subject: [PATCH 163/318] code review --- interface/src/avatar/AvatarActionHold.cpp | 29 +++++++++++++++++++---- interface/src/avatar/AvatarActionHold.h | 3 ++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b2343c8bce..be562e2773 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -78,8 +78,16 @@ void AvatarActionHold::prepareForPhysicsSimulation() { // bullet has moved the av's rigid body but the rigid body's location has not yet been // copied out into the Avatar class. glm::quat avatarRotationInverse = glm::inverse(avatarRigidBodyRotation); - _palmOffsetFromRigidBody = avatarRotationInverse * (palmPosition - avatarRigidBodyPosition); - _palmRotationFromRigidBody = avatarRotationInverse * palmRotation; + + // the offset should be in the frame of the avatar, but something about the order + // things are updated makes this wrong: + // _palmOffsetFromRigidBody = avatarRotationInverse * (palmPosition - avatarRigidBodyPosition); + // I'll leave it here as a comment in case avatar handling changes. + _palmOffsetFromRigidBody = palmPosition - avatarRigidBodyPosition; + + // rotation should also be needed, but again, the order of updates makes this unneeded. leaving + // code here for future reference. + // _palmRotationFromRigidBody = avatarRotationInverse * palmRotation; }); } @@ -116,8 +124,21 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will // be stale. Instead, determine the current palm position with the current avatar's rigid body // location and the saved offsets. - palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; - palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; + + // this line is more correct but breaks for the current way avatar data is updated. + // palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; + // instead, use this for now: + palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; + + // the item jitters the least by getting the rotation based on the opinion of Avatar.h rather + // than that of the rigid body. leaving this next line here for future reference: + // palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; + + if (isRightHand) { + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmRotation = holdingAvatar->getLeftPalmRotation(); + } } else { if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index fc8baf6dcc..b97ec59780 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -61,7 +61,8 @@ private: glm::vec3 _previousPositionalDelta; glm::vec3 _palmOffsetFromRigidBody; - glm::quat _palmRotationFromRigidBody; + // leaving this here for future refernece. + // glm::quat _palmRotationFromRigidBody; }; #endif // hifi_AvatarActionHold_h From 8e2128c69226e629291db183bf1fc77317826ee7 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 11:59:21 -0800 Subject: [PATCH 164/318] update light volume when you move light parent --- examples/controllers/handControllerGrab.js | 29 +- examples/libraries/entitySelectionTool.js | 3101 +++++++++++++---- examples/light_modifier/lightModifier.js | 2 +- .../light_modifier/lightModifierTestScene.js | 2 + examples/light_modifier/lightParent.js | 42 + 5 files changed, 2387 insertions(+), 789 deletions(-) create mode 100644 examples/light_modifier/lightParent.js diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f21df807b4..f53a66444f 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -1256,27 +1256,21 @@ function MyController(hand) { var defaultReleaseVelocityData = { disableReleaseVelocity: false }; - + //sometimes we want things to stay right where they are when we let go. var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData); if (releaseVelocityData.disableReleaseVelocity === true) { - print('SHOULD NOT BE KINEMATIC AT RELEASE') - // Entities.updateAction(this.grabbedEntity, this.actionID, { - // ttl: 1, - // kinematic: false, - // kinematicSetVelocity: false, - // }); - Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.deleteAction(this.grabbedEntity, this.actionID); - Entities.editEntity(this.grabbedEntity,{ - velocity:{ - x:0, - y:0, - z:0 + Entities.editEntity(this.grabbedEntity, { + velocity: { + x: 0, + y: 0, + z: 0 }, - angularVelocity:{ - x:0, - y:0, - z:0 + angularVelocity: { + x: 0, + y: 0, + z: 0 } }) Entities.deleteAction(this.grabbedEntity, this.actionID); @@ -1288,6 +1282,7 @@ function MyController(hand) { } } } + this.deactivateEntity(this.grabbedEntity); this.grabbedEntity = null; diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 6edbe6844b..9b213760c2 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -16,23 +16,73 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; SPACE_LOCAL = "local"; SPACE_WORLD = "world"; + SelectionManager = (function() { var that = {}; + + function subscribeToUpdateMessages() { + Messages.subscribe('entityToolUpdates'); + Messages.messageReceived.connect(handleEntitySelectionToolUpdates); + } + + function handleEntitySelectionToolUpdates(channel, message, sender) { + if (channel !== 'entityToolUpdates') { + return; + } + if (sender !== MyAvatar.sessionUUID) { + return; + } + + if (message === 'callUpdate') { + that._update(); + } + } + + subscribeToUpdateMessages(); + that.savedProperties = {}; that.selections = []; var listeners = []; that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); - that.localPosition = { x: 0, y: 0, z: 0 }; - that.localDimensions = { x: 0, y: 0, z: 0 }; - that.localRegistrationPoint = { x: 0.5, y: 0.5, z: 0.5 }; + that.localPosition = { + x: 0, + y: 0, + z: 0 + }; + that.localDimensions = { + x: 0, + y: 0, + z: 0 + }; + that.localRegistrationPoint = { + x: 0.5, + y: 0.5, + z: 0.5 + }; that.worldRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); - that.worldPosition = { x: 0, y: 0, z: 0 }; - that.worldDimensions = { x: 0, y: 0, z: 0 }; - that.worldRegistrationPoint = { x: 0.5, y: 0.5, z: 0.5 }; - that.centerPosition = { x: 0, y: 0, z: 0 }; + that.worldPosition = { + x: 0, + y: 0, + z: 0 + }; + that.worldDimensions = { + x: 0, + y: 0, + z: 0 + }; + that.worldRegistrationPoint = { + x: 0.5, + y: 0.5, + z: 0.5 + }; + that.centerPosition = { + x: 0, + y: 0, + z: 0 + }; that.saveProperties = function() { that.savedProperties = {}; @@ -177,9 +227,9 @@ function getRelativeCenterPosition(dimensions, registrationPoint) { } } -SelectionDisplay = (function () { +SelectionDisplay = (function() { var that = {}; - + var MINIMUM_DIMENSION = 0.001; var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075; @@ -194,14 +244,18 @@ SelectionDisplay = (function () { var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg"; var showExtendedStretchHandles = false; - + var spaceMode = SPACE_LOCAL; var mode = "UNKNOWN"; var overlayNames = new Array(); var lastCameraPosition = Camera.getPosition(); var lastCameraOrientation = Camera.getOrientation(); - var handleHoverColor = { red: 224, green: 67, blue: 36 }; + var handleHoverColor = { + red: 224, + green: 67, + blue: 36 + }; var handleHoverAlpha = 1.0; var rotateOverlayTargetSize = 10000; // really big target @@ -221,19 +275,27 @@ SelectionDisplay = (function () { var pitchNormal; var rollNormal; var rotationNormal; - + var originalRotation; var originalPitch; var originalYaw; var originalRoll; - - var handleColor = { red: 255, green: 255, blue: 255 }; + + var handleColor = { + red: 255, + green: 255, + blue: 255 + }; var handleAlpha = 0.7; - var highlightedHandleColor = { red: 183, green: 64, blue: 44 }; + var highlightedHandleColor = { + red: 183, + green: 64, + blue: 44 + }; var highlightedHandleAlpha = 0.9; - + var previousHandle = false; var previousHandleColor; var previousHandleAlpha; @@ -242,115 +304,182 @@ SelectionDisplay = (function () { var grabberSizeEdge = 0.015; var grabberSizeFace = 0.025; var grabberAlpha = 1; - var grabberColorCorner = { red: 120, green: 120, blue: 120 }; - var grabberColorEdge = { red: 0, green: 0, blue: 0 }; - var grabberColorFace = { red: 120, green: 120, blue: 120 }; + var grabberColorCorner = { + red: 120, + green: 120, + blue: 120 + }; + var grabberColorEdge = { + red: 0, + green: 0, + blue: 0 + }; + var grabberColorFace = { + red: 120, + green: 120, + blue: 120 + }; var grabberLineWidth = 0.5; var grabberSolid = true; - var grabberMoveUpPosition = { x: 0, y: 0, z: 0 }; + var grabberMoveUpPosition = { + x: 0, + y: 0, + z: 0 + }; - var lightOverlayColor = { red: 255, green: 153, blue: 0 }; + var lightOverlayColor = { + red: 255, + green: 153, + blue: 0 + }; var grabberPropertiesCorner = { - position: { x:0, y: 0, z: 0}, - size: grabberSizeCorner, - color: grabberColorCorner, - alpha: 1, - solid: grabberSolid, - visible: false, - dashed: false, - lineWidth: grabberLineWidth, - drawInFront: true, - borderSize: 1.4, - }; + position: { + x: 0, + y: 0, + z: 0 + }, + size: grabberSizeCorner, + color: grabberColorCorner, + alpha: 1, + solid: grabberSolid, + visible: false, + dashed: false, + lineWidth: grabberLineWidth, + drawInFront: true, + borderSize: 1.4, + }; var grabberPropertiesEdge = { - position: { x:0, y: 0, z: 0}, - size: grabberSizeEdge, - color: grabberColorEdge, - alpha: 1, - solid: grabberSolid, - visible: false, - dashed: false, - lineWidth: grabberLineWidth, - drawInFront: true, - borderSize: 1.4, - }; + position: { + x: 0, + y: 0, + z: 0 + }, + size: grabberSizeEdge, + color: grabberColorEdge, + alpha: 1, + solid: grabberSolid, + visible: false, + dashed: false, + lineWidth: grabberLineWidth, + drawInFront: true, + borderSize: 1.4, + }; var grabberPropertiesFace = { - position: { x:0, y: 0, z: 0}, - size: grabberSizeFace, - color: grabberColorFace, - alpha: 1, - solid: grabberSolid, - visible: false, - dashed: false, - lineWidth: grabberLineWidth, - drawInFront: true, - borderSize: 1.4, - }; - + position: { + x: 0, + y: 0, + z: 0 + }, + size: grabberSizeFace, + color: grabberColorFace, + alpha: 1, + solid: grabberSolid, + visible: false, + dashed: false, + lineWidth: grabberLineWidth, + drawInFront: true, + borderSize: 1.4, + }; + var spotLightLineProperties = { color: lightOverlayColor, lineWidth: 1.5, }; - + var highlightBox = Overlays.addOverlay("cube", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 90, green: 90, blue: 90}, - alpha: 1, - solid: false, - visible: false, - dashed: true, - lineWidth: 2.0, - ignoreRayIntersection: true, // this never ray intersects - drawInFront: true - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 90, + green: 90, + blue: 90 + }, + alpha: 1, + solid: false, + visible: false, + dashed: true, + lineWidth: 2.0, + ignoreRayIntersection: true, // this never ray intersects + drawInFront: true + }); var selectionBox = Overlays.addOverlay("cube", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 255, green: 0, blue: 0}, - alpha: 1, - solid: false, - visible: false, - dashed: false, - lineWidth: 1.0, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 255, + green: 0, + blue: 0 + }, + alpha: 1, + solid: false, + visible: false, + dashed: false, + lineWidth: 1.0, + }); var selectionBoxes = []; var rotationDegreesDisplay = Overlays.addOverlay("text3d", { - position: { x:0, y: 0, z: 0}, - text: "", - color: { red: 0, green: 0, blue: 0}, - backgroundColor: { red: 255, green: 255, blue: 255 }, - alpha: 0.7, - backgroundAlpha: 0.7, - visible: false, - isFacingAvatar: true, - drawInFront: true, - ignoreRayIntersection: true, - dimensions: { x: 0, y: 0 }, - lineHeight: 0.0, - topMargin: 0, - rightMargin: 0, - bottomMargin: 0, - leftMargin: 0, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + text: "", + color: { + red: 0, + green: 0, + blue: 0 + }, + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 0.7, + backgroundAlpha: 0.7, + visible: false, + isFacingAvatar: true, + drawInFront: true, + ignoreRayIntersection: true, + dimensions: { + x: 0, + y: 0 + }, + lineHeight: 0.0, + topMargin: 0, + rightMargin: 0, + bottomMargin: 0, + leftMargin: 0, + }); var grabberMoveUp = Overlays.addOverlay("image3d", { - url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg", - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: true, - drawInFront: true, - }); + url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg", + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: true, + drawInFront: true, + }); // var normalLine = Overlays.addOverlay("line3d", { // visible: true, @@ -360,7 +489,7 @@ SelectionDisplay = (function () { // color: { red: 255, green: 255, blue: 0 }, // ignoreRayIntersection: true, // }); - + var grabberLBN = Overlays.addOverlay("cube", grabberPropertiesCorner); var grabberRBN = Overlays.addOverlay("cube", grabberPropertiesCorner); var grabberLBF = Overlays.addOverlay("cube", grabberPropertiesCorner); @@ -481,171 +610,324 @@ SelectionDisplay = (function () { ]; - var baseOverlayAngles = { x: 0, y: 0, z: 0 }; + var baseOverlayAngles = { + x: 0, + y: 0, + z: 0 + }; var baseOverlayRotation = Quat.fromVec3Degrees(baseOverlayAngles); var baseOfEntityProjectionOverlay = Overlays.addOverlay("rectangle3d", { - position: { x: 1, y: 0, z: 0}, - color: { red: 51, green: 152, blue: 203 }, - alpha: 0.5, - solid: true, - visible: false, - width: 300, height: 200, - rotation: baseOverlayRotation, - ignoreRayIntersection: true, // always ignore this - }); + position: { + x: 1, + y: 0, + z: 0 + }, + color: { + red: 51, + green: 152, + blue: 203 + }, + alpha: 0.5, + solid: true, + visible: false, + width: 300, + height: 200, + rotation: baseOverlayRotation, + ignoreRayIntersection: true, // always ignore this + }); - var yawOverlayAngles = { x: 90, y: 0, z: 0 }; + var yawOverlayAngles = { + x: 90, + y: 0, + z: 0 + }; var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles); - var pitchOverlayAngles = { x: 0, y: 90, z: 0 }; + var pitchOverlayAngles = { + x: 0, + y: 90, + z: 0 + }; var pitchOverlayRotation = Quat.fromVec3Degrees(pitchOverlayAngles); - var rollOverlayAngles = { x: 0, y: 180, z: 0 }; + var rollOverlayAngles = { + x: 0, + y: 180, + z: 0 + }; var rollOverlayRotation = Quat.fromVec3Degrees(rollOverlayAngles); var xRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 1.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 255, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - visible: false, - }); + visible: false, + lineWidth: 1.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 255, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + visible: false, + }); var yRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 1.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 255, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - visible: false, - }); + visible: false, + lineWidth: 1.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 0, + green: 255, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + visible: false, + }); var zRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 1.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - ignoreRayIntersection: true, // always ignore this - visible: false, - }); + visible: false, + lineWidth: 1.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 0, + green: 0, + blue: 255 + }, + ignoreRayIntersection: true, // always ignore this + visible: false, + }); var rotateZeroOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 2.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 255, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - }); + visible: false, + lineWidth: 2.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 255, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateCurrentOverlay = Overlays.addOverlay("line3d", { - visible: false, - lineWidth: 2.0, - start: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - ignoreRayIntersection: true, // always ignore this - }); + visible: false, + lineWidth: 2.0, + start: { + x: 0, + y: 0, + z: 0 + }, + end: { + x: 0, + y: 0, + z: 0 + }, + color: { + red: 0, + green: 0, + blue: 255 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateOverlayTarget = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: rotateOverlayTargetSize, - color: { red: 0, green: 0, blue: 0 }, - alpha: 0.0, - solid: true, - visible: false, - rotation: yawOverlayRotation, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: rotateOverlayTargetSize, + color: { + red: 0, + green: 0, + blue: 0 + }, + alpha: 0.0, + solid: true, + visible: false, + rotation: yawOverlayRotation, + }); var rotateOverlayInner = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 51, green: 152, blue: 203 }, - alpha: 0.2, - solid: true, - visible: false, - rotation: yawOverlayRotation, - hasTickMarks: true, - majorTickMarksAngle: innerSnapAngle, - minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, - minorTickMarksLength: 0, - majorTickMarksColor: { red: 0, green: 0, blue: 0 }, - minorTickMarksColor: { red: 0, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 51, + green: 152, + blue: 203 + }, + alpha: 0.2, + solid: true, + visible: false, + rotation: yawOverlayRotation, + hasTickMarks: true, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + majorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + minorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateOverlayOuter = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 51, green: 152, blue: 203 }, - alpha: 0.2, - solid: true, - visible: false, - rotation: yawOverlayRotation, + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 51, + green: 152, + blue: 203 + }, + alpha: 0.2, + solid: true, + visible: false, + rotation: yawOverlayRotation, - hasTickMarks: true, - majorTickMarksAngle: 45.0, - minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, - minorTickMarksLength: 0.1, - majorTickMarksColor: { red: 0, green: 0, blue: 0 }, - minorTickMarksColor: { red: 0, green: 0, blue: 0 }, - ignoreRayIntersection: true, // always ignore this - }); + hasTickMarks: true, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + majorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + minorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + ignoreRayIntersection: true, // always ignore this + }); var rotateOverlayCurrent = Overlays.addOverlay("circle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, - color: { red: 224, green: 67, blue: 36}, - alpha: 0.8, - solid: true, - visible: false, - rotation: yawOverlayRotation, - ignoreRayIntersection: true, // always ignore this - hasTickMarks: true, - majorTickMarksColor: { red: 0, green: 0, blue: 0 }, - minorTickMarksColor: { red: 0, green: 0, blue: 0 }, - }); + position: { + x: 0, + y: 0, + z: 0 + }, + size: 1, + color: { + red: 224, + green: 67, + blue: 36 + }, + alpha: 0.8, + solid: true, + visible: false, + rotation: yawOverlayRotation, + ignoreRayIntersection: true, // always ignore this + hasTickMarks: true, + majorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + minorTickMarksColor: { + red: 0, + green: 0, + blue: 0 + }, + }); var yawHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true, - }); + url: ROTATE_ARROW_WEST_NORTH_URL, + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: false, + drawInFront: true, + }); var pitchHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true, - }); + url: ROTATE_ARROW_WEST_NORTH_URL, + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: false, + drawInFront: true, + }); var rollHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: { x:0, y: 0, z: 0}, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true, - }); + url: ROTATE_ARROW_WEST_NORTH_URL, + position: { + x: 0, + y: 0, + z: 0 + }, + color: handleColor, + alpha: handleAlpha, + visible: false, + size: 0.1, + scale: 0.1, + isFacingAvatar: false, + drawInFront: true, + }); var allOverlays = [ highlightBox, @@ -703,7 +985,7 @@ SelectionDisplay = (function () { overlayNames[grabberEdgeNL] = "grabberEdgeNL"; overlayNames[grabberEdgeFR] = "grabberEdgeFR"; overlayNames[grabberEdgeFL] = "grabberEdgeFL"; - + overlayNames[yawHandle] = "yawHandle"; overlayNames[pitchHandle] = "pitchHandle"; overlayNames[rollHandle] = "rollHandle"; @@ -718,6 +1000,7 @@ SelectionDisplay = (function () { var activeTool = null; var grabberTools = {}; + function addGrabberTool(overlay, tool) { grabberTools[overlay] = { mode: tool.mode, @@ -727,8 +1010,8 @@ SelectionDisplay = (function () { } } - - that.cleanup = function () { + + that.cleanup = function() { for (var i = 0; i < allOverlays.length; i++) { Overlays.deleteOverlay(allOverlays[i]); } @@ -741,19 +1024,21 @@ SelectionDisplay = (function () { var properties = Entities.getEntityProperties(entityID); Overlays.editOverlay(highlightBox, { visible: true, - position: properties.boundingBox.center, + position: properties.boundingBox.center, dimensions: properties.dimensions, rotation: properties.rotation }); }; that.unhighlightSelectable = function(entityID) { - Overlays.editOverlay(highlightBox,{ visible: false}); + Overlays.editOverlay(highlightBox, { + visible: false + }); }; that.select = function(entityID, event) { var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - + lastCameraPosition = Camera.getPosition(); lastCameraOrientation = Camera.getOrientation(); @@ -766,12 +1051,16 @@ SelectionDisplay = (function () { print(" event.y:" + event.y); Vec3.print(" current position:", properties.position); } - - + + } - Entities.editEntity(entityID, { localRenderAlpha: 0.1 }); - Overlays.editOverlay(highlightBox, { visible: false }); + Entities.editEntity(entityID, { + localRenderAlpha: 0.1 + }); + Overlays.editOverlay(highlightBox, { + visible: false + }); that.updateHandles(); } @@ -789,7 +1078,7 @@ SelectionDisplay = (function () { } var rotateHandleOffset = 0.05; - + var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF; var dimensions, rotation; @@ -828,136 +1117,320 @@ SelectionDisplay = (function () { * ------------------------------*/ - + var cameraPosition = Camera.getPosition(); if (cameraPosition.x > objectCenter.x) { // must be BRF or BRN if (cameraPosition.z < objectCenter.z) { - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 90, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 90, z: 0 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 0 }); + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 90, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 90, + z: 0 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 0 + }); - yawNormal = { x: 0, y: 1, z: 0 }; - pitchNormal = { x: 1, y: 0, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; - yawCorner = { x: left + rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: near - rotateHandleOffset }; + yawCorner = { + x: left + rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: near - rotateHandleOffset + }; - pitchCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset}; + pitchCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - rollCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset }; + rollCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z}; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far }; - + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + pitchCenter = { + x: right, + y: boundsCenter.y, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: far + }; + + + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_SOUTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_SOUTH_URL + }); - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL }); - } else { - - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 0, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 90 }); - yawNormal = { x: 0, y: 1, z: 0 }; - pitchNormal = { x: 1, y: 0, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 0, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 180, + y: 270, + z: 0 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 90 + }); + + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; - yawCorner = { x: left + rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: far + rotateHandleOffset }; + yawCorner = { + x: left + rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: far + rotateHandleOffset + }; - pitchCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset }; + pitchCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - rollCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset}; + rollCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z }; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near}; + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + pitchCenter = { + x: right, + y: boundsCenter.y, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: near + }; - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); } } else { - + // must be BLF or BLN if (cameraPosition.z < objectCenter.z) { - - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 180, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 90, y: 0, z: 90 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 }); - yawNormal = { x: 0, y: 1, z: 0 }; - pitchNormal = { x: 1, y: 0, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 180, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 90, + y: 0, + z: 90 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 180 + }); - yawCorner = { x: right - rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: near - rotateHandleOffset }; + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; - pitchCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset }; + yawCorner = { + x: right - rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: near - rotateHandleOffset + }; - rollCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset}; + pitchCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z }; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far}; + rollCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + pitchCenter = { + x: left, + y: boundsCenter.y, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: far + }; + + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); } else { - - yawHandleRotation = Quat.fromVec3Degrees({ x: 270, y: 270, z: 0 }); - pitchHandleRotation = Quat.fromVec3Degrees({ x: 180, y: 270, z: 0 }); - rollHandleRotation = Quat.fromVec3Degrees({ x: 0, y: 0, z: 180 }); - yawNormal = { x: 0, y: 1, z: 0 }; - rollNormal = { x: 0, y: 0, z: 1 }; - pitchNormal = { x: 1, y: 0, z: 0 }; + yawHandleRotation = Quat.fromVec3Degrees({ + x: 270, + y: 270, + z: 0 + }); + pitchHandleRotation = Quat.fromVec3Degrees({ + x: 180, + y: 270, + z: 0 + }); + rollHandleRotation = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: 180 + }); - yawCorner = { x: right - rotateHandleOffset, - y: bottom - rotateHandleOffset, - z: far + rotateHandleOffset }; + yawNormal = { + x: 0, + y: 1, + z: 0 + }; + rollNormal = { + x: 0, + y: 0, + z: 1 + }; + pitchNormal = { + x: 1, + y: 0, + z: 0 + }; - rollCorner = { x: right - rotateHandleOffset, - y: top + rotateHandleOffset, - z: near - rotateHandleOffset }; + yawCorner = { + x: right - rotateHandleOffset, + y: bottom - rotateHandleOffset, + z: far + rotateHandleOffset + }; - pitchCorner = { x: left + rotateHandleOffset, - y: top + rotateHandleOffset, - z: far + rotateHandleOffset}; + rollCorner = { + x: right - rotateHandleOffset, + y: top + rotateHandleOffset, + z: near - rotateHandleOffset + }; - yawCenter = { x: boundsCenter.x, y: bottom, z: boundsCenter.z }; - rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near }; - pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z}; + pitchCorner = { + x: left + rotateHandleOffset, + y: top + rotateHandleOffset, + z: far + rotateHandleOffset + }; - Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); - Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + yawCenter = { + x: boundsCenter.x, + y: bottom, + z: boundsCenter.z + }; + rollCenter = { + x: boundsCenter.x, + y: boundsCenter.y, + z: near + }; + pitchCenter = { + x: left, + y: boundsCenter.y, + z: boundsCenter.z + }; + + Overlays.editOverlay(pitchHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); + Overlays.editOverlay(rollHandle, { + url: ROTATE_ARROW_WEST_NORTH_URL + }); } } - + var rotateHandlesVisible = true; var rotationOverlaysVisible = false; var translateHandlesVisible = true; @@ -984,20 +1457,38 @@ SelectionDisplay = (function () { rotateHandlesVisible = false; translateHandlesVisible = false; } - + var rotation = selectionManager.worldRotation; var dimensions = selectionManager.worldDimensions; var position = selectionManager.worldPosition; - - Overlays.editOverlay(rotateOverlayTarget, { visible: rotationOverlaysVisible }); - Overlays.editOverlay(rotateZeroOverlay, { visible: rotationOverlaysVisible }); - Overlays.editOverlay(rotateCurrentOverlay, { visible: rotationOverlaysVisible }); + + Overlays.editOverlay(rotateOverlayTarget, { + visible: rotationOverlaysVisible + }); + Overlays.editOverlay(rotateZeroOverlay, { + visible: rotationOverlaysVisible + }); + Overlays.editOverlay(rotateCurrentOverlay, { + visible: rotationOverlaysVisible + }); // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden - Overlays.editOverlay(yawHandle, { visible: rotateHandlesVisible, position: yawCorner, rotation: yawHandleRotation}); - Overlays.editOverlay(pitchHandle, { visible: rotateHandlesVisible, position: pitchCorner, rotation: pitchHandleRotation}); - Overlays.editOverlay(rollHandle, { visible: rotateHandlesVisible, position: rollCorner, rotation: rollHandleRotation}); + Overlays.editOverlay(yawHandle, { + visible: rotateHandlesVisible, + position: yawCorner, + rotation: yawHandleRotation + }); + Overlays.editOverlay(pitchHandle, { + visible: rotateHandlesVisible, + position: pitchCorner, + rotation: pitchHandleRotation + }); + Overlays.editOverlay(rollHandle, { + visible: rotateHandlesVisible, + position: rollCorner, + rotation: rollHandleRotation + }); }; that.setSpaceMode = function(newSpaceMode) { @@ -1016,8 +1507,7 @@ SelectionDisplay = (function () { that.updateHandles(); }; - that.unselectAll = function () { - }; + that.unselectAll = function() {}; that.updateHandles = function() { if (SelectionManager.selections.length == 0) { @@ -1061,34 +1551,138 @@ SelectionDisplay = (function () { var worldTop = SelectionManager.worldDimensions.y / 2; - var LBN = { x: left, y: bottom, z: near }; - var RBN = { x: right, y: bottom, z: near }; - var LBF = { x: left, y: bottom, z: far }; - var RBF = { x: right, y: bottom, z: far }; - var LTN = { x: left, y: top, z: near }; - var RTN = { x: right, y: top, z: near }; - var LTF = { x: left, y: top, z: far }; - var RTF = { x: right, y: top, z: far }; + var LBN = { + x: left, + y: bottom, + z: near + }; + var RBN = { + x: right, + y: bottom, + z: near + }; + var LBF = { + x: left, + y: bottom, + z: far + }; + var RBF = { + x: right, + y: bottom, + z: far + }; + var LTN = { + x: left, + y: top, + z: near + }; + var RTN = { + x: right, + y: top, + z: near + }; + var LTF = { + x: left, + y: top, + z: far + }; + var RTF = { + x: right, + y: top, + z: far + }; - var TOP = { x: center.x, y: top, z: center.z }; - var BOTTOM = { x: center.x, y: bottom, z: center.z }; - var LEFT = { x: left, y: center.y, z: center.z }; - var RIGHT = { x: right, y: center.y, z: center.z }; - var NEAR = { x: center.x, y: center.y, z: near }; - var FAR = { x: center.x, y: center.y, z: far }; + var TOP = { + x: center.x, + y: top, + z: center.z + }; + var BOTTOM = { + x: center.x, + y: bottom, + z: center.z + }; + var LEFT = { + x: left, + y: center.y, + z: center.z + }; + var RIGHT = { + x: right, + y: center.y, + z: center.z + }; + var NEAR = { + x: center.x, + y: center.y, + z: near + }; + var FAR = { + x: center.x, + y: center.y, + z: far + }; - var EdgeTR = { x: right, y: top, z: center.z }; - var EdgeTL = { x: left, y: top, z: center.z }; - var EdgeTF = { x: center.x, y: top, z: front }; - var EdgeTN = { x: center.x, y: top, z: near }; - var EdgeBR = { x: right, y: bottom, z: center.z }; - var EdgeBL = { x: left, y: bottom, z: center.z }; - var EdgeBF = { x: center.x, y: bottom, z: front }; - var EdgeBN = { x: center.x, y: bottom, z: near }; - var EdgeNR = { x: right, y: center.y, z: near }; - var EdgeNL = { x: left, y: center.y, z: near }; - var EdgeFR = { x: right, y: center.y, z: front }; - var EdgeFL = { x: left, y: center.y, z: front }; + var EdgeTR = { + x: right, + y: top, + z: center.z + }; + var EdgeTL = { + x: left, + y: top, + z: center.z + }; + var EdgeTF = { + x: center.x, + y: top, + z: front + }; + var EdgeTN = { + x: center.x, + y: top, + z: near + }; + var EdgeBR = { + x: right, + y: bottom, + z: center.z + }; + var EdgeBL = { + x: left, + y: bottom, + z: center.z + }; + var EdgeBF = { + x: center.x, + y: bottom, + z: front + }; + var EdgeBN = { + x: center.x, + y: bottom, + z: near + }; + var EdgeNR = { + x: right, + y: center.y, + z: near + }; + var EdgeNL = { + x: left, + y: center.y, + z: near + }; + var EdgeFR = { + x: right, + y: center.y, + z: front + }; + var EdgeFL = { + x: left, + y: center.y, + z: front + }; LBN = Vec3.multiplyQbyV(rotation, LBN); RBN = Vec3.multiplyQbyV(rotation, RBN); @@ -1151,7 +1745,7 @@ SelectionDisplay = (function () { var stretchHandlesVisible = spaceMode == SPACE_LOCAL; var extendedStretchHandlesVisible = stretchHandlesVisible && showExtendedStretchHandles; - if (selectionManager.selections.length == 1 ) { + if (selectionManager.selections.length == 1) { var properties = Entities.getEntityProperties(selectionManager.selections[0]); if (properties.type == "Light" && properties.isSpotlight == true) { var stretchHandlesVisible = false; @@ -1190,7 +1784,11 @@ SelectionDisplay = (function () { }); Overlays.editOverlay(grabberSpotLightCircle, { position: NEAR, - dimensions: { x: distance, y: distance, z: 1 }, + dimensions: { + x: distance, + y: distance, + z: 1 + }, lineWidth: 1.5, rotation: rotation, visible: true, @@ -1217,15 +1815,33 @@ SelectionDisplay = (function () { visible: true, }); - Overlays.editOverlay(grabberPointLightCircleX, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleY, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleZ, { visible: false }); - Overlays.editOverlay(grabberPointLightT, { visible: false }); - Overlays.editOverlay(grabberPointLightB, { visible: false }); - Overlays.editOverlay(grabberPointLightL, { visible: false }); - Overlays.editOverlay(grabberPointLightR, { visible: false }); - Overlays.editOverlay(grabberPointLightF, { visible: false }); - Overlays.editOverlay(grabberPointLightN, { visible: false }); + Overlays.editOverlay(grabberPointLightCircleX, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleY, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleZ, { + visible: false + }); + Overlays.editOverlay(grabberPointLightT, { + visible: false + }); + Overlays.editOverlay(grabberPointLightB, { + visible: false + }); + Overlays.editOverlay(grabberPointLightL, { + visible: false + }); + Overlays.editOverlay(grabberPointLightR, { + visible: false + }); + Overlays.editOverlay(grabberPointLightF, { + visible: false + }); + Overlays.editOverlay(grabberPointLightN, { + visible: false + }); } else if (properties.type == "Light" && properties.isSpotlight == false) { var stretchHandlesVisible = false; var extendedStretchHandlesVisible = false; @@ -1262,75 +1878,203 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberPointLightCircleX, { position: position, rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, 90, 0)), - dimensions: { x: properties.dimensions.z / 2.0, y: properties.dimensions.z / 2.0, z: 1 }, + dimensions: { + x: properties.dimensions.z / 2.0, + y: properties.dimensions.z / 2.0, + z: 1 + }, visible: true, }); Overlays.editOverlay(grabberPointLightCircleY, { position: position, rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(90, 0, 0)), - dimensions: { x: properties.dimensions.z / 2.0, y: properties.dimensions.z / 2.0, z: 1 }, + dimensions: { + x: properties.dimensions.z / 2.0, + y: properties.dimensions.z / 2.0, + z: 1 + }, visible: true, }); Overlays.editOverlay(grabberPointLightCircleZ, { position: position, rotation: rotation, - dimensions: { x: properties.dimensions.z / 2.0, y: properties.dimensions.z / 2.0, z: 1 }, + dimensions: { + x: properties.dimensions.z / 2.0, + y: properties.dimensions.z / 2.0, + z: 1 + }, visible: true, }); - Overlays.editOverlay(grabberSpotLightRadius, { visible: false }); - Overlays.editOverlay(grabberSpotLightL, { visible: false }); - Overlays.editOverlay(grabberSpotLightR, { visible: false }); - Overlays.editOverlay(grabberSpotLightT, { visible: false }); - Overlays.editOverlay(grabberSpotLightB, { visible: false }); - Overlays.editOverlay(grabberSpotLightCircle, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineL, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineR, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineT, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineB, { visible: false }); + Overlays.editOverlay(grabberSpotLightRadius, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightB, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightCircle, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineB, { + visible: false + }); } else { - Overlays.editOverlay(grabberSpotLightCenter, { visible: false }); - Overlays.editOverlay(grabberSpotLightRadius, { visible: false }); - Overlays.editOverlay(grabberSpotLightL, { visible: false }); - Overlays.editOverlay(grabberSpotLightR, { visible: false }); - Overlays.editOverlay(grabberSpotLightT, { visible: false }); - Overlays.editOverlay(grabberSpotLightB, { visible: false }); - Overlays.editOverlay(grabberSpotLightCircle, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineL, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineR, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineT, { visible: false }); - Overlays.editOverlay(grabberSpotLightLineB, { visible: false }); + Overlays.editOverlay(grabberSpotLightCenter, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightRadius, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightB, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightCircle, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineL, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineR, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineT, { + visible: false + }); + Overlays.editOverlay(grabberSpotLightLineB, { + visible: false + }); - Overlays.editOverlay(grabberPointLightCircleX, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleY, { visible: false }); - Overlays.editOverlay(grabberPointLightCircleZ, { visible: false }); - Overlays.editOverlay(grabberPointLightT, { visible: false }); - Overlays.editOverlay(grabberPointLightB, { visible: false }); - Overlays.editOverlay(grabberPointLightL, { visible: false }); - Overlays.editOverlay(grabberPointLightR, { visible: false }); - Overlays.editOverlay(grabberPointLightF, { visible: false }); - Overlays.editOverlay(grabberPointLightN, { visible: false }); + Overlays.editOverlay(grabberPointLightCircleX, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleY, { + visible: false + }); + Overlays.editOverlay(grabberPointLightCircleZ, { + visible: false + }); + Overlays.editOverlay(grabberPointLightT, { + visible: false + }); + Overlays.editOverlay(grabberPointLightB, { + visible: false + }); + Overlays.editOverlay(grabberPointLightL, { + visible: false + }); + Overlays.editOverlay(grabberPointLightR, { + visible: false + }); + Overlays.editOverlay(grabberPointLightF, { + visible: false + }); + Overlays.editOverlay(grabberPointLightN, { + visible: false + }); } } - Overlays.editOverlay(grabberLBN, { visible: stretchHandlesVisible, rotation: rotation, position: LBN }); - Overlays.editOverlay(grabberRBN, { visible: stretchHandlesVisible, rotation: rotation, position: RBN }); - Overlays.editOverlay(grabberLBF, { visible: stretchHandlesVisible, rotation: rotation, position: LBF }); - Overlays.editOverlay(grabberRBF, { visible: stretchHandlesVisible, rotation: rotation, position: RBF }); + Overlays.editOverlay(grabberLBN, { + visible: stretchHandlesVisible, + rotation: rotation, + position: LBN + }); + Overlays.editOverlay(grabberRBN, { + visible: stretchHandlesVisible, + rotation: rotation, + position: RBN + }); + Overlays.editOverlay(grabberLBF, { + visible: stretchHandlesVisible, + rotation: rotation, + position: LBF + }); + Overlays.editOverlay(grabberRBF, { + visible: stretchHandlesVisible, + rotation: rotation, + position: RBF + }); - Overlays.editOverlay(grabberLTN, { visible: extendedStretchHandlesVisible, rotation: rotation, position: LTN }); - Overlays.editOverlay(grabberRTN, { visible: extendedStretchHandlesVisible, rotation: rotation, position: RTN }); - Overlays.editOverlay(grabberLTF, { visible: extendedStretchHandlesVisible, rotation: rotation, position: LTF }); - Overlays.editOverlay(grabberRTF, { visible: extendedStretchHandlesVisible, rotation: rotation, position: RTF }); + Overlays.editOverlay(grabberLTN, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: LTN + }); + Overlays.editOverlay(grabberRTN, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: RTN + }); + Overlays.editOverlay(grabberLTF, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: LTF + }); + Overlays.editOverlay(grabberRTF, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: RTF + }); - Overlays.editOverlay(grabberTOP, { visible: stretchHandlesVisible, rotation: rotation, position: TOP }); - Overlays.editOverlay(grabberBOTTOM, { visible: stretchHandlesVisible, rotation: rotation, position: BOTTOM }); - Overlays.editOverlay(grabberLEFT, { visible: extendedStretchHandlesVisible, rotation: rotation, position: LEFT }); - Overlays.editOverlay(grabberRIGHT, { visible: extendedStretchHandlesVisible, rotation: rotation, position: RIGHT }); - Overlays.editOverlay(grabberNEAR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: NEAR }); - Overlays.editOverlay(grabberFAR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: FAR }); + Overlays.editOverlay(grabberTOP, { + visible: stretchHandlesVisible, + rotation: rotation, + position: TOP + }); + Overlays.editOverlay(grabberBOTTOM, { + visible: stretchHandlesVisible, + rotation: rotation, + position: BOTTOM + }); + Overlays.editOverlay(grabberLEFT, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: LEFT + }); + Overlays.editOverlay(grabberRIGHT, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: RIGHT + }); + Overlays.editOverlay(grabberNEAR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: NEAR + }); + Overlays.editOverlay(grabberFAR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: FAR + }); var boxPosition = Vec3.multiplyQbyV(rotation, center); boxPosition = Vec3.sum(position, boxPosition); @@ -1346,9 +2090,17 @@ SelectionDisplay = (function () { for (var i = 0; i < overlaysNeeded; i++) { selectionBoxes.push( Overlays.addOverlay("cube", { - position: { x: 0, y: 0, z: 0 }, + position: { + x: 0, + y: 0, + z: 0 + }, size: 1, - color: { red: 255, green: 153, blue: 0 }, + color: { + red: 255, + green: 153, + blue: 0 + }, alpha: 1, solid: false, visible: false, @@ -1366,7 +2118,11 @@ SelectionDisplay = (function () { // Adjust overlay position to take registrationPoint into account // centeredRP = registrationPoint with range [-0.5, 0.5] - var centeredRP = Vec3.subtract(properties.registrationPoint, { x: 0.5, y: 0.5, z: 0.5 }); + var centeredRP = Vec3.subtract(properties.registrationPoint, { + x: 0.5, + y: 0.5, + z: 0.5 + }); var offset = vec3Mult(properties.dimensions, centeredRP); offset = Vec3.multiply(-1, offset); offset = Vec3.multiplyQbyV(properties.rotation, offset); @@ -1382,25 +2138,81 @@ SelectionDisplay = (function () { } // Hide any remaining selection boxes for (; i < selectionBoxes.length; i++) { - Overlays.editOverlay(selectionBoxes[i], { visible: false }); + Overlays.editOverlay(selectionBoxes[i], { + visible: false + }); } - Overlays.editOverlay(grabberEdgeTR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTR }); - Overlays.editOverlay(grabberEdgeTL, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTL }); - Overlays.editOverlay(grabberEdgeTF, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTF }); - Overlays.editOverlay(grabberEdgeTN, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeTN }); - Overlays.editOverlay(grabberEdgeBR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBR }); - Overlays.editOverlay(grabberEdgeBL, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBL }); - Overlays.editOverlay(grabberEdgeBF, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBF }); - Overlays.editOverlay(grabberEdgeBN, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeBN }); - Overlays.editOverlay(grabberEdgeNR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeNR }); - Overlays.editOverlay(grabberEdgeNL, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeNL }); - Overlays.editOverlay(grabberEdgeFR, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeFR }); - Overlays.editOverlay(grabberEdgeFL, { visible: extendedStretchHandlesVisible, rotation: rotation, position: EdgeFL }); + Overlays.editOverlay(grabberEdgeTR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTR + }); + Overlays.editOverlay(grabberEdgeTL, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTL + }); + Overlays.editOverlay(grabberEdgeTF, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTF + }); + Overlays.editOverlay(grabberEdgeTN, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeTN + }); + Overlays.editOverlay(grabberEdgeBR, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBR + }); + Overlays.editOverlay(grabberEdgeBL, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBL + }); + Overlays.editOverlay(grabberEdgeBF, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBF + }); + Overlays.editOverlay(grabberEdgeBN, { + visible: stretchHandlesVisible, + rotation: rotation, + position: EdgeBN + }); + Overlays.editOverlay(grabberEdgeNR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeNR + }); + Overlays.editOverlay(grabberEdgeNL, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeNL + }); + Overlays.editOverlay(grabberEdgeFR, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeFR + }); + Overlays.editOverlay(grabberEdgeFL, { + visible: extendedStretchHandlesVisible, + rotation: rotation, + position: EdgeFL + }); var grabberMoveUpOffset = 0.1; - grabberMoveUpPosition = { x: position.x, y: position.y + worldTop + grabberMoveUpOffset, z: position.z } - Overlays.editOverlay(grabberMoveUp, { visible: activeTool == null || mode == "TRANSLATE_UP_DOWN" }); + grabberMoveUpPosition = { + x: position.x, + y: position.y + worldTop + grabberMoveUpOffset, + z: position.z + } + Overlays.editOverlay(grabberMoveUp, { + visible: activeTool == null || mode == "TRANSLATE_UP_DOWN" + }); Overlays.editOverlay(baseOfEntityProjectionOverlay, { visible: mode != "ROTATE_YAW" && mode != "ROTATE_PITCH" && mode != "ROTATE_ROLL", @@ -1423,16 +2235,19 @@ SelectionDisplay = (function () { that.setOverlaysVisible = function(isVisible) { var length = allOverlays.length; for (var i = 0; i < length; i++) { - Overlays.editOverlay(allOverlays[i], { visible: isVisible }); + Overlays.editOverlay(allOverlays[i], { + visible: isVisible + }); } length = selectionBoxes.length; for (var i = 0; i < length; i++) { - Overlays.editOverlay(selectionBoxes[i], { visible: isVisible }); + Overlays.editOverlay(selectionBoxes[i], { + visible: isVisible + }); } }; - that.unselect = function (entityID) { - }; + that.unselect = function(entityID) {}; var initialXZPick = null; var isConstrained = false; @@ -1447,7 +2262,11 @@ SelectionDisplay = (function () { var dimensions = SelectionManager.worldDimensions; var pickRay = Camera.computePickRay(event.x, event.y); - initialXZPick = rayPlaneIntersection(pickRay, startPosition, { x: 0, y: 1, z: 0 }); + initialXZPick = rayPlaneIntersection(pickRay, startPosition, { + x: 0, + y: 1, + z: 0 + }); // Duplicate entities if alt is pressed. This will make a // copy of the selected entities and move the _original_ entities, not @@ -1473,13 +2292,21 @@ SelectionDisplay = (function () { onEnd: function(event, reason) { pushCommandForSelections(duplicatedEntityIDs); - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + Overlays.editOverlay(xRailOverlay, { + visible: false + }); + Overlays.editOverlay(zRailOverlay, { + visible: false + }); }, onMove: function(event) { pickRay = Camera.computePickRay(event.x, event.y); - var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 }); + var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { + x: 0, + y: 1, + z: 0 + }); var vector = Vec3.subtract(pick, initialXZPick); // If shifted, constrain to one axis @@ -1490,19 +2317,49 @@ SelectionDisplay = (function () { vector.x = 0; } if (!isConstrained) { - Overlays.editOverlay(xRailOverlay, { visible: true }); - var xStart = Vec3.sum(startPosition, { x: -10000, y: 0, z: 0 }); - var xEnd = Vec3.sum(startPosition, { x: 10000, y: 0, z: 0 }); - var zStart = Vec3.sum(startPosition, { x: 0, y: 0, z: -10000 }); - var zEnd = Vec3.sum(startPosition, { x: 0, y: 0, z: 10000 }); - Overlays.editOverlay(xRailOverlay, { start: xStart, end: xEnd, visible: true }); - Overlays.editOverlay(zRailOverlay, { start: zStart, end: zEnd, visible: true }); + Overlays.editOverlay(xRailOverlay, { + visible: true + }); + var xStart = Vec3.sum(startPosition, { + x: -10000, + y: 0, + z: 0 + }); + var xEnd = Vec3.sum(startPosition, { + x: 10000, + y: 0, + z: 0 + }); + var zStart = Vec3.sum(startPosition, { + x: 0, + y: 0, + z: -10000 + }); + var zEnd = Vec3.sum(startPosition, { + x: 0, + y: 0, + z: 10000 + }); + Overlays.editOverlay(xRailOverlay, { + start: xStart, + end: xEnd, + visible: true + }); + Overlays.editOverlay(zRailOverlay, { + start: zStart, + end: zEnd, + visible: true + }); isConstrained = true; } } else { if (isConstrained) { - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + Overlays.editOverlay(xRailOverlay, { + visible: false + }); + Overlays.editOverlay(zRailOverlay, { + visible: false + }); isConstrained = false; } } @@ -1510,14 +2367,18 @@ SelectionDisplay = (function () { constrainMajorOnly = event.isControl; var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, selectionManager.worldDimensions)); vector = Vec3.subtract( - grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), - cornerPosition); + 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]]; - var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z }); + var newPosition = Vec3.sum(properties.position, { + x: vector.x, + y: 0, + z: vector.z + }); Entities.editEntity(SelectionManager.selections[i], { position: newPosition, }); @@ -1533,7 +2394,7 @@ SelectionDisplay = (function () { SelectionManager._update(); } }; - + var lastXYPick = null var upDownPickNormal = null; addGrabberTool(grabberMoveUp, { @@ -1579,11 +2440,11 @@ SelectionDisplay = (function () { var vector = Vec3.subtract(newIntersection, lastXYPick); vector = grid.snapToGrid(vector); - + // we only care about the Y axis vector.x = 0; vector.z = 0; - + var wantDebug = false; if (wantDebug) { print("translateUpDown... "); @@ -1609,12 +2470,16 @@ SelectionDisplay = (function () { }); var vec3Mult = function(v1, v2) { - return { x: v1.x * v2.x, y: v1.y * v2.y, z: v1.z * v2.z }; - } - // stretchMode - name of mode - // direction - direction to stretch in - // pivot - point to use as a pivot - // offset - the position of the overlay tool relative to the selections center position + return { + x: v1.x * v2.x, + y: v1.y * v2.y, + z: v1.z * v2.z + }; + } + // stretchMode - name of mode + // direction - direction to stretch in + // pivot - point to use as a pivot + // offset - the position of the overlay tool relative to the selections center position var makeStretchTool = function(stretchMode, direction, pivot, offset, customOnMove) { var signs = { x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0), @@ -1659,7 +2524,11 @@ SelectionDisplay = (function () { } // Modify range of registrationPoint to be [-0.5, 0.5] - var centeredRP = Vec3.subtract(registrationPoint, { x: 0.5, y: 0.5, z: 0.5 }); + var centeredRP = Vec3.subtract(registrationPoint, { + x: 0.5, + y: 0.5, + z: 0.5 + }); // Scale pivot to be in the same range as registrationPoint var scaledPivot = Vec3.multiply(0.5, pivot) @@ -1675,9 +2544,17 @@ SelectionDisplay = (function () { pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); if (numDimensions == 1 && mask.x) { - var start = Vec3.multiplyQbyV(rotation, { x: -10000, y: 0, z: 0 }); + var start = Vec3.multiplyQbyV(rotation, { + x: -10000, + y: 0, + z: 0 + }); start = Vec3.sum(start, properties.position); - var end = Vec3.multiplyQbyV(rotation, { x: 10000, y: 0, z: 0 }); + var end = Vec3.multiplyQbyV(rotation, { + x: 10000, + y: 0, + z: 0 + }); end = Vec3.sum(end, properties.position); Overlays.editOverlay(xRailOverlay, { start: start, @@ -1686,9 +2563,17 @@ SelectionDisplay = (function () { }); } if (numDimensions == 1 && mask.y) { - var start = Vec3.multiplyQbyV(rotation, { x: 0, y: -10000, z: 0 }); + var start = Vec3.multiplyQbyV(rotation, { + x: 0, + y: -10000, + z: 0 + }); start = Vec3.sum(start, properties.position); - var end = Vec3.multiplyQbyV(rotation, { x: 0, y: 10000, z: 0 }); + var end = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 10000, + z: 0 + }); end = Vec3.sum(end, properties.position); Overlays.editOverlay(yRailOverlay, { start: start, @@ -1697,9 +2582,17 @@ SelectionDisplay = (function () { }); } if (numDimensions == 1 && mask.z) { - var start = Vec3.multiplyQbyV(rotation, { x: 0, y: 0, z: -10000 }); + var start = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 0, + z: -10000 + }); start = Vec3.sum(start, properties.position); - var end = Vec3.multiplyQbyV(rotation, { x: 0, y: 0, z: 10000 }); + var end = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 0, + z: 10000 + }); end = Vec3.sum(end, properties.position); Overlays.editOverlay(zRailOverlay, { start: start, @@ -1709,26 +2602,50 @@ SelectionDisplay = (function () { } if (numDimensions == 1) { if (mask.x == 1) { - planeNormal = { x: 0, y: 1, z: 0 }; + planeNormal = { + x: 0, + y: 1, + z: 0 + }; } else if (mask.y == 1) { - planeNormal = { x: 1, y: 0, z: 0 }; + planeNormal = { + x: 1, + y: 0, + z: 0 + }; } else { - planeNormal = { x: 0, y: 1, z: 0 }; + planeNormal = { + x: 0, + y: 1, + z: 0 + }; } } else if (numDimensions == 2) { if (mask.x == 0) { - planeNormal = { x: 1, y: 0, z: 0 }; + planeNormal = { + x: 1, + y: 0, + z: 0 + }; } else if (mask.y == 0) { - planeNormal = { x: 0, y: 1, z: 0 }; + planeNormal = { + x: 0, + y: 1, + z: 0 + }; } else { - planeNormal = { x: 0, y: 0, z: z }; + planeNormal = { + x: 0, + y: 0, + z: z + }; } } planeNormal = Vec3.multiplyQbyV(rotation, planeNormal); var pickRay = Camera.computePickRay(event.x, event.y); lastPick = rayPlaneIntersection(pickRay, - pickRayPosition, - planeNormal); + pickRayPosition, + planeNormal); // Overlays.editOverlay(normalLine, { // start: initialPosition, @@ -1739,9 +2656,15 @@ SelectionDisplay = (function () { }; var onEnd = function(event, reason) { - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(yRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + Overlays.editOverlay(xRailOverlay, { + visible: false + }); + Overlays.editOverlay(yRailOverlay, { + visible: false + }); + Overlays.editOverlay(zRailOverlay, { + visible: false + }); pushCommandForSelections(); }; @@ -1762,8 +2685,8 @@ SelectionDisplay = (function () { var pickRay = Camera.computePickRay(event.x, event.y); newPick = rayPlaneIntersection(pickRay, - pickRayPosition, - planeNormal); + pickRayPosition, + planeNormal); var vector = Vec3.subtract(newPick, lastPick); vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); @@ -1798,14 +2721,14 @@ SelectionDisplay = (function () { } else { newDimensions = Vec3.sum(initialDimensions, changeInDimensions); } - + newDimensions.x = Math.max(newDimensions.x, MINIMUM_DIMENSION); newDimensions.y = Math.max(newDimensions.y, MINIMUM_DIMENSION); newDimensions.z = Math.max(newDimensions.z, MINIMUM_DIMENSION); - + var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(deltaPivot, changeInDimensions)); var newPosition = Vec3.sum(initialPosition, changeInPosition); - + for (var i = 0; i < SelectionManager.selections.length; i++) { Entities.editEntity(SelectionManager.selections[i], { position: newPosition, @@ -1882,7 +2805,11 @@ SelectionDisplay = (function () { size = props.dimensions.z + change.z; } - var newDimensions = { x: size, y: size, z: size }; + var newDimensions = { + x: size, + y: size, + z: size + }; Entities.editEntity(selectionManager.selections[0], { dimensions: newDimensions, @@ -1891,47 +2818,411 @@ SelectionDisplay = (function () { SelectionManager._update(); } - addStretchTool(grabberNEAR, "STRETCH_NEAR", { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }); - addStretchTool(grabberFAR, "STRETCH_FAR", { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }); - addStretchTool(grabberTOP, "STRETCH_TOP", { x: 0, y: -1, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }); - addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { x: 0, y: 1, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }); - addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { x: -1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }); - addStretchTool(grabberLEFT, "STRETCH_LEFT", { x: 1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }); + addStretchTool(grabberNEAR, "STRETCH_NEAR", { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: -1 + }); + addStretchTool(grabberFAR, "STRETCH_FAR", { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: 0, + z: 1 + }); + addStretchTool(grabberTOP, "STRETCH_TOP", { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }); + addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }); + addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { + x: -1, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }); + addStretchTool(grabberLEFT, "STRETCH_LEFT", { + x: 1, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }); - addStretchTool(grabberSpotLightRadius, "STRETCH_RADIUS", { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }); - addStretchTool(grabberSpotLightT, "STRETCH_CUTOFF_T", { x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 1, z: 0 }, cutoffStretchFunc); - addStretchTool(grabberSpotLightB, "STRETCH_CUTOFF_B", { x: 0, y: 0, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: -1, z: 0 }, cutoffStretchFunc); - addStretchTool(grabberSpotLightL, "STRETCH_CUTOFF_L", { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, cutoffStretchFunc); - addStretchTool(grabberSpotLightR, "STRETCH_CUTOFF_R", { x: 0, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, cutoffStretchFunc); + addStretchTool(grabberSpotLightRadius, "STRETCH_RADIUS", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: -1 + }); + addStretchTool(grabberSpotLightT, "STRETCH_CUTOFF_T", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, cutoffStretchFunc); + addStretchTool(grabberSpotLightB, "STRETCH_CUTOFF_B", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, cutoffStretchFunc); + addStretchTool(grabberSpotLightL, "STRETCH_CUTOFF_L", { + x: 0, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, cutoffStretchFunc); + addStretchTool(grabberSpotLightR, "STRETCH_CUTOFF_R", { + x: 0, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, cutoffStretchFunc); - addStretchTool(grabberPointLightT, "STRETCH_RADIUS_T", { x: 0, y: 0, z: 0 }, { x: 0, y: -1, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightB, "STRETCH_RADIUS_B", { x: 0, y: 0, z: 0 }, { x: 0, y: 1, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightL, "STRETCH_RADIUS_L", { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightR, "STRETCH_RADIUS_R", { x: 0, y: 0, z: 0 }, { x: -1, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightF, "STRETCH_RADIUS_F", { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: -1 }, { x: 0, y: 0, z: 1 }, radiusStretchFunc); - addStretchTool(grabberPointLightN, "STRETCH_RADIUS_N", { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 1 }, { x: 0, y: 0, z: -1 }, radiusStretchFunc); + addStretchTool(grabberPointLightT, "STRETCH_RADIUS_T", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: -1, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightB, "STRETCH_RADIUS_B", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 1, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightL, "STRETCH_RADIUS_L", { + x: 0, + y: 0, + z: 0 + }, { + x: 1, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightR, "STRETCH_RADIUS_R", { + x: 0, + y: 0, + z: 0 + }, { + x: -1, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightF, "STRETCH_RADIUS_F", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: 0, + z: 1 + }, radiusStretchFunc); + addStretchTool(grabberPointLightN, "STRETCH_RADIUS_N", { + x: 0, + y: 0, + z: 0 + }, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: 0, + z: -1 + }, radiusStretchFunc); - addStretchTool(grabberLBN, "STRETCH_LBN", null, {x: 1, y: 0, z: 1}, { x: -1, y: -1, z: -1 }); - addStretchTool(grabberRBN, "STRETCH_RBN", null, {x: -1, y: 0, z: 1}, { x: 1, y: -1, z: -1 }); - addStretchTool(grabberLBF, "STRETCH_LBF", null, {x: 1, y: 0, z: -1}, { x: -1, y: -1, z: 1 }); - addStretchTool(grabberRBF, "STRETCH_RBF", null, {x: -1, y: 0, z: -1}, { x: 1, y: -1, z: 1 }); - addStretchTool(grabberLTN, "STRETCH_LTN", null, {x: 1, y: 0, z: 1}, { x: -1, y: 1, z: -1 }); - addStretchTool(grabberRTN, "STRETCH_RTN", null, {x: -1, y: 0, z: 1}, { x: 1, y: 1, z: -1 }); - addStretchTool(grabberLTF, "STRETCH_LTF", null, {x: 1, y: 0, z: -1}, { x: -1, y: 1, z: 1 }); - addStretchTool(grabberRTF, "STRETCH_RTF", null, {x: -1, y: 0, z: -1}, { x: 1, y: 1, z: 1 }); + addStretchTool(grabberLBN, "STRETCH_LBN", null, { + x: 1, + y: 0, + z: 1 + }, { + x: -1, + y: -1, + z: -1 + }); + addStretchTool(grabberRBN, "STRETCH_RBN", null, { + x: -1, + y: 0, + z: 1 + }, { + x: 1, + y: -1, + z: -1 + }); + addStretchTool(grabberLBF, "STRETCH_LBF", null, { + x: 1, + y: 0, + z: -1 + }, { + x: -1, + y: -1, + z: 1 + }); + addStretchTool(grabberRBF, "STRETCH_RBF", null, { + x: -1, + y: 0, + z: -1 + }, { + x: 1, + y: -1, + z: 1 + }); + addStretchTool(grabberLTN, "STRETCH_LTN", null, { + x: 1, + y: 0, + z: 1 + }, { + x: -1, + y: 1, + z: -1 + }); + addStretchTool(grabberRTN, "STRETCH_RTN", null, { + x: -1, + y: 0, + z: 1 + }, { + x: 1, + y: 1, + z: -1 + }); + addStretchTool(grabberLTF, "STRETCH_LTF", null, { + x: 1, + y: 0, + z: -1 + }, { + x: -1, + y: 1, + z: 1 + }); + addStretchTool(grabberRTF, "STRETCH_RTF", null, { + x: -1, + y: 0, + z: -1 + }, { + x: 1, + y: 1, + z: 1 + }); - addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, {x: 1, y: 1, z: 0}, { x: 1, y: 1, z: 0 }); - addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, {x: -1, y: 1, z: 0}, { x: -1, y: 1, z: 0 }); - addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, {x: 0, y: 1, z: -1}, { x: 0, y: 1, z: -1 }); - addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, {x: 0, y: 1, z: 1}, { x: 0, y: 1, z: 1 }); - addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, {x: -1, y: 0, z: 0}, { x: 1, y: -1, z: 0 }); - addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, {x: 1, y: 0, z: 0}, { x: -1, y: -1, z: 0 }); - addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, {x: 0, y: 0, z: -1}, { x: 0, y: -1, z: -1 }); - addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, {x: 0, y: 0, z: 1}, { x: 0, y: -1, z: 1 }); - addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, {x: -1, y: 0, z: 1}, { x: 1, y: 0, z: -1 }); - addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, {x: 1, y: 0, z: 1}, { x: -1, y: 0, z: -1 }); - addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, {x: -1, y: 0, z: -1}, { x: 1, y: 0, z: 1 }); - addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, {x: 1, y: 0, z: -1}, { x: -1, y: 0, z: 1 }); + addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, { + x: 1, + y: 1, + z: 0 + }, { + x: 1, + y: 1, + z: 0 + }); + addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, { + x: -1, + y: 1, + z: 0 + }, { + x: -1, + y: 1, + z: 0 + }); + addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, { + x: 0, + y: 1, + z: -1 + }, { + x: 0, + y: 1, + z: -1 + }); + addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, { + x: 0, + y: 1, + z: 1 + }, { + x: 0, + y: 1, + z: 1 + }); + addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, { + x: -1, + y: 0, + z: 0 + }, { + x: 1, + y: -1, + z: 0 + }); + addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, { + x: 1, + y: 0, + z: 0 + }, { + x: -1, + y: -1, + z: 0 + }); + addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, { + x: 0, + y: 0, + z: -1 + }, { + x: 0, + y: -1, + z: -1 + }); + addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, { + x: 0, + y: 0, + z: 1 + }, { + x: 0, + y: -1, + z: 1 + }); + addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, { + x: -1, + y: 0, + z: 1 + }, { + x: 1, + y: 0, + z: -1 + }); + addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, { + x: 1, + y: 0, + z: 1 + }, { + x: -1, + y: 0, + z: -1 + }); + addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, { + x: -1, + y: 0, + z: -1 + }, { + x: 1, + y: 0, + z: 1 + }); + addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, { + x: 1, + y: 0, + z: -1 + }, { + x: -1, + y: 0, + z: 1 + }); function updateRotationDegreesOverlay(angleFromZero, handleRotation, centerPosition) { var angle = angleFromZero * (Math.PI / 180); @@ -1967,34 +3258,31 @@ SelectionDisplay = (function () { outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, - { - visible: true, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + size: innerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: innerAlpha + }); - Overlays.editOverlay(rotateOverlayOuter, - { - visible: true, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: true, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); Overlays.editOverlay(rotationDegreesDisplay, { visible: true, @@ -2003,19 +3291,35 @@ SelectionDisplay = (function () { updateRotationDegreesOverlay(0, yawHandleRotation, yawCenter); }, onEnd: function(event, reason) { - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); + Overlays.editOverlay(rotationDegreesDisplay, { + visible: false + }); pushCommandForSelections(); }, onMove: function(event) { var pickRay = Camera.computePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); - Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); - + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(baseOfEntityProjectionOverlay, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(rotateOverlayTarget, { + ignoreRayIntersection: false + }); + var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2028,7 +3332,11 @@ SelectionDisplay = (function () { var snapToInner = distanceFromCenter < innerRadius; var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); + var yawChange = Quat.fromVec3Degrees({ + x: 0, + y: angleFromZero, + z: 0 + }); // Entities should only reposition if we are rotating multiple selections around // the selections center point. Otherwise, the rotation will be around the entities @@ -2066,19 +3374,43 @@ SelectionDisplay = (function () { endAtRemainder = startAtCurrent; } if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius, - majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, minorTickMarksLength: 0, }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: innerRadius, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + }); } else { - Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius, - majorTickMarksAngle: 45.0, minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: outerRadius, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + }); } - + } } }); @@ -2096,34 +3428,31 @@ SelectionDisplay = (function () { outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, - { - visible: true, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + size: innerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: innerAlpha + }); - Overlays.editOverlay(rotateOverlayOuter, - { - visible: true, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: true, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); Overlays.editOverlay(rotationDegreesDisplay, { visible: true, @@ -2132,18 +3461,34 @@ SelectionDisplay = (function () { updateRotationDegreesOverlay(0, pitchHandleRotation, pitchCenter); }, onEnd: function(event, reason) { - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); + Overlays.editOverlay(rotationDegreesDisplay, { + visible: false + }); pushCommandForSelections(); }, onMove: function(event) { var pickRay = Camera.computePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); - Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(baseOfEntityProjectionOverlay, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(rotateOverlayTarget, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2158,8 +3503,12 @@ SelectionDisplay = (function () { var snapToInner = distanceFromCenter < innerRadius; var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - - var pitchChange = Quat.fromVec3Degrees({ x: angleFromZero, y: 0, z: 0 }); + + var pitchChange = Quat.fromVec3Degrees({ + x: angleFromZero, + y: 0, + z: 0 + }); for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; @@ -2188,17 +3537,41 @@ SelectionDisplay = (function () { endAtRemainder = startAtCurrent; } if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius, - majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, minorTickMarksLength: 0, }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: innerRadius, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + }); } else { - Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius, - majorTickMarksAngle: 45.0, minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: outerRadius, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + }); } } } @@ -2217,34 +3590,31 @@ SelectionDisplay = (function () { outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, - { - visible: true, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + size: innerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: innerAlpha + }); - Overlays.editOverlay(rotateOverlayOuter, - { - visible: true, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: true, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); Overlays.editOverlay(rotationDegreesDisplay, { visible: true, @@ -2253,18 +3623,34 @@ SelectionDisplay = (function () { updateRotationDegreesOverlay(0, rollHandleRotation, rollCenter); }, onEnd: function(event, reason) { - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); + Overlays.editOverlay(rotationDegreesDisplay, { + visible: false + }); pushCommandForSelections(); }, onMove: function(event) { var pickRay = Camera.computePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); - Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(baseOfEntityProjectionOverlay, { + ignoreRayIntersection: true, + visible: false + }); + Overlays.editOverlay(rotateOverlayTarget, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2280,7 +3666,11 @@ SelectionDisplay = (function () { var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - var rollChange = Quat.fromVec3Degrees({ x: 0, y: 0, z: angleFromZero }); + var rollChange = Quat.fromVec3Degrees({ + x: 0, + y: 0, + z: angleFromZero + }); for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; var properties = Entities.getEntityProperties(entityID); @@ -2308,17 +3698,41 @@ SelectionDisplay = (function () { endAtRemainder = startAtCurrent; } if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayInner, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: innerRadius, - majorTickMarksAngle: innerSnapAngle, minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, minorTickMarksLength: 0, }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: innerRadius, + majorTickMarksAngle: innerSnapAngle, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + }); } else { - Overlays.editOverlay(rotateOverlayInner, { startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayOuter, { startAt: startAtRemainder, endAt: endAtRemainder }); - Overlays.editOverlay(rotateOverlayCurrent, { startAt: startAtCurrent, endAt: endAtCurrent, size: outerRadius, - majorTickMarksAngle: 45.0, minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, minorTickMarksLength: 0.1, }); + Overlays.editOverlay(rotateOverlayInner, { + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayOuter, { + startAt: startAtRemainder, + endAt: endAtRemainder + }); + Overlays.editOverlay(rotateOverlayCurrent, { + startAt: startAtCurrent, + endAt: endAtCurrent, + size: outerRadius, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + }); } } } @@ -2329,10 +3743,10 @@ SelectionDisplay = (function () { // FIXME - this cause problems with editing in the entity properties window //SelectionManager._update(); - + if (!Vec3.equal(Camera.getPosition(), lastCameraPosition) || !Quat.equal(Camera.getOrientation(), lastCameraOrientation)) { - + that.updateRotationHandles(); } } @@ -2347,12 +3761,20 @@ SelectionDisplay = (function () { var somethingClicked = false; var pickRay = Camera.computePickRay(event.x, event.y); - + // before we do a ray test for grabbers, disable the ray intersection for our selection box - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true }); - Overlays.editOverlay(yawHandle, { ignoreRayIntersection: true }); - Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: true }); - Overlays.editOverlay(rollHandle, { ignoreRayIntersection: true }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: true + }); + Overlays.editOverlay(yawHandle, { + ignoreRayIntersection: true + }); + Overlays.editOverlay(pitchHandle, { + ignoreRayIntersection: true + }); + Overlays.editOverlay(rollHandle, { + ignoreRayIntersection: true + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { @@ -2377,14 +3799,16 @@ SelectionDisplay = (function () { activeTool.onBegin(event); } } else { - switch(result.overlayID) { + switch (result.overlayID) { case grabberMoveUp: mode = "TRANSLATE_UP_DOWN"; somethingClicked = true; // in translate mode, we hide our stretch handles... for (var i = 0; i < stretchHandles.length; i++) { - Overlays.editOverlay(stretchHandles[i], { visible: false }); + Overlays.editOverlay(stretchHandles[i], { + visible: false + }); } break; @@ -2397,8 +3821,8 @@ SelectionDisplay = (function () { break; case grabberFAR: - case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching? - case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching? + case grabberEdgeTF: // TODO: maybe this should be TOP+FAR stretching? + case grabberEdgeBF: // TODO: maybe this should be BOTTOM+FAR stretching? mode = "STRETCH_FAR"; somethingClicked = true; break; @@ -2411,14 +3835,14 @@ SelectionDisplay = (function () { somethingClicked = true; break; case grabberRIGHT: - case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching? - case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching? + case grabberEdgeTR: // TODO: maybe this should be TOP+RIGHT stretching? + case grabberEdgeBR: // TODO: maybe this should be BOTTOM+RIGHT stretching? mode = "STRETCH_RIGHT"; somethingClicked = true; break; case grabberLEFT: - case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching? - case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching? + case grabberEdgeTL: // TODO: maybe this should be TOP+LEFT stretching? + case grabberEdgeBL: // TODO: maybe this should be BOTTOM+LEFT stretching? mode = "STRETCH_LEFT"; somethingClicked = true; break; @@ -2429,29 +3853,43 @@ SelectionDisplay = (function () { } } } - + // if one of the items above was clicked, then we know we are in translate or stretch mode, and we // should hide our rotate handles... if (somethingClicked) { - Overlays.editOverlay(yawHandle, { visible: false }); - Overlays.editOverlay(pitchHandle, { visible: false }); - Overlays.editOverlay(rollHandle, { visible: false }); - + Overlays.editOverlay(yawHandle, { + visible: false + }); + Overlays.editOverlay(pitchHandle, { + visible: false + }); + Overlays.editOverlay(rollHandle, { + visible: false + }); + if (mode != "TRANSLATE_UP_DOWN") { - Overlays.editOverlay(grabberMoveUp, { visible: false }); + Overlays.editOverlay(grabberMoveUp, { + visible: false + }); } } - + if (!somethingClicked) { - + print("rotate handle case..."); - + // After testing our stretch handles, then check out rotate handles - Overlays.editOverlay(yawHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(rollHandle, { ignoreRayIntersection: false }); + Overlays.editOverlay(yawHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(pitchHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(rollHandle, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); - + var overlayOrientation; var overlayCenter; @@ -2460,12 +3898,12 @@ SelectionDisplay = (function () { var pitch = angles.x; var yaw = angles.y; var roll = angles.z; - + originalRotation = properties.rotation; originalPitch = pitch; originalYaw = yaw; originalRoll = roll; - + if (result.intersects) { var tool = grabberTools[result.overlayID]; if (tool) { @@ -2476,7 +3914,7 @@ SelectionDisplay = (function () { activeTool.onBegin(event); } } - switch(result.overlayID) { + switch (result.overlayID) { case yawHandle: mode = "ROTATE_YAW"; somethingClicked = true; @@ -2514,59 +3952,147 @@ SelectionDisplay = (function () { print(" somethingClicked:" + somethingClicked); print(" mode:" + mode); - + if (somethingClicked) { - - Overlays.editOverlay(rotateOverlayTarget, { visible: true, rotation: overlayOrientation, position: overlayCenter }); - Overlays.editOverlay(rotateOverlayInner, { visible: true, rotation: overlayOrientation, position: overlayCenter }); - Overlays.editOverlay(rotateOverlayOuter, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 360 }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 0 }); - Overlays.editOverlay(yawHandle, { visible: false }); - Overlays.editOverlay(pitchHandle, { visible: false }); - Overlays.editOverlay(rollHandle, { visible: false }); + + Overlays.editOverlay(rotateOverlayTarget, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter + }); + Overlays.editOverlay(rotateOverlayInner, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter, + startAt: 0, + endAt: 360 + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: true, + rotation: overlayOrientation, + position: overlayCenter, + startAt: 0, + endAt: 0 + }); + Overlays.editOverlay(yawHandle, { + visible: false + }); + Overlays.editOverlay(pitchHandle, { + visible: false + }); + Overlays.editOverlay(rollHandle, { + visible: false + }); - Overlays.editOverlay(yawHandle, { visible: false }); - Overlays.editOverlay(pitchHandle, { visible: false }); - Overlays.editOverlay(rollHandle, { visible: false }); - Overlays.editOverlay(grabberMoveUp, { visible: false }); - Overlays.editOverlay(grabberLBN, { visible: false }); - Overlays.editOverlay(grabberLBF, { visible: false }); - Overlays.editOverlay(grabberRBN, { visible: false }); - Overlays.editOverlay(grabberRBF, { visible: false }); - Overlays.editOverlay(grabberLTN, { visible: false }); - Overlays.editOverlay(grabberLTF, { visible: false }); - Overlays.editOverlay(grabberRTN, { visible: false }); - Overlays.editOverlay(grabberRTF, { visible: false }); + Overlays.editOverlay(yawHandle, { + visible: false + }); + Overlays.editOverlay(pitchHandle, { + visible: false + }); + Overlays.editOverlay(rollHandle, { + visible: false + }); + Overlays.editOverlay(grabberMoveUp, { + visible: false + }); + Overlays.editOverlay(grabberLBN, { + visible: false + }); + Overlays.editOverlay(grabberLBF, { + visible: false + }); + Overlays.editOverlay(grabberRBN, { + visible: false + }); + Overlays.editOverlay(grabberRBF, { + visible: false + }); + Overlays.editOverlay(grabberLTN, { + visible: false + }); + Overlays.editOverlay(grabberLTF, { + visible: false + }); + Overlays.editOverlay(grabberRTN, { + visible: false + }); + Overlays.editOverlay(grabberRTF, { + visible: false + }); - Overlays.editOverlay(grabberTOP, { visible: false }); - Overlays.editOverlay(grabberBOTTOM, { visible: false }); - Overlays.editOverlay(grabberLEFT, { visible: false }); - Overlays.editOverlay(grabberRIGHT, { visible: false }); - Overlays.editOverlay(grabberNEAR, { visible: false }); - Overlays.editOverlay(grabberFAR, { visible: false }); + Overlays.editOverlay(grabberTOP, { + visible: false + }); + Overlays.editOverlay(grabberBOTTOM, { + visible: false + }); + Overlays.editOverlay(grabberLEFT, { + visible: false + }); + Overlays.editOverlay(grabberRIGHT, { + visible: false + }); + Overlays.editOverlay(grabberNEAR, { + visible: false + }); + Overlays.editOverlay(grabberFAR, { + visible: false + }); - Overlays.editOverlay(grabberEdgeTR, { visible: false }); - Overlays.editOverlay(grabberEdgeTL, { visible: false }); - Overlays.editOverlay(grabberEdgeTF, { visible: false }); - Overlays.editOverlay(grabberEdgeTN, { visible: false }); - Overlays.editOverlay(grabberEdgeBR, { visible: false }); - Overlays.editOverlay(grabberEdgeBL, { visible: false }); - Overlays.editOverlay(grabberEdgeBF, { visible: false }); - Overlays.editOverlay(grabberEdgeBN, { visible: false }); - Overlays.editOverlay(grabberEdgeNR, { visible: false }); - Overlays.editOverlay(grabberEdgeNL, { visible: false }); - Overlays.editOverlay(grabberEdgeFR, { visible: false }); - Overlays.editOverlay(grabberEdgeFL, { visible: false }); + Overlays.editOverlay(grabberEdgeTR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeTL, { + visible: false + }); + Overlays.editOverlay(grabberEdgeTF, { + visible: false + }); + Overlays.editOverlay(grabberEdgeTN, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBL, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBF, { + visible: false + }); + Overlays.editOverlay(grabberEdgeBN, { + visible: false + }); + Overlays.editOverlay(grabberEdgeNR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeNL, { + visible: false + }); + Overlays.editOverlay(grabberEdgeFR, { + visible: false + }); + Overlays.editOverlay(grabberEdgeFL, { + visible: false + }); } } if (!somethingClicked) { - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: false }); + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: false + }); var result = Overlays.findRayIntersection(pickRay); if (result.intersects) { - switch(result.overlayID) { + switch (result.overlayID) { case selectionBox: activeTool = translateXZTool; mode = translateXZTool.mode; @@ -2584,17 +4110,25 @@ SelectionDisplay = (function () { if (somethingClicked) { pickRay = Camera.computePickRay(event.x, event.y); if (wantDebug) { - print("mousePressEvent()...... " + overlayNames[result.overlayID]); + print("mousePressEvent()...... " + overlayNames[result.overlayID]); } } // reset everything as intersectable... // TODO: we could optimize this since some of these were already flipped back - Overlays.editOverlay(selectionBox, { ignoreRayIntersection: false }); - Overlays.editOverlay(yawHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(pitchHandle, { ignoreRayIntersection: false }); - Overlays.editOverlay(rollHandle, { ignoreRayIntersection: false }); - + Overlays.editOverlay(selectionBox, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(yawHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(pitchHandle, { + ignoreRayIntersection: false + }); + Overlays.editOverlay(rollHandle, { + ignoreRayIntersection: false + }); + return somethingClicked; }; @@ -2613,7 +4147,7 @@ SelectionDisplay = (function () { var highlightNeeded = false; if (result.intersects) { - switch(result.overlayID) { + switch (result.overlayID) { case yawHandle: case pitchHandle: case rollHandle: @@ -2621,7 +4155,7 @@ SelectionDisplay = (function () { pickedAlpha = handleAlpha; highlightNeeded = true; break; - + case grabberMoveUp: pickedColor = handleColor; pickedAlpha = handleAlpha; @@ -2682,30 +4216,42 @@ SelectionDisplay = (function () { default: if (previousHandle) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha }); + Overlays.editOverlay(previousHandle, { + color: previousHandleColor, + alpha: previousHandleAlpha + }); previousHandle = false; } break; } - + if (highlightNeeded) { if (previousHandle) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha }); + Overlays.editOverlay(previousHandle, { + color: previousHandleColor, + alpha: previousHandleAlpha + }); previousHandle = false; } - Overlays.editOverlay(result.overlayID, { color: highlightedHandleColor, alpha: highlightedHandleAlpha }); + Overlays.editOverlay(result.overlayID, { + color: highlightedHandleColor, + alpha: highlightedHandleAlpha + }); previousHandle = result.overlayID; previousHandleColor = pickedColor; previousHandleAlpha = pickedAlpha; } - + } else { if (previousHandle) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor, alpha: previousHandleAlpha }); + Overlays.editOverlay(previousHandle, { + color: previousHandleColor, + alpha: previousHandleAlpha + }); previousHandle = false; } } - + return false; }; @@ -2728,7 +4274,11 @@ SelectionDisplay = (function () { Overlays.editOverlay(rollHandle, { scale: handleSize, }); - var pos = Vec3.sum(grabberMoveUpPosition, { x: 0, y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3, z: 0 }); + var pos = Vec3.sum(grabberMoveUpPosition, { + x: 0, + y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3, + z: 0 + }); Overlays.editOverlay(grabberMoveUp, { position: pos, scale: handleSize / 2, @@ -2745,34 +4295,43 @@ SelectionDisplay = (function () { activeTool = null; // hide our rotation overlays..., and show our handles if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL") { - Overlays.editOverlay(rotateOverlayTarget, { visible: false }); - Overlays.editOverlay(rotateOverlayInner, { visible: false }); - Overlays.editOverlay(rotateOverlayOuter, { visible: false }); - Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); + Overlays.editOverlay(rotateOverlayTarget, { + visible: false + }); + Overlays.editOverlay(rotateOverlayInner, { + visible: false + }); + Overlays.editOverlay(rotateOverlayOuter, { + visible: false + }); + Overlays.editOverlay(rotateOverlayCurrent, { + visible: false + }); showHandles = true; } if (mode != "UNKNOWN") { showHandles = true; } - + mode = "UNKNOWN"; - + // if something is selected, then reset the "original" properties for any potential next click+move operation if (SelectionManager.hasSelection()) { if (showHandles) { that.select(SelectionManager.selections[0], event); } } - + }; // NOTE: mousePressEvent and mouseMoveEvent from the main script should call us., so we don't hook these: // Controller.mousePressEvent.connect(that.mousePressEvent); // Controller.mouseMoveEvent.connect(that.mouseMoveEvent); Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent); - + + + return that; -}()); - +}()); \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 8eae5cc2a4..8f71f161a2 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -25,7 +25,7 @@ var lightOverlayManager; if (SHOW_OVERLAYS === true) { Script.include('../libraries/gridTool.js'); - Script.include('../libraries/entitySelectionTool.js'); + Script.include('../libraries/entitySelectionTool.js?'+Math.random(0-100)); Script.include('../libraries/lightOverlayManager.js'); var grid = Grid(); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 761eb4786d..8381b9d434 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -10,6 +10,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?'+Math.random(0-100)); var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot))); @@ -74,6 +75,7 @@ function createBlock() { blue: 255 }, position: position, + script:PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { disableReleaseVelocity: true diff --git a/examples/light_modifier/lightParent.js b/examples/light_modifier/lightParent.js new file mode 100644 index 0000000000..2d7cfe8042 --- /dev/null +++ b/examples/light_modifier/lightParent.js @@ -0,0 +1,42 @@ + // + // slider.js + // + // Created by James Pollack @imgntn on 12/15/2015 + // Copyright 2015 High Fidelity, Inc. + // + // Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. + // + // Distributed under the Apache License, Version 2.0. + // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + // + + (function() { + + function LightParent() { + return this; + } + + LightParent.prototype = { + preload: function(entityID) { + print('LIGHT PARENT SCRIPT GO') + this.entityID = entityID; + var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + this.initialProperties = entityProperties + this.userData = JSON.parse(entityProperties.userData); + }, + startNearGrab: function() {}, + startDistantGrab: function() { + + }, + continueNearGrab: function() { + this.continueDistantGrab(); + }, + continueDistantGrab: function() { + print('distant grab, should send message!') + Messages.sendMessage('entityToolUpdates', 'callUpdate'); + }, + + }; + + return new LightParent(); + }); \ No newline at end of file From 82c865af2c79be998c3d9c72abb6cfd87d3a9cdd Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 17 Dec 2015 12:20:38 -0800 Subject: [PATCH 165/318] Rename QmlWebWindow to OverlayWebWindow, move ctor registration to script engine --- examples/tests/qmlWebTest.js | 2 +- interface/src/Application.cpp | 1 - libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 3 +++ tests/ui/src/main.cpp | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/tests/qmlWebTest.js b/examples/tests/qmlWebTest.js index 250852abe7..f905e494dc 100644 --- a/examples/tests/qmlWebTest.js +++ b/examples/tests/qmlWebTest.js @@ -1,6 +1,6 @@ print("Launching web window"); -webWindow = new QmlWebWindow('Test Event Bridge', "file:///C:/Users/bdavis/Git/hifi/examples/html/qmlWebTest.html", 320, 240, false); +webWindow = new OverlayWebWindow('Test Event Bridge', "file:///C:/Users/bdavis/Git/hifi/examples/html/qmlWebTest.html", 320, 240, false); print("JS Side window: " + webWindow); print("JS Side bridge: " + webWindow.eventBridge); webWindow.eventBridge.webEventReceived.connect(function(data) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0d41f0426..8bff85688e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4155,7 +4155,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); - scriptEngine->registerFunction("QmlWebWindow", QmlWebWindowClass::constructor); scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 3796abd92a..c1131765f7 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME script-engine) setup_hifi_library(Gui Network Script WebSockets Widgets) -link_hifi_libraries(shared networking octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) +link_hifi_libraries(shared networking ui octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ded3db11e9..5f39bee9fa 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -350,6 +351,8 @@ void ScriptEngine::init() { qScriptRegisterSequenceMetaType >(this); qScriptRegisterSequenceMetaType >(this); + + registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor); QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 75397ad95f..00d1f2dc00 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -250,7 +250,7 @@ private: registerGlobalObject("Script", this); qScriptRegisterSequenceMetaType>(this); qScriptRegisterSequenceMetaType>(this); - globalObject().setProperty("QmlWebWindow", newFunction(QmlWebWindowClass::constructor)); + globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor)); QScriptValue printConstructorValue = newFunction(debugPrint); globalObject().setProperty("print", printConstructorValue); } From 5088eec2a2a2bd67f442083c285dd90573b2818e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 17 Dec 2015 12:23:39 -0800 Subject: [PATCH 166/318] Move directory web UI into the overlay --- examples/directory.js | 2 +- interface/resources/qml/QmlWebWindow.qml | 20 +++++++++++++++++++- libraries/ui/src/QmlWebWindowClass.cpp | 7 +++++++ libraries/ui/src/QmlWebWindowClass.h | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/examples/directory.js b/examples/directory.js index b1fac19e8b..d2a3768051 100644 --- a/examples/directory.js +++ b/examples/directory.js @@ -62,7 +62,7 @@ var directory = (function () { function setUp() { viewport = Controller.getViewportDimensions(); - directoryWindow = new WebWindow('Directory', DIRECTORY_URL, 900, 700, false); + directoryWindow = new OverlayWebWindow('Directory', DIRECTORY_URL, 900, 700, false); directoryWindow.setVisible(false); directoryButton = Overlays.addOverlay("image", { diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index d59ef4955e..9664c0edb8 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -19,12 +19,27 @@ VrDialog { backgroundColor: "#7f000000" property url source: "about:blank" + signal navigating(string url) + Component.onCompleted: { enabled = true console.log("Web Window Created " + root); webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); }); + + webview.loadingChanged.connect(handleWebviewLoading) + } + + + function handleWebviewLoading(loadRequest) { + var HIFI_URL_PATTERN = /^hifi:\/\//; + if (WebEngineView.LoadStartedStatus == loadRequest.status) { + var newUrl = loadRequest.url.toString(); + if (newUrl.match(HIFI_URL_PATTERN)) { + root.navigating(newUrl); + } + } } Item { @@ -35,11 +50,14 @@ VrDialog { y: root.clientY width: root.clientWidth height: root.clientHeight - + WebEngineView { id: webview url: root.source anchors.fill: parent + profile: WebEngineProfile { + httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)" + } } } // item } // dialog diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 3797034e79..2b7270edf0 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "impl/websocketclientwrapper.h" @@ -86,8 +87,14 @@ QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) qDebug() << "Created window with ID " << _windowId; Q_ASSERT(_qmlWindow); Q_ASSERT(dynamic_cast(_qmlWindow)); + QObject::connect(_qmlWindow, SIGNAL(navigating(QString)), this, SLOT(handleNavigation(QString))); } +void QmlWebWindowClass::handleNavigation(const QString& url) { + DependencyManager::get()->handleLookupString(url); +} + + void QmlWebWindowClass::setVisible(bool visible) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index c166fd2c20..1575ec7916 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -81,6 +81,7 @@ signals: private slots: void hasClosed(); + void handleNavigation(const QString& url); private: QmlScriptEventBridge* _eventBridge; From 6f82d680b9cb7873f091614fde07c6fd055a0ccd Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 12:38:25 -0800 Subject: [PATCH 167/318] removed unwanted file --- examples/flowArts/lightBall/particles.js | 129 ----------------------- 1 file changed, 129 deletions(-) delete mode 100644 examples/flowArts/lightBall/particles.js diff --git a/examples/flowArts/lightBall/particles.js b/examples/flowArts/lightBall/particles.js deleted file mode 100644 index 86616d5099..0000000000 --- a/examples/flowArts/lightBall/particles.js +++ /dev/null @@ -1,129 +0,0 @@ -Script.include("../../libraries/utils.js"); - -LightBall = function(spawnPosition) { - - var colorPalette = [{ - red: 25, - green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(spawnPosition, { - x: 0, - y: .5, - z: 0 - }), - dimensions: { - x: .1, - y: .1, - z: .1 - }, - color: { - red: 15, - green: 10, - blue: 150 - }, - collisionsWillMove: true, - gravity: {x: 0, y: -.5, z: 0}, - visible: false, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: .1, - z: 0 - } - }, - invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var lightBall = Entities.addEntity({ - type: "ParticleEffect", - position: spawnPosition, - // parentID: containerBall, - isEmitting: true, - "name": "ParticlesTest Emitter", - "colorStart": { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - "colorFinish": { - red: 25, - green: 20, - blue: 255 - }, - "maxParticles": 100000, - "lifespan": 2, - "emitRate": 10000, - "emitSpeed": .0, - "speedSpread": 0.0, - "emitDimensions": { - "x": 5, - "y":0 , - "z": 0 - }, - // "polarStart": 0, - // "polarFinish": Math.PI, - // "azimuthStart": -Math.PI, - // "azimuthFinish": Math.PI, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": .00, - "y": .0, - "z": .00 - }, - "particleRadius": 0.02, - "radiusSpread": 0, - "radiusStart": 0.03, - "radiusFinish": 0.0003, - "alpha": 0, - "alphaSpread": .5, - "alphaStart": 0, - "alphaFinish": 0.5, - // "textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - "textures": "file:///C:/Users/Eric/Desktop/Particle-Sprite-Smoke-1.png?v1" + Math.random(), - emitterShouldTrail: true - }) - - - - function cleanup() { - Entities.deleteEntity(lightBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } - - this.cleanup = cleanup; -} - -LightBall(); \ No newline at end of file From 92f96cbb2f403a556a62bae17326def1e90c4c8f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 12:49:30 -0800 Subject: [PATCH 168/318] Removed un-needed libraries from particle effect entity --- libraries/entities/src/ParticleEffectEntityItem.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index da8e369841..16196aa129 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include "EntityTree.h" #include "EntityTreeElement.h" From 035ca25b485d6d712abeac8975bd9eecda455fe1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 13:31:27 -0800 Subject: [PATCH 169/318] arc ball finds other balls --- examples/flowArts/arcBall/arcBall.js | 149 ++++++++++++++++++ .../flowArts/arcBall/arcBallEntityScript.js | 45 ++++++ examples/flowArts/flowArtsHutSpawner.js | 9 +- examples/flowArts/lightBall/lightBall.js | 10 +- 4 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 examples/flowArts/arcBall/arcBall.js create mode 100644 examples/flowArts/arcBall/arcBallEntityScript.js diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js new file mode 100644 index 0000000000..3853830863 --- /dev/null +++ b/examples/flowArts/arcBall/arcBall.js @@ -0,0 +1,149 @@ +// +// arcBall.js +// examples/arcBall +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creats a particle light ball which makes particle trails as you move it. +// +// +// 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 scriptURL = Script.resolvePath("arcBallEntityScript.js"); +ArcBall = function(spawnPosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + name: "Arc Ball", + script: scriptURL, + position: Vec3.sum(spawnPosition, { + x: 0, + y: .5, + z: 0 + }), + dimensions: { + x: .1, + y: .1, + z: .1 + }, + color: { + red: 15, + green: 10, + blue: 150 + }, + mass: 10, + collisionsWillMove: true, + // gravity: { + // x: 0, + // y: -0.5, + // z: 0 + // }, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: .1, + z: 0 + } + }, + invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + name: "ballLight", + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var arcBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + name: "Arc Ball Particle Effect", + colorStart: { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: { + red: 25, + green: 20, + blue: 255 + }, + maxParticles: 100000, + lifespan: 2, + emitRate: 10000, + emitSpeed: .1, + lifetime: -1, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 + }, + polarStart: 0, + polarFinish: Math.PI, + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + particleRadius: 0.02, + radiusSpread: 0, + radiusStart: 0.03, + radiusFinish: 0.0003, + alpha: 0, + alphaSpread: .5, + alphaStart: 0, + alphaFinish: 0.5, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true + }) + + + + function cleanup() { + Entities.deleteEntity(arcBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; +} \ No newline at end of file diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js new file mode 100644 index 0000000000..bcdb2bc5a9 --- /dev/null +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -0,0 +1,45 @@ +// arcBallEntityScript.js +// +// Script Type: Entity +// Created by Eric Levin on 12/17/15. +// Copyright 2015 High Fidelity, Inc. +// +// This entity script handles the logic for the arcBall rave toy +// 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 _this; + var ArcBall = function() { + _this = this; + }; + + ArcBall.prototype = { + isGrabbed: false, + startNearGrab: function() { + //Search for nearby balls and create an arc to it if one is found + var position = Entities.getEntityProperties(this.entityID, "position").position + var entities = Entities.findEntities(position, 10); + entities.forEach(function(entity) { + var props = Entities.getEntityProperties(entity, ["position", "name"]); + if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + print ("WE FOUND ANOTHER ARC BALL"); + } + }) + + }, + + continueNearGrab: function() { + }, + + releaseGrab: function() { + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + }; + return new ArcBall(); +}); diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 3762c67fe4..742b239981 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -17,6 +17,7 @@ Script.include("../../libraries/utils.js"); Script.include("lightBall/LightBall.js"); Script.include("raveStick/RaveStick.js"); Script.include("lightSaber/LightSaber.js"); +Script.include("arcBall/ArcBall.js"); @@ -24,7 +25,10 @@ var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Ca basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS -var lightBall = new LightBall(basePosition); +//var lightBall = new LightBall(basePosition); + +var arcBall = new ArcBall(basePosition); +var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); @@ -77,7 +81,8 @@ function cleanup() { Entities.deleteEntity(raveRoom); Entities.deleteEntity(lightZone) Entities.deleteEntity(floor); - lightBall.cleanup(); + arcBall.cleanup(); + arcBall2.cleanup(); raveStick.cleanup(); lightSaber.cleanup(); } diff --git a/examples/flowArts/lightBall/lightBall.js b/examples/flowArts/lightBall/lightBall.js index 1898f86eef..df62b1b786 100644 --- a/examples/flowArts/lightBall/lightBall.js +++ b/examples/flowArts/lightBall/lightBall.js @@ -42,11 +42,11 @@ LightBall = function(spawnPosition) { blue: 150 }, collisionsWillMove: true, - gravity: { - x: 0, - y: -0.5, - z: 0 - }, + // gravity: { + // x: 0, + // y: -0.5, + // z: 0 + // }, userData: JSON.stringify({ grabbableKey: { spatialKey: { From 3e6ae7c5710e99f2508022bb80082b4fcc73911b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 15:02:25 -0800 Subject: [PATCH 170/318] added lightball back --- examples/flowArts/arcBall/arcBall.js | 8 +- .../flowArts/arcBall/arcBallEntityScript.js | 80 +++++++++++++++++-- examples/flowArts/flowArtsHutSpawner.js | 13 +-- .../lightSaber/lightSaberEntityScript.js | 3 +- 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 3853830863..34578cce76 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -35,9 +35,9 @@ ArcBall = function(spawnPosition) { z: 0 }), dimensions: { - x: .1, - y: .1, - z: .1 + x: .2, + y: .2, + z: .2 }, color: { red: 15, @@ -102,7 +102,7 @@ ArcBall = function(spawnPosition) { }, maxParticles: 100000, lifespan: 2, - emitRate: 10000, + emitRate: 1000, emitSpeed: .1, lifetime: -1, speedSpread: 0.0, diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index bcdb2bc5a9..f1ba9aeb95 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -25,16 +25,86 @@ entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { - print ("WE FOUND ANOTHER ARC BALL"); + _this.createBeam(position, props.position); } - }) + }); }, - continueNearGrab: function() { + createBeam: function(startPosition, endPosition) { + print("CREATE BEAM") + // Creates particle arc from start position to end position + var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + + testBox = Entities.addEntity({ + type: "Box", + dimensions: {x: .1, y: .1, z: 1}, + color: {red: 200, green: 10, blue: 10}, + position: startPosition, + rotation: emitOrientation + }); + var color = { + red: 200, + green: 10, + blue: 10 + }; + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 1000, + emitOrientation: emitOrientation, + emitSpeed: .4, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + adiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false + } + this.particleArc = Entities.addEntity(props); }, - releaseGrab: function() { + continueNearGrab: function() {}, + + releaseGrab: function() {}, + + unload: function() { + Entities.deleteEntity(this.particleArc); + Entities.deleteEntity(testBox); }, preload: function(entityID) { @@ -42,4 +112,4 @@ }, }; return new ArcBall(); -}); +}); \ No newline at end of file diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 742b239981..e03d2bf0e8 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -25,10 +25,10 @@ var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Ca basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS -//var lightBall = new LightBall(basePosition); +var lightBall = new LightBall(basePosition); -var arcBall = new ArcBall(basePosition); -var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); +// var arcBall = new ArcBall(basePosition); +// var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); @@ -79,10 +79,11 @@ var lightZone = Entities.addEntity({ function cleanup() { Entities.deleteEntity(raveRoom); - Entities.deleteEntity(lightZone) + Entities.deleteEntity(lightZone); Entities.deleteEntity(floor); - arcBall.cleanup(); - arcBall2.cleanup(); + lightBall.cleanup(); + // arcBall.cleanup(); + // arcBall2.cleanup(); raveStick.cleanup(); lightSaber.cleanup(); } diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 6f396bf6e3..794e241924 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -56,7 +56,8 @@ this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); // forwardVec = Vec3.normalize(forwardVec); - var forwardQuat = orientationOf(forwardVec); + // var forwardQuat = orientationOf(forwardVec); + var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec); var position = Vec3.sum(this.props.position, Vec3.multiply(Quat.getFront(this.props.rotation), 0.1)); position.z += 0.1; position.x += -0.035; From b271542b73b0446e656e016e829adfd2d13c50af Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 12:06:49 -0800 Subject: [PATCH 171/318] Save DebugMode to setting, restore on script start --- examples/utilities/tools/renderEngineDebug.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 2c0dc352b4..5e4eded640 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -1,6 +1,7 @@ // -// SunLightExample.js -// examples +// renderEngineDebug.js +// examples/utilities/tools +// // Sam Gateau // Copyright 2015 High Fidelity, Inc. // @@ -12,6 +13,7 @@ Script.include("cookies.js"); var MENU = "Developer>Render>Debug Deferred Buffer"; var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "Custom"]; +var SETTINGS_KEY = "EngineDebugScript.DebugMode"; Number.prototype.clamp = function(min, max) { return Math.min(Math.max(this, min), max); @@ -69,6 +71,9 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", ); var resizing = false; +var previousMode = Settings.getValue(SETTINGS_KEY, -1); +Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); +Scene.setEngineDeferredDebugMode(previousMode); Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size function setEngineDeferredDebugSize(eventX) { @@ -152,11 +157,11 @@ Controller.mousePressEvent.connect(mousePressEvent); Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Menu.menuItemEvent.connect(menuItemEvent); -Menu.addActionGroup(MENU, ACTIONS, ACTIONS[0]); function scriptEnding() { panel.destroy(); Menu.removeActionGroup(MENU); + Settings.setValue(SETTINGS_KEY, Scene.getEngineDeferredDebugMode()); Scene.setEngineDeferredDebugMode(-1); Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size } From 06d7de7106c4b87e0f5fd83d840a58135acdf3a4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 15:16:37 -0800 Subject: [PATCH 172/318] Make Shader interface take more consts --- libraries/gpu/src/gpu/Shader.cpp | 4 ++-- libraries/gpu/src/gpu/Shader.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index ddb3a0d755..74b7734618 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -23,7 +23,7 @@ Shader::Shader(Type type, const Source& source): { } -Shader::Shader(Type type, Pointer& vertex, Pointer& pixel): +Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel): _type(type) { _shaders.resize(2); @@ -44,7 +44,7 @@ Shader::Pointer Shader::createPixel(const Source& source) { return Pointer(new Shader(PIXEL, source)); } -Shader::Pointer Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { +Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) { if (vertexShader && vertexShader->getType() == VERTEX && pixelShader && pixelShader->getType() == PIXEL) { return Pointer(new Shader(PROGRAM, vertexShader, pixelShader)); diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index bceb00c71e..b737a42e12 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -111,7 +111,7 @@ public: static Pointer createVertex(const Source& source); static Pointer createPixel(const Source& source); - static Pointer createProgram(Pointer& vertexShader, Pointer& pixelShader); + static Pointer createProgram(const Pointer& vertexShader, const Pointer& pixelShader); ~Shader(); @@ -157,7 +157,7 @@ public: protected: Shader(Type type, const Source& source); - Shader(Type type, Pointer& vertex, Pointer& pixel); + Shader(Type type, const Pointer& vertex, const Pointer& pixel); Shader(const Shader& shader); // deep copy of the sysmem shader Shader& operator=(const Shader& shader); // deep copy of the sysmem texture From 9d6618c341236d81d12a4153baa09a82fc4beca8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 15:17:03 -0800 Subject: [PATCH 173/318] Cleanup DebugDeferredBuffer code --- examples/utilities/tools/renderEngineDebug.js | 1 - .../render-utils/src/DebugDeferredBuffer.cpp | 115 ++++++++---------- .../render-utils/src/DebugDeferredBuffer.h | 10 +- .../src/debug_deferred_buffer.slf | 6 +- 4 files changed, 57 insertions(+), 75 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 5e4eded640..5e89bff53b 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -90,7 +90,6 @@ function menuItemEvent(menuItem) { var index = ACTIONS.indexOf(menuItem); if (index >= 0) { Scene.setEngineDeferredDebugMode(index - 1); - print(menuItem); } } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 169ae0b58e..2046a48d4a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -11,8 +11,6 @@ #include "DebugDeferredBuffer.h" -#include - #include #include #include @@ -31,73 +29,62 @@ enum Slots { Normal, Specular, Depth, - Lighting, - - NUM_SLOTS + Lighting }; -static const std::array SLOT_NAMES {{ - "diffuseMap", - "normalMap", - "specularMap", - "depthMap", - "lightingMap" -}}; -static const std::string COMPUTE_PLACEHOLDER { "/*COMPUTE_PLACEHOLDER*/" }; // required -static const std::string FUNCTIONS_PLACEHOLDER { "/*FUNCTIONS_PLACEHOLDER*/" }; // optional - -std::string DebugDeferredBuffer::getCode(Modes mode) { +std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode) { switch (mode) { - case DiffuseMode: { - QString code = "return vec4(pow(texture(%1, uv).xyz, vec3(1.0 / 2.2)), 1.0);"; - return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString(); - } - case AlphaMode: { - QString code = "return vec4(vec3(texture(%1, uv).a), 1.0);"; - return code.arg(SLOT_NAMES[Diffuse].c_str()).toStdString(); - } - case SpecularMode: { - QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; - return code.arg(SLOT_NAMES[Specular].c_str()).toStdString(); - } - case RoughnessMode: { - QString code = "return vec4(vec3(texture(%1, uv).a), 1.0);"; - return code.arg(SLOT_NAMES[Specular].c_str()).toStdString(); - } - case NormalMode: { - QString code = "return vec4(texture(%1, uv).xyz, 1.0);"; - return code.arg(SLOT_NAMES[Normal].c_str()).toStdString(); - } - case DepthMode: { - QString code = "return vec4(vec3(texture(%1, uv).x), 1.0);"; - return code.arg(SLOT_NAMES[Depth].c_str()).toStdString(); - } - case LightingMode: { - QString code = "return vec4(pow(texture(%1, uv).xyz, vec3(1.0 / 2.2)), 1.0);"; - return code.arg(SLOT_NAMES[Lighting].c_str()).toStdString(); - } + case DiffuseMode: + return "vec4 getFragmentColor() { return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0); }"; + case AlphaMode: + return "vec4 getFragmentColor() { return vec4(vec3(texture(diffuseMap, uv).a), 1.0); }"; + case SpecularMode: + return "vec4 getFragmentColor() { return vec4(texture(specularMap, uv).xyz, 1.0); }"; + case RoughnessMode: + return "vec4 getFragmentColor() { return vec4(vec3(texture(specularMap, uv).a), 1.0); }"; + case NormalMode: + return "vec4 getFragmentColor() { return vec4(texture(normalMap, uv).xyz, 1.0); }"; + case DepthMode: + return "vec4 getFragmentColor() { return vec4(vec3(texture(depthMap, uv).x), 1.0); }"; + case LightingMode: + return "vec4 getFragmentColor() { return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0); }"; case CustomMode: - return std::string("return vec4(1.0);"); - case NUM_MODES: - Q_UNIMPLEMENTED(); - return std::string("return vec4(1.0);"); + return "vec4 getFragmentColor() { return vec4(1.0); }"; } } +bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode) const { + if (mode != CustomMode) { + return !_pipelines[mode]; + } + + + + return true; +} + const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode) { - if (!_pipelines[mode]) { - std::string fragmentShader = debug_deferred_buffer_frag; - fragmentShader.replace(fragmentShader.find(COMPUTE_PLACEHOLDER), COMPUTE_PLACEHOLDER.size(), - getCode(mode)); + if (pipelineNeedsUpdate(mode)) { + static const std::string VERTEX_SHADER { debug_deferred_buffer_vert }; + static const std::string FRAGMENT_SHADER { debug_deferred_buffer_frag }; + static const std::string SOURCE_PLACEHOLDER { "//SOURCE_PLACEHOLDER" }; + static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER); + Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, "Could not find source placeholder"); - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex({ debug_deferred_buffer_vert })); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShader)); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto bakedFragmentShader = FRAGMENT_SHADER; + bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), + getShaderSourceCode(mode)); + + const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); + const auto ps = gpu::Shader::createPixel(bakedFragmentShader); + const auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - for (int slot = 0; slot < NUM_SLOTS; ++slot) { - slotBindings.insert(gpu::Shader::Binding(SLOT_NAMES[slot], slot)); - } + slotBindings.insert(gpu::Shader::Binding("diffuseMap", Diffuse)); + 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("lightingMap", Lighting)); gpu::Shader::makeProgram(*program, slotBindings); // Good to go add the brand new pipeline @@ -110,10 +97,10 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode) { void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); - RenderArgs* args = renderContext->args; + const RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - auto geometryBuffer = DependencyManager::get(); - auto framebufferCache = DependencyManager::get(); + const auto geometryBuffer = DependencyManager::get(); + const auto framebufferCache = DependencyManager::get(); glm::mat4 projMat; @@ -132,9 +119,9 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture()); batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture()); - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); - glm::vec2 topRight(renderContext->_deferredDebugSize.z, renderContext->_deferredDebugSize.w); + const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y); + const glm::vec2 topRight(renderContext->_deferredDebugSize.z, renderContext->_deferredDebugSize.w); geometryBuffer->renderQuad(batch, bottomLeft, topRight, color); }); } \ No newline at end of file diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 8628d9e21e..144a72571c 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -21,7 +21,7 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); private: - enum Modes : int { + enum Modes : uint8_t { DiffuseMode = 0, AlphaMode, SpecularMode, @@ -29,15 +29,15 @@ private: NormalMode, DepthMode, LightingMode, - CustomMode, - NUM_MODES + CustomMode // Needs to stay last }; + bool pipelineNeedsUpdate(Modes mode) const; const gpu::PipelinePointer& getPipeline(Modes mode); - std::string getCode(Modes mode); + std::string getShaderSourceCode(Modes mode); - std::array _pipelines; + std::array _pipelines; }; #endif // hifi_DebugDeferredBuffer_h \ No newline at end of file diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index d8ff6e71a9..375972cdc3 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -17,11 +17,7 @@ in vec2 uv; out vec4 outFragColor; -/*FUNCTIONS_PLACEHOLDER*/ - -vec4 getFragmentColor() { - /*COMPUTE_PLACEHOLDER*/ -} +//SOURCE_PLACEHOLDER void main(void) { outFragColor = getFragmentColor(); From d8a389ff925f795ad364e7e1f425b0784af65955 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 17:20:51 -0800 Subject: [PATCH 174/318] First cut at custom pipelines --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 14 +++++++++++--- libraries/render-utils/src/DebugDeferredBuffer.h | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 2046a48d4a..7dbeddd07a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -11,6 +11,8 @@ #include "DebugDeferredBuffer.h" +#include + #include #include #include @@ -32,6 +34,14 @@ enum Slots { Lighting }; +static std::string getFileContent(std::string fileName, std::string defaultContent = std::string()) { + QFile customFile(QString::fromStdString(fileName)); + if (customFile.open(QIODevice::ReadOnly)) { + return customFile.readAll().toStdString(); + } + return defaultContent; +} + std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode) { switch (mode) { case DiffuseMode: @@ -49,7 +59,7 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode) { case LightingMode: return "vec4 getFragmentColor() { return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0); }"; case CustomMode: - return "vec4 getFragmentColor() { return vec4(1.0); }"; + return getFileContent(CUSTOM_FILE, "vec4 getFragmentColor() { return vec4(1.0); }"); } } @@ -58,8 +68,6 @@ bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode) const { return !_pipelines[mode]; } - - return true; } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 144a72571c..a0df42c05a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -33,6 +33,8 @@ private: CustomMode // Needs to stay last }; + const std::string CUSTOM_FILE { "/Users/clement/Desktop/custom.slh" }; + bool pipelineNeedsUpdate(Modes mode) const; const gpu::PipelinePointer& getPipeline(Modes mode); std::string getShaderSourceCode(Modes mode); From f41ca9fc50752913984400514cc15aab32f692d5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 17 Dec 2015 15:13:09 -0800 Subject: [PATCH 175/318] More custom debug work --- .../render-utils/src/DebugDeferredBuffer.cpp | 115 +++++++++++++++--- .../render-utils/src/DebugDeferredBuffer.h | 21 +++- 2 files changed, 111 insertions(+), 25 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 7dbeddd07a..6bdfbb57ff 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -34,56 +34,119 @@ enum Slots { Lighting }; +static const std::string DEEFAULT_DIFFUSE_SHADER { + "vec4 getFragmentColor() {" + " return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" + " }" +}; +static const std::string DEEFAULT_ALPHA_SHADER { + "vec4 getFragmentColor() {" + " return vec4(vec3(texture(diffuseMap, uv).a), 1.0);" + " }" +}; +static const std::string DEEFAULT_SPECULAR_SHADER { + "vec4 getFragmentColor() {" + " return vec4(texture(specularMap, uv).xyz, 1.0);" + " }" +}; +static const std::string DEEFAULT_ROUGHNESS_SHADER { + "vec4 getFragmentColor() {" + " return vec4(vec3(texture(specularMap, uv).a), 1.0);" + " }" +}; +static const std::string DEEFAULT_NORMAL_SHADER { + "vec4 getFragmentColor() {" + " return vec4(texture(normalMap, uv).xyz, 1.0);" + " }" +}; +static const std::string DEEFAULT_DEPTH_SHADER { + "vec4 getFragmentColor() {" + " return vec4(vec3(texture(depthMap, uv).x), 1.0);" + " }" +}; +static const std::string DEEFAULT_LIGHTING_SHADER { + "vec4 getFragmentColor() {" + " return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" + " }" +}; +static const std::string DEEFAULT_CUSTOM_SHADER { + "vec4 getFragmentColor() {" + " return vec4(1.0, 0.0, 0.0, 1.0);" + " }" +}; + static std::string getFileContent(std::string fileName, std::string defaultContent = std::string()) { - QFile customFile(QString::fromStdString(fileName)); + QFile customFile(QUrl(QString::fromStdString(fileName)).toLocalFile()); if (customFile.open(QIODevice::ReadOnly)) { return customFile.readAll().toStdString(); } + qWarning() << "DebugDeferredBuffer::getFileContent(): Could not open" + << QUrl(QString::fromStdString(fileName)).toLocalFile(); return defaultContent; } -std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode) { +#include // TODO REMOVE: Temporary until UI +DebugDeferredBuffer::DebugDeferredBuffer() { + // TODO REMOVE: Temporary until UI + static const auto DESKTOP_PATH = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + static const auto CUSTOM_FILE = "file://" + DESKTOP_PATH.toStdString() + "/custom.slh"; + CustomPipeline pipeline; + pipeline.info = QFileInfo(DESKTOP_PATH + "/custom.slh"); + _customPipelines.emplace(CUSTOM_FILE, pipeline); +} + +std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string customFile) { switch (mode) { case DiffuseMode: - return "vec4 getFragmentColor() { return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0); }"; + return DEEFAULT_DIFFUSE_SHADER; case AlphaMode: - return "vec4 getFragmentColor() { return vec4(vec3(texture(diffuseMap, uv).a), 1.0); }"; + return DEEFAULT_ALPHA_SHADER; case SpecularMode: - return "vec4 getFragmentColor() { return vec4(texture(specularMap, uv).xyz, 1.0); }"; + return DEEFAULT_SPECULAR_SHADER; case RoughnessMode: - return "vec4 getFragmentColor() { return vec4(vec3(texture(specularMap, uv).a), 1.0); }"; + return DEEFAULT_ROUGHNESS_SHADER; case NormalMode: - return "vec4 getFragmentColor() { return vec4(texture(normalMap, uv).xyz, 1.0); }"; + return DEEFAULT_NORMAL_SHADER; case DepthMode: - return "vec4 getFragmentColor() { return vec4(vec3(texture(depthMap, uv).x), 1.0); }"; + return DEEFAULT_DEPTH_SHADER; case LightingMode: - return "vec4 getFragmentColor() { return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0); }"; + return DEEFAULT_LIGHTING_SHADER; case CustomMode: - return getFileContent(CUSTOM_FILE, "vec4 getFragmentColor() { return vec4(1.0); }"); + return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER); } } -bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode) const { +bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode, std::string customFile) const { if (mode != CustomMode) { return !_pipelines[mode]; } + auto it = _customPipelines.find(customFile); + if (it != _customPipelines.end() && it->second.pipeline) { + auto& info = it->second.info; + + auto lastModified = info.lastModified(); + info.refresh(); + return lastModified != info.lastModified(); + } + return true; } -const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode) { - if (pipelineNeedsUpdate(mode)) { +const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::string customFile) { + if (pipelineNeedsUpdate(mode, customFile)) { static const std::string VERTEX_SHADER { debug_deferred_buffer_vert }; static const std::string FRAGMENT_SHADER { debug_deferred_buffer_frag }; static const std::string SOURCE_PLACEHOLDER { "//SOURCE_PLACEHOLDER" }; static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER); - Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, "Could not find source placeholder"); + Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, + "Could not find source placeholder"); auto bakedFragmentShader = FRAGMENT_SHADER; bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), - getShaderSourceCode(mode)); + getShaderSourceCode(mode, customFile)); - const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); + static const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); const auto ps = gpu::Shader::createPixel(bakedFragmentShader); const auto program = gpu::Shader::createProgram(vs, ps); @@ -95,10 +158,21 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode) { slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting)); gpu::Shader::makeProgram(*program, slotBindings); + auto pipeline = gpu::Pipeline::create(program, std::make_shared()); + // Good to go add the brand new pipeline - _pipelines[mode] = gpu::Pipeline::create(program, std::make_shared()); + if (mode != CustomMode) { + _pipelines[mode] = pipeline; + } else { + _customPipelines[customFile].pipeline = pipeline; + } + } + + if (mode != CustomMode) { + return _pipelines[mode]; + } else { + return _customPipelines[customFile].pipeline; } - return _pipelines[mode]; } @@ -118,8 +192,11 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); + + // TODO REMOVE: Temporary until UI + auto first = _customPipelines.begin()->first; - batch.setPipeline(getPipeline(Modes(renderContext->_deferredDebugMode))); + batch.setPipeline(getPipeline(Modes(renderContext->_deferredDebugMode), first)); batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture()); batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture()); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index a0df42c05a..682888b2af 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -12,12 +12,16 @@ #ifndef hifi_DebugDeferredBuffer_h #define hifi_DebugDeferredBuffer_h +#include + #include class DebugDeferredBuffer { public: using JobModel = render::Job::Model; + DebugDeferredBuffer(); + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); private: @@ -32,14 +36,19 @@ private: CustomMode // Needs to stay last }; + struct CustomPipeline { + gpu::PipelinePointer pipeline; + mutable QFileInfo info; + }; + using StandardPipelines = std::array; + using CustomPipelines = std::unordered_map; - const std::string CUSTOM_FILE { "/Users/clement/Desktop/custom.slh" }; + bool pipelineNeedsUpdate(Modes mode, std::string customFile = std::string()) const; + const gpu::PipelinePointer& getPipeline(Modes mode, std::string customFile = std::string()); + std::string getShaderSourceCode(Modes mode, std::string customFile = std::string()); - bool pipelineNeedsUpdate(Modes mode) const; - const gpu::PipelinePointer& getPipeline(Modes mode); - std::string getShaderSourceCode(Modes mode); - - std::array _pipelines; + StandardPipelines _pipelines; + CustomPipelines _customPipelines; }; #endif // hifi_DebugDeferredBuffer_h \ No newline at end of file From aa1f77ab1c6e0294983e2f8f4c18bfa7dbef2772 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 15:42:52 -0800 Subject: [PATCH 176/318] adding ravestick to toybox demo room --- examples/flowArts/raveStick/RaveStick.js | 62 +++++++++ .../raveStick/raveStickEntityScript.js | 62 --------- unpublishedScripts/hiddenEntityReset.js | 115 ++++++++++++++++- unpublishedScripts/masterReset.js | 118 +++++++++++++++++- 4 files changed, 292 insertions(+), 65 deletions(-) diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/RaveStick.js index fd3c98b6e5..3e4cf16136 100644 --- a/examples/flowArts/raveStick/RaveStick.js +++ b/examples/flowArts/raveStick/RaveStick.js @@ -64,11 +64,73 @@ RaveStick = function(spawnPosition) { intensity: 5 }); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) + var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + var position = Vec3.sum(spawnPosition, Vec3.multiply(Quat.getFront(rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = { + red: 0, + green: 200, + blue: 40 + }; + var props = { + type: "ParticleEffect", + position: position, + parentID: stick, + isEmitting: true, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: forwardQuat, + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false, + } + var beam = Entities.addEntity(props); + function cleanup() { Entities.deleteEntity(stick); Entities.deleteEntity(light); + Entities.deleteEntity(beam); } this.cleanup = cleanup; diff --git a/examples/flowArts/raveStick/raveStickEntityScript.js b/examples/flowArts/raveStick/raveStickEntityScript.js index 171b53e0cf..2e174c78f0 100644 --- a/examples/flowArts/raveStick/raveStickEntityScript.js +++ b/examples/flowArts/raveStick/raveStickEntityScript.js @@ -58,7 +58,6 @@ isGrabbed: false, startNearGrab: function() { - // this.createBeam(); this.trailBasePosition = Entities.getEntityProperties(this.entityID, "position").position; Entities.editEntity(this.trail, { position: this.trailBasePosition @@ -125,7 +124,6 @@ preload: function(entityID) { this.entityID = entityID; - this.createBeam(); }, unload: function() { @@ -134,66 +132,6 @@ if (this.trailEraseInterval) { Script.clearInterval(this.trailEraseInterval); } - }, - - createBeam: function() { - - var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); - var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); - forwardVec = Vec3.normalize(forwardVec); - var forwardQuat = orientationOf(forwardVec); - var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.1)); - position.z += 0.1; - position.x += -0.035; - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; - var props = { - type: "ParticleEffect", - position: position, - parentID: this.entityID, - isEmitting: true, - name: "raveBeam", - colorStart: color, - colorSpread: { - red: 200, - green: 10, - blue: 10 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: forwardQuat, - emitSpeed: .2, - speedSpread: 0.0, - polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.03, - radiusFinish: 0.025, - alpha: 0.7, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false - } - this.beam = Entities.addEntity(props); } }; return new RaveStick(); diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index ee53e36f9e..e4cf434bf8 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -24,6 +24,7 @@ var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var bowScriptURL = Script.resolvePath('../examples/toybox/bow/bow.js'); + var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); @@ -106,6 +107,13 @@ z: 505.78 }); + createRaveStick({ + x: 547.4, + y: 495.4, + z: 504.5 + }); + + createCombinedArmChair({ x: 549.29, y: 494.9, @@ -160,6 +168,111 @@ }); } + function createRaveStick(position) { + var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; + var stick = Entities.addEntity({ + type: "Model", + name: "raveStick", + modelURL: modelURL, + position: position, + shapeType: 'box', + collisionsWillMove: true, + script: raveStickEntityScriptURL, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.31 + }, + gravity: { + x: 0, + y: -3, + z: 0 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.1 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, + invertSolidWhileHeld: true + } + }) + }); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) + var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = { + red: 0, + green: 200, + blue: 40 + }; + var props = { + type: "ParticleEffect", + position: position, + parentID: stick, + isEmitting: true, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: forwardQuat, + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true + } + }) + } + var beam = Entities.addEntity(props); + + } + function createGun(position) { var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx"; @@ -1391,4 +1504,4 @@ }; // entity scripts always need to return a newly constructed object of our type return new ResetSwitch(); -}); +}); \ No newline at end of file diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 1837f4d656..66c8c74edd 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -23,10 +23,12 @@ var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js"); var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js"); var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var bowScriptURL = Script.resolvePath("../examples/toybox/bow/bow.js"); +var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); + MasterReset = function() { var resetKey = "resetMe"; @@ -80,6 +82,12 @@ MasterReset = function() { z: 505.78 }); + createRaveStick({ + x: 547.4, + y: 495.4, + z: 504.5 + }); + createCombinedArmChair({ @@ -94,6 +102,8 @@ MasterReset = function() { z: 504.53 }); + + createPingPongBallGun(); createTargets(); createTargetResetter(); @@ -137,6 +147,110 @@ MasterReset = function() { }); } + function createRaveStick(position) { + var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx"; + var stick = Entities.addEntity({ + type: "Model", + name: "raveStick", + modelURL: modelURL, + position: position, + shapeType: 'box', + collisionsWillMove: true, + script: raveStickEntityScriptURL, + dimensions: { + x: 0.06, + y: 0.06, + z: 0.31 + }, + gravity: { + x: 0, + y: -3, + z: 0 + }, + userData: JSON.stringify({ + resetMe: { + resetMe: true + }, + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.1 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) + }, + invertSolidWhileHeld: true + } + }) + }); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0) + var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); + forwardVec = Vec3.normalize(forwardVec); + var forwardQuat = orientationOf(forwardVec); + position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1)); + position.z += 0.1; + position.x += -0.035; + var color = { + red: 0, + green: 200, + blue: 40 + }; + var props = { + type: "ParticleEffect", + position: position, + parentID: stick, + isEmitting: true, + name: "raveBeam", + colorStart: color, + colorSpread: { + red: 200, + green: 10, + blue: 10 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: forwardQuat, + emitSpeed: .2, + speedSpread: 0.0, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: false, + userData: JSON.stringify({ + resetMe: { + resetMe: true + } + }) + } + var beam = Entities.addEntity(props); + + } function createGun(position) { var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx"; @@ -1349,7 +1463,7 @@ MasterReset = function() { resetMe: true }, grabbableKey: { - invertSolidWhileHeld: true + invertSolidWhileHeld: true } }) }); @@ -1366,4 +1480,4 @@ MasterReset = function() { Script.scriptEnding.connect(cleanup); } -}; +}; \ No newline at end of file From 17af34a3be36fdc30ae832f602d5f260358e5cb4 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 17 Dec 2015 15:48:05 -0800 Subject: [PATCH 177/318] fixed spelling error --- unpublishedScripts/hiddenEntityReset.js | 2 +- unpublishedScripts/masterReset.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index e4cf434bf8..cc4037beb4 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -24,7 +24,7 @@ var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var bowScriptURL = Script.resolvePath('../examples/toybox/bow/bow.js'); - var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); + var raveStickEntityScriptURL = Script.resolvePath("../examples/flowArts/raveStick/raveStickEntityScript.js"); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 66c8c74edd..a1545a3b67 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -23,7 +23,7 @@ var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js"); var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js"); var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); var bowScriptURL = Script.resolvePath("../examples/toybox/bow/bow.js"); -var raveStickEntityScriptURL = Script.resolvePath("../examples/flowarts/raveStick/raveStickEntityScript.js"); +var raveStickEntityScriptURL = Script.resolvePath("../examples/flowArts/raveStick/raveStickEntityScript.js"); var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js'); var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js'); From c0a675dd9e49a137669ba189c1ad44441c4ebdc5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 17 Dec 2015 16:02:49 -0800 Subject: [PATCH 178/318] Fix msvc warning --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 6bdfbb57ff..3458712106 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -114,6 +114,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus case CustomMode: return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER); } + Q_UNREACHABLE(); + return std::string(); } bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode, std::string customFile) const { From 78b805a19a50a286a446f252dc3bd84db1f8e1ee Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 17 Dec 2015 16:06:55 -0800 Subject: [PATCH 179/318] Fix file shader file lookup on windows --- libraries/render-utils/src/DebugDeferredBuffer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 3458712106..d61b131844 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -76,12 +76,12 @@ static const std::string DEEFAULT_CUSTOM_SHADER { }; static std::string getFileContent(std::string fileName, std::string defaultContent = std::string()) { - QFile customFile(QUrl(QString::fromStdString(fileName)).toLocalFile()); + QFile customFile(QString::fromStdString(fileName)); if (customFile.open(QIODevice::ReadOnly)) { return customFile.readAll().toStdString(); } qWarning() << "DebugDeferredBuffer::getFileContent(): Could not open" - << QUrl(QString::fromStdString(fileName)).toLocalFile(); + << QString::fromStdString(fileName); return defaultContent; } @@ -89,9 +89,9 @@ static std::string getFileContent(std::string fileName, std::string defaultConte DebugDeferredBuffer::DebugDeferredBuffer() { // TODO REMOVE: Temporary until UI static const auto DESKTOP_PATH = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - static const auto CUSTOM_FILE = "file://" + DESKTOP_PATH.toStdString() + "/custom.slh"; + static const auto CUSTOM_FILE = DESKTOP_PATH.toStdString() + "/custom.slh"; CustomPipeline pipeline; - pipeline.info = QFileInfo(DESKTOP_PATH + "/custom.slh"); + pipeline.info = QFileInfo(QString::fromStdString(CUSTOM_FILE)); _customPipelines.emplace(CUSTOM_FILE, pipeline); } From a25feb5578adfb989824aa6d2e723564a317c6bf Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 16:58:38 -0800 Subject: [PATCH 180/318] switching branches --- examples/controllers/handControllerGrab.js | 2 +- examples/libraries/entitySelectionTool.js | 1 - examples/light_modifier/lightModifier.js | 179 ++++++++++++------ .../light_modifier/lightModifierTestScene.js | 13 +- examples/light_modifier/lightParent.js | 2 - 5 files changed, 131 insertions(+), 66 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f53a66444f..0f927f39c8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -517,7 +517,7 @@ function MyController(hand) { } var intersection = Entities.findRayIntersection(pickRayBacked, true); - + Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked)); if (intersection.intersects) { // the ray is intersecting something we can move. var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 9b213760c2..94ffb48a71 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -20,7 +20,6 @@ SPACE_WORLD = "world"; SelectionManager = (function() { var that = {}; - function subscribeToUpdateMessages() { Messages.subscribe('entityToolUpdates'); Messages.messageReceived.connect(handleEntitySelectionToolUpdates); diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 8f71f161a2..26fb7b7f36 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -22,10 +22,13 @@ var selectionDisplay; var selectionManager; var lightOverlayManager; +//for when we make a block parent for the light +var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100)); + if (SHOW_OVERLAYS === true) { Script.include('../libraries/gridTool.js'); - Script.include('../libraries/entitySelectionTool.js?'+Math.random(0-100)); + Script.include('../libraries/entitySelectionTool.js?' + Math.random(0 - 100)); Script.include('../libraries/lightOverlayManager.js'); var grid = Grid(); @@ -90,8 +93,8 @@ var WHITE = { var ORANGE = { red: 255, - green: 0, - blue: 128 + green: 165, + blue: 0 } var SLIDER_DIMENSIONS = { @@ -100,6 +103,18 @@ var SLIDER_DIMENSIONS = { z: 0.075 }; +var CLOSE_BUTTON_DIMENSIONS ={ + x:0.1, + y:0.1, + z:0.1 +} + +var LIGHT_MODEL_DIMENSIONS={ + x:0.04, + y:0.04, + z:0.09 +} + var PER_ROW_OFFSET = { x: 0, y: -0.2, @@ -348,7 +363,6 @@ var light = null; function makeSliders(light) { // selectionManager.setSelections([entityID]); - if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -383,9 +397,25 @@ function makeSliders(light) { // selectionManager.setSelections([entityID]); slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 6); sliders.push(slidersRef.exponent); } + + var closeButtonPosition; + + createCloseButton(closeButtonPosition); subscribeToSliderMessages(); }; +function createCloseButton(position){ + var buttonProperties = { + type:'Model', + modelURL:CLOSE_BUTTON_MODEL_URL, + dimensions:CLOSE_BUTTON_DIMENSIONS, + position:position, + rotation:Quat.fromPitchYawRollDegrees(90,0,0); + } + + var button = Entities.addEntity(buttonProperties); +} + function subScribeToNewLights() { Messages.subscribe('Hifi-Light-Mod-Receiver'); Messages.messageReceived.connect(handleLightModMessages); @@ -396,6 +426,12 @@ function subscribeToSliderMessages() { Messages.messageReceived.connect(handleValueMessages); } +function subscribeToLightOverlayRayCheckMessages() { + Messages.subscribe('Hifi-Light-Overlay-Ray-Check'); + Messages.messageReceived.connect(handleLightOverlayRayCheckMessages); +} + + function handleLightModMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Mod-Receiver') { return; @@ -425,6 +461,86 @@ function handleValueMessages(channel, message, sender) { slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage); } +var currentLight; + +function handleLightOverlayRayCheckMessages(channel, message, sender) { + if (channel !== 'Hifi-Light-Overlay-Ray-Check') { + return; + } + if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) { + return; + } + + print('RAY CHECK GOT MESSAGE::' + message); + var pickRay = JSON.parse(message); + + var doesIntersect = lightOverlayManager.findRayIntersection(pickRay); + print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects); + if (doesIntersect.intersects === true) { + print('FULL MESSAGE:::' + JSON.stringify(doesIntersect)) + + var lightID = doesIntersect.entityID; + if (currentLight === lightID) { + print('ALREADY HAVE A BLOCK, EXIT') + return; + } + print('LIGHT ID::' + lightID); + currentLight = lightID; + var lightProperties = Entities.getEntityProperties(lightID); + var block = createBlock(lightProperties.position); + + var light = { + id: lightID, + type: 'spotlight', + initialProperties: lightProperties + } + + makeSliders(light); + print('AFTER MAKE SLIDERS') + if (SHOW_LIGHT_VOLUME === true) { + selectionManager.setSelections([lightID]); + print('SET SELECTIOIO MANAGER TO::: '+ lightID); + print('hasSelection???' + selectionManager.hasSelection()) + } + print('BLOCK IS:::' + block); + Entities.editEntity(lightID, { + parentID: block + }); + + + } +} +function createBlock(position) { + print('CREATE BLOCK') + + var blockProperties = { + name: 'Hifi-Spotlight-Block', + type: 'Box', + dimensions: { + x: 1, + y: 1, + z: 1 + }, + collisionsWillMove: true, + color: { + red: 0, + green: 0, + blue: 255 + }, + position: position, + script: PARENT_SCRIPT_URL, + userData: JSON.stringify({ + handControllerKey: { + disableReleaseVelocity: true + } + }) + }; + + var block = Entities.addEntity(blockProperties); + + return block +} + function cleanup() { var i; for (i = 0; i < sliders.length; i++) { @@ -440,7 +556,6 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -subScribeToNewLights(); function deleteEntity(entityID) { if (entityID === light) { @@ -448,60 +563,10 @@ function deleteEntity(entityID) { } } - - Entities.deletingEntity.connect(deleteEntity); -// search for lights to make grabbable - -// var USE_DEBOUNCE = true; -// var sinceLastUpdate = 0; - -// function searchForLightsToVisualize() { - -// var deltaTime = interval(); - -// if (USE_DEBOUNCE === true) { -// sinceLastUpdate = sinceLastUpdate + deltaTime; - -// if (sinceLastUpdate > 60) { -// sinceLastUpdate = 0; -// } else { -// return; -// } -// } - -// print('SEARCHING FOR LIGHTS'); - -// var entitites = Entities.findEntities(MyAvatar.position, 50); -// for (i = 0; i < entities.length; i++) { -// var entityProperties = Entities.getEntityProperties(entities[i], ['type', 'parentID']) -// var parentID = entityProperties.parentID; -// var type = entityProperties.type; - -// if (type !== 'Light') { -// return; -// } - -// if (type === "Light" && parentID !== DEFAULT_PARENT_ID && parentID !== null) { -// var light = entities[i]; -// //do something with the light. -// } - -// } - -// } - -// function interval() { -// var lastTime = new Date().getTime(); - -// return function getInterval() { -// var newTime = new Date().getTime(); -// var delta = newTime - lastTime; -// lastTime = newTime; -// return delta; -// }; -// } +subscribeToLightOverlayRayCheckMessages(); +subScribeToNewLights(); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 8381b9d434..4b78484a31 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -19,7 +19,10 @@ var light, block; function createLight() { var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); - var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); + var position = basePosition; + position.y += 3; + var lightTransform = evalLightWorldTransform(position,avatarRot); + // var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); var lightProperties = { name: 'Hifi-Spotlight', type: "Light", @@ -29,7 +32,7 @@ function createLight() { y: 2, z: 8 }, - parentID: block, + // parentID: block, color: { red: 255, green: 0, @@ -53,7 +56,7 @@ function createLight() { } }; - Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); +// Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); } @@ -104,11 +107,11 @@ function evalLightWorldTransform(modelPos, modelRot) { } function cleanup() { - Entities.deleteEntity(block); + //Entities.deleteEntity(block); Entities.deleteEntity(light); } Script.scriptEnding.connect(cleanup); -createBlock(); +//createBlock(); createLight(); \ No newline at end of file diff --git a/examples/light_modifier/lightParent.js b/examples/light_modifier/lightParent.js index 2d7cfe8042..0d91b93f93 100644 --- a/examples/light_modifier/lightParent.js +++ b/examples/light_modifier/lightParent.js @@ -18,7 +18,6 @@ LightParent.prototype = { preload: function(entityID) { - print('LIGHT PARENT SCRIPT GO') this.entityID = entityID; var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); this.initialProperties = entityProperties @@ -32,7 +31,6 @@ this.continueDistantGrab(); }, continueDistantGrab: function() { - print('distant grab, should send message!') Messages.sendMessage('entityToolUpdates', 'callUpdate'); }, From 7a542a678b709d5a68ce0f75cb9a9c874c94c480 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 17:17:04 -0800 Subject: [PATCH 181/318] prep for close button --- examples/light_modifier/closeButton.js | 41 +++++++++++++ examples/light_modifier/lightModifier.js | 76 +++++++++++++++++------- examples/light_modifier/lightParent.js | 22 +++---- 3 files changed, 106 insertions(+), 33 deletions(-) create mode 100644 examples/light_modifier/closeButton.js diff --git a/examples/light_modifier/closeButton.js b/examples/light_modifier/closeButton.js new file mode 100644 index 0000000000..045882fd33 --- /dev/null +++ b/examples/light_modifier/closeButton.js @@ -0,0 +1,41 @@ +// +// closeButton.js +// +// Created by James Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Entity script that closes sliders when interacted with. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + + function CloseButton() { + return this; + } + + CloseButton.prototype = { + preload: function(entityID) { + this.entityID = entityID; + var entityProperties = Entities.getEntityProperties(this.entityID, "userData"); + this.initialProperties = entityProperties + this.userData = JSON.parse(entityProperties.userData); + }, + startNearGrab: function() { + + }, + startDistantGrab: function() { + + }, + continueNearGrab: function() { + this.continueDistantGrab(); + }, + continueDistantGrab: function() { + }, + + }; + + return new CloseButton(); +}); \ No newline at end of file diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 26fb7b7f36..29d66ca821 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,6 +60,8 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); +var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; +var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); var RED = { red: 255, @@ -103,16 +105,16 @@ var SLIDER_DIMENSIONS = { z: 0.075 }; -var CLOSE_BUTTON_DIMENSIONS ={ - x:0.1, - y:0.1, - z:0.1 +var CLOSE_BUTTON_DIMENSIONS = { + x: 0.1, + y: 0.1, + z: 0.1 } -var LIGHT_MODEL_DIMENSIONS={ - x:0.04, - y:0.04, - z:0.09 +var LIGHT_MODEL_DIMENSIONS = { + x: 0.04, + y: 0.04, + z: 0.09 } var PER_ROW_OFFSET = { @@ -361,7 +363,7 @@ var slidersRef = { } var light = null; -function makeSliders(light) { // selectionManager.setSelections([entityID]); +function makeSliders(light) { if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; @@ -398,22 +400,50 @@ function makeSliders(light) { // selectionManager.setSelections([entityID]); sliders.push(slidersRef.exponent); } - var closeButtonPosition; + createCloseButton(7); - createCloseButton(closeButtonPosition); subscribeToSliderMessages(); }; -function createCloseButton(position){ +var closeButtons = []; + +function createCloseButton(row) { + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); + var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + var downPosition = Vec3.sum(basePosition, verticalOffset); + var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + var rightVector = Quat.getRight(avatarRot); + var extension = Vec3.multiply(AXIS_SCALE, rightVector); + var position = Vec3.sum(downPosition, extension); + var buttonProperties = { - type:'Model', - modelURL:CLOSE_BUTTON_MODEL_URL, - dimensions:CLOSE_BUTTON_DIMENSIONS, - position:position, - rotation:Quat.fromPitchYawRollDegrees(90,0,0); + type: 'Model', + modelURL: CLOSE_BUTTON_MODEL_URL, + dimensions: CLOSE_BUTTON_DIMENSIONS, + position: position, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + collisionsWillMove: false + //need to add wantsTrigger stuff so we can interact with it with our beamz } var button = Entities.addEntity(buttonProperties); + + closeButtons.push(button); + + Script.update.connect(rotateCloseButtons); +} + +function rotateCloseButtons() { + closeButtons.forEach(function(button) { + Entities.editEntity(button, { + angularVelocity: { + x: 0, + y: 0.25, + z: 0 + } + }) + + }) } function subScribeToNewLights() { @@ -471,7 +501,6 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { return; } - print('RAY CHECK GOT MESSAGE::' + message); var pickRay = JSON.parse(message); var doesIntersect = lightOverlayManager.findRayIntersection(pickRay); @@ -484,7 +513,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { print('ALREADY HAVE A BLOCK, EXIT') return; } - print('LIGHT ID::' + lightID); + currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); var block = createBlock(lightProperties.position); @@ -496,13 +525,13 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { } makeSliders(light); - print('AFTER MAKE SLIDERS') + if (SHOW_LIGHT_VOLUME === true) { selectionManager.setSelections([lightID]); - print('SET SELECTIOIO MANAGER TO::: '+ lightID); + print('SET SELECTIOIO MANAGER TO::: ' + lightID); print('hasSelection???' + selectionManager.hasSelection()) } - print('BLOCK IS:::' + block); + Entities.editEntity(lightID, { parentID: block }); @@ -510,6 +539,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { } } + function createBlock(position) { print('CREATE BLOCK') @@ -553,6 +583,8 @@ function cleanup() { Entities.deletingEntity.disconnect(deleteEntity); lightOverlayManager.setVisible(false); + Script.update.disconnect(rotateCloseButtons); + } Script.scriptEnding.connect(cleanup); diff --git a/examples/light_modifier/lightParent.js b/examples/light_modifier/lightParent.js index 0d91b93f93..2b53c05d0a 100644 --- a/examples/light_modifier/lightParent.js +++ b/examples/light_modifier/lightParent.js @@ -1,14 +1,14 @@ - // - // slider.js - // - // Created by James Pollack @imgntn on 12/15/2015 - // Copyright 2015 High Fidelity, Inc. - // - // Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis. - // - // Distributed under the Apache License, Version 2.0. - // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - // +// +// lightParent.js +// +// Created by James Pollack @imgntn on 12/15/2015 +// Copyright 2015 High Fidelity, Inc. +// +// Entity script that tells the light parent to update the selection tool when we move it. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// (function() { From 762aefbbca611dd51a6c14b7d310738ff50cf8a6 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Dec 2015 17:38:20 -0800 Subject: [PATCH 182/318] add hand driven reticle --- examples/controllers/reticleHandTest.js | 35 +++++++++++++++ examples/controllers/reticleTests.js | 43 ------------------- .../src/controllers/ScriptingInterface.h | 3 ++ 3 files changed, 38 insertions(+), 43 deletions(-) create mode 100644 examples/controllers/reticleHandTest.js diff --git a/examples/controllers/reticleHandTest.js b/examples/controllers/reticleHandTest.js new file mode 100644 index 0000000000..5d0e2f238a --- /dev/null +++ b/examples/controllers/reticleHandTest.js @@ -0,0 +1,35 @@ +// +// reticleTest.js +// examples/controllers +// +// Created by Brad Hefta-Gaub on 2015/12/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +function moveReticle(pitch, yaw) { + //print("pitch:" + pitch); + //print("yaw:" + yaw); + + var globalPos = Controller.getReticlePosition(); + globalPos.x += yaw; + globalPos.y += pitch; + Controller.setReticlePosition(globalPos); +} + +var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand"; +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from(Controller.Standard.RightHand).peek().to(function(pose) { + var angularVelocityEADs = Quat.safeEulerAngles(pose.angularVelocity); // degrees + var yaw = isNaN(angularVelocityEADs.y) ? 0 : (-angularVelocityEADs.y / 10); + var pitch = isNaN(angularVelocityEADs.x) ? 0 : (-angularVelocityEADs.x / 10); + moveReticle(pitch, yaw); +}); +mapping.enable(); + + +Script.scriptEnding.connect(function(){ + mapping.disable(); +}); diff --git a/examples/controllers/reticleTests.js b/examples/controllers/reticleTests.js index 3392d1b7d9..56b2ba413a 100644 --- a/examples/controllers/reticleTests.js +++ b/examples/controllers/reticleTests.js @@ -33,49 +33,6 @@ var mappingJSON = { mapping = Controller.parseMapping(JSON.stringify(mappingJSON)); mapping.enable(); - - -var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand"; -var mapping2 = Controller.newMapping(MAPPING_NAME); -//mapping2.from(Controller.Standard.RightHand).debug(true).to(Controller.Actions.LeftHand); - -/* -mapping2.from(Controller.Standard.RightHand).peek().to(function(pose) { - print("Controller.Standard.RightHand value:" + JSON.stringify(pose)); - }); -*/ - -var translation = { x: 0, y: 0.1, z: 0 }; -var translationDx = 0.01; -var translationDy = 0.01; -var translationDz = 0.01; -var TRANSLATION_LIMIT = 0.5; -var rotation = Quat.fromPitchYawRollDegrees(45, 0, 45); -mapping2.from(function() { - translation.x = translation.x + translationDx; - translation.y = translation.y + translationDy; - translation.z = translation.z + translationDz; - if ((translation.x > TRANSLATION_LIMIT) || (translation.x < (-1 *TRANSLATION_LIMIT))) { - translationDx = translationDx * -1; - } - if ((translation.y > TRANSLATION_LIMIT) || (translation.y < (-1 *TRANSLATION_LIMIT))) { - translationDy = translationDy * -1; - } - if ((translation.z > TRANSLATION_LIMIT) || (translation.z < (-1 *TRANSLATION_LIMIT))) { - translationDz = translationDz * -1; - } - var pose = { - translation: translation, - rotation: rotation, - velocity: { x: 0, y: 0, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0, w: 1 } - }; - return pose; -}).debug(true).to(Controller.Standard.LeftHand); - -Controller.enableMapping(MAPPING_NAME); - - Script.scriptEnding.connect(function(){ mapping.disable(); }); diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 9af478e709..9d3942cd55 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -87,6 +88,8 @@ namespace controller { Q_INVOKABLE QObject* parseMapping(const QString& json); Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl); + Q_INVOKABLE glm::vec2 getReticlePosition() { return toGlm(QCursor::pos()); } + Q_INVOKABLE void setReticlePosition(glm::vec2 position) { QCursor::setPos(position.x, position.y); } //Q_INVOKABLE bool isPrimaryButtonPressed() const; //Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const; From 32bb8f020cc88c606951a77e16e47273c673a227 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 17 Dec 2015 17:40:35 -0800 Subject: [PATCH 183/318] FIxing the diffuse contribution bug maybe --- .../render-utils/src/DeferredGlobalLight.slh | 6 +++--- .../render-utils/src/DeferredLighting.slh | 20 ++++++------------- libraries/render-utils/src/point_light.slf | 2 +- libraries/render-utils/src/spot_light.slf | 2 +- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 983b8002f7..11e157a50c 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -83,7 +83,7 @@ vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(diffuse * shading.w + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); return color; } @@ -106,7 +106,7 @@ vec3 evalAmbienSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(diffuse * shading.w + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); return color; } @@ -129,7 +129,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(diffuse * shading.w + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); return color; } diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index d01b36f553..f4863bbadf 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -23,19 +23,16 @@ 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(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); specularPower *= (gloss * 128.0 * 0.125 + 0.25); float shlickPower = (1.0 - dot(fragLightDir,halfDir)); float shlickPower2 = shlickPower * shlickPower; float shlickPower5 = shlickPower2 * shlickPower2 * shlickPower; - vec3 schlick = specular * (1.0 - shlickPower5) + vec3(shlickPower5); - vec3 reflect = specularPower * schlick; + vec3 fresnel = specular * (1.0 - shlickPower5) + vec3(shlickPower5); + vec3 reflect = specularPower * fresnel * diffuse; - // FIXME: - //return vec4(reflect, diffuse * (1 - length(schlick))); - return vec4(reflect, diffuse); + return vec4(reflect, diffuse * (1 - fresnel.x))); } <@endfunc@> @@ -51,7 +48,7 @@ vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 vec3 halfDir = normalize(fragEyeDir + fragLightDir); float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0); - vec3 reflect = specularPower * specular; + vec3 reflect = specularPower * specular * diffuse; return vec4(reflect, diffuse); } @@ -61,14 +58,9 @@ 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) { - - /*if (gl_FragCoord.x > 1000) { - return evalBlinnShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss); - } else {*/ - return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss); - //} + return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss); } <@endif@> diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index e9045e18c5..716a39aee9 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -66,7 +66,7 @@ void main(void) { float radialAttenuation = evalLightAttenuation(light, fragLightDistance); // Final Lighting color - vec3 fragColor = shading.w * (frag.diffuse + shading.xyz); + vec3 fragColor = (shading.w * frag.diffuse + shading.xyz); _fragColor = vec4(fragColor * radialAttenuation * getLightColor(light) * getLightIntensity(light), 0.0); if (getLightShowContour(light) > 0.0) { diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 73b081260e..d7a20fc5e5 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -73,7 +73,7 @@ void main(void) { float angularAttenuation = evalLightSpotAttenuation(light, cosSpotAngle); // Final Lighting color - vec3 fragColor = shading.w * (frag.diffuse + shading.xyz); + vec3 fragColor = (shading.w * frag.diffuse + shading.xyz); _fragColor = vec4(fragColor * angularAttenuation * radialAttenuation * getLightColor(light) * getLightIntensity(light), 0.0); if (getLightShowContour(light) > 0.0) { From c891bcb8cdc26a4cc265b13f59b897065b079191 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 17 Dec 2015 17:44:40 -0800 Subject: [PATCH 184/318] FIxing the diffuse contribution bug maybe --- libraries/render-utils/src/DeferredLighting.slh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLighting.slh b/libraries/render-utils/src/DeferredLighting.slh index f4863bbadf..cf03861c2f 100755 --- a/libraries/render-utils/src/DeferredLighting.slh +++ b/libraries/render-utils/src/DeferredLighting.slh @@ -32,7 +32,7 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 sp vec3 fresnel = specular * (1.0 - shlickPower5) + vec3(shlickPower5); vec3 reflect = specularPower * fresnel * diffuse; - return vec4(reflect, diffuse * (1 - fresnel.x))); + return vec4(reflect, diffuse * (1 - fresnel.x)); } <@endfunc@> From 5aef309b8a67fc456124a3f322bea42c44e05479 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 18 Dec 2015 15:09:36 +1300 Subject: [PATCH 185/318] Get particles in particlesTest.js emitting again --- examples/example/entities/particlesTest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index 5f95c348b2..10ff314702 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -255,7 +255,6 @@ textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", color: { red: 255, green: 255, blue: 255 }, lifespan: 5.0, - visible: false, locked: false, isEmitting: false, lifetime: 3600 // 1 hour; just in case From d344ef6e2a98cc26da192ce81024f805265a683e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Dec 2015 18:10:41 -0800 Subject: [PATCH 186/318] fix warning in my PR --- libraries/controllers/src/controllers/Pose.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index 2e1d30cff2..8f43242431 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -42,7 +42,6 @@ namespace controller { } void Pose::fromScriptValue(const QScriptValue& object, Pose& pose) { - bool isValid = true; auto translation = object.property("translation"); auto rotation = object.property("rotation"); auto velocity = object.property("velocity"); From e2ecc388ca2efc69e900db2e155c063245c05e54 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 18 Dec 2015 15:10:47 +1300 Subject: [PATCH 187/318] Indicate particle properties that (temporarily) aren't working --- examples/example/entities/particlesTest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index 10ff314702..2b1ab62791 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -60,7 +60,7 @@ }); break; case 3: - print("Radius spread"); + print("Radius spread - temporarily not working"); Entities.editEntity(particles, { accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 }, radiusSpread: 0.035 @@ -83,7 +83,7 @@ }); break; case 6: - print("Alpha spread"); + print("Alpha spread - temporarily not working"); Entities.editEntity(particles, { alpha: 0.5, alphaSpread: 0.5 @@ -99,7 +99,7 @@ }); break; case 8: - print("Color spread"); + print("Color spread - temporarily not working"); Entities.editEntity(particles, { alpha: 1.0, alphaStart: 1.0, From c3e3af7c8c73c43c0a302804ba27ed6de4a35818 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 18 Dec 2015 15:11:43 +1300 Subject: [PATCH 188/318] Document effect of Bezier interpolation on particle radius simulation --- examples/example/entities/particlesTest.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/example/entities/particlesTest.js b/examples/example/entities/particlesTest.js index 2b1ab62791..e7f88ce468 100644 --- a/examples/example/entities/particlesTest.js +++ b/examples/example/entities/particlesTest.js @@ -71,6 +71,7 @@ Entities.editEntity(particles, { radiusSpread: 0.0, radiusStart: 0.0, + particleRadius: 2 * PARTICLE_RADIUS, // Bezier interpolation used means that middle value isn't intersected radiusFinish: 0.0 }); break; @@ -78,6 +79,7 @@ print("Alpha 0.5"); Entities.editEntity(particles, { radiusStart: PARTICLE_RADIUS, + particleRadius: PARTICLE_RADIUS, radiusFinish: PARTICLE_RADIUS, alpha: 0.5 }); From 9a7c0cb182aa527cfce75206889e38b283423988 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 18 Dec 2015 15:12:03 +1300 Subject: [PATCH 189/318] Typo noticed in passing --- libraries/entities-renderer/src/textured_particle.slv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 1e9275ec72..e1f18c2b5f 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -82,7 +82,7 @@ void main(void) { varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age); // anchor point in eye space - float radius = bezierInterpolate(particle.radius.start, particle.radius.middle, particle.radius.finish , age); + float radius = bezierInterpolate(particle.radius.start, particle.radius.middle, particle.radius.finish, age); vec4 quadPos = radius * UNIT_QUAD[twoTriID]; vec4 anchorPoint; From f84a441c7daeb09c54acef636791986df0353609 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 17 Dec 2015 18:33:17 -0800 Subject: [PATCH 190/318] close button --- examples/light_modifier/lightModifier.js | 44 ++++++++++++++++++++---- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 29d66ca821..d82afc09bb 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,6 +60,7 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); +var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_good.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); @@ -112,9 +113,9 @@ var CLOSE_BUTTON_DIMENSIONS = { } var LIGHT_MODEL_DIMENSIONS = { - x: 0.04, - y: 0.04, - z: 0.09 + x: 0.68, + y: 0.68, + z: 1.54 } var PER_ROW_OFFSET = { @@ -408,15 +409,16 @@ function makeSliders(light) { var closeButtons = []; function createCloseButton(row) { - var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot))); + var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); var downPosition = Vec3.sum(basePosition, verticalOffset); - var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); var rightVector = Quat.getRight(avatarRot); var extension = Vec3.multiply(AXIS_SCALE, rightVector); var position = Vec3.sum(downPosition, extension); var buttonProperties = { + name:'Hifi-Close-Button', type: 'Model', modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, @@ -492,6 +494,7 @@ function handleValueMessages(channel, message, sender) { } var currentLight; +var block; function handleLightOverlayRayCheckMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Overlay-Ray-Check') { @@ -516,7 +519,8 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - var block = createBlock(lightProperties.position); + block = createBlock(lightProperties.position); + // block = createLightModel(lightProperties.position); var light = { id: lightID, @@ -540,6 +544,30 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { } } +function createLightModel(position) { + print('CREATE MODEL') + var blockProperties = { + name: 'Hifi-Spotlight-Model', + type: 'Model', + shapeType: 'box', + modelURL: LIGHT_MODEL_URL, + dimensions: LIGHT_MODEL_DIMENSIONS, + collisionsWillMove: true, + position: position, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + script: PARENT_SCRIPT_URL, + userData: JSON.stringify({ + handControllerKey: { + disableReleaseVelocity: true + } + }) + }; + + var block = Entities.addEntity(blockProperties); + + return block +} + function createBlock(position) { print('CREATE BLOCK') @@ -551,12 +579,12 @@ function createBlock(position) { y: 1, z: 1 }, - collisionsWillMove: true, color: { red: 0, green: 0, blue: 255 }, + collisionsWillMove: true, position: position, script: PARENT_SCRIPT_URL, userData: JSON.stringify({ @@ -578,11 +606,13 @@ function cleanup() { Entities.deleteEntity(sliders[i].sliderIndicator); } + Entities.deleteEntity(block); Messages.messageReceived.disconnect(handleLightModMessages); Messages.messageReceived.disconnect(handleValueMessages); Entities.deletingEntity.disconnect(deleteEntity); lightOverlayManager.setVisible(false); + selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); } From 0b781a3589be3a3b604054f36e531714d7aff94a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Dec 2015 18:39:05 -0800 Subject: [PATCH 191/318] fix warnings --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/AvatarActionHold.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f8040754d7..6094a0b9fe 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -157,7 +157,7 @@ void Avatar::animateScaleChanges(float deltaTime) { // snap to the end when we get close enough const float MIN_RELATIVE_SCALE_ERROR = 0.03f; - if (fabsf(_targetScale - currentScale) / _targetScale < 0.03f) { + if (fabsf(_targetScale - currentScale) / _targetScale < MIN_RELATIVE_SCALE_ERROR) { animatedScale = _targetScale; } diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index be562e2773..689d557c48 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -77,7 +77,7 @@ void AvatarActionHold::prepareForPhysicsSimulation() { // getTarget would get the palm position of the previous location of the avatar (because // bullet has moved the av's rigid body but the rigid body's location has not yet been // copied out into the Avatar class. - glm::quat avatarRotationInverse = glm::inverse(avatarRigidBodyRotation); + //glm::quat avatarRotationInverse = glm::inverse(avatarRigidBodyRotation); // the offset should be in the frame of the avatar, but something about the order // things are updated makes this wrong: diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index e5ecdfe217..abc3520c83 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -34,7 +34,6 @@ static const quint64 MSECS_TO_USECS = 1000ULL; static const quint64 TOOLTIP_DELAY = 500 * MSECS_TO_USECS; -static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; static const float reticleSize = TWO_PI / 100.0f; static const float CURSOR_PIXEL_SIZE = 32.0f; From a7824a06d0b2d3bfa9d4fba2da1761d8e7bbf384 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 17 Dec 2015 18:51:27 -0800 Subject: [PATCH 192/318] fix Assignment copy constructor warning --- libraries/networking/src/Assignment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 4c72a16f1d..e6163c776b 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -91,7 +91,7 @@ Assignment::Assignment(ReceivedMessage& message) : #endif -Assignment::Assignment(const Assignment& otherAssignment) { +Assignment::Assignment(const Assignment& otherAssignment) : QObject() { _uuid = otherAssignment._uuid; _command = otherAssignment._command; _type = otherAssignment._type; From 919a4b6728d950226a0be472bb193efd2aa9d5c6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 17 Dec 2015 16:03:18 -0800 Subject: [PATCH 193/318] Split global JS Scene into Render --- interface/src/Application.cpp | 58 +++------- .../render-utils/src/RenderDeferredTask.cpp | 74 ++++++------ .../src/RenderScriptingInterface.cpp | 41 +++++++ .../src/RenderScriptingInterface.h | 95 +++++++++++++++ libraries/render/src/render/Engine.cpp | 10 ++ libraries/render/src/render/Engine.h | 87 ++++++++++---- .../src/SceneScriptingInterface.cpp | 95 +++------------ .../src/SceneScriptingInterface.h | 109 ++---------------- libraries/script-engine/src/ScriptEngine.cpp | 1 - 9 files changed, 293 insertions(+), 277 deletions(-) create mode 100644 libraries/render-utils/src/RenderScriptingInterface.cpp create mode 100644 libraries/render-utils/src/RenderScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21648f9118..fedc64174f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -341,6 +342,7 @@ bool setupEssentials(int& argc, char** argv) { #endif DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -3674,40 +3676,22 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // For now every frame pass the renderContext { PerformanceTimer perfTimer("EngineRun"); - render::RenderContext renderContext; - - auto sceneInterface = DependencyManager::get(); - - renderContext._cullOpaque = sceneInterface->doEngineCullOpaque(); - renderContext._sortOpaque = sceneInterface->doEngineSortOpaque(); - renderContext._renderOpaque = sceneInterface->doEngineRenderOpaque(); - renderContext._cullTransparent = sceneInterface->doEngineCullTransparent(); - renderContext._sortTransparent = sceneInterface->doEngineSortTransparent(); - renderContext._renderTransparent = sceneInterface->doEngineRenderTransparent(); - - renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems(); - renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems(); - renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems(); - - renderContext._deferredDebugMode = sceneInterface->getEngineDeferredDebugMode(); - renderContext._deferredDebugSize = sceneInterface->getEngineDeferredDebugSize(); - - renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); - if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { - renderContext._drawItemStatus |= render::showNetworkStatusFlag; - } - renderContext._drawHitEffect = sceneInterface->doEngineDisplayHitEffect(); - - renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); - renderContext._fxaaStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); - - renderContext._toneMappingExposure = sceneInterface->getEngineToneMappingExposure(); - renderContext._toneMappingToneCurve = sceneInterface->getEngineToneMappingToneCurveValue(); renderArgs->_shouldRender = LODManager::shouldRender; - - renderContext.args = renderArgs; renderArgs->_viewFrustum = getDisplayViewFrustum(); + + auto renderInterface = DependencyManager::get(); + auto renderItemsMeta = renderInterface->getItemsMeta(); + auto renderTone = renderInterface->getTone(); + int drawStatus = renderInterface->getDrawStatus(); + bool drawHitEffect = renderInterface->getDrawHitEffect(); + + bool occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); + bool antialiasingStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); + bool showOwnedStatus = Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned); + + render::RenderContext renderContext{renderArgs, renderItemsMeta, renderTone}; + renderContext.setOptions(drawStatus, drawHitEffect, occlusionStatus, antialiasingStatus, showOwnedStatus); _renderEngine->setRenderContext(renderContext); // Before the deferred pass, let's try to use the render engine @@ -3715,15 +3699,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se _renderEngine->run(); myAvatar->endRenderRun(); - auto engineRC = _renderEngine->getRenderContext(); - sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems); - sceneInterface->setEngineDrawnOpaqueItems(engineRC->_numDrawnOpaqueItems); - - sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); - sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); - - sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems); - sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); + auto engineContext = _renderEngine->getRenderContext(); + renderInterface->setItemCounts(engineContext->getItemsMeta()); } activeRenderingThread = nullptr; @@ -4177,6 +4154,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0); scriptEngine->registerGlobalObject("Scene", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Render", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget()); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 5423d928a7..820f2b86bb 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -37,23 +37,24 @@ using namespace render; void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - DependencyManager::get()->prepare(renderContext->args); + DependencyManager::get()->prepare(renderContext->getArgs()); } void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - DependencyManager::get()->render(renderContext->args); + DependencyManager::get()->render(renderContext->getArgs()); } void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { PerformanceTimer perfTimer("ToneMappingDeferred"); - _toneMappingEffect.render(renderContext->args); + _toneMappingEffect.render(renderContext->getArgs()); } RenderDeferredTask::RenderDeferredTask() : Task() { // CPU only, create the list of renderedOpaques items _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { - context->_numFeedOpaqueItems = count; + context->getItemsMeta()._opaque._numFeed = count; + auto& opaque = context->getItemsMeta()._opaque; }) ))); _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); @@ -64,7 +65,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", FetchItems(ItemFilter::Builder::transparentShape().withoutLayered(), [](const RenderContextPointer& context, int count) { - context->_numFeedTransparentItems = count; + context->getItemsMeta()._transparent._numFeed = count; }) ))); _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); @@ -146,7 +147,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend // Is it possible that we render without a viewFrustum ? - if (!(renderContext->args && renderContext->args->_viewFrustum)) { + if (!(renderContext->getArgs() && renderContext->getArgs()->_viewFrustum)) { return; } @@ -154,21 +155,21 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setDrawDebugDeferredBuffer(renderContext->_deferredDebugMode); // Make sure we turn the displayItemStatus on/off - setDrawItemStatus(renderContext->_drawItemStatus); + setDrawItemStatus(renderContext->getDrawStatus()); // Make sure we display hit effect on screen, as desired from a script - setDrawHitEffect(renderContext->_drawHitEffect); + setDrawHitEffect(renderContext->getDrawHitEffect()); // TODO: turn on/off AO through menu item - setOcclusionStatus(renderContext->_occlusionStatus); + setOcclusionStatus(renderContext->getOcclusionStatus()); - setAntialiasingStatus(renderContext->_fxaaStatus); + setAntialiasingStatus(renderContext->getFxaaStatus()); - setToneMappingExposure(renderContext->_toneMappingExposure); - setToneMappingToneCurve(renderContext->_toneMappingToneCurve); + setToneMappingExposure(renderContext->getTone()._exposure); + setToneMappingToneCurve(renderContext->getTone()._toneCurve); - renderContext->args->_context->syncCache(); + renderContext->getArgs()->_context->syncCache(); for (auto job : _jobs) { job.run(sceneContext, renderContext); @@ -177,16 +178,17 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend }; void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; - renderContext->_numDrawnOpaqueItems = (int)inItems.size(); + auto& opaque = renderContext->getItemsMeta()._opaque; + opaque._numDrawn = (int)inItems.size(); glm::mat4 projMat; Transform viewMat; @@ -200,22 +202,23 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend const float OPAQUE_ALPHA_THRESHOLD = 0.5f; args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD; } - renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOpaqueItems); + renderItems(sceneContext, renderContext, inItems, opaque._maxDrawn); args->_batch = nullptr; }); } void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; - renderContext->_numDrawnTransparentItems = (int)inItems.size(); + auto& transparent = renderContext->getItemsMeta()._transparent; + transparent._numDrawn = (int)inItems.size(); glm::mat4 projMat; Transform viewMat; @@ -228,7 +231,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; - renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnTransparentItems); + renderItems(sceneContext, renderContext, inItems, transparent._maxDrawn); args->_batch = nullptr; }); } @@ -251,8 +254,8 @@ const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() { } void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); // render backgrounds auto& scene = sceneContext->_scene; @@ -267,11 +270,12 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon inItems.emplace_back(id); } } - renderContext->_numFeedOverlay3DItems = (int)inItems.size(); - renderContext->_numDrawnOverlay3DItems = (int)inItems.size(); + auto& overlay3D = renderContext->getItemsMeta()._overlay3D; + overlay3D._numFeed = (int)inItems.size(); + overlay3D._numDrawn = (int)inItems.size(); if (!inItems.empty()) { - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); // Clear the framebuffer without stereo // Needs to be distinct from the other batch because using the clear call @@ -300,7 +304,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderItems(sceneContext, renderContext, inItems, renderContext->_maxDrawnOverlay3DItems); + renderItems(sceneContext, renderContext, inItems, renderContext->getItemsMeta()._overlay3D._maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); @@ -329,11 +333,11 @@ const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() { } void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); // from the touched pixel generate the stencil buffer - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; @@ -355,8 +359,8 @@ void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const Ren } void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); // render backgrounds auto& scene = sceneContext->_scene; @@ -368,7 +372,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const for (auto id : items) { inItems.emplace_back(id); } - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; diff --git a/libraries/render-utils/src/RenderScriptingInterface.cpp b/libraries/render-utils/src/RenderScriptingInterface.cpp new file mode 100644 index 0000000000..3b283e3058 --- /dev/null +++ b/libraries/render-utils/src/RenderScriptingInterface.cpp @@ -0,0 +1,41 @@ +// +// RenderScriptingInterface.cpp +// libraries/render-utils +// +// Created by Zach Pomerantz on 12/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RenderScriptingInterface.h" + +RenderScriptingInterface::RenderScriptingInterface() {}; + +void RenderScriptingInterface::setEngineToneMappingToneCurve(const QString& toneCurve) { + if (toneCurve == QString("None")) { + _tone._toneCurve = 0; + } else if (toneCurve == QString("Gamma22")) { + _tone._toneCurve = 1; + } else if (toneCurve == QString("Reinhard")) { + _tone._toneCurve = 2; + } else if (toneCurve == QString("Filmic")) { + _tone._toneCurve = 3; + } +} + +QString RenderScriptingInterface::getEngineToneMappingToneCurve() const { + switch (_tone._toneCurve) { + case 0: + return QString("None"); + case 1: + return QString("Gamma22"); + case 2: + return QString("Reinhard"); + case 3: + return QString("Filmic"); + default: + return QString("Filmic"); + }; +} \ No newline at end of file diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h new file mode 100644 index 0000000000..ec3b5be669 --- /dev/null +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -0,0 +1,95 @@ +// +// RenderScriptingInterface.h +// libraries/render-utils +// +// Created by Zach Pomerantz on 12/16/15. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RenderScriptingInterface_h +#define hifi_RenderScriptingInterface_h + +#include // QObject +#include // Dependency + +#include "render/Engine.h" + +class RenderScriptingInterface : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + + public: + Q_INVOKABLE void setEngineRenderOpaque(bool renderOpaque) { _items._opaque._render = renderOpaque; }; + Q_INVOKABLE bool doEngineRenderOpaque() const { return _items._opaque._render; } + Q_INVOKABLE void setEngineRenderTransparent(bool renderTransparent) { _items._transparent._render = renderTransparent; }; + Q_INVOKABLE bool doEngineRenderTransparent() const { return _items._transparent._render; } + + Q_INVOKABLE void setEngineCullOpaque(bool cullOpaque) { _items._opaque._cull = cullOpaque; }; + Q_INVOKABLE bool doEngineCullOpaque() const { return _items._opaque._cull; } + Q_INVOKABLE void setEngineCullTransparent(bool cullTransparent) { _items._transparent._cull = cullTransparent; }; + Q_INVOKABLE bool doEngineCullTransparent() const { return _items._transparent._cull; } + + Q_INVOKABLE void setEngineSortOpaque(bool sortOpaque) { _items._opaque._sort = sortOpaque; }; + Q_INVOKABLE bool doEngineSortOpaque() const { return _items._opaque._sort; } + Q_INVOKABLE void setEngineSortTransparent(bool sortTransparent) { _items._transparent._sort = sortTransparent; }; + Q_INVOKABLE bool doEngineSortTransparent() const { return _items._transparent._sort; } + + Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _items._opaque._numDrawn; } + Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _items._transparent._numDrawn; } + Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _items._overlay3D._numDrawn; } + + Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _items._opaque._numFeed; } + Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _items._transparent._numFeed; } + Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _items._overlay3D._numFeed; } + + Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _items._opaque._maxDrawn = count; } + Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _items._opaque._maxDrawn; } + Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _items._transparent._maxDrawn = count; } + Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _items._transparent._maxDrawn; } + Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _items._overlay3D._maxDrawn = count; } + Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _items._overlay3D._maxDrawn; } + + Q_INVOKABLE void setEngineDeferredDebugMode(int mode) { _deferredDebugMode = mode; } + Q_INVOKABLE int getEngineDeferredDebugMode() { return _deferredDebugMode; } + Q_INVOKABLE void setEngineDeferredDebugSize(glm::vec4 size) { _deferredDebugSize = size; } + Q_INVOKABLE glm::vec4 getEngineDeferredDebugSize() { return _deferredDebugSize; } + + Q_INVOKABLE void setEngineDisplayItemStatus(int display) { _drawStatus = display; } + Q_INVOKABLE int doEngineDisplayItemStatus() { return _drawStatus; } + + Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } + Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } + + Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _tone._exposure = exposure; } + Q_INVOKABLE float getEngineToneMappingExposure() const { return _tone._exposure; } + + Q_INVOKABLE void setEngineToneMappingToneCurve(const QString& curve); + Q_INVOKABLE QString getEngineToneMappingToneCurve() const; + int getEngineToneMappingToneCurveValue() const { return _tone._toneCurve; } + + inline int getDrawStatus() { return _drawStatus; } + inline bool getDrawHitEffect() { return _drawHitEffect; } + inline const render::RenderContext::ItemsMeta& getItemsMeta() { return _items; } + inline const render::RenderContext::Tone& getTone() { return _tone; } + void setItemCounts(const render::RenderContext::ItemsMeta& items) { _items.setCounts(items); }; + +protected: + RenderScriptingInterface(); + ~RenderScriptingInterface() {}; + + render::RenderContext::ItemsMeta _items; + render::RenderContext::Tone _tone; + + // Options + int _drawStatus = 0; + bool _drawHitEffect = false; + + // Debugging + int _deferredDebugMode = -1; + glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f }; +}; + +#endif // hifi_RenderScriptingInterface_h diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 86f35eb831..0cf09e0ca4 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -13,6 +13,16 @@ #include "DrawTask.h" using namespace render; +void RenderContext::setOptions(int drawStatus, bool drawHitEffect, bool occlusion, bool fxaa, bool showOwned) { + _drawStatus = drawStatus; + _occlusionStatus = occlusion; + _fxaaStatus = fxaa; + _drawHitEffect = drawHitEffect; + + if (showOwned) { + _drawStatus |= render::showNetworkStatusFlag; + } +}; Engine::Engine() : _sceneContext(std::make_shared()), diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index abfef03039..dcfe28a444 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -23,7 +23,7 @@ public: SceneContext() {} }; -typedef std::shared_ptr SceneContextPointer; +using SceneContextPointer = std::shared_ptr; // see examples/utilities/tools/renderEngineDebug.js const int showDisplayStatusFlag = 1; @@ -32,43 +32,80 @@ const int showNetworkStatusFlag = 2; class RenderContext { public: - RenderArgs* args; + struct ItemsMeta { + inline void setCounts(const ItemsMeta& items) { + _opaque.setCounts(items._opaque); + _transparent.setCounts(items._transparent); + _overlay3D.setCounts(items._overlay3D); + }; - bool _cullOpaque = true; - bool _sortOpaque = true; - bool _renderOpaque = true; - bool _cullTransparent = true; - bool _sortTransparent = true; - bool _renderTransparent = true; + struct Counter { + Counter() {}; + Counter(const Counter& counter) { + _numFeed = _numDrawn = 0; + _maxDrawn = counter._maxDrawn; + }; - int _numFeedOpaqueItems = 0; - int _numDrawnOpaqueItems = 0; - int _maxDrawnOpaqueItems = -1; + inline void setCounts(const Counter& counter) { + _numFeed = counter._numFeed; + _numDrawn = counter._numDrawn; + }; + + int _numFeed = 0; + int _numDrawn = 0; + int _maxDrawn = -1; + }; + + struct State : public Counter { + bool _render = true; + bool _cull = true; + bool _sort = true; + + Counter _counter{}; + }; + + // TODO: Store state/counter in a map instead of manually enumerated members + State _opaque{}; + State _transparent{}; + Counter _overlay3D{}; + }; + + struct Tone { + int _toneCurve = 3; + float _exposure = 0.0; + }; - int _numFeedTransparentItems = 0; - int _numDrawnTransparentItems = 0; - int _maxDrawnTransparentItems = -1; + RenderContext(RenderArgs* args, ItemsMeta items, Tone tone) : _args{args}, _items{items}, _tone{tone} {}; + RenderContext() : RenderContext(nullptr, {}, {}) {}; - int _numFeedOverlay3DItems = 0; - int _numDrawnOverlay3DItems = 0; - int _maxDrawnOverlay3DItems = -1; + inline RenderArgs* getArgs() { return _args; } + inline int getDrawStatus() { return _drawStatus; } + inline bool getDrawHitEffect() { return _drawHitEffect; } + inline bool getOcclusionStatus() { return _occlusionStatus; } + inline bool getFxaaStatus() { return _fxaaStatus; } + inline ItemsMeta& getItemsMeta() { return _items; } + inline Tone& getTone() { return _tone; } + void setOptions(int drawStatus, bool drawHitEffect, bool occlusion, bool fxaa, bool showOwned); + // Debugging int _deferredDebugMode = -1; glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f }; - int _drawItemStatus = 0; - bool _drawHitEffect = false; +protected: + RenderArgs* _args; + + // Options + int _drawStatus = 0; // bitflag + bool _drawHitEffect = false; bool _occlusionStatus = false; bool _fxaaStatus = false; - float _toneMappingExposure = 0.0; - int _toneMappingToneCurve = 3; - - RenderContext() {} + ItemsMeta _items; + Tone _tone; }; typedef std::shared_ptr RenderContextPointer; -// THe base class for a task that runs on the SceneContext +// The base class for a task that runs on the SceneContext class Task { public: Task() {} @@ -81,7 +118,7 @@ protected: typedef std::shared_ptr TaskPointer; typedef std::vector Tasks; -// The root of the takss, the Engine, should not be known from the Tasks, +// The root of the tasks, the Engine, should not be known from the Tasks, // The SceneContext is what navigates from the engine down to the Tasks class Engine { public: diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 3e22a9e929..39bceba9d9 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -1,6 +1,6 @@ // // SceneScriptingInterface.cpp -// interface/src/scripting +// libraries/script-engine // // Created by Sam Gateau on 2/24/15. // Copyright 2014 High Fidelity, Inc. @@ -11,16 +11,27 @@ #include "SceneScriptingInterface.h" -#include - - #include SceneScriptingInterface::SceneScriptingInterface() { - // Let's make sure the sunSkyStage is using a proceduralSKybox + // Let's make sure the sunSkyStage is using a proceduralSkybox _skyStage->setSkybox(model::SkyboxPointer(new ProceduralSkybox())); } +void SceneScriptingInterface::setShouldRenderAvatars(bool shouldRenderAvatars) { + if (shouldRenderAvatars != _shouldRenderAvatars) { + _shouldRenderAvatars = shouldRenderAvatars; + emit shouldRenderAvatarsChanged(_shouldRenderAvatars); + } +} + +void SceneScriptingInterface::setShouldRenderEntities(bool shouldRenderEntities) { + if (shouldRenderEntities != _shouldRenderEntities) { + _shouldRenderEntities = shouldRenderEntities; + emit shouldRenderEntitiesChanged(_shouldRenderEntities); + } +} + void SceneScriptingInterface::setStageOrientation(const glm::quat& orientation) { _skyStage->setOriginOrientation(orientation); } @@ -120,77 +131,3 @@ QString SceneScriptingInterface::getBackgroundMode() const { model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; } - -void SceneScriptingInterface::setShouldRenderAvatars(bool shouldRenderAvatars) { - if (shouldRenderAvatars != _shouldRenderAvatars) { - _shouldRenderAvatars = shouldRenderAvatars; - emit shouldRenderAvatarsChanged(_shouldRenderAvatars); - } -} - -void SceneScriptingInterface::setShouldRenderEntities(bool shouldRenderEntities) { - if (shouldRenderEntities != _shouldRenderEntities) { - _shouldRenderEntities = shouldRenderEntities; - emit shouldRenderEntitiesChanged(_shouldRenderEntities); - } -} - -void SceneScriptingInterface::setEngineRenderOpaque(bool renderOpaque) { - _engineRenderOpaque = renderOpaque; -} - -void SceneScriptingInterface::setEngineRenderTransparent(bool renderTransparent) { - _engineRenderTransparent = renderTransparent; -} - -void SceneScriptingInterface::setEngineCullOpaque(bool cullOpaque) { - _engineCullOpaque = cullOpaque; -} - -void SceneScriptingInterface::setEngineCullTransparent(bool cullTransparent) { - _engineCullTransparent = cullTransparent; -} - -void SceneScriptingInterface::setEngineSortOpaque(bool sortOpaque) { - _engineSortOpaque = sortOpaque; -} - -void SceneScriptingInterface::setEngineSortTransparent(bool sortTransparent) { - _engineSortOpaque = sortTransparent; -} - -void SceneScriptingInterface::clearEngineCounters() { - _numFeedOpaqueItems = 0; - _numDrawnOpaqueItems = 0; - _numFeedTransparentItems = 0; - _numDrawnTransparentItems = 0; - _numFeedOverlay3DItems = 0; - _numDrawnOverlay3DItems = 0; -} - - -void SceneScriptingInterface::setEngineToneMappingToneCurve(const QString& toneCurve) { - if (toneCurve == QString("None")) { - _engineToneMappingToneCurve = 0; - } else if (toneCurve == QString("Gamma22")) { - _engineToneMappingToneCurve = 1; - } else if (toneCurve == QString("Reinhard")) { - _engineToneMappingToneCurve = 2; - } else if (toneCurve == QString("Filmic")) { - _engineToneMappingToneCurve = 3; - } -} -QString SceneScriptingInterface::getEngineToneMappingToneCurve() const { - switch (_engineToneMappingToneCurve) { - case 0: - return QString("None"); - case 1: - return QString("Gamma22"); - case 2: - return QString("Reinhard"); - case 3: - return QString("Filmic"); - default: - return QString("Filmic"); - }; -} \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 246f624b08..abc4ee68a9 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -1,6 +1,6 @@ // // SceneScriptingInterface.h -// interface/src/scripting +// libraries/script-engine // // Created by Sam Gateau on 2/24/15. // Copyright 2014 High Fidelity, Inc. @@ -12,9 +12,8 @@ #ifndef hifi_SceneScriptingInterface_h #define hifi_SceneScriptingInterface_h -#include - -#include +#include // QObject +#include // Dependency #include "model/Stage.h" @@ -22,10 +21,16 @@ class SceneScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY +public: Q_PROPERTY(bool shouldRenderAvatars READ shouldRenderAvatars WRITE setShouldRenderAvatars) Q_PROPERTY(bool shouldRenderEntities READ shouldRenderEntities WRITE setShouldRenderEntities) -public: + Q_INVOKABLE void setShouldRenderAvatars(bool shouldRenderAvatars); + Q_INVOKABLE bool shouldRenderAvatars() const { return _shouldRenderAvatars; } + + Q_INVOKABLE void setShouldRenderEntities(bool shouldRenderEntities); + Q_INVOKABLE bool shouldRenderEntities() const { return _shouldRenderEntities; } + Q_INVOKABLE void setStageOrientation(const glm::quat& orientation); Q_INVOKABLE void setStageLocation(float longitude, float latitude, float altitude); @@ -43,7 +48,6 @@ public: Q_INVOKABLE void setStageSunModelEnable(bool isEnabled); Q_INVOKABLE bool isStageSunModelEnabled() const; - Q_INVOKABLE void setKeyLightColor(const glm::vec3& color); Q_INVOKABLE glm::vec3 getKeyLightColor() const; Q_INVOKABLE void setKeyLightIntensity(float intensity); @@ -61,108 +65,19 @@ public: Q_INVOKABLE QString getBackgroundMode() const; model::SunSkyStagePointer getSkyStage() const; - - Q_INVOKABLE void setShouldRenderAvatars(bool shouldRenderAvatars); - Q_INVOKABLE bool shouldRenderAvatars() const { return _shouldRenderAvatars; } - - Q_INVOKABLE void setShouldRenderEntities(bool shouldRenderEntities); - Q_INVOKABLE bool shouldRenderEntities() const { return _shouldRenderEntities; } - - - // Controlling the rendering engine - Q_INVOKABLE void setEngineRenderOpaque(bool renderOpaque); - Q_INVOKABLE bool doEngineRenderOpaque() const { return _engineRenderOpaque; } - Q_INVOKABLE void setEngineRenderTransparent(bool renderTransparent); - Q_INVOKABLE bool doEngineRenderTransparent() const { return _engineRenderTransparent; } - - Q_INVOKABLE void setEngineCullOpaque(bool cullOpaque); - Q_INVOKABLE bool doEngineCullOpaque() const { return _engineCullOpaque; } - Q_INVOKABLE void setEngineCullTransparent(bool cullTransparent); - Q_INVOKABLE bool doEngineCullTransparent() const { return _engineCullTransparent; } - - Q_INVOKABLE void setEngineSortOpaque(bool sortOpaque); - Q_INVOKABLE bool doEngineSortOpaque() const { return _engineSortOpaque; } - Q_INVOKABLE void setEngineSortTransparent(bool sortTransparent); - Q_INVOKABLE bool doEngineSortTransparent() const { return _engineSortTransparent; } - - void clearEngineCounters(); - void setEngineDrawnOpaqueItems(int count) { _numDrawnOpaqueItems = count; } - Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _numDrawnOpaqueItems; } - void setEngineDrawnTransparentItems(int count) { _numDrawnTransparentItems = count; } - Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _numDrawnTransparentItems; } - void setEngineDrawnOverlay3DItems(int count) { _numDrawnOverlay3DItems = count; } - Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _numDrawnOverlay3DItems; } - - void setEngineFeedOpaqueItems(int count) { _numFeedOpaqueItems = count; } - Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _numFeedOpaqueItems; } - void setEngineFeedTransparentItems(int count) { _numFeedTransparentItems = count; } - Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _numFeedTransparentItems; } - void setEngineFeedOverlay3DItems(int count) { _numFeedOverlay3DItems = count; } - Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _numFeedOverlay3DItems; } - - Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _maxDrawnOpaqueItems = count; } - Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _maxDrawnOpaqueItems; } - Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _maxDrawnTransparentItems = count; } - Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; } - Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } - Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } - - Q_INVOKABLE void setEngineDeferredDebugMode(int mode) { _deferredDebugMode = mode; } - Q_INVOKABLE int getEngineDeferredDebugMode() { return _deferredDebugMode; } - Q_INVOKABLE void setEngineDeferredDebugSize(glm::vec4 size) { _deferredDebugSize = size; } - Q_INVOKABLE glm::vec4 getEngineDeferredDebugSize() { return _deferredDebugSize; } - - Q_INVOKABLE void setEngineDisplayItemStatus(int display) { _drawItemStatus = display; } - Q_INVOKABLE int doEngineDisplayItemStatus() { return _drawItemStatus; } - - Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } - Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } - - Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _engineToneMappingExposure = exposure; } - Q_INVOKABLE float getEngineToneMappingExposure() const { return _engineToneMappingExposure; } - - Q_INVOKABLE void setEngineToneMappingToneCurve(const QString& curve); - Q_INVOKABLE QString getEngineToneMappingToneCurve() const; - int getEngineToneMappingToneCurveValue() const { return _engineToneMappingToneCurve; } signals: void shouldRenderAvatarsChanged(bool shouldRenderAvatars); void shouldRenderEntitiesChanged(bool shouldRenderEntities); + protected: SceneScriptingInterface(); ~SceneScriptingInterface() {}; model::SunSkyStagePointer _skyStage = std::make_shared(); - + bool _shouldRenderAvatars = true; bool _shouldRenderEntities = true; - - bool _engineRenderOpaque = true; - bool _engineRenderTransparent = true; - bool _engineCullOpaque = true; - bool _engineCullTransparent = true; - bool _engineSortOpaque = true; - bool _engineSortTransparent = true; - - int _numFeedOpaqueItems = 0; - int _numDrawnOpaqueItems = 0; - int _numFeedTransparentItems = 0; - int _numDrawnTransparentItems = 0; - int _numFeedOverlay3DItems = 0; - int _numDrawnOverlay3DItems = 0; - - int _maxDrawnOpaqueItems = -1; - int _maxDrawnTransparentItems = -1; - int _maxDrawnOverlay3DItems = -1; - - int _deferredDebugMode = -1; - glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f }; - int _drawItemStatus = 0; - - bool _drawHitEffect = false; - - float _engineToneMappingExposure = 0.0f; - int _engineToneMappingToneCurve = 3; }; #endif // hifi_SceneScriptingInterface_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ded3db11e9..ef448e93f0 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -46,7 +46,6 @@ #include "XMLHttpRequestClass.h" #include "WebSocketClass.h" -#include "SceneScriptingInterface.h" #include "RecordingScriptingInterface.h" #include "MIDIEvent.h" From cdcb2d565d0dc6e6966ba505d0f16db4733c0d3d Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 17 Dec 2015 17:51:07 -0800 Subject: [PATCH 194/318] Use new RenderContext accessors for rendering --- .../src/AmbientOcclusionEffect.cpp | 6 ++-- .../render-utils/src/AntialiasingEffect.cpp | 8 ++--- .../render-utils/src/DebugDeferredBuffer.cpp | 8 ++--- libraries/render-utils/src/HitEffect.cpp | 6 ++-- libraries/render/src/render/DrawStatus.cpp | 10 +++--- libraries/render/src/render/DrawTask.cpp | 36 +++++++++---------- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 1b631aed9c..c32bf2654d 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -175,10 +175,10 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { } void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { auto framebufferCache = DependencyManager::get(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index fb59f37941..3acc88f953 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -93,14 +93,14 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { } void Antialiasing::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); - if (renderContext->args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { + if (renderContext->getArgs()->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { return; } - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index d61b131844..23150a1779 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -179,9 +179,9 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - const RenderArgs* args = renderContext->args; + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); + RenderArgs* args = renderContext->getArgs(); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { const auto geometryBuffer = DependencyManager::get(); const auto framebufferCache = DependencyManager::get(); @@ -211,4 +211,4 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren const glm::vec2 topRight(renderContext->_deferredDebugSize.z, renderContext->_deferredDebugSize.w); geometryBuffer->renderQuad(batch, bottomLeft, topRight, color); }); -} \ No newline at end of file +} diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index 32915aea0e..bf65eaf059 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -61,9 +61,9 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { } void HitEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - RenderArgs* args = renderContext->args; + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); + RenderArgs* args = renderContext->getArgs(); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { glm::mat4 projMat; diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 3f37ce378b..fa177bd0d4 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -97,9 +97,9 @@ const gpu::TexturePointer DrawStatus::getStatusIconMap() const { void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); - RenderArgs* args = renderContext->args; + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); + RenderArgs* args = renderContext->getArgs(); auto& scene = sceneContext->_scene; const int NUM_STATUS_VEC4_PER_ITEM = 2; const int VEC4_LENGTH = 4; @@ -179,7 +179,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const unsigned int VEC3_ADRESS_OFFSET = 3; - if ((renderContext->_drawItemStatus & showDisplayStatusFlag) > 0) { + if ((renderContext->getDrawStatus() & showDisplayStatusFlag) > 0) { for (int i = 0; i < nbItems; i++) { batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i)); batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); @@ -192,7 +192,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, batch.setPipeline(getDrawItemStatusPipeline()); - if ((renderContext->_drawItemStatus & showNetworkStatusFlag) > 0) { + if ((renderContext->getDrawStatus() & showNetworkStatusFlag) > 0) { for (int i = 0; i < nbItems; i++) { batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i)); batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index c0e50037e0..44ba57143f 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -37,7 +37,7 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon // Is it possible that we render without a viewFrustum ? - if (!(renderContext->args && renderContext->args->_viewFrustum)) { + if (!(renderContext->getArgs() && renderContext->getArgs()->_viewFrustum)) { return; } @@ -54,11 +54,11 @@ Job::~Job() { void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); - RenderArgs* args = renderContext->args; - auto renderDetails = renderContext->args->_details._item; + RenderArgs* args = renderContext->getArgs(); + auto renderDetails = renderContext->getArgs()->_details._item; renderDetails->_considered += inItems.size(); @@ -115,7 +115,7 @@ void CullItems::run(const SceneContextPointer& sceneContext, const RenderContext outItems.clear(); outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); args->_details.pointTo(RenderDetails::OTHER_ITEM); cullItems(sceneContext, renderContext, inItems, outItems); } @@ -124,7 +124,7 @@ void CullItemsOpaque::run(const SceneContextPointer& sceneContext, const RenderC outItems.clear(); outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); args->_details.pointTo(RenderDetails::OPAQUE_ITEM); cullItems(sceneContext, renderContext, inItems, outItems); } @@ -133,7 +133,7 @@ void CullItemsTransparent::run(const SceneContextPointer& sceneContext, const Re outItems.clear(); outItems.reserve(inItems.size()); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); args->_details.pointTo(RenderDetails::TRANSLUCENT_ITEM); cullItems(sceneContext, renderContext, inItems, outItems); } @@ -163,11 +163,11 @@ struct BackToFrontSort { }; void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); auto& scene = sceneContext->_scene; - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); // Allocate and simply copy @@ -211,7 +211,7 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) { auto& scene = sceneContext->_scene; - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); // render if ((maxDrawnItems < 0) || (maxDrawnItems > (int) inItems.size())) { for (auto itemDetails : inItems) { @@ -236,8 +236,8 @@ void render::renderItems(const SceneContextPointer& sceneContext, const RenderCo } void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); // render lights auto& scene = sceneContext->_scene; @@ -253,7 +253,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext ItemIDsBounds culledItems; culledItems.reserve(inItems.size()); - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); args->_details.pointTo(RenderDetails::OTHER_ITEM); cullItems(sceneContext, renderContext, inItems, culledItems); @@ -265,8 +265,8 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext } void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - assert(renderContext->args); - assert(renderContext->args->_viewFrustum); + assert(renderContext->getArgs()); + assert(renderContext->getArgs()->_viewFrustum); // render backgrounds auto& scene = sceneContext->_scene; @@ -278,7 +278,7 @@ void DrawBackground::run(const SceneContextPointer& sceneContext, const RenderCo for (auto id : items) { inItems.emplace_back(id); } - RenderArgs* args = renderContext->args; + RenderArgs* args = renderContext->getArgs(); doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; batch.enableSkybox(true); From de9e03a3794ac7a6567e498b23930440756500e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 18 Dec 2015 10:54:04 -0800 Subject: [PATCH 195/318] remove qxmpp external --- cmake/externals/qxmpp/CMakeLists.txt | 77 ---------------------------- 1 file changed, 77 deletions(-) delete mode 100644 cmake/externals/qxmpp/CMakeLists.txt diff --git a/cmake/externals/qxmpp/CMakeLists.txt b/cmake/externals/qxmpp/CMakeLists.txt deleted file mode 100644 index 600aa7b2ff..0000000000 --- a/cmake/externals/qxmpp/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -set(EXTERNAL_NAME qxmpp) - -# we need to find qmake inside QT_DIR -find_program(QMAKE_COMMAND NAME qmake PATHS ${QT_DIR}/bin $ENV{QTTOOLDIR} NO_DEFAULT_PATH) - -if (NOT QMAKE_COMMAND) - message(FATAL_ERROR "Could not find qmake. Qxmpp cannot be compiled without qmake.") -endif () - -if (ANDROID) - set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") -endif () - -if (WIN32) - find_program(PLATFORM_BUILD_COMMAND nmake PATHS "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin") - - if (NOT PLATFORM_BUILD_COMMAND) - message(FATAL_ERROR "You asked CMake to grap QXmpp and build it, but nmake was not found. Please make sure the folder containing nmake.exe is in your PATH.") - endif () -else () - find_program(PLATFORM_BUILD_COMMAND make) -endif () - -include(ExternalProject) -ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://qxmpp.googlecode.com/files/qxmpp-0.7.6.tar.gz - URL_MD5 ee45a97313306ded2ff0f6618a3ed1e1 - BUILD_IN_SOURCE 1 - PATCH_COMMAND patch -p2 -t -N --verbose < ${CMAKE_CURRENT_SOURCE_DIR}/qxmpp.patch - CONFIGURE_COMMAND ${QMAKE_COMMAND} PREFIX= - BUILD_COMMAND ${PLATFORM_BUILD_COMMAND} - INSTALL_COMMAND ${PLATFORM_BUILD_COMMAND} install - LOG_DOWNLOAD 1 - LOG_CONFIGURE 1 - LOG_BUILD 1 -) - -# Hide this external target (for ide users) -set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - -ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - -if (CMAKE_GENERATOR STREQUAL Xcode) - find_program(DITTO_COMMAND ditto) - - ExternalProject_Add_Step( - ${EXTERNAL_NAME} - copy-from-xcode-install - COMMENT "Copying from /tmp/hifi.dst${INSTALL_DIR} to move install to proper location" - COMMAND ${DITTO_COMMAND} /tmp/hifi.dst${INSTALL_DIR} ${INSTALL_DIR} - DEPENDEES install - LOG 1 - ) -endif () - -string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Qxmpp include directory") - -set(_LIB_DIR ${INSTALL_DIR}/lib) - -if (WIN32) - set(_LIB_EXT "0.lib") - - set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${_LIB_DIR} CACHE PATH "Location of QXmpp DLL") -else () - if (APPLE) - set(_LIB_EXT ".dylib") - else () - set(_LIB_EXT ".so") - endif () - - set(_LIB_PREFIX "lib") -endif () - -set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/${_LIB_PREFIX}qxmpp${_LIB_EXT} CACHE FILEPATH "Path to QXmpp release library") -set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to QXmpp debug library") From d6541e9ee77ce1fdca7ea003b08f4030b3854b4e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Dec 2015 11:06:58 -0800 Subject: [PATCH 196/318] angular velocity is a vector, not a quaternion --- interface/src/avatar/MyAvatar.cpp | 14 ++++++------ libraries/avatars/src/HandData.cpp | 8 +++---- libraries/avatars/src/HandData.h | 19 ++++++++-------- .../controllers/src/controllers/Pose.cpp | 6 ++--- libraries/controllers/src/controllers/Pose.h | 6 ++--- plugins/hifiSixense/src/SixenseManager.cpp | 22 ++++++++----------- plugins/hifiSixense/src/SixenseManager.h | 8 +++---- 7 files changed, 39 insertions(+), 44 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5c8230bd88..c989f1dc71 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -509,25 +509,25 @@ glm::vec3 MyAvatar::getRightHandTipPosition() const { controller::Pose MyAvatar::getLeftHandPose() const { auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand); return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(), - palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose(); + palmData.getVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); } controller::Pose MyAvatar::getRightHandPose() const { auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand); return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(), - palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose(); + palmData.getVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); } controller::Pose MyAvatar::getLeftHandTipPose() const { auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand); return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(), - palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose(); + palmData.getTipVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); } controller::Pose MyAvatar::getRightHandTipPose() const { auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand); return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(), - palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose(); + palmData.getTipVelocity(), palmData.getRawAngularVelocity()) : controller::Pose(); } // virtual @@ -536,7 +536,7 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (!_shouldRender) { return; // exit early } - + Avatar::render(renderArgs, cameraPosition); } @@ -799,7 +799,7 @@ void MyAvatar::updateLookAtTargetAvatar() { const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; AvatarHash hash = DependencyManager::get()->getHashCopy(); - + foreach (const AvatarSharedPointer& avatarPointer, hash) { auto avatar = static_pointer_cast(avatarPointer); bool isCurrentTarget = avatar->getIsLookAtTarget(); @@ -1175,7 +1175,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (!_skeletonModel.isRenderable()) { return; // wait until all models are loaded } - + fixupModelsInScene(); // Render head so long as the camera isn't inside it diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 5d783a671e..7ba23b01ad 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -14,7 +14,7 @@ #include #include -#include "AvatarData.h" +#include "AvatarData.h" #include "HandData.h" @@ -38,7 +38,7 @@ PalmData& HandData::addNewPalm(Hand whichHand) { PalmData HandData::getCopyOfPalmData(Hand hand) const { QReadLocker locker(&_palmsLock); - // the palms are not necessarily added in left-right order, + // the palms are not necessarily added in left-right order, // so we have to search for the correct hand for (const auto& palm : _palms) { if (palm.whichHand() == hand && palm.isActive()) { @@ -64,7 +64,7 @@ void PalmData::addToPosition(const glm::vec3& delta) { _rawPosition += _owningHandData->worldToLocalVector(delta); } -bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, +bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, const PalmData*& collidingPalm) const { QReadLocker locker(&_palmsLock); @@ -93,7 +93,7 @@ glm::vec3 HandData::getBasePosition() const { float HandData::getBaseScale() const { return _owningAvatarData->getTargetScale(); } - + glm::vec3 PalmData::getFingerDirection() const { // finger points along yAxis in hand-frame const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 1.0f, 0.0f); diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index d782f240ee..34ed610f80 100644 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -38,7 +38,7 @@ public: HandData(AvatarData* owningAvatar); virtual ~HandData() {} - + // position conversion glm::vec3 localToWorldPosition(const glm::vec3& localPosition) { return getBasePosition() + getBaseOrientation() * localPosition * getBaseScale(); @@ -60,7 +60,7 @@ public: /// \param penetration[out] the vector in which to store the penetration /// \param collidingPalm[out] a const PalmData* to the palm that was collided with /// \return whether or not the sphere penetrated - bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, + bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, const PalmData*& collidingPalm) const; glm::quat getBaseOrientation() const; @@ -74,7 +74,7 @@ protected: AvatarData* _owningAvatarData; std::vector _palms; mutable QReadWriteLock _palmsLock{ QReadWriteLock::Recursive }; - + glm::vec3 getBasePosition() const; float getBaseScale() const; @@ -112,13 +112,12 @@ public: void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; } const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; } - glm::quat getRawAngularVelocityAsQuat() const { return glm::quat(_rawAngularVelocity); } void addToPosition(const glm::vec3& delta); void addToPenetration(const glm::vec3& penetration) { _totalPenetration += penetration; } void resolvePenetrations() { addToPosition(-_totalPenetration); _totalPenetration = glm::vec3(0.0f); } - + void setTipPosition(const glm::vec3& position) { _tipPosition = position; } const glm::vec3 getTipPosition() const { return _owningHandData->localToWorldPosition(_tipPosition); } const glm::vec3& getTipRawPosition() const { return _tipPosition; } @@ -126,16 +125,16 @@ public: void setTipVelocity(const glm::vec3& velocity) { _tipVelocity = velocity; } const glm::vec3 getTipVelocity() const { return _owningHandData->localToWorldDirection(_tipVelocity); } const glm::vec3& getTipRawVelocity() const { return _tipVelocity; } - + void incrementFramesWithoutData() { _numFramesWithoutData++; } void resetFramesWithoutData() { _numFramesWithoutData = 0; } int getFramesWithoutData() const { return _numFramesWithoutData; } - + // FIXME - these are used in SkeletonModel::updateRig() the skeleton/rig should probably get this information // from an action and/or the UserInputMapper instead of piping it through here. void setTrigger(float trigger) { _trigger = trigger; } float getTrigger() const { return _trigger; } - + // return world-frame: glm::vec3 getFingerDirection() const; glm::vec3 getNormal() const; @@ -148,13 +147,13 @@ private: glm::vec3 _rawAngularVelocity; glm::quat _rawDeltaRotation; glm::quat _lastRotation; - + glm::vec3 _tipPosition; glm::vec3 _tipVelocity; glm::vec3 _totalPenetration; /// accumulator for per-frame penetrations float _trigger; - + bool _isActive; /// This has current valid data int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost. HandData* _owningHandData; diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index 2281fc98ff..f07472e9e0 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -16,7 +16,7 @@ namespace controller { Pose::Pose(const vec3& translation, const quat& rotation, - const vec3& velocity, const quat& angularVelocity) : + const vec3& velocity, const vec3& angularVelocity) : translation(translation), rotation(rotation), velocity(velocity), angularVelocity(angularVelocity), valid (true) { } bool Pose::operator==(const Pose& right) const { @@ -26,7 +26,7 @@ namespace controller { } // FIXME add margin of error? Or add an additional withinEpsilon function? - return translation == right.getTranslation() && rotation == right.getRotation() && + return translation == right.getTranslation() && rotation == right.getRotation() && velocity == right.getVelocity() && angularVelocity == right.getAngularVelocity(); } @@ -35,7 +35,7 @@ namespace controller { obj.setProperty("translation", vec3toScriptValue(engine, pose.translation)); obj.setProperty("rotation", quatToScriptValue(engine, pose.rotation)); obj.setProperty("velocity", vec3toScriptValue(engine, pose.velocity)); - obj.setProperty("angularVelocity", quatToScriptValue(engine, pose.angularVelocity)); + obj.setProperty("angularVelocity", vec3toScriptValue(engine, pose.angularVelocity)); obj.setProperty("valid", pose.valid); return obj; diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h index b8d27824f3..a8a4452758 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -23,12 +23,12 @@ namespace controller { vec3 translation; quat rotation; vec3 velocity; - quat angularVelocity; + vec3 angularVelocity; bool valid{ false }; Pose() {} Pose(const vec3& translation, const quat& rotation, - const vec3& velocity = vec3(), const quat& angularVelocity = quat()); + const vec3& velocity = vec3(), const vec3& angularVelocity = vec3()); Pose(const Pose&) = default; Pose& operator = (const Pose&) = default; @@ -38,7 +38,7 @@ namespace controller { vec3 getTranslation() const { return translation; } quat getRotation() const { return rotation; } vec3 getVelocity() const { return velocity; } - quat getAngularVelocity() const { return angularVelocity; } + vec3 getAngularVelocity() const { return angularVelocity; } static QScriptValue toScriptValue(QScriptEngine* engine, const Pose& event); static void fromScriptValue(const QScriptValue& object, Pose& event); diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 93329d768e..fb47697166 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -191,7 +191,7 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) { // Rotation of Palm glm::quat rotation(data->rot_quat[3], data->rot_quat[0], data->rot_quat[1], data->rot_quat[2]); handlePoseEvent(deltaTime, position, rotation, left); - rawPoses[i] = controller::Pose(position, rotation, glm::vec3(0), glm::quat()); + rawPoses[i] = controller::Pose(position, rotation, Vectors::ZERO, Vectors::ZERO); } else { _poseStateMap.clear(); _collectedSamples.clear(); @@ -457,25 +457,21 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand; glm::vec3 velocity(0.0f); - glm::quat angularVelocity; + glm::vec3 angularVelocity(0.0f); if (prevPose.isValid() && deltaTime > std::numeric_limits::epsilon()) { + auto& samples = _collectedSamples[hand]; velocity = (position - prevPose.getTranslation()) / deltaTime; + samples.first.addSample(velocity); + velocity = samples.first.average; auto deltaRot = rotation * glm::conjugate(prevPose.getRotation()); auto axis = glm::axis(deltaRot); - auto angle = glm::angle(deltaRot); - angularVelocity = glm::angleAxis(angle / deltaTime, axis); - - // Average - auto& samples = _collectedSamples[hand]; - samples.first.addSample(velocity); - velocity = samples.first.average; - - // FIXME: // Not using quaternion average yet for angular velocity because it s probably wrong but keep the MovingAverage in place - //samples.second.addSample(glm::vec4(angularVelocity.x, angularVelocity.y, angularVelocity.z, angularVelocity.w)); - //angularVelocity = glm::quat(samples.second.average.w, samples.second.average.x, samples.second.average.y, samples.second.average.z); + auto speed = glm::angle(deltaRot) / deltaTime; + angularVelocity = speed * axis; + samples.second.addSample(angularVelocity); + angularVelocity = samples.second.average; } else if (!prevPose.isValid()) { _collectedSamples[hand].first.clear(); _collectedSamples[hand].second.clear(); diff --git a/plugins/hifiSixense/src/SixenseManager.h b/plugins/hifiSixense/src/SixenseManager.h index 5cd4dc2451..0de5fe93aa 100644 --- a/plugins/hifiSixense/src/SixenseManager.h +++ b/plugins/hifiSixense/src/SixenseManager.h @@ -49,12 +49,12 @@ private: static const int CALIBRATION_STATE_IDLE = 0; static const int CALIBRATION_STATE_IN_PROGRESS = 1; static const int CALIBRATION_STATE_COMPLETE = 2; - static const glm::vec3 DEFAULT_AVATAR_POSITION; + static const glm::vec3 DEFAULT_AVATAR_POSITION; static const float CONTROLLER_THRESHOLD; - + template using SampleAverage = MovingAverage; - using Samples = std::pair, SampleAverage>; + using Samples = std::pair, SampleAverage>; using MovingAverageMap = std::map; class InputDevice : public controller::InputDevice { @@ -81,7 +81,7 @@ private: // these are calibration results glm::vec3 _avatarPosition { DEFAULT_AVATAR_POSITION }; // in hydra-frame glm::quat _avatarRotation; // in hydra-frame - + float _lastDistance; bool _requestReset { false }; bool _debugDrawRaw { false }; From 08a087c5aa40885185ea80371dd0536cd42fe074 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Dec 2015 11:19:01 -0800 Subject: [PATCH 197/318] PR comments --- libraries/ui/src/QmlWebWindowClass.cpp | 235 +++++------------- libraries/ui/src/QmlWebWindowClass.h | 14 +- .../ui/src/impl/websocketclientwrapper.cpp | 72 ------ .../ui/src/impl/websocketclientwrapper.h | 63 ----- libraries/ui/src/impl/websockettransport.cpp | 100 -------- libraries/ui/src/impl/websockettransport.h | 60 ----- 6 files changed, 73 insertions(+), 471 deletions(-) delete mode 100644 libraries/ui/src/impl/websocketclientwrapper.cpp delete mode 100644 libraries/ui/src/impl/websocketclientwrapper.h delete mode 100644 libraries/ui/src/impl/websockettransport.cpp delete mode 100644 libraries/ui/src/impl/websockettransport.h diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 2b7270edf0..eeadb361ae 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -17,32 +17,23 @@ #include #include +#include #include +#include +#include #include #include -#include "impl/websocketclientwrapper.h" -#include "impl/websockettransport.h" #include "OffscreenUi.h" -static QWebSocketServer * webChannelServer { nullptr }; -static WebSocketClientWrapper * webChannelClientWrapper { nullptr }; +QWebSocketServer* QmlWebWindowClass::_webChannelServer { nullptr }; static QWebChannel webChannel; -static std::once_flag webChannelSetup; static const uint16_t WEB_CHANNEL_PORT = 51016; static std::atomic nextWindowId; - -void initWebChannelServer() { - std::call_once(webChannelSetup, [] { - webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); - webChannelClientWrapper = new WebSocketClientWrapper(webChannelServer); - if (!webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { - qFatal("Failed to open web socket server."); - } - QObject::connect(webChannelClientWrapper, &WebSocketClientWrapper::clientConnected, &webChannel, &QWebChannel::connectTo); - }); -} +static const char* const URL_PROPERTY = "source"; +static const char* const TITLE_PROPERTY = "title"; +static const QRegExp HIFI_URL_PATTERN { "^hifi://" }; void QmlScriptEventBridge::emitWebEvent(const QString& data) { QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); @@ -50,11 +41,49 @@ void QmlScriptEventBridge::emitWebEvent(const QString& data) { void QmlScriptEventBridge::emitScriptEvent(const QString& data) { QMetaObject::invokeMethod(this, "scriptEventReceived", Qt::QueuedConnection, - Q_ARG(int, _webWindow->getWindowId()), - Q_ARG(QString, data) - ); + Q_ARG(int, _webWindow->getWindowId()), Q_ARG(QString, data)); } +class QmlWebTransport : public QWebChannelAbstractTransport { + Q_OBJECT +public: + QmlWebTransport(QWebSocket* webSocket) : _webSocket(webSocket) { + // Translate from the websocket layer to the webchannel layer + connect(webSocket, &QWebSocket::textMessageReceived, [this](const QString& message) { + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(message.toUtf8(), &error); + if (error.error || !document.isObject()) { + qWarning() << "Unable to parse incoming JSON message" << message; + return; + } + emit messageReceived(document.object(), this); + }); + } + + virtual void sendMessage(const QJsonObject &message) override { + // Translate from the webchannel layer to the websocket layer + _webSocket->sendTextMessage(QJsonDocument(message).toJson(QJsonDocument::Compact)); + } + +private: + QWebSocket* const _webSocket; +}; + + +void QmlWebWindowClass::setupServer() { + if (!_webChannelServer) { + _webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); + if (!_webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { + qFatal("Failed to open web socket server."); + } + + QObject::connect(_webChannelServer, &QWebSocketServer::newConnection, [] { + webChannel.connectTo(new QmlWebTransport(_webChannelServer->nextPendingConnection())); + }); + } +} + +// Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { QmlWebWindowClass* retVal { nullptr }; const QString title = context->argument(0).toString(); @@ -69,20 +98,19 @@ QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngi QMetaObject::invokeMethod(DependencyManager::get().data(), "load", Qt::BlockingQueuedConnection, Q_ARG(const QString&, "QmlWebWindow.qml"), Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { - initWebChannelServer(); + setupServer(); retVal = new QmlWebWindowClass(object); webChannel.registerObject(url.toLower(), retVal); retVal->setTitle(title); retVal->setURL(url); retVal->setSize(width, height); - }) - ); + })); connect(engine, &QScriptEngine::destroyed, retVal, &QmlWebWindowClass::deleteLater); return engine->newQObject(retVal); } QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) - : _isToolWindow(false), _windowId(++nextWindowId), _eventBridge(new QmlScriptEventBridge(this)), _qmlWindow(qmlWindow) + : _isToolWindow(false), _windowId(++nextWindowId), _qmlWindow(qmlWindow) { qDebug() << "Created window with ID " << _windowId; Q_ASSERT(_qmlWindow); @@ -94,7 +122,6 @@ void QmlWebWindowClass::handleNavigation(const QString& url) { DependencyManager::get()->handleLookupString(url); } - void QmlWebWindowClass::setVisible(bool visible) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); @@ -108,6 +135,10 @@ void QmlWebWindowClass::setVisible(bool visible) { } } +QQuickItem* QmlWebWindowClass::asQuickItem() const { + return dynamic_cast(_qmlWindow); +} + bool QmlWebWindowClass::isVisible() const { if (QThread::currentThread() != thread()) { bool result; @@ -115,7 +146,7 @@ bool QmlWebWindowClass::isVisible() const { return result; } - return ((QQuickItem*)_qmlWindow)->isEnabled(); + return asQuickItem()->isEnabled(); } @@ -126,7 +157,7 @@ glm::vec2 QmlWebWindowClass::getPosition() const { return result; } - return glm::vec2(((QQuickItem*)_qmlWindow)->x(), ((QQuickItem*)_qmlWindow)->y()); + return glm::vec2(asQuickItem()->x(), asQuickItem()->y()); } @@ -136,7 +167,7 @@ void QmlWebWindowClass::setPosition(const glm::vec2& position) { return; } - ((QQuickItem*)_qmlWindow)->setPosition(QPointF(position.x, position.y)); + asQuickItem()->setPosition(QPointF(position.x, position.y)); } void QmlWebWindowClass::setPosition(int x, int y) { @@ -150,7 +181,7 @@ glm::vec2 QmlWebWindowClass::getSize() const { return result; } - return glm::vec2(((QQuickItem*)_qmlWindow)->width(), ((QQuickItem*)_qmlWindow)->height()); + return glm::vec2(asQuickItem()->width(), asQuickItem()->height()); } void QmlWebWindowClass::setSize(const glm::vec2& size) { @@ -158,15 +189,13 @@ void QmlWebWindowClass::setSize(const glm::vec2& size) { QMetaObject::invokeMethod(this, "setSize", Qt::QueuedConnection, Q_ARG(glm::vec2, size)); } - ((QQuickItem*)_qmlWindow)->setSize(QSizeF(size.x, size.y)); + asQuickItem()->setSize(QSizeF(size.x, size.y)); } void QmlWebWindowClass::setSize(int width, int height) { setSize(glm::vec2(width, height)); } -static const char* const URL_PROPERTY = "source"; - QString QmlWebWindowClass::getURL() const { if (QThread::currentThread() != thread()) { QString result; @@ -183,7 +212,6 @@ void QmlWebWindowClass::setURL(const QString& urlString) { _qmlWindow->setProperty(URL_PROPERTY, urlString); } -static const char* const TITLE_PROPERTY = "title"; void QmlWebWindowClass::setTitle(const QString& title) { if (QThread::currentThread() != thread()) { @@ -206,146 +234,7 @@ void QmlWebWindowClass::hasClosed() { } void QmlWebWindowClass::raise() { + // FIXME } -#if 0 - -#include - -#include - -WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow) - : QObject(NULL), _eventBridge(new ScriptEventBridge(this)), _isToolWindow(isToolWindow) { - /* - if (_isToolWindow) { - ToolWindow* toolWindow = qApp->getToolWindow(); - - auto dockWidget = new QDockWidget(title, toolWindow); - dockWidget->setFeatures(QDockWidget::DockWidgetMovable); - connect(dockWidget, &QDockWidget::visibilityChanged, this, &WebWindowClass::visibilityChanged); - - _webView = new QWebView(dockWidget); - addEventBridgeToWindowObject(); - - dockWidget->setWidget(_webView); - - auto titleWidget = new QWidget(dockWidget); - dockWidget->setTitleBarWidget(titleWidget); - - toolWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget, Qt::Horizontal); - - _windowWidget = dockWidget; - } else { - auto dialogWidget = new QDialog(qApp->getWindow(), Qt::Window); - dialogWidget->setWindowTitle(title); - dialogWidget->resize(width, height); - dialogWidget->installEventFilter(this); - connect(dialogWidget, &QDialog::finished, this, &WebWindowClass::hasClosed); - - auto layout = new QVBoxLayout(dialogWidget); - layout->setContentsMargins(0, 0, 0, 0); - dialogWidget->setLayout(layout); - - _webView = new QWebView(dialogWidget); - - layout->addWidget(_webView); - - addEventBridgeToWindowObject(); - - _windowWidget = dialogWidget; - } - - auto style = QStyleFactory::create("fusion"); - if (style) { - _webView->setStyle(style); - } - - _webView->setPage(new DataWebPage()); - if (!url.startsWith("http") && !url.startsWith("file://")) { - _webView->setUrl(QUrl::fromLocalFile(url)); - } else { - _webView->setUrl(url); - } - connect(this, &WebWindowClass::destroyed, _windowWidget, &QWidget::deleteLater); - connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, - this, &WebWindowClass::addEventBridgeToWindowObject); - */ -} - -void WebWindowClass::hasClosed() { - emit closed(); -} - - -void WebWindowClass::setVisible(bool visible) { -} - -QString WebWindowClass::getURL() const { - return QString(); -} - -void WebWindowClass::setURL(const QString& url) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url)); - return; - } -} - -QSizeF WebWindowClass::getSize() const { - QSizeF size; - return size; -} - -void WebWindowClass::setSize(const QSizeF& size) { - setSize(size.width(), size.height()); -} - -void WebWindowClass::setSize(int width, int height) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setSize", Qt::AutoConnection, Q_ARG(int, width), Q_ARG(int, height)); - return; - } -} - -glm::vec2 WebWindowClass::getPosition() const { - return glm::vec2(); -} - -void WebWindowClass::setPosition(const glm::vec2& position) { - setPosition(position.x, position.y); -} - -void WebWindowClass::setPosition(int x, int y) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setPosition", Qt::AutoConnection, Q_ARG(int, x), Q_ARG(int, y)); - return; - } -} - -void WebWindowClass::raise() { -} - -QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { - WebWindowClass* retVal { nullptr }; - //QString file = context->argument(0).toString(); - //QMetaObject::invokeMethod(DependencyManager::get().data(), "doCreateWebWindow", Qt::BlockingQueuedConnection, - // Q_RETURN_ARG(WebWindowClass*, retVal), - // Q_ARG(const QString&, file), - // Q_ARG(QString, context->argument(1).toString()), - // Q_ARG(int, context->argument(2).toInteger()), - // Q_ARG(int, context->argument(3).toInteger()), - // Q_ARG(bool, context->argument(4).toBool())); - - //connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater); - - return engine->newQObject(retVal); -} - -void WebWindowClass::setTitle(const QString& title) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setTitle", Qt::AutoConnection, Q_ARG(QString, title)); - return; - } -} - -#endif \ No newline at end of file +#include "QmlWebWindowClass.moc" diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index 1575ec7916..90d355e162 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -13,10 +13,13 @@ #include #include #include +#include class QScriptEngine; class QScriptContext; class QmlWebWindowClass; +class QWebSocketServer; +class QWebSocket; class QmlScriptEventBridge : public QObject { Q_OBJECT @@ -33,6 +36,7 @@ signals: private: const QmlWebWindowClass* _webWindow { nullptr }; + QWebSocket *_socket { nullptr }; }; // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping @@ -84,9 +88,13 @@ private slots: void handleNavigation(const QString& url); private: - QmlScriptEventBridge* _eventBridge; - bool _isToolWindow { false }; - QObject* _qmlWindow; + static void setupServer(); + static QWebSocketServer* _webChannelServer; + + QQuickItem* asQuickItem() const; + QmlScriptEventBridge* const _eventBridge { new QmlScriptEventBridge(this) }; + const bool _isToolWindow; + QObject* const _qmlWindow; const int _windowId; }; diff --git a/libraries/ui/src/impl/websocketclientwrapper.cpp b/libraries/ui/src/impl/websocketclientwrapper.cpp deleted file mode 100644 index 00ddd6e009..0000000000 --- a/libraries/ui/src/impl/websocketclientwrapper.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWebChannel module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "websocketclientwrapper.h" - -#include - -#include "websockettransport.h" - -/*! - \brief Wrapps connected QWebSockets clients in WebSocketTransport objects. - - This code is all that is required to connect incoming WebSockets to the WebChannel. Any kind - of remote JavaScript client that supports WebSockets can thus receive messages and access the - published objects. -*/ - -QT_BEGIN_NAMESPACE - -/*! - Construct the client wrapper with the given parent. - - All clients connecting to the QWebSocketServer will be automatically wrapped - in WebSocketTransport objects. -*/ -WebSocketClientWrapper::WebSocketClientWrapper(QWebSocketServer *server, QObject *parent) - : QObject(parent) - , m_server(server) -{ - connect(server, &QWebSocketServer::newConnection, - this, &WebSocketClientWrapper::handleNewConnection); -} - -/*! - Wrap an incoming WebSocket connection in a WebSocketTransport object. -*/ -void WebSocketClientWrapper::handleNewConnection() -{ - emit clientConnected(new WebSocketTransport(m_server->nextPendingConnection())); -} - -QT_END_NAMESPACE diff --git a/libraries/ui/src/impl/websocketclientwrapper.h b/libraries/ui/src/impl/websocketclientwrapper.h deleted file mode 100644 index edb0a1b1a3..0000000000 --- a/libraries/ui/src/impl/websocketclientwrapper.h +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWebChannel module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef WEBSOCKETTRANSPORTSERVER_H -#define WEBSOCKETTRANSPORTSERVER_H - -#include - -QT_BEGIN_NAMESPACE - -class QWebSocketServer; -class WebSocketTransport; - -class WebSocketClientWrapper : public QObject -{ - Q_OBJECT - -public: - WebSocketClientWrapper(QWebSocketServer *server, QObject *parent = 0); - -Q_SIGNALS: - void clientConnected(WebSocketTransport* client); - -private Q_SLOTS: - void handleNewConnection(); - -private: - QWebSocketServer *m_server; -}; - -QT_END_NAMESPACE - -#endif // WEBSOCKETTRANSPORTSERVER_H diff --git a/libraries/ui/src/impl/websockettransport.cpp b/libraries/ui/src/impl/websockettransport.cpp deleted file mode 100644 index 8ed330c72d..0000000000 --- a/libraries/ui/src/impl/websockettransport.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWebChannel module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "websockettransport.h" - -#include -#include -#include - -#include - -/*! - \brief QWebChannelAbstractSocket implementation that uses a QWebSocket internally. - - The transport delegates all messages received over the QWebSocket over its - textMessageReceived signal. Analogously, all calls to sendTextMessage will - be send over the QWebSocket to the remote client. -*/ - -QT_BEGIN_NAMESPACE - -/*! - Construct the transport object and wrap the given socket. - - The socket is also set as the parent of the transport object. -*/ -WebSocketTransport::WebSocketTransport(QWebSocket *socket) -: QWebChannelAbstractTransport(socket) -, m_socket(socket) -{ - connect(socket, &QWebSocket::textMessageReceived, - this, &WebSocketTransport::textMessageReceived); -} - -/*! - Destroys the WebSocketTransport. -*/ -WebSocketTransport::~WebSocketTransport() -{ - -} - -/*! - Serialize the JSON message and send it as a text message via the WebSocket to the client. -*/ -void WebSocketTransport::sendMessage(const QJsonObject &message) -{ - QJsonDocument doc(message); - m_socket->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact))); -} - -/*! - Deserialize the stringified JSON messageData and emit messageReceived. -*/ -void WebSocketTransport::textMessageReceived(const QString &messageData) -{ - QJsonParseError error; - QJsonDocument message = QJsonDocument::fromJson(messageData.toUtf8(), &error); - if (error.error) { - qWarning() << "Failed to parse text message as JSON object:" << messageData - << "Error is:" << error.errorString(); - return; - } else if (!message.isObject()) { - qWarning() << "Received JSON message that is not an object: " << messageData; - return; - } - emit messageReceived(message.object(), this); -} - -QT_END_NAMESPACE diff --git a/libraries/ui/src/impl/websockettransport.h b/libraries/ui/src/impl/websockettransport.h deleted file mode 100644 index a1fdd3553a..0000000000 --- a/libraries/ui/src/impl/websockettransport.h +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWebChannel module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef WEBSOCKETTRANSPORT_H -#define WEBSOCKETTRANSPORT_H - -#include - -QT_BEGIN_NAMESPACE - -class QWebSocket; -class WebSocketTransport : public QWebChannelAbstractTransport -{ - Q_OBJECT -public: - explicit WebSocketTransport(QWebSocket *socket); - virtual ~WebSocketTransport(); - - void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void textMessageReceived(const QString &message); - -private: - QWebSocket *m_socket; -}; - -QT_END_NAMESPACE - -#endif // WEBSOCKETTRANSPORT_H From d057239023dcabd7b734e0268a2c3410ef2c23c4 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 18 Dec 2015 11:48:40 -0800 Subject: [PATCH 198/318] Rename RenderContext::ItemsMeta to ItemsConfig --- interface/src/Application.cpp | 6 +++--- libraries/render-utils/src/RenderDeferredTask.cpp | 14 +++++++------- .../render-utils/src/RenderScriptingInterface.h | 6 +++--- libraries/render/src/render/Engine.h | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fedc64174f..3cd185db0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3681,7 +3681,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderArgs->_viewFrustum = getDisplayViewFrustum(); auto renderInterface = DependencyManager::get(); - auto renderItemsMeta = renderInterface->getItemsMeta(); + auto renderItemsConfig = renderInterface->getItemsConfig(); auto renderTone = renderInterface->getTone(); int drawStatus = renderInterface->getDrawStatus(); bool drawHitEffect = renderInterface->getDrawHitEffect(); @@ -3690,7 +3690,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se bool antialiasingStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing); bool showOwnedStatus = Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned); - render::RenderContext renderContext{renderArgs, renderItemsMeta, renderTone}; + render::RenderContext renderContext{renderArgs, renderItemsConfig, renderTone}; renderContext.setOptions(drawStatus, drawHitEffect, occlusionStatus, antialiasingStatus, showOwnedStatus); _renderEngine->setRenderContext(renderContext); @@ -3700,7 +3700,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se myAvatar->endRenderRun(); auto engineContext = _renderEngine->getRenderContext(); - renderInterface->setItemCounts(engineContext->getItemsMeta()); + renderInterface->setItemCounts(engineContext->getItemsConfig()); } activeRenderingThread = nullptr; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 820f2b86bb..2594c9503e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -53,8 +53,8 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // CPU only, create the list of renderedOpaques items _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { - context->getItemsMeta()._opaque._numFeed = count; - auto& opaque = context->getItemsMeta()._opaque; + context->getItemsConfig()._opaque._numFeed = count; + auto& opaque = context->getItemsConfig()._opaque; }) ))); _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); @@ -65,7 +65,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", FetchItems(ItemFilter::Builder::transparentShape().withoutLayered(), [](const RenderContextPointer& context, int count) { - context->getItemsMeta()._transparent._numFeed = count; + context->getItemsConfig()._transparent._numFeed = count; }) ))); _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); @@ -187,7 +187,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setStateScissorRect(args->_viewport); args->_batch = &batch; - auto& opaque = renderContext->getItemsMeta()._opaque; + auto& opaque = renderContext->getItemsConfig()._opaque; opaque._numDrawn = (int)inItems.size(); glm::mat4 projMat; @@ -217,7 +217,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setStateScissorRect(args->_viewport); args->_batch = &batch; - auto& transparent = renderContext->getItemsMeta()._transparent; + auto& transparent = renderContext->getItemsConfig()._transparent; transparent._numDrawn = (int)inItems.size(); glm::mat4 projMat; @@ -270,7 +270,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon inItems.emplace_back(id); } } - auto& overlay3D = renderContext->getItemsMeta()._overlay3D; + auto& overlay3D = renderContext->getItemsConfig()._overlay3D; overlay3D._numFeed = (int)inItems.size(); overlay3D._numDrawn = (int)inItems.size(); @@ -304,7 +304,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderItems(sceneContext, renderContext, inItems, renderContext->getItemsMeta()._overlay3D._maxDrawn); + renderItems(sceneContext, renderContext, inItems, renderContext->getItemsConfig()._overlay3D._maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index ec3b5be669..8e33d7b929 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -72,15 +72,15 @@ class RenderScriptingInterface : public QObject, public Dependency { inline int getDrawStatus() { return _drawStatus; } inline bool getDrawHitEffect() { return _drawHitEffect; } - inline const render::RenderContext::ItemsMeta& getItemsMeta() { return _items; } + inline const render::RenderContext::ItemsConfig& getItemsConfig() { return _items; } inline const render::RenderContext::Tone& getTone() { return _tone; } - void setItemCounts(const render::RenderContext::ItemsMeta& items) { _items.setCounts(items); }; + void setItemCounts(const render::RenderContext::ItemsConfig& items) { _items.setCounts(items); }; protected: RenderScriptingInterface(); ~RenderScriptingInterface() {}; - render::RenderContext::ItemsMeta _items; + render::RenderContext::ItemsConfig _items; render::RenderContext::Tone _tone; // Options diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index dcfe28a444..3b1bad45e7 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -32,8 +32,8 @@ const int showNetworkStatusFlag = 2; class RenderContext { public: - struct ItemsMeta { - inline void setCounts(const ItemsMeta& items) { + struct ItemsConfig { + inline void setCounts(const ItemsConfig& items) { _opaque.setCounts(items._opaque); _transparent.setCounts(items._transparent); _overlay3D.setCounts(items._overlay3D); @@ -75,7 +75,7 @@ public: float _exposure = 0.0; }; - RenderContext(RenderArgs* args, ItemsMeta items, Tone tone) : _args{args}, _items{items}, _tone{tone} {}; + RenderContext(RenderArgs* args, ItemsConfig items, Tone tone) : _args{args}, _items{items}, _tone{tone} {}; RenderContext() : RenderContext(nullptr, {}, {}) {}; inline RenderArgs* getArgs() { return _args; } @@ -83,7 +83,7 @@ public: inline bool getDrawHitEffect() { return _drawHitEffect; } inline bool getOcclusionStatus() { return _occlusionStatus; } inline bool getFxaaStatus() { return _fxaaStatus; } - inline ItemsMeta& getItemsMeta() { return _items; } + inline ItemsConfig& getItemsConfig() { return _items; } inline Tone& getTone() { return _tone; } void setOptions(int drawStatus, bool drawHitEffect, bool occlusion, bool fxaa, bool showOwned); @@ -100,7 +100,7 @@ protected: bool _occlusionStatus = false; bool _fxaaStatus = false; - ItemsMeta _items; + ItemsConfig _items; Tone _tone; }; typedef std::shared_ptr RenderContextPointer; From 674bfa4f370780cb892aa5b85c71d8dd8385b7f3 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 18 Dec 2015 12:04:21 -0800 Subject: [PATCH 199/318] Replace RenderContext substructs with subclasses --- .../render-utils/src/RenderDeferredTask.cpp | 30 +++++----- .../src/RenderScriptingInterface.cpp | 10 ++-- .../src/RenderScriptingInterface.h | 54 +++++++++--------- libraries/render/src/render/Engine.h | 56 ++++++++++--------- 4 files changed, 77 insertions(+), 73 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 2594c9503e..ddfb6bc7a3 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -53,8 +53,8 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // CPU only, create the list of renderedOpaques items _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { - context->getItemsConfig()._opaque._numFeed = count; - auto& opaque = context->getItemsConfig()._opaque; + context->getItemsConfig().opaque.numFeed = count; + auto& opaque = context->getItemsConfig().opaque; }) ))); _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); @@ -65,7 +65,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", FetchItems(ItemFilter::Builder::transparentShape().withoutLayered(), [](const RenderContextPointer& context, int count) { - context->getItemsConfig()._transparent._numFeed = count; + context->getItemsConfig().transparent.numFeed = count; }) ))); _jobs.push_back(Job(new CullItemsTransparent::JobModel("CullTransparent", _jobs.back().getOutput()))); @@ -166,8 +166,8 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend setAntialiasingStatus(renderContext->getFxaaStatus()); - setToneMappingExposure(renderContext->getTone()._exposure); - setToneMappingToneCurve(renderContext->getTone()._toneCurve); + setToneMappingExposure(renderContext->getTone().exposure); + setToneMappingToneCurve(renderContext->getTone().toneCurve); renderContext->getArgs()->_context->syncCache(); @@ -187,8 +187,8 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend batch.setStateScissorRect(args->_viewport); args->_batch = &batch; - auto& opaque = renderContext->getItemsConfig()._opaque; - opaque._numDrawn = (int)inItems.size(); + auto& opaque = renderContext->getItemsConfig().opaque; + opaque.numDrawn = (int)inItems.size(); glm::mat4 projMat; Transform viewMat; @@ -202,7 +202,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend const float OPAQUE_ALPHA_THRESHOLD = 0.5f; args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD; } - renderItems(sceneContext, renderContext, inItems, opaque._maxDrawn); + renderItems(sceneContext, renderContext, inItems, opaque.maxDrawn); args->_batch = nullptr; }); } @@ -217,8 +217,8 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const batch.setStateScissorRect(args->_viewport); args->_batch = &batch; - auto& transparent = renderContext->getItemsConfig()._transparent; - transparent._numDrawn = (int)inItems.size(); + auto& transparent = renderContext->getItemsConfig().transparent; + transparent.numDrawn = (int)inItems.size(); glm::mat4 projMat; Transform viewMat; @@ -231,7 +231,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f; args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD; - renderItems(sceneContext, renderContext, inItems, transparent._maxDrawn); + renderItems(sceneContext, renderContext, inItems, transparent.maxDrawn); args->_batch = nullptr; }); } @@ -270,9 +270,9 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon inItems.emplace_back(id); } } - auto& overlay3D = renderContext->getItemsConfig()._overlay3D; - overlay3D._numFeed = (int)inItems.size(); - overlay3D._numDrawn = (int)inItems.size(); + auto& overlay3D = renderContext->getItemsConfig().overlay3D; + overlay3D.numFeed = (int)inItems.size(); + overlay3D.numDrawn = (int)inItems.size(); if (!inItems.empty()) { RenderArgs* args = renderContext->getArgs(); @@ -304,7 +304,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon batch.setPipeline(getOpaquePipeline()); batch.setResourceTexture(0, args->_whiteTexture); - renderItems(sceneContext, renderContext, inItems, renderContext->getItemsConfig()._overlay3D._maxDrawn); + renderItems(sceneContext, renderContext, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn); }); args->_batch = nullptr; args->_whiteTexture.reset(); diff --git a/libraries/render-utils/src/RenderScriptingInterface.cpp b/libraries/render-utils/src/RenderScriptingInterface.cpp index 3b283e3058..71ca929cfd 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.cpp +++ b/libraries/render-utils/src/RenderScriptingInterface.cpp @@ -15,18 +15,18 @@ RenderScriptingInterface::RenderScriptingInterface() {}; void RenderScriptingInterface::setEngineToneMappingToneCurve(const QString& toneCurve) { if (toneCurve == QString("None")) { - _tone._toneCurve = 0; + _tone.toneCurve = 0; } else if (toneCurve == QString("Gamma22")) { - _tone._toneCurve = 1; + _tone.toneCurve = 1; } else if (toneCurve == QString("Reinhard")) { - _tone._toneCurve = 2; + _tone.toneCurve = 2; } else if (toneCurve == QString("Filmic")) { - _tone._toneCurve = 3; + _tone.toneCurve = 3; } } QString RenderScriptingInterface::getEngineToneMappingToneCurve() const { - switch (_tone._toneCurve) { + switch (_tone.toneCurve) { case 0: return QString("None"); case 1: diff --git a/libraries/render-utils/src/RenderScriptingInterface.h b/libraries/render-utils/src/RenderScriptingInterface.h index 8e33d7b929..49926864df 100644 --- a/libraries/render-utils/src/RenderScriptingInterface.h +++ b/libraries/render-utils/src/RenderScriptingInterface.h @@ -22,35 +22,35 @@ class RenderScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - Q_INVOKABLE void setEngineRenderOpaque(bool renderOpaque) { _items._opaque._render = renderOpaque; }; - Q_INVOKABLE bool doEngineRenderOpaque() const { return _items._opaque._render; } - Q_INVOKABLE void setEngineRenderTransparent(bool renderTransparent) { _items._transparent._render = renderTransparent; }; - Q_INVOKABLE bool doEngineRenderTransparent() const { return _items._transparent._render; } + Q_INVOKABLE void setEngineRenderOpaque(bool renderOpaque) { _items.opaque.render = renderOpaque; }; + Q_INVOKABLE bool doEngineRenderOpaque() const { return _items.opaque.render; } + Q_INVOKABLE void setEngineRenderTransparent(bool renderTransparent) { _items.transparent.render = renderTransparent; }; + Q_INVOKABLE bool doEngineRenderTransparent() const { return _items.transparent.render; } - Q_INVOKABLE void setEngineCullOpaque(bool cullOpaque) { _items._opaque._cull = cullOpaque; }; - Q_INVOKABLE bool doEngineCullOpaque() const { return _items._opaque._cull; } - Q_INVOKABLE void setEngineCullTransparent(bool cullTransparent) { _items._transparent._cull = cullTransparent; }; - Q_INVOKABLE bool doEngineCullTransparent() const { return _items._transparent._cull; } + Q_INVOKABLE void setEngineCullOpaque(bool cullOpaque) { _items.opaque.cull = cullOpaque; }; + Q_INVOKABLE bool doEngineCullOpaque() const { return _items.opaque.cull; } + Q_INVOKABLE void setEngineCullTransparent(bool cullTransparent) { _items.transparent.cull = cullTransparent; }; + Q_INVOKABLE bool doEngineCullTransparent() const { return _items.transparent.cull; } - Q_INVOKABLE void setEngineSortOpaque(bool sortOpaque) { _items._opaque._sort = sortOpaque; }; - Q_INVOKABLE bool doEngineSortOpaque() const { return _items._opaque._sort; } - Q_INVOKABLE void setEngineSortTransparent(bool sortTransparent) { _items._transparent._sort = sortTransparent; }; - Q_INVOKABLE bool doEngineSortTransparent() const { return _items._transparent._sort; } + Q_INVOKABLE void setEngineSortOpaque(bool sortOpaque) { _items.opaque.sort = sortOpaque; }; + Q_INVOKABLE bool doEngineSortOpaque() const { return _items.opaque.sort; } + Q_INVOKABLE void setEngineSortTransparent(bool sortTransparent) { _items.transparent.sort = sortTransparent; }; + Q_INVOKABLE bool doEngineSortTransparent() const { return _items.transparent.sort; } - Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _items._opaque._numDrawn; } - Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _items._transparent._numDrawn; } - Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _items._overlay3D._numDrawn; } + Q_INVOKABLE int getEngineNumDrawnOpaqueItems() { return _items.opaque.numDrawn; } + Q_INVOKABLE int getEngineNumDrawnTransparentItems() { return _items.transparent.numDrawn; } + Q_INVOKABLE int getEngineNumDrawnOverlay3DItems() { return _items.overlay3D.numDrawn; } - Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _items._opaque._numFeed; } - Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _items._transparent._numFeed; } - Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _items._overlay3D._numFeed; } + Q_INVOKABLE int getEngineNumFeedOpaqueItems() { return _items.opaque.numFeed; } + Q_INVOKABLE int getEngineNumFeedTransparentItems() { return _items.transparent.numFeed; } + Q_INVOKABLE int getEngineNumFeedOverlay3DItems() { return _items.overlay3D.numFeed; } - Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _items._opaque._maxDrawn = count; } - Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _items._opaque._maxDrawn; } - Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _items._transparent._maxDrawn = count; } - Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _items._transparent._maxDrawn; } - Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _items._overlay3D._maxDrawn = count; } - Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _items._overlay3D._maxDrawn; } + Q_INVOKABLE void setEngineMaxDrawnOpaqueItems(int count) { _items.opaque.maxDrawn = count; } + Q_INVOKABLE int getEngineMaxDrawnOpaqueItems() { return _items.opaque.maxDrawn; } + Q_INVOKABLE void setEngineMaxDrawnTransparentItems(int count) { _items.transparent.maxDrawn = count; } + Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _items.transparent.maxDrawn; } + Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _items.overlay3D.maxDrawn = count; } + Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _items.overlay3D.maxDrawn; } Q_INVOKABLE void setEngineDeferredDebugMode(int mode) { _deferredDebugMode = mode; } Q_INVOKABLE int getEngineDeferredDebugMode() { return _deferredDebugMode; } @@ -63,12 +63,12 @@ class RenderScriptingInterface : public QObject, public Dependency { Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } - Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _tone._exposure = exposure; } - Q_INVOKABLE float getEngineToneMappingExposure() const { return _tone._exposure; } + Q_INVOKABLE void setEngineToneMappingExposure(float exposure) { _tone.exposure = exposure; } + Q_INVOKABLE float getEngineToneMappingExposure() const { return _tone.exposure; } Q_INVOKABLE void setEngineToneMappingToneCurve(const QString& curve); Q_INVOKABLE QString getEngineToneMappingToneCurve() const; - int getEngineToneMappingToneCurveValue() const { return _tone._toneCurve; } + int getEngineToneMappingToneCurveValue() const { return _tone.toneCurve; } inline int getDrawStatus() { return _drawStatus; } inline bool getDrawHitEffect() { return _drawHitEffect; } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 3b1bad45e7..40196e320e 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -32,59 +32,63 @@ const int showNetworkStatusFlag = 2; class RenderContext { public: - struct ItemsConfig { + class ItemsConfig { + public: inline void setCounts(const ItemsConfig& items) { - _opaque.setCounts(items._opaque); - _transparent.setCounts(items._transparent); - _overlay3D.setCounts(items._overlay3D); + opaque.setCounts(items.opaque); + transparent.setCounts(items.transparent); + overlay3D.setCounts(items.overlay3D); }; - struct Counter { + class Counter { + public: Counter() {}; Counter(const Counter& counter) { - _numFeed = _numDrawn = 0; - _maxDrawn = counter._maxDrawn; + numFeed = numDrawn = 0; + maxDrawn = counter.maxDrawn; }; inline void setCounts(const Counter& counter) { - _numFeed = counter._numFeed; - _numDrawn = counter._numDrawn; + numFeed = counter.numFeed; + numDrawn = counter.numDrawn; }; - int _numFeed = 0; - int _numDrawn = 0; - int _maxDrawn = -1; + int numFeed = 0; + int numDrawn = 0; + int maxDrawn = -1; }; - struct State : public Counter { - bool _render = true; - bool _cull = true; - bool _sort = true; + class State : public Counter { + public: + bool render = true; + bool cull = true; + bool sort = true; - Counter _counter{}; + Counter counter{}; }; - // TODO: Store state/counter in a map instead of manually enumerated members - State _opaque{}; - State _transparent{}; - Counter _overlay3D{}; + // TODO: If member count increases, store counters in a map instead of multiple members + State opaque{}; + State transparent{}; + Counter overlay3D{}; }; - struct Tone { - int _toneCurve = 3; - float _exposure = 0.0; + class Tone { + public: + int toneCurve = 3; + float exposure = 0.0; }; RenderContext(RenderArgs* args, ItemsConfig items, Tone tone) : _args{args}, _items{items}, _tone{tone} {}; RenderContext() : RenderContext(nullptr, {}, {}) {}; inline RenderArgs* getArgs() { return _args; } + inline ItemsConfig& getItemsConfig() { return _items; } + inline Tone& getTone() { return _tone; } inline int getDrawStatus() { return _drawStatus; } inline bool getDrawHitEffect() { return _drawHitEffect; } inline bool getOcclusionStatus() { return _occlusionStatus; } inline bool getFxaaStatus() { return _fxaaStatus; } - inline ItemsConfig& getItemsConfig() { return _items; } - inline Tone& getTone() { return _tone; } void setOptions(int drawStatus, bool drawHitEffect, bool occlusion, bool fxaa, bool showOwned); // Debugging From 5701ad2e8cdf4f700938f033442990888c411569 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Dec 2015 12:38:50 -0800 Subject: [PATCH 200/318] update to new angular velocity --- examples/controllers/proceduralHandPoseExample.js | 2 +- libraries/controllers/src/controllers/Pose.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/controllers/proceduralHandPoseExample.js b/examples/controllers/proceduralHandPoseExample.js index 5d0b10c46a..8b735f579f 100644 --- a/examples/controllers/proceduralHandPoseExample.js +++ b/examples/controllers/proceduralHandPoseExample.js @@ -63,7 +63,7 @@ mapping.from(function() { translation: translation, rotation: rotation, velocity: { x: 0, y: 0, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0, w: 1 } + angularVelocity: { x: 0, y: 0, z: 0 } }; return pose; }).debug(true).to(Controller.Standard.LeftHand); diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index 6b2d12e5df..d9641618c1 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -53,7 +53,7 @@ namespace controller { vec3FromScriptValue(translation, pose.translation); quatFromScriptValue(rotation, pose.rotation); vec3FromScriptValue(velocity, pose.velocity); - quatFromScriptValue(angularVelocity, pose.angularVelocity); + vec3FromScriptValue(angularVelocity, pose.angularVelocity); pose.valid = true; } else { pose.valid = false; From 3014b3bd5ba410659c09bbee1bb3f1c2c5d00f81 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 18 Dec 2015 12:50:21 -0800 Subject: [PATCH 201/318] Adding Gamma correction to all the Color coming for the attribute stream if used as color --- .../entities-renderer/src/paintStroke.slv | 4 +- libraries/gpu/src/gpu/Color.slh | 52 +++++++++++++++++++ libraries/render-utils/src/animdebugdraw.slv | 5 +- libraries/render-utils/src/model.slv | 8 ++- libraries/render-utils/src/model_lightmap.slv | 6 +-- .../src/model_lightmap_normal_map.slv | 6 +-- .../render-utils/src/model_normal_map.slv | 5 +- libraries/render-utils/src/overlay3D.slv | 5 +- libraries/render-utils/src/simple.slv | 5 +- libraries/render-utils/src/skin_model.slv | 5 +- .../src/skin_model_normal_map.slv | 5 +- .../src/standardTransformPNTC.slv | 5 +- libraries/render-utils/src/stars.slv | 5 +- 13 files changed, 79 insertions(+), 37 deletions(-) create mode 100644 libraries/gpu/src/gpu/Color.slh diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv index 7d7523deb9..c7dd112bcc 100644 --- a/libraries/entities-renderer/src/paintStroke.slv +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -13,8 +13,8 @@ // <@include gpu/Inputs.slh@> +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> // the interpolated normal @@ -30,7 +30,7 @@ void main(void) { varTexcoord = inTexCoord0.st; // pass along the diffuse color - varColor = inColor; + varColor = colorToLinearRGBA(inColor); // standard transform TransformCamera cam = getTransformCamera(); diff --git a/libraries/gpu/src/gpu/Color.slh b/libraries/gpu/src/gpu/Color.slh new file mode 100644 index 0000000000..f633e6e2d4 --- /dev/null +++ b/libraries/gpu/src/gpu/Color.slh @@ -0,0 +1,52 @@ + +<@if not GPU_COLOR_SLH@> +<@def GPU_COLOR_SLH@> + 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 colorToLinear(vec3 srgb) { + return vec3(colorComponentToLinear(srgb.x), colorComponentToLinear(srgb.y), colorComponentToLinear(srgb.z)); +} +!> + +vec3 colorToLinearRGB(vec3 srgb) { + const float GAMMA_22 = 2.2; + return pow(srgb, vec3(GAMMA_22)); +} + +vec4 colorToLinearRGBA(vec4 srgba) { + return vec4(colorToLinearRGB(srgba.xyz), srgba.w); +} + +<@endif@> \ No newline at end of file diff --git a/libraries/render-utils/src/animdebugdraw.slv b/libraries/render-utils/src/animdebugdraw.slv index f3117714b0..3cb356c055 100644 --- a/libraries/render-utils/src/animdebugdraw.slv +++ b/libraries/render-utils/src/animdebugdraw.slv @@ -9,16 +9,15 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> out vec4 _color; void main(void) { // pass along the diffuse color - _color = inColor.rgba; + _color = colorToLinearRGBA(inColor.rgba); TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); diff --git a/libraries/render-utils/src/model.slv b/libraries/render-utils/src/model.slv index 6d56833de1..47de20a5d9 100755 --- a/libraries/render-utils/src/model.slv +++ b/libraries/render-utils/src/model.slv @@ -12,9 +12,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; @@ -27,9 +26,8 @@ out vec3 _color; out vec2 _texCoord0; void main(void) { - - // pass along the diffuse color - _color = inColor.xyz; + // pass along the diffuse color in linear space + _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; diff --git a/libraries/render-utils/src/model_lightmap.slv b/libraries/render-utils/src/model_lightmap.slv index 7742896228..eacc91245c 100755 --- a/libraries/render-utils/src/model_lightmap.slv +++ b/libraries/render-utils/src/model_lightmap.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; @@ -29,7 +28,8 @@ out vec3 _normal; out vec3 _color; void main(void) { - _color = inColor.xyz; + // pass along the diffuse color in linear space + _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slv b/libraries/render-utils/src/model_lightmap_normal_map.slv index f63030301f..6046a67e10 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slv +++ b/libraries/render-utils/src/model_lightmap_normal_map.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; @@ -30,7 +29,8 @@ out vec3 _tangent; out vec3 _color; void main(void) { - _color = inColor.xyz; + // pass along the diffuse color in linear space + _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; diff --git a/libraries/render-utils/src/model_normal_map.slv b/libraries/render-utils/src/model_normal_map.slv index e989c1c294..5ed4e37278 100755 --- a/libraries/render-utils/src/model_normal_map.slv +++ b/libraries/render-utils/src/model_normal_map.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; @@ -30,7 +29,7 @@ out vec3 _color; void main(void) { // pass along the diffuse color - _color = inColor.rgb; + _color = colorToLinearRGB(inColor.xyz); // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.xy, 0.0, 1.0)).st; diff --git a/libraries/render-utils/src/overlay3D.slv b/libraries/render-utils/src/overlay3D.slv index a57f02d854..74416f0c1f 100644 --- a/libraries/render-utils/src/overlay3D.slv +++ b/libraries/render-utils/src/overlay3D.slv @@ -11,9 +11,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> out vec2 varTexcoord; @@ -30,7 +29,7 @@ void main(void) { varTexcoord = inTexCoord0.xy; // pass along the color - varColor = inColor; + varColor = colorToLinearRGBA(inColor); // standard transform TransformCamera cam = getTransformCamera(); diff --git a/libraries/render-utils/src/simple.slv b/libraries/render-utils/src/simple.slv index 823654ec27..59b16cf0e5 100644 --- a/libraries/render-utils/src/simple.slv +++ b/libraries/render-utils/src/simple.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> uniform bool Instanced = false; @@ -28,7 +27,7 @@ out vec2 _texCoord0; out vec4 _position; void main(void) { - _color = inColor.rgb; + _color = colorToLinearRGB(inColor.rgb); _texCoord0 = inTexCoord0.st; _position = inPosition; _modelNormal = inNormal.xyz; diff --git a/libraries/render-utils/src/skin_model.slv b/libraries/render-utils/src/skin_model.slv index cba419dd4d..8ab475e1fd 100755 --- a/libraries/render-utils/src/skin_model.slv +++ b/libraries/render-utils/src/skin_model.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> <@include Skinning.slh@> @@ -34,7 +33,7 @@ void main(void) { skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal); // pass along the diffuse color - _color = inColor.rgb; + _color = colorToLinearRGB(inColor.rgb); // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; diff --git a/libraries/render-utils/src/skin_model_normal_map.slv b/libraries/render-utils/src/skin_model_normal_map.slv index 5dfe5ba957..cec93a024e 100755 --- a/libraries/render-utils/src/skin_model_normal_map.slv +++ b/libraries/render-utils/src/skin_model_normal_map.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> <@include Skinning.slh@> @@ -36,7 +35,7 @@ void main(void) { skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz); // pass along the diffuse color - _color = inColor.rgb; + _color = colorToLinearRGB(inColor.rgb); // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; diff --git a/libraries/render-utils/src/standardTransformPNTC.slv b/libraries/render-utils/src/standardTransformPNTC.slv index 340dfd9c8e..f7e72b6997 100644 --- a/libraries/render-utils/src/standardTransformPNTC.slv +++ b/libraries/render-utils/src/standardTransformPNTC.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> out vec3 varPosition; @@ -25,7 +24,7 @@ out vec4 varColor; void main(void) { varTexCoord0 = inTexCoord0.st; - varColor = inColor; + varColor = colorToLinearRGBA(inColor); // standard transform TransformCamera cam = getTransformCamera(); diff --git a/libraries/render-utils/src/stars.slv b/libraries/render-utils/src/stars.slv index b9ad736d5e..d00bb8b7dd 100644 --- a/libraries/render-utils/src/stars.slv +++ b/libraries/render-utils/src/stars.slv @@ -13,9 +13,8 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> // TODO we need to get the viewport resolution and FOV passed to us so we can modify the point size @@ -26,7 +25,7 @@ out vec4 varColor; out float varSize; void main(void) { - varColor = inColor.rgba; + varColor = colorToLinearRGBA(inColor); // standard transform TransformCamera cam = getTransformCamera(); From 16dd24f3d8be0a9cbcd05bcbc44b13a7b84f4ce2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Dec 2015 13:02:45 -0800 Subject: [PATCH 202/318] Removing unused LGPL JS file --- interface/resources/qml/qwebchannel.js | 413 ------------------------- 1 file changed, 413 deletions(-) delete mode 100644 interface/resources/qml/qwebchannel.js diff --git a/interface/resources/qml/qwebchannel.js b/interface/resources/qml/qwebchannel.js deleted file mode 100644 index d8c28bc663..0000000000 --- a/interface/resources/qml/qwebchannel.js +++ /dev/null @@ -1,413 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtWebChannel module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -"use strict"; - -var QWebChannelMessageTypes = { - signal: 1, - propertyUpdate: 2, - init: 3, - idle: 4, - debug: 5, - invokeMethod: 6, - connectToSignal: 7, - disconnectFromSignal: 8, - setProperty: 9, - response: 10, -}; - -var QWebChannel = function(transport, initCallback) -{ - if (typeof transport !== "object" || typeof transport.send !== "function") { - console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." + - " Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send)); - return; - } - - var channel = this; - this.transport = transport; - - this.send = function(data) - { - if (typeof(data) !== "string") { - data = JSON.stringify(data); - } - channel.transport.send(data); - } - - this.transport.onmessage = function(message) - { - var data = message.data; - if (typeof data === "string") { - data = JSON.parse(data); - } - switch (data.type) { - case QWebChannelMessageTypes.signal: - channel.handleSignal(data); - break; - case QWebChannelMessageTypes.response: - channel.handleResponse(data); - break; - case QWebChannelMessageTypes.propertyUpdate: - channel.handlePropertyUpdate(data); - break; - default: - console.error("invalid message received:", message.data); - break; - } - } - - this.execCallbacks = {}; - this.execId = 0; - this.exec = function(data, callback) - { - if (!callback) { - // if no callback is given, send directly - channel.send(data); - return; - } - if (channel.execId === Number.MAX_VALUE) { - // wrap - channel.execId = Number.MIN_VALUE; - } - if (data.hasOwnProperty("id")) { - console.error("Cannot exec message with property id: " + JSON.stringify(data)); - return; - } - data.id = channel.execId++; - channel.execCallbacks[data.id] = callback; - channel.send(data); - }; - - this.objects = {}; - - this.handleSignal = function(message) - { - var object = channel.objects[message.object]; - if (object) { - object.signalEmitted(message.signal, message.args); - } else { - console.warn("Unhandled signal: " + message.object + "::" + message.signal); - } - } - - this.handleResponse = function(message) - { - if (!message.hasOwnProperty("id")) { - console.error("Invalid response message received: ", JSON.stringify(message)); - return; - } - channel.execCallbacks[message.id](message.data); - delete channel.execCallbacks[message.id]; - } - - this.handlePropertyUpdate = function(message) - { - for (var i in message.data) { - var data = message.data[i]; - var object = channel.objects[data.object]; - if (object) { - object.propertyUpdate(data.signals, data.properties); - } else { - console.warn("Unhandled property update: " + data.object + "::" + data.signal); - } - } - channel.exec({type: QWebChannelMessageTypes.idle}); - } - - this.debug = function(message) - { - channel.send({type: QWebChannelMessageTypes.debug, data: message}); - }; - - channel.exec({type: QWebChannelMessageTypes.init}, function(data) { - for (var objectName in data) { - var object = new QObject(objectName, data[objectName], channel); - } - // now unwrap properties, which might reference other registered objects - for (var objectName in channel.objects) { - channel.objects[objectName].unwrapProperties(); - } - if (initCallback) { - initCallback(channel); - } - channel.exec({type: QWebChannelMessageTypes.idle}); - }); -}; - -function QObject(name, data, webChannel) -{ - this.__id__ = name; - webChannel.objects[name] = this; - - // List of callbacks that get invoked upon signal emission - this.__objectSignals__ = {}; - - // Cache of all properties, updated when a notify signal is emitted - this.__propertyCache__ = {}; - - var object = this; - - // ---------------------------------------------------------------------- - - this.unwrapQObject = function(response) - { - if (response instanceof Array) { - // support list of objects - var ret = new Array(response.length); - for (var i = 0; i < response.length; ++i) { - ret[i] = object.unwrapQObject(response[i]); - } - return ret; - } - if (!response - || !response["__QObject*__"] - || response.id === undefined) { - return response; - } - - var objectId = response.id; - if (webChannel.objects[objectId]) - return webChannel.objects[objectId]; - - if (!response.data) { - console.error("Cannot unwrap unknown QObject " + objectId + " without data."); - return; - } - - var qObject = new QObject( objectId, response.data, webChannel ); - qObject.destroyed.connect(function() { - if (webChannel.objects[objectId] === qObject) { - delete webChannel.objects[objectId]; - // reset the now deleted QObject to an empty {} object - // just assigning {} though would not have the desired effect, but the - // below also ensures all external references will see the empty map - // NOTE: this detour is necessary to workaround QTBUG-40021 - var propertyNames = []; - for (var propertyName in qObject) { - propertyNames.push(propertyName); - } - for (var idx in propertyNames) { - delete qObject[propertyNames[idx]]; - } - } - }); - // here we are already initialized, and thus must directly unwrap the properties - qObject.unwrapProperties(); - return qObject; - } - - this.unwrapProperties = function() - { - for (var propertyIdx in object.__propertyCache__) { - object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]); - } - } - - function addSignal(signalData, isPropertyNotifySignal) - { - var signalName = signalData[0]; - var signalIndex = signalData[1]; - object[signalName] = { - connect: function(callback) { - if (typeof(callback) !== "function") { - console.error("Bad callback given to connect to signal " + signalName); - return; - } - - object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; - object.__objectSignals__[signalIndex].push(callback); - - if (!isPropertyNotifySignal && signalName !== "destroyed") { - // only required for "pure" signals, handled separately for properties in propertyUpdate - // also note that we always get notified about the destroyed signal - webChannel.exec({ - type: QWebChannelMessageTypes.connectToSignal, - object: object.__id__, - signal: signalIndex - }); - } - }, - disconnect: function(callback) { - if (typeof(callback) !== "function") { - console.error("Bad callback given to disconnect from signal " + signalName); - return; - } - object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; - var idx = object.__objectSignals__[signalIndex].indexOf(callback); - if (idx === -1) { - console.error("Cannot find connection of signal " + signalName + " to " + callback.name); - return; - } - object.__objectSignals__[signalIndex].splice(idx, 1); - if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) { - // only required for "pure" signals, handled separately for properties in propertyUpdate - webChannel.exec({ - type: QWebChannelMessageTypes.disconnectFromSignal, - object: object.__id__, - signal: signalIndex - }); - } - } - }; - } - - /** - * Invokes all callbacks for the given signalname. Also works for property notify callbacks. - */ - function invokeSignalCallbacks(signalName, signalArgs) - { - var connections = object.__objectSignals__[signalName]; - if (connections) { - connections.forEach(function(callback) { - callback.apply(callback, signalArgs); - }); - } - } - - this.propertyUpdate = function(signals, propertyMap) - { - // update property cache - for (var propertyIndex in propertyMap) { - var propertyValue = propertyMap[propertyIndex]; - object.__propertyCache__[propertyIndex] = propertyValue; - } - - for (var signalName in signals) { - // Invoke all callbacks, as signalEmitted() does not. This ensures the - // property cache is updated before the callbacks are invoked. - invokeSignalCallbacks(signalName, signals[signalName]); - } - } - - this.signalEmitted = function(signalName, signalArgs) - { - invokeSignalCallbacks(signalName, signalArgs); - } - - function addMethod(methodData) - { - var methodName = methodData[0]; - var methodIdx = methodData[1]; - object[methodName] = function() { - var args = []; - var callback; - for (var i = 0; i < arguments.length; ++i) { - if (typeof arguments[i] === "function") - callback = arguments[i]; - else - args.push(arguments[i]); - } - - webChannel.exec({ - "type": QWebChannelMessageTypes.invokeMethod, - "object": object.__id__, - "method": methodIdx, - "args": args - }, function(response) { - if (response !== undefined) { - var result = object.unwrapQObject(response); - if (callback) { - (callback)(result); - } - } - }); - }; - } - - function bindGetterSetter(propertyInfo) - { - var propertyIndex = propertyInfo[0]; - var propertyName = propertyInfo[1]; - var notifySignalData = propertyInfo[2]; - // initialize property cache with current value - // NOTE: if this is an object, it is not directly unwrapped as it might - // reference other QObject that we do not know yet - object.__propertyCache__[propertyIndex] = propertyInfo[3]; - - if (notifySignalData) { - if (notifySignalData[0] === 1) { - // signal name is optimized away, reconstruct the actual name - notifySignalData[0] = propertyName + "Changed"; - } - addSignal(notifySignalData, true); - } - - Object.defineProperty(object, propertyName, { - configurable: true, - get: function () { - var propertyValue = object.__propertyCache__[propertyIndex]; - if (propertyValue === undefined) { - // This shouldn't happen - console.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__); - } - - return propertyValue; - }, - set: function(value) { - if (value === undefined) { - console.warn("Property setter for " + propertyName + " called with undefined value!"); - return; - } - object.__propertyCache__[propertyIndex] = value; - webChannel.exec({ - "type": QWebChannelMessageTypes.setProperty, - "object": object.__id__, - "property": propertyIndex, - "value": value - }); - } - }); - - } - - // ---------------------------------------------------------------------- - - data.methods.forEach(addMethod); - - data.properties.forEach(bindGetterSetter); - - data.signals.forEach(function(signal) { addSignal(signal, false); }); - - for (var name in data.enums) { - object[name] = data.enums[name]; - } -} - -//required for use with nodejs -if (typeof module === 'object') { - module.exports = { - QWebChannel: QWebChannel - }; -} From 2c2b794683104c4c53fef39c26b5877c51465464 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 18 Dec 2015 13:16:05 -0800 Subject: [PATCH 203/318] Stop modelMesh render if pipeline is not found --- libraries/render-utils/src/MeshPartPayload.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2d8d7b598b..2fae09a158 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -470,6 +470,9 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, args, locations); + if (!locations) { // the pipeline could not be found + return; + } // Bind the model transform and the skinCLusterMatrices if needed bindTransform(batch, locations); From 0492bb1c6dd5473d309121d8467d4159f52ee133 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 18 Dec 2015 13:50:28 -0800 Subject: [PATCH 204/318] Final cleans and tests using R11G11B10 for lighting buffer --- libraries/render-utils/src/FramebufferCache.cpp | 5 +++-- libraries/render-utils/src/ToneMappingEffect.cpp | 11 ++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index e64e245806..9f3d4ba0fe 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -89,9 +89,10 @@ void FramebufferCache::createPrimaryFramebuffer() { auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); + // FIXME: Decide on the proper one, let s stick to R11G11B10 for now //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler)); - //lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); - _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, smoothSampler)); + _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler)); + //_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler)); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 29e5da6e2a..a00a66fe69 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -64,13 +64,9 @@ void ToneMappingEffect::init() { out vec4 outFragColor; void main(void) { - vec4 fragColorRaw = textureLod(colorMap, varTexCoord0, 0); + vec4 fragColorRaw = texture(colorMap, varTexCoord0); vec3 fragColor = fragColorRaw.xyz; -/* - vec4 fragColorAverage = textureLod(colorMap, varTexCoord0, 10); - float averageIntensity = length(fragColorAverage.xyz); - fragColor /= averageIntensity; -*/ + vec3 srcColor = fragColor * getTwoPowExposure(); int toneCurve = getToneCurve(); @@ -124,7 +120,8 @@ void ToneMappingEffect::render(RenderArgs* args) { auto destFbo = framebufferCache->getPrimaryFramebuffer(); batch.setFramebuffer(destFbo); - batch.generateTextureMips(lightingBuffer); + // FIXME: Generate the Luminosity map + //batch.generateTextureMips(lightingBuffer); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); From 4e76e9e50b9088358f6be7465d506c19174d0506 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 18 Dec 2015 13:40:35 -0800 Subject: [PATCH 205/318] prevent nan values in measure of angularVelocity --- plugins/hifiSixense/src/SixenseManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index fb47697166..b534c09055 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -466,9 +466,10 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos samples.first.addSample(velocity); velocity = samples.first.average; - auto deltaRot = rotation * glm::conjugate(prevPose.getRotation()); + auto deltaRot = glm::normalize(rotation * glm::conjugate(prevPose.getRotation())); auto axis = glm::axis(deltaRot); auto speed = glm::angle(deltaRot) / deltaTime; + assert(!glm::isnan(speed)); angularVelocity = speed * axis; samples.second.addSample(angularVelocity); angularVelocity = samples.second.average; From 88b88a3306b049d9ebb15f6a34c35256a6ed3ac5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Dec 2015 13:45:07 -0800 Subject: [PATCH 206/318] Fixing warnings --- libraries/gl/src/gl/QOpenGLContextWrapper.cpp | 7 +++++- libraries/gl/src/gl/QOpenGLContextWrapper.h | 6 +++++ libraries/ui/src/QmlWebWindowClass.cpp | 4 ++-- libraries/ui/src/QmlWebWindowClass.h | 7 ++++-- tests/ui/src/main.cpp | 22 ++++--------------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 3e879df7af..6397d30e13 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -39,6 +39,11 @@ void QOpenGLContextWrapper::doneCurrent() { _context->doneCurrent(); } +void QOpenGLContextWrapper::setShareContext(QOpenGLContext* otherContext) { + _context->setShareContext(otherContext); +} + bool isCurrentContext(QOpenGLContext* context) { return QOpenGLContext::currentContext() == context; -} \ No newline at end of file +} + diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.h b/libraries/gl/src/gl/QOpenGLContextWrapper.h index 832119162c..b736253213 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.h +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.h @@ -25,6 +25,12 @@ public: void swapBuffers(QSurface* surface); bool makeCurrent(QSurface* surface); void doneCurrent(); + void setShareContext(QOpenGLContext* otherContext); + + QOpenGLContext* getContext() { + return _context; + } + private: QOpenGLContext* _context { nullptr }; diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index eeadb361ae..d5cdc1fde9 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -110,7 +110,7 @@ QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngi } QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) - : _isToolWindow(false), _windowId(++nextWindowId), _qmlWindow(qmlWindow) + : _windowId(++nextWindowId), _qmlWindow(qmlWindow) { qDebug() << "Created window with ID " << _windowId; Q_ASSERT(_qmlWindow); @@ -128,7 +128,7 @@ void QmlWebWindowClass::setVisible(bool visible) { return; } - auto qmlWindow = (QQuickItem*)_qmlWindow; + auto qmlWindow = asQuickItem(); if (qmlWindow->isEnabled() != visible) { qmlWindow->setEnabled(visible); emit visibilityChanged(visible); diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index 90d355e162..2b563e68ba 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -93,9 +93,12 @@ private: QQuickItem* asQuickItem() const; QmlScriptEventBridge* const _eventBridge { new QmlScriptEventBridge(this) }; - const bool _isToolWindow; - QObject* const _qmlWindow; + + // FIXME needs to be initialized in the ctor once we have support + // for tool window panes in QML + const bool _isToolWindow { false }; const int _windowId; + QObject* const _qmlWindow; }; #endif diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 00d1f2dc00..59e7376f1b 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -26,8 +26,7 @@ #include #include -#include -#include +#include #include @@ -403,7 +402,6 @@ private: std::atomic _isFinished { false }; std::atomic _isRunning { false }; bool _wantSignals { true }; - bool _isThreaded { false }; QHash _timerFunctionMap; }; @@ -423,7 +421,7 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; + QOpenGLContextWrapper* _context{ nullptr }; QSize _size; bool _altPressed{ false }; RateCounter fps; @@ -450,7 +448,7 @@ public: setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); setFormat(format); - _context = new QOpenGLContext; + _context = new QOpenGLContextWrapper(); _context->setFormat(format); _context->setShareContext(_chromiumShareContext->getContext()); } @@ -464,18 +462,6 @@ public: makeCurrent(); - - { - qDebug() << (const char*)glGetString(GL_VERSION); - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - logger->enableMessages(); - connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { - qDebug() << debugMessage; - }); - //logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); - } - glewExperimental = true; glewInit(); glGetError(); @@ -492,7 +478,7 @@ public: auto offscreenUi = DependencyManager::set(); { - offscreenUi->create(_context); + offscreenUi->create(_context->getContext()); offscreenUi->setProxyWindow(this); connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { From 77264b3f99283694ef126d859680760a10e39032 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 14:52:39 -0800 Subject: [PATCH 207/318] Ping pong gun lines up with hand --- examples/flowArts/lightSaber/LightSaber.js | 13 +++++++++++++ unpublishedScripts/hiddenEntityReset.js | 8 ++++++++ unpublishedScripts/masterReset.js | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/LightSaber.js index 8a4f3f2902..50984110bc 100644 --- a/examples/flowArts/lightSaber/LightSaber.js +++ b/examples/flowArts/lightSaber/LightSaber.js @@ -44,6 +44,19 @@ LightSaber = function(spawnPosition) { }) }); + var light = Entities.addEntity({ + type: 'Light', + name: "raveLight", + parentID: saberHandle, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: {red: 200, green: 10, blue: 200}, + intensity: 5 + }); + function cleanup() { Entities.deleteEntity(saberHandle); diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index cc4037beb4..c8a2c97b0f 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1153,6 +1153,14 @@ resetMe: true }, grabbableKey: { + spatialKey: { + relativePosition: { + x: -0.05, + y: 0, + z: 0.0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) + }, invertSolidWhileHeld: true } diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index a1545a3b67..3d985e9a92 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1134,6 +1134,14 @@ MasterReset = function() { resetMe: true }, grabbableKey: { + spatialKey: { + relativePosition: { + x: -0.05, + y: 0, + z: 0.0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90) + }, invertSolidWhileHeld: true } From 387c30d83fa1abe3fa2a97ed512918ac7ad073ea Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 15:04:13 -0800 Subject: [PATCH 208/318] close button --- examples/controllers/handControllerGrab.js | 2 +- examples/light_modifier/README.md | 6 +- examples/light_modifier/lightModifier.js | 58 +++++++++++-------- .../light_modifier/lightModifierTestScene.js | 2 +- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0f927f39c8..1b256f67c0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -842,7 +842,7 @@ function MyController(hand) { this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); } } else { - print('should not head move!'); + // print('should not head move!'); } diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index d978c73b5b..3bd456d525 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -3,11 +3,15 @@ This PR demonstrates one way in-world editing of objects might work. We start w To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js -When you run the lightLoader.js script, 4 scripts will be loaded: +When you run the lightLoader.js script, several scripts will be loaded: - handControllerGrab.js (custom) - lightModifier.js (listens for message to create sliders for a given light) - lightModifierTestScene.js (creates a light and parents it to a block, then sends a message ^^) - slider.js (attached to each slider entity) +- lightParent.js (attached to the entity to which a light is parented, so you can move it around) +- closeButton.js (for closing the ui) +- ../libraries/lightOverlayManager.js (custom) +- ../libraries/entitySelectionTool.js diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index d82afc09bb..76c1cdc873 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,7 +60,7 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); -var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_good.fbx'; +var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_rotated.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); @@ -108,14 +108,14 @@ var SLIDER_DIMENSIONS = { var CLOSE_BUTTON_DIMENSIONS = { x: 0.1, - y: 0.1, + y: 0.025, z: 0.1 } var LIGHT_MODEL_DIMENSIONS = { - x: 0.68, - y: 0.68, - z: 1.54 + x: 0.58, + y: 1.21, + z: 0.57 } var PER_ROW_OFFSET = { @@ -262,6 +262,7 @@ entitySlider.prototype = { color: this.color, position: sliderPosition, script: SLIDER_SCRIPT_URL, + ignoreForCollisions:true, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, @@ -401,29 +402,34 @@ function makeSliders(light) { sliders.push(slidersRef.exponent); } - createCloseButton(7); + createCloseButton(slidersRef.exponent.endOfAxis); subscribeToSliderMessages(); }; var closeButtons = []; -function createCloseButton(row) { - var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); - var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - var downPosition = Vec3.sum(basePosition, verticalOffset); - var rightVector = Quat.getRight(avatarRot); - var extension = Vec3.multiply(AXIS_SCALE, rightVector); - var position = Vec3.sum(downPosition, extension); +function createCloseButton(endOfAxis) { + // var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); + // var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); + // var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); + // var verticalOffset = lastRowVerticalOffset; + // var downPosition = Vec3.sum(basePosition, verticalOffset); + // var rightVector = Quat.getRight(avatarRot); + // var extension = Vec3.multiply(AXIS_SCALE, rightVector); + // var position = Vec3.sum(downPosition, extension); var buttonProperties = { name:'Hifi-Close-Button', type: 'Model', modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, - position: position, - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + position: Vec3.sum(endOfAxis,{ + x:0, + y:-0.15, + z:0 + }), + rotation: Quat.fromPitchYawRollDegrees(0, 45, 90), collisionsWillMove: false //need to add wantsTrigger stuff so we can interact with it with our beamz } @@ -440,7 +446,7 @@ function rotateCloseButtons() { Entities.editEntity(button, { angularVelocity: { x: 0, - y: 0.25, + y: 0.5, z: 0 } }) @@ -519,8 +525,8 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - block = createBlock(lightProperties.position); - // block = createLightModel(lightProperties.position); + // block = createBlock(lightProperties.position); + block = createLightModel(lightProperties.position); var light = { id: lightID, @@ -532,12 +538,11 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { if (SHOW_LIGHT_VOLUME === true) { selectionManager.setSelections([lightID]); - print('SET SELECTIOIO MANAGER TO::: ' + lightID); - print('hasSelection???' + selectionManager.hasSelection()) } Entities.editEntity(lightID, { - parentID: block + parentID: block, + parentJointIndex:-1 }); @@ -551,10 +556,11 @@ function createLightModel(position) { type: 'Model', shapeType: 'box', modelURL: LIGHT_MODEL_URL, + // modelURL:"http://hifi-content.s3.amazonaws.com/james/light_modifier/box4.fbx", dimensions: LIGHT_MODEL_DIMENSIONS, collisionsWillMove: true, position: position, - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + // rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), script: PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { @@ -576,7 +582,7 @@ function createBlock(position) { type: 'Box', dimensions: { x: 1, - y: 1, + y: 4, z: 1 }, color: { @@ -606,6 +612,10 @@ function cleanup() { Entities.deleteEntity(sliders[i].sliderIndicator); } + while(closeButtons.length>0){ + Entities.deleteEntity(closeButtons.pop()); + } + Entities.deleteEntity(block); Messages.messageReceived.disconnect(handleLightModMessages); Messages.messageReceived.disconnect(handleValueMessages); diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 4b78484a31..8df83b09bf 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -20,7 +20,7 @@ var light, block; function createLight() { var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); var position = basePosition; - position.y += 3; + position.y += 2; var lightTransform = evalLightWorldTransform(position,avatarRot); // var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); var lightProperties = { From 2dbb3bd84abf25e2d5d6f0fc0f90ae3d02682012 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:12:46 -0800 Subject: [PATCH 209/318] Added grab offsets to createPingPongGun.js --- examples/toybox/ping_pong_gun/createPingPongGun.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 4b93842896..7835dbf7f9 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -38,6 +38,14 @@ var pingPongGun = Entities.addEntity({ collisionSoundURL: COLLISION_SOUND_URL, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: -0.05, + y: 0, + z: 0.0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) + }, invertSolidWhileHeld: true } }) From 2c02e7ad631ddec997bbcca99a462b701554d92b Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:22:23 -0800 Subject: [PATCH 210/318] grabbing works with left hand for ping pong gun now --- unpublishedScripts/hiddenEntityReset.js | 2 +- unpublishedScripts/masterReset.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index c8a2c97b0f..21971a18ad 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1125,7 +1125,7 @@ z: 503.39 }; - var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0); var pingPongGun = Entities.addEntity({ type: "Model", diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 3d985e9a92..3d0773ca10 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1106,7 +1106,7 @@ MasterReset = function() { z: 503.39 }; - var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0); + var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0); var pingPongGun = Entities.addEntity({ type: "Model", From 514cb7a329b835c282cdf448807a221143796eb0 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:26:21 -0800 Subject: [PATCH 211/318] Beams arc to each other. BAM --- examples/flowArts/arcBall/arcBall.js | 11 ++--------- examples/flowArts/arcBall/arcBallEntityScript.js | 5 ++++- examples/flowArts/flowArtsHutSpawner.js | 12 ++++++------ 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 34578cce76..e39a9af2d6 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -26,7 +26,7 @@ ArcBall = function(spawnPosition) { var containerBall = Entities.addEntity({ - type: "Sphere", + type: "Box", name: "Arc Ball", script: scriptURL, position: Vec3.sum(spawnPosition, { @@ -37,7 +37,7 @@ ArcBall = function(spawnPosition) { dimensions: { x: .2, y: .2, - z: .2 + z: .5 }, color: { red: 15, @@ -53,13 +53,6 @@ ArcBall = function(spawnPosition) { // }, userData: JSON.stringify({ grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: .1, - z: 0 - } - }, invertSolidWhileHeld: true } }) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index f1ba9aeb95..8c37f170bb 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -42,7 +42,8 @@ dimensions: {x: .1, y: .1, z: 1}, color: {red: 200, green: 10, blue: 10}, position: startPosition, - rotation: emitOrientation + rotation: emitOrientation, + visible: false }); var color = { red: 200, @@ -53,6 +54,8 @@ type: "ParticleEffect", name: "Particle Arc", parentID: this.entityID, + parentJointIndex: -1, + position: startPosition, isEmitting: true, colorStart: color, color: { diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index e03d2bf0e8..39dcf15698 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -25,10 +25,10 @@ var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Ca basePosition.y = MyAvatar.position.y + 1; // RAVE ITEMS -var lightBall = new LightBall(basePosition); +// var lightBall = new LightBall(basePosition); -// var arcBall = new ArcBall(basePosition); -// var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); +var arcBall = new ArcBall(basePosition); +var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0})); var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1})); var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1})); @@ -81,9 +81,9 @@ function cleanup() { Entities.deleteEntity(raveRoom); Entities.deleteEntity(lightZone); Entities.deleteEntity(floor); - lightBall.cleanup(); - // arcBall.cleanup(); - // arcBall2.cleanup(); + // lightBall.cleanup(); + arcBall.cleanup(); + arcBall2.cleanup(); raveStick.cleanup(); lightSaber.cleanup(); } From f24800cf10181b3cb89a21d9df9f982739f8ea37 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 18 Dec 2015 15:35:01 -0800 Subject: [PATCH 212/318] Change the default tone curve to jusimple gamma correct and fix the renaming in the renderENgineDebug script --- examples/utilities/tools/renderEngineDebug.js | 62 +++++++++---------- libraries/render/src/render/Engine.h | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js index 5e89bff53b..9412f57ca4 100755 --- a/examples/utilities/tools/renderEngineDebug.js +++ b/examples/utilities/tools/renderEngineDebug.js @@ -50,46 +50,46 @@ function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, cap }; var opaquesCounter = new CounterWidget(panel, "Opaques", - function () { return Scene.getEngineNumFeedOpaqueItems(); }, - function () { return Scene.getEngineNumDrawnOpaqueItems(); }, - function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); }, - function () { return Scene.getEngineMaxDrawnOpaqueItems(); } + function () { return Render.getEngineNumFeedOpaqueItems(); }, + function () { return Render.getEngineNumDrawnOpaqueItems(); }, + function(value) { Render.setEngineMaxDrawnOpaqueItems(value); }, + function () { return Render.getEngineMaxDrawnOpaqueItems(); } ); var transparentsCounter = new CounterWidget(panel, "Transparents", - function () { return Scene.getEngineNumFeedTransparentItems(); }, - function () { return Scene.getEngineNumDrawnTransparentItems(); }, - function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, - function () { return Scene.getEngineMaxDrawnTransparentItems(); } + function () { return Render.getEngineNumFeedTransparentItems(); }, + function () { return Render.getEngineNumDrawnTransparentItems(); }, + function(value) { Render.setEngineMaxDrawnTransparentItems(value); }, + function () { return Render.getEngineMaxDrawnTransparentItems(); } ); var overlaysCounter = new CounterWidget(panel, "Overlays", - function () { return Scene.getEngineNumFeedOverlay3DItems(); }, - function () { return Scene.getEngineNumDrawnOverlay3DItems(); }, - function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, - function () { return Scene.getEngineMaxDrawnOverlay3DItems(); } + function () { return Render.getEngineNumFeedOverlay3DItems(); }, + function () { return Render.getEngineNumDrawnOverlay3DItems(); }, + function(value) { Render.setEngineMaxDrawnOverlay3DItems(value); }, + function () { return Render.getEngineMaxDrawnOverlay3DItems(); } ); var resizing = false; var previousMode = Settings.getValue(SETTINGS_KEY, -1); Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]); -Scene.setEngineDeferredDebugMode(previousMode); -Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size +Render.setEngineDeferredDebugMode(previousMode); +Render.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size function setEngineDeferredDebugSize(eventX) { var scaledX = (2.0 * (eventX / Window.innerWidth) - 1.0).clamp(-1.0, 1.0); - Scene.setEngineDeferredDebugSize({ x: scaledX, y: -1.0, z: 1.0, w: 1.0 }); + Render.setEngineDeferredDebugSize({ x: scaledX, y: -1.0, z: 1.0, w: 1.0 }); } function shouldStartResizing(eventX) { - var x = Math.abs(eventX - Window.innerWidth * (1.0 + Scene.getEngineDeferredDebugSize().x) / 2.0); - var mode = Scene.getEngineDeferredDebugMode(); + var x = Math.abs(eventX - Window.innerWidth * (1.0 + Render.getEngineDeferredDebugSize().x) / 2.0); + var mode = Render.getEngineDeferredDebugMode(); return mode !== -1 && x < 20; } function menuItemEvent(menuItem) { var index = ACTIONS.indexOf(menuItem); if (index >= 0) { - Scene.setEngineDeferredDebugMode(index - 1); + Render.setEngineDeferredDebugMode(index - 1); } } @@ -98,24 +98,24 @@ var showDisplayStatusFlag = 1; var showNetworkStatusFlag = 2; panel.newCheckbox("Display status", - function(value) { Scene.setEngineDisplayItemStatus(value ? - Scene.doEngineDisplayItemStatus() | showDisplayStatusFlag : - Scene.doEngineDisplayItemStatus() & ~showDisplayStatusFlag); }, - function() { return (Scene.doEngineDisplayItemStatus() & showDisplayStatusFlag) > 0; }, + function(value) { Render.setEngineDisplayItemStatus(value ? + Render.doEngineDisplayItemStatus() | showDisplayStatusFlag : + Render.doEngineDisplayItemStatus() & ~showDisplayStatusFlag); }, + function() { return (Render.doEngineDisplayItemStatus() & showDisplayStatusFlag) > 0; }, function(value) { return (value & showDisplayStatusFlag) > 0; } ); panel.newCheckbox("Network/Physics status", - function(value) { Scene.setEngineDisplayItemStatus(value ? - Scene.doEngineDisplayItemStatus() | showNetworkStatusFlag : - Scene.doEngineDisplayItemStatus() & ~showNetworkStatusFlag); }, - function() { return (Scene.doEngineDisplayItemStatus() & showNetworkStatusFlag) > 0; }, + function(value) { Render.setEngineDisplayItemStatus(value ? + Render.doEngineDisplayItemStatus() | showNetworkStatusFlag : + Render.doEngineDisplayItemStatus() & ~showNetworkStatusFlag); }, + function() { return (Render.doEngineDisplayItemStatus() & showNetworkStatusFlag) > 0; }, function(value) { return (value & showNetworkStatusFlag) > 0; } ); panel.newSlider("Tone Mapping Exposure", -10, 10, - function (value) { Scene.setEngineToneMappingExposure(value); }, - function() { return Scene.getEngineToneMappingExposure(); }, + function (value) { Render.setEngineToneMappingExposure(value); }, + function() { return Render.getEngineToneMappingExposure(); }, function (value) { return (value); }); var tickTackPeriod = 500; @@ -160,9 +160,9 @@ Menu.menuItemEvent.connect(menuItemEvent); function scriptEnding() { panel.destroy(); Menu.removeActionGroup(MENU); - Settings.setValue(SETTINGS_KEY, Scene.getEngineDeferredDebugMode()); - Scene.setEngineDeferredDebugMode(-1); - Scene.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size + Settings.setValue(SETTINGS_KEY, Render.getEngineDeferredDebugMode()); + Render.setEngineDeferredDebugMode(-1); + Render.setEngineDeferredDebugSize({ x: 0.0, y: -1.0, z: 1.0, w: 1.0 }); // Reset to default size } Script.scriptEnding.connect(scriptEnding); diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 40196e320e..542db9b3ae 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -75,7 +75,7 @@ public: class Tone { public: - int toneCurve = 3; + int toneCurve = 1; // Means just Gamma 2.2 correction float exposure = 0.0; }; From fffe6dbb9bd32ec6dcb7ce71a8c787dcbc00df66 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 15:38:01 -0800 Subject: [PATCH 213/318] relative rotation --- examples/flowArts/arcBall/arcBall.js | 13 ++++--------- examples/flowArts/arcBall/arcBallEntityScript.js | 4 +++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index e39a9af2d6..736920ddd5 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -35,22 +35,17 @@ ArcBall = function(spawnPosition) { z: 0 }), dimensions: { - x: .2, - y: .2, - z: .5 + x: .1, + y: .1, + z: .2 }, color: { red: 15, green: 10, blue: 150 }, - mass: 10, + damping: 0.8, collisionsWillMove: true, - // gravity: { - // x: 0, - // y: -0.5, - // z: 0 - // }, userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 8c37f170bb..4ad0d66257 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -34,8 +34,10 @@ createBeam: function(startPosition, endPosition) { print("CREATE BEAM") // Creates particle arc from start position to end position + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); testBox = Entities.addEntity({ type: "Box", @@ -65,7 +67,7 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 2, + lifespan: 6, emitRate: 1000, emitOrientation: emitOrientation, emitSpeed: .4, From 4075f355a3dfa9a0e9e5016de4570b9ab68feedc Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Dec 2015 15:44:01 -0800 Subject: [PATCH 214/318] more work on hand movement --- examples/controllers/reticleHandTest.js | 82 ++++++++++++++++--- interface/src/Application.cpp | 36 ++++++-- .../src/controllers/ScriptingInterface.h | 18 +++- 3 files changed, 117 insertions(+), 19 deletions(-) diff --git a/examples/controllers/reticleHandTest.js b/examples/controllers/reticleHandTest.js index 5d0e2f238a..4132c80d85 100644 --- a/examples/controllers/reticleHandTest.js +++ b/examples/controllers/reticleHandTest.js @@ -9,23 +9,83 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -function moveReticle(pitch, yaw) { - //print("pitch:" + pitch); - //print("yaw:" + yaw); - var globalPos = Controller.getReticlePosition(); - globalPos.x += yaw; - globalPos.y += pitch; - Controller.setReticlePosition(globalPos); +function msecTimestampNow() { + var d = new Date(); + return d.getTime(); } +function length(posA, posB) { + var dx = posA.x - posB.x; + var dy = posA.y - posB.y; + var length = Math.sqrt((dx*dx) + (dy*dy)) + return length; +} + +var EXPECTED_CHANGE = 50; +var lastPos = Controller.getReticlePosition(); +function moveReticle(dX, dY) { + var globalPos = Controller.getReticlePosition(); + + // some debugging to see if position is jumping around on us... + var distanceSinceLastMove = length(lastPos, globalPos); + if (distanceSinceLastMove > EXPECTED_CHANGE) { + print("distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); + } + + if (Math.abs(dX) > EXPECTED_CHANGE) { + print("surpressing unexpectedly large change dX:" + dX + "----------------------------"); + dX = 0; + } + if (Math.abs(dY) > EXPECTED_CHANGE) { + print("surpressing unexpectedly large change dY:" + dY + "----------------------------"); + dY = 0; + } + + globalPos.x += dX; + globalPos.y += dY; + Controller.setReticlePosition(globalPos); + lastPos = globalPos; +} + +var lastTime = msecTimestampNow(); + var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand"; var mapping = Controller.newMapping(MAPPING_NAME); mapping.from(Controller.Standard.RightHand).peek().to(function(pose) { - var angularVelocityEADs = Quat.safeEulerAngles(pose.angularVelocity); // degrees - var yaw = isNaN(angularVelocityEADs.y) ? 0 : (-angularVelocityEADs.y / 10); - var pitch = isNaN(angularVelocityEADs.x) ? 0 : (-angularVelocityEADs.x / 10); - moveReticle(pitch, yaw); + + + // pose.angularVelocity - is the angularVelocity in a "physics" sense, that + // means the direction of the vector is the axis of symetry of rotation + // and the scale of the vector is the speed in radians/second of rotation + // around that axis. + // + // we want to deconstruct that in the portion of the rotation on the Y axis + // and make that portion move our reticle in the horizontal/X direction + // and the portion of the rotation on the X axis and make that portion + // move our reticle in the veritcle/Y direction + var xPart = -pose.angularVelocity.y; + var yPart = -pose.angularVelocity.x; + + + var MOVE_SCALE = 1; + var MSECS_PER_SECOND = 1000; + var now = msecTimestampNow(); + var secondsSinceLast = (now - lastTime) / MSECS_PER_SECOND; + lastTime = now; + + //print("secondsSinceLast:" + secondsSinceLast); + + //print("x part:" + xPart); + //print("y part:" + yPart); + + var dX = (xPart * MOVE_SCALE) / secondsSinceLast; + var dY = (yPart * MOVE_SCALE) / secondsSinceLast; + + //print("dX:" + dX); + //print("dY:" + dY); + + moveReticle(dX, dY); }); mapping.enable(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fa5565417d..045b8beb40 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -686,13 +686,37 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { VrMenu::toggle(); // show context menu even on non-stereo displays } else if (action == controller::toInt(controller::Action::RETICLE_X)) { - auto globalPos = QCursor::pos(); - globalPos.setX(globalPos.x() + state); - QCursor::setPos(globalPos); + auto oldPos = QCursor::pos(); + auto newPos = oldPos; + newPos.setX(oldPos.x() + state); + QCursor::setPos(newPos); + + + // NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies, + // remove it after we're done + const float REASONABLE_CHANGE = 50.0f; + glm::vec2 oldPosG = { oldPos.x(), oldPos.y() }; + glm::vec2 newPosG = { newPos.x(), newPos.y() }; + auto distance = glm::distance(oldPosG, newPosG); + if (distance > REASONABLE_CHANGE) { + qDebug() << "Action::RETICLE_X... UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPosG << " newPos:" << newPosG; + } + } else if (action == controller::toInt(controller::Action::RETICLE_Y)) { - auto globalPos = QCursor::pos(); - globalPos.setY(globalPos.y() + state); - QCursor::setPos(globalPos); + auto oldPos = QCursor::pos(); + auto newPos = oldPos; + newPos.setY(oldPos.y() + state); + QCursor::setPos(newPos); + + // NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies, + // remove it after we're done + const float REASONABLE_CHANGE = 50.0f; + glm::vec2 oldPosG = { oldPos.x(), oldPos.y() }; + glm::vec2 newPosG = { newPos.x(), newPos.y() }; + auto distance = glm::distance(oldPosG, newPosG); + if (distance > REASONABLE_CHANGE) { + qDebug() << "Action::RETICLE_Y... UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPosG << " newPos:" << newPosG; + } } } }); diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 9d3942cd55..52ec52e852 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -30,6 +30,7 @@ #include #include +#include #include "UserInputMapper.h" #include "StandardControls.h" @@ -88,8 +89,21 @@ namespace controller { Q_INVOKABLE QObject* parseMapping(const QString& json); Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl); - Q_INVOKABLE glm::vec2 getReticlePosition() { return toGlm(QCursor::pos()); } - Q_INVOKABLE void setReticlePosition(glm::vec2 position) { QCursor::setPos(position.x, position.y); } + Q_INVOKABLE glm::vec2 getReticlePosition() { + return toGlm(QCursor::pos()); + } + Q_INVOKABLE void setReticlePosition(glm::vec2 position) { + // NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies, + // remove it after we're done + const float REASONABLE_CHANGE = 50.0f; + glm::vec2 oldPos = toGlm(QCursor::pos()); + auto distance = glm::distance(oldPos, position); + if (distance > REASONABLE_CHANGE) { + qDebug() << "Contrller::ScriptingInterface ---- UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPos << " newPos:" << position; + } + + QCursor::setPos(position.x, position.y); + } //Q_INVOKABLE bool isPrimaryButtonPressed() const; //Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const; From a621579f17043ee5db822f183e50a6f1a017ed94 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Dec 2015 15:44:21 -0800 Subject: [PATCH 215/318] add philips version of hand movement --- examples/controllers/philipsVersion.js | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 examples/controllers/philipsVersion.js diff --git a/examples/controllers/philipsVersion.js b/examples/controllers/philipsVersion.js new file mode 100644 index 0000000000..4ae617cf0b --- /dev/null +++ b/examples/controllers/philipsVersion.js @@ -0,0 +1,87 @@ +// +// reticleTest.js +// examples/controllers +// +// Created by Brad Hefta-Gaub on 2015/12/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +function length(posA, posB) { + var dx = posA.x - posB.x; + var dy = posA.y - posB.y; + var length = Math.sqrt((dx*dx) + (dy*dy)) + return length; +} + +var PITCH_DEADZONE = 1.0; +var PITCH_MAX = 20.0; +var YAW_DEADZONE = 1.0; +var YAW_MAX = 20.0; +var PITCH_SCALING = 10.0; +var YAW_SCALING = 10.0; + +var EXPECTED_CHANGE = 50; +var lastPos = Controller.getReticlePosition(); +function moveReticle(dY, dX) { + var globalPos = Controller.getReticlePosition(); + + // some debugging to see if position is jumping around on us... + var distanceSinceLastMove = length(lastPos, globalPos); + if (distanceSinceLastMove > EXPECTED_CHANGE) { + print("distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); + } + + if (Math.abs(dX) > EXPECTED_CHANGE) { + print("UNEXPECTED dX:" + dX + "----------------------------"); + dX = 0; + } + if (Math.abs(dY) > EXPECTED_CHANGE) { + print("UNEXPECTED dY:" + dY + "----------------------------"); + dY = 0; + } + + globalPos.x += dX; + globalPos.y += dY; + Controller.setReticlePosition(globalPos); + lastPos = globalPos; +} + + +var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand"; +var mapping = Controller.newMapping(MAPPING_NAME); + +var lastHandPitch = 0; +var lastHandYaw = 0; + +mapping.from(Controller.Standard.LeftHand).peek().to(function(pose) { + var handEulers = Quat.safeEulerAngles(pose.rotation); + //Vec3.print("handEulers:", handEulers); + + var handPitch = handEulers.y; + var handYaw = handEulers.x; + var changePitch = (handPitch - lastHandPitch) * PITCH_SCALING; + var changeYaw = (handYaw - lastHandYaw) * YAW_SCALING; + if (Math.abs(changePitch) > PITCH_MAX) { + print("Pitch: " + changePitch); + changePitch = 0; + } + if (Math.abs(changeYaw) > YAW_MAX) { + print("Yaw: " + changeYaw); + changeYaw = 0; + } + changePitch = Math.abs(changePitch) < PITCH_DEADZONE ? 0 : changePitch; + changeYaw = Math.abs(changeYaw) < YAW_DEADZONE ? 0 : changeYaw; + moveReticle(changePitch, changeYaw); + lastHandPitch = handPitch; + lastHandYaw = handYaw; + +}); +mapping.enable(); + + +Script.scriptEnding.connect(function(){ + mapping.disable(); +}); From 0e530900d4a40bbe7c741db2812bb1ca4160637e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:22:20 -0800 Subject: [PATCH 216/318] sequential editing --- examples/light_modifier/closeButton.js | 12 +- examples/light_modifier/lightModifier.js | 161 +++++++++++------------ 2 files changed, 81 insertions(+), 92 deletions(-) diff --git a/examples/light_modifier/closeButton.js b/examples/light_modifier/closeButton.js index 045882fd33..7b2869cc8e 100644 --- a/examples/light_modifier/closeButton.js +++ b/examples/light_modifier/closeButton.js @@ -24,16 +24,12 @@ this.userData = JSON.parse(entityProperties.userData); }, startNearGrab: function() { - - }, - startDistantGrab: function() { }, - continueNearGrab: function() { - this.continueDistantGrab(); - }, - continueDistantGrab: function() { - }, + startFarTrigger: function() { + print('START FAR TRIGGER ON CLOSE BUTTON!!!') + Messages.sendMessage('Hifi-Light-Modifier-Cleanup', 'callCleanup') + } }; diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 76c1cdc873..5aa367dbbc 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -262,7 +262,7 @@ entitySlider.prototype = { color: this.color, position: sliderPosition, script: SLIDER_SCRIPT_URL, - ignoreForCollisions:true, + ignoreForCollisions: true, userData: JSON.stringify({ lightModifierKey: { lightID: this.lightID, @@ -407,30 +407,52 @@ function makeSliders(light) { subscribeToSliderMessages(); }; + +function createLightModel(position) { + var blockProperties = { + name: 'Hifi-Spotlight-Model', + type: 'Model', + shapeType: 'box', + modelURL: LIGHT_MODEL_URL, + dimensions: LIGHT_MODEL_DIMENSIONS, + collisionsWillMove: true, + position: position, + script: PARENT_SCRIPT_URL, + userData: JSON.stringify({ + handControllerKey: { + disableReleaseVelocity: true + } + }) + }; + + var block = Entities.addEntity(blockProperties); + + return block +} + var closeButtons = []; function createCloseButton(endOfAxis) { - // var avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); - // var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(avatarRot))); - // var verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET); - // var verticalOffset = lastRowVerticalOffset; - // var downPosition = Vec3.sum(basePosition, verticalOffset); - // var rightVector = Quat.getRight(avatarRot); - // var extension = Vec3.multiply(AXIS_SCALE, rightVector); - // var position = Vec3.sum(downPosition, extension); var buttonProperties = { - name:'Hifi-Close-Button', + name: 'Hifi-Close-Button', type: 'Model', modelURL: CLOSE_BUTTON_MODEL_URL, dimensions: CLOSE_BUTTON_DIMENSIONS, - position: Vec3.sum(endOfAxis,{ - x:0, - y:-0.15, - z:0 + position: Vec3.sum(endOfAxis, { + x: 0, + y: -0.15, + z: 0 }), rotation: Quat.fromPitchYawRollDegrees(0, 45, 90), - collisionsWillMove: false + collisionsWillMove: false, + ignoreForCollisions: true, + script: CLOSE_BUTTON_SCRIPT_URL, + userData: JSON.stringify({ + grabbableKey: { + wantsTrigger: true + } + }) //need to add wantsTrigger stuff so we can interact with it with our beamz } @@ -469,6 +491,11 @@ function subscribeToLightOverlayRayCheckMessages() { Messages.messageReceived.connect(handleLightOverlayRayCheckMessages); } +function subscribeToCleanupMessages() { + Messages.subscribe('Hifi-Light-Modifier-Cleanup'); + Messages.messageReceived.connect(handleCleanupMessages); +} + function handleLightModMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Mod-Receiver') { @@ -513,9 +540,9 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { var pickRay = JSON.parse(message); var doesIntersect = lightOverlayManager.findRayIntersection(pickRay); - print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects); + // print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects); if (doesIntersect.intersects === true) { - print('FULL MESSAGE:::' + JSON.stringify(doesIntersect)) + // print('FULL MESSAGE:::' + JSON.stringify(doesIntersect)) var lightID = doesIntersect.entityID; if (currentLight === lightID) { @@ -525,7 +552,6 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - // block = createBlock(lightProperties.position); block = createLightModel(lightProperties.position); var light = { @@ -542,103 +568,70 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { Entities.editEntity(lightID, { parentID: block, - parentJointIndex:-1 + parentJointIndex: -1 }); - } } -function createLightModel(position) { - print('CREATE MODEL') - var blockProperties = { - name: 'Hifi-Spotlight-Model', - type: 'Model', - shapeType: 'box', - modelURL: LIGHT_MODEL_URL, - // modelURL:"http://hifi-content.s3.amazonaws.com/james/light_modifier/box4.fbx", - dimensions: LIGHT_MODEL_DIMENSIONS, - collisionsWillMove: true, - position: position, - // rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - script: PARENT_SCRIPT_URL, - userData: JSON.stringify({ - handControllerKey: { - disableReleaseVelocity: true - } - }) - }; +function handleCleanupMessages(channel, message, sender) { - var block = Entities.addEntity(blockProperties); - - return block + if (channel !== 'Hifi-Light-Modifier-Cleanup') { + return; + } + if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) { + return; + } + if (message === 'callCleanup') { + print('GOT CLEANUP CALL!!!'); + cleanup(true); + } } -function createBlock(position) { - print('CREATE BLOCK') - - var blockProperties = { - name: 'Hifi-Spotlight-Block', - type: 'Box', - dimensions: { - x: 1, - y: 4, - z: 1 - }, - color: { - red: 0, - green: 0, - blue: 255 - }, - collisionsWillMove: true, - position: position, - script: PARENT_SCRIPT_URL, - userData: JSON.stringify({ - handControllerKey: { - disableReleaseVelocity: true - } - }) - }; - - var block = Entities.addEntity(blockProperties); - - return block -} - -function cleanup() { +function cleanup(fromMessage) { var i; for (i = 0; i < sliders.length; i++) { Entities.deleteEntity(sliders[i].axis); Entities.deleteEntity(sliders[i].sliderIndicator); } - while(closeButtons.length>0){ + while (closeButtons.length > 0) { Entities.deleteEntity(closeButtons.pop()); } - Entities.deleteEntity(block); + //if the light was already parented to something we will want to restore that. or come up with groups or something clever. + Entities.editEntity(currentLight, { + parentID: null, + }); + + if(fromMessage!==true){ Messages.messageReceived.disconnect(handleLightModMessages); Messages.messageReceived.disconnect(handleValueMessages); - Entities.deletingEntity.disconnect(deleteEntity); - + Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages); lightOverlayManager.setVisible(false); + } + + selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); + print('DELETE LIGHT MODEL::: ' + block); + Entities.deleteEntity(block); + currentLight = null; + + } Script.scriptEnding.connect(cleanup); -function deleteEntity(entityID) { - if (entityID === light) { - // cleanup(); - } -} +Script.scriptEnding.connect(function() { + lightOverlayManager.setVisible(false); +}) -Entities.deletingEntity.connect(deleteEntity); subscribeToLightOverlayRayCheckMessages(); subScribeToNewLights(); +subscribeToCleanupMessages(); From e405311cc8018fc870cf3291a2082174cec89ec1 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:35:06 -0800 Subject: [PATCH 217/318] cleanup --- examples/light_modifier/closeButton.js | 1 - examples/light_modifier/lightModifier.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/examples/light_modifier/closeButton.js b/examples/light_modifier/closeButton.js index 7b2869cc8e..72fcfbc382 100644 --- a/examples/light_modifier/closeButton.js +++ b/examples/light_modifier/closeButton.js @@ -27,7 +27,6 @@ }, startFarTrigger: function() { - print('START FAR TRIGGER ON CLOSE BUTTON!!!') Messages.sendMessage('Hifi-Light-Modifier-Cleanup', 'callCleanup') } diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 5aa367dbbc..d813216be5 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -583,7 +583,6 @@ function handleCleanupMessages(channel, message, sender) { return; } if (message === 'callCleanup') { - print('GOT CLEANUP CALL!!!'); cleanup(true); } } @@ -615,7 +614,6 @@ function cleanup(fromMessage) { selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); - print('DELETE LIGHT MODEL::: ' + block); Entities.deleteEntity(block); currentLight = null; From f83476599090eef8ae08488283ebe898e5d0e0da Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:39:21 -0800 Subject: [PATCH 218/318] readme --- examples/light_modifier/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 3bd456d525..73c2199ec9 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -1,5 +1,7 @@ This PR demonstrates one way in-world editing of objects might work. We start with a spotlight. When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. +Enter edit mode by running your distance beam through a light overlay. Exit using the red X. + To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js @@ -23,6 +25,4 @@ intensity cutoff exponent -To-Do: Determine how to enter / exit edit mode , support near grab, add other input types (checkbox, etc), prevent velocity drift on slider release,button to hide entity - -![capture](https://cloud.githubusercontent.com/assets/843228/11830366/2f2dfe70-a359-11e5-84f0-33a380ebeac7.PNG) +![capture](https://cloud.githubusercontent.com/assets/843228/11910139/afaaf1ae-a5a5-11e5-8b66-0eb3fc6976df.PNG) From 4afdd0242bfaf907b4dbdf4a6c707e1ca2aebd24 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:44:20 -0800 Subject: [PATCH 219/318] cleanup --- .../light_modifier/lightModifierTestScene.js | 52 ++----------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/examples/light_modifier/lightModifierTestScene.js b/examples/light_modifier/lightModifierTestScene.js index 8df83b09bf..58956850f2 100644 --- a/examples/light_modifier/lightModifierTestScene.js +++ b/examples/light_modifier/lightModifierTestScene.js @@ -10,19 +10,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?'+Math.random(0-100)); +var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100)); var basePosition, avatarRot; avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0); basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot))); -var light, block; +var light; function createLight() { - var blockProperties = Entities.getEntityProperties(block, ["position", "rotation"]); - var position = basePosition; + var position = basePosition; position.y += 2; - var lightTransform = evalLightWorldTransform(position,avatarRot); - // var lightTransform = evalLightWorldTransform(blockProperties.position, blockProperties.rotation); + var lightTransform = evalLightWorldTransform(position, avatarRot); var lightProperties = { name: 'Hifi-Spotlight', type: "Light", @@ -32,7 +30,6 @@ function createLight() { y: 2, z: 8 }, - // parentID: block, color: { red: 255, green: 0, @@ -48,45 +45,6 @@ function createLight() { light = Entities.addEntity(lightProperties); - var message = { - light: { - id: light, - type: 'spotlight', - initialProperties: lightProperties - } - }; - -// Messages.sendMessage('Hifi-Light-Mod-Receiver', JSON.stringify(message)); - -} - -function createBlock() { - var position = basePosition; - position.y += 3; - var blockProperties = { - name: 'Hifi-Spotlight-Block', - type: 'Box', - dimensions: { - x: 1, - y: 1, - z: 1 - }, - collisionsWillMove: true, - color: { - red: 0, - green: 0, - blue: 255 - }, - position: position, - script:PARENT_SCRIPT_URL, - userData: JSON.stringify({ - handControllerKey: { - disableReleaseVelocity: true - } - }) - }; - - block = Entities.addEntity(blockProperties); } function evalLightWorldTransform(modelPos, modelRot) { @@ -107,11 +65,9 @@ function evalLightWorldTransform(modelPos, modelRot) { } function cleanup() { - //Entities.deleteEntity(block); Entities.deleteEntity(light); } Script.scriptEnding.connect(cleanup); -//createBlock(); createLight(); \ No newline at end of file From b0da1773c246f4d619824355c336c2dac1c2869e Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 18 Dec 2015 16:53:41 -0800 Subject: [PATCH 220/318] have right rotation on sequential edits --- examples/light_modifier/lightModifier.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index d813216be5..0d07f2c011 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -60,7 +60,7 @@ var CUTOFF_MAX = 360; var EXPONENT_MAX = 1; var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100)); -var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_rotated.fbx'; +var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_very_good.fbx'; var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx'; var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100)); @@ -408,7 +408,7 @@ function makeSliders(light) { }; -function createLightModel(position) { +function createLightModel(position,rotation) { var blockProperties = { name: 'Hifi-Spotlight-Model', type: 'Model', @@ -417,6 +417,7 @@ function createLightModel(position) { dimensions: LIGHT_MODEL_DIMENSIONS, collisionsWillMove: true, position: position, + rotation:rotation, script: PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { @@ -552,7 +553,7 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - block = createLightModel(lightProperties.position); + block = createLightModel(lightProperties.position,lightProperties.rotation); var light = { id: lightID, From 1f3adeb66622a0d527e4f4b2307330e60593728d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Dec 2015 17:09:38 -0800 Subject: [PATCH 221/318] Revert "Migrate QML based web views to Qt WebEngine" --- .../PackageLibrariesForDeployment.cmake | 2 +- examples/directory.js | 2 +- examples/html/eventBridgeLoader.js | 59 -- examples/html/qmlWebTest.html | 31 - examples/tests/qmlWebTest.js | 32 - interface/CMakeLists.txt | 18 +- interface/resources/qml/Browser.qml | 28 +- interface/resources/qml/InfoView.qml | 16 +- interface/resources/qml/MarketplaceDialog.qml | 37 +- interface/resources/qml/QmlWebWindow.qml | 63 -- interface/resources/qml/TestMenu.qml | 109 +++ interface/resources/qml/WebEntity.qml | 6 +- interface/src/Application.cpp | 17 - libraries/gl/src/gl/OffscreenQmlSurface.cpp | 13 +- libraries/gl/src/gl/OffscreenQmlSurface.h | 4 +- libraries/gl/src/gl/QOpenGLContextWrapper.cpp | 7 +- libraries/gl/src/gl/QOpenGLContextWrapper.h | 6 - libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 3 - libraries/ui/CMakeLists.txt | 2 +- libraries/ui/src/QmlWebWindowClass.cpp | 240 ------- libraries/ui/src/QmlWebWindowClass.h | 104 --- tests/ui/CMakeLists.txt | 19 +- tests/ui/src/main.cpp | 636 +++++------------- 24 files changed, 344 insertions(+), 1112 deletions(-) delete mode 100644 examples/html/eventBridgeLoader.js delete mode 100644 examples/html/qmlWebTest.html delete mode 100644 examples/tests/qmlWebTest.js delete mode 100644 interface/resources/qml/QmlWebWindow.qml delete mode 100644 libraries/ui/src/QmlWebWindowClass.cpp delete mode 100644 libraries/ui/src/QmlWebWindowClass.h diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index 17b5d5f49d..bb0b268dd4 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -40,7 +40,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release> $" + COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} $<$,$,$>:--release> $" ) elseif (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE) find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH) diff --git a/examples/directory.js b/examples/directory.js index d2a3768051..b1fac19e8b 100644 --- a/examples/directory.js +++ b/examples/directory.js @@ -62,7 +62,7 @@ var directory = (function () { function setUp() { viewport = Controller.getViewportDimensions(); - directoryWindow = new OverlayWebWindow('Directory', DIRECTORY_URL, 900, 700, false); + directoryWindow = new WebWindow('Directory', DIRECTORY_URL, 900, 700, false); directoryWindow.setVisible(false); directoryButton = Overlays.addOverlay("image", { diff --git a/examples/html/eventBridgeLoader.js b/examples/html/eventBridgeLoader.js deleted file mode 100644 index b62e7d9384..0000000000 --- a/examples/html/eventBridgeLoader.js +++ /dev/null @@ -1,59 +0,0 @@ - -//public slots: -// void emitWebEvent(const QString& data); -// void emitScriptEvent(const QString& data); -// -//signals: -// void webEventReceived(const QString& data); -// void scriptEventReceived(const QString& data); -// - -EventBridgeConnectionProxy = function(parent) { - this.parent = parent; - this.realSignal = this.parent.realBridge.scriptEventReceived - this.webWindowId = this.parent.webWindow.windowId; -} - -EventBridgeConnectionProxy.prototype.connect = function(callback) { - var that = this; - this.realSignal.connect(function(id, message) { - if (id === that.webWindowId) { callback(message); } - }); -} - -EventBridgeProxy = function(webWindow) { - this.webWindow = webWindow; - this.realBridge = this.webWindow.eventBridge; - this.scriptEventReceived = new EventBridgeConnectionProxy(this); -} - -EventBridgeProxy.prototype.emitWebEvent = function(data) { - this.realBridge.emitWebEvent(data); -} - -openEventBridge = function(callback) { - EVENT_BRIDGE_URI = "ws://localhost:51016"; - socket = new WebSocket(this.EVENT_BRIDGE_URI); - - socket.onclose = function() { - console.error("web channel closed"); - }; - - socket.onerror = function(error) { - console.error("web channel error: " + error); - }; - - socket.onopen = function() { - channel = new QWebChannel(socket, function(channel) { - console.log("Document url is " + document.URL); - for(var key in channel.objects){ - console.log("registered object: " + key); - } - var webWindow = channel.objects[document.URL.toLowerCase()]; - console.log("WebWindow is " + webWindow) - eventBridgeProxy = new EventBridgeProxy(webWindow); - if (callback) { callback(eventBridgeProxy); } - }); - } -} - diff --git a/examples/html/qmlWebTest.html b/examples/html/qmlWebTest.html deleted file mode 100644 index e59535701d..0000000000 --- a/examples/html/qmlWebTest.html +++ /dev/null @@ -1,31 +0,0 @@ - - -Properties - - - - - - - - - - - - - diff --git a/examples/tests/qmlWebTest.js b/examples/tests/qmlWebTest.js deleted file mode 100644 index f905e494dc..0000000000 --- a/examples/tests/qmlWebTest.js +++ /dev/null @@ -1,32 +0,0 @@ -print("Launching web window"); - -webWindow = new OverlayWebWindow('Test Event Bridge', "file:///C:/Users/bdavis/Git/hifi/examples/html/qmlWebTest.html", 320, 240, false); -print("JS Side window: " + webWindow); -print("JS Side bridge: " + webWindow.eventBridge); -webWindow.eventBridge.webEventReceived.connect(function(data) { - print("JS Side event received: " + data); -}); - -var titles = ["A", "B", "C"]; -var titleIndex = 0; - -Script.setInterval(function() { - webWindow.eventBridge.emitScriptEvent("JS Event sent"); - var size = webWindow.size; - var position = webWindow.position; - print("Window url: " + webWindow.url) - print("Window visible: " + webWindow.visible) - print("Window size: " + size.x + "x" + size.y) - print("Window pos: " + position.x + "x" + position.y) - webWindow.setVisible(!webWindow.visible); - webWindow.setTitle(titles[titleIndex]); - webWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100); - titleIndex += 1; - titleIndex %= titles.length; -}, 2 * 1000); - -Script.setTimeout(function() { - print("Closing script"); - webWindow.close(); - Script.stop(); -}, 15 * 1000) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1d9557a835..87cf1a384c 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -45,9 +45,7 @@ else () list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) endif () -find_package(Qt5 COMPONENTS - Gui Multimedia Network OpenGL Qml Quick Script Svg - WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets) +find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets WebSockets) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) @@ -177,17 +175,9 @@ include_directories("${PROJECT_SOURCE_DIR}/src") target_link_libraries( ${TARGET_NAME} - Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL - Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg - Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets + Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets ) -# Issue causes build failure unless we add this directory. -# See https://bugreports.qt.io/browse/QTBUG-43351 -if (WIN32) - add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) -endif() - # assume we are using a Qt build without bearer management add_definitions(-DQT_NO_BEARERMANAGEMENT) @@ -219,9 +209,5 @@ else (APPLE) endif() endif (APPLE) -if (WIN32) - set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") -endif() - package_libraries_for_deployment() consolidate_stack_components() diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 8f3cd0e1e7..947bf739fc 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,6 +1,6 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtWebEngine 1.1 +import QtWebKit 3.0 import "controls" import "styles" @@ -39,10 +39,9 @@ VrDialog { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.bottom: webview.top + anchors.bottom: scrollView.top color: "white" } - Row { id: buttons spacing: 4 @@ -113,21 +112,25 @@ VrDialog { } } - WebEngineView { - id: webview - url: "http://highfidelity.com" + ScrollView { + id: scrollView anchors.top: buttons.bottom anchors.topMargin: 8 anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - onLoadingChanged: { - if (loadRequest.status == WebEngineView.LoadSucceededStatus) { - addressBar.text = loadRequest.url + WebView { + id: webview + url: "http://highfidelity.com" + anchors.fill: parent + onLoadingChanged: { + if (loadRequest.status == WebView.LoadSucceededStarted) { + addressBar.text = loadRequest.url + } + } + onIconChanged: { + barIcon.source = icon } - } - onIconChanged: { - console.log("New icon: " + icon) } } } // item @@ -143,4 +146,5 @@ VrDialog { break; } } + } // dialog diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 75b82342ca..012f04f1fd 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -2,7 +2,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -import QtWebEngine 1.1 +import QtWebKit 3.0 import "controls" VrDialog { @@ -18,11 +18,15 @@ VrDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - WebEngineView { - id: webview - objectName: "WebView" + ScrollView { anchors.fill: parent - url: infoView.url - } + WebView { + objectName: "WebView" + id: webview + url: infoView.url + anchors.fill: parent + } + } + } } diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml index 3a66c5340f..946f32e84a 100644 --- a/interface/resources/qml/MarketplaceDialog.qml +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -2,7 +2,7 @@ import Hifi 1.0 import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -import QtWebEngine 1.1 +import QtWebKit 3.0 import "controls" VrDialog { @@ -24,22 +24,27 @@ VrDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - WebEngineView { - objectName: "WebView" - id: webview - url: "https://metaverse.highfidelity.com/marketplace" + + ScrollView { anchors.fill: parent - onNavigationRequested: { - console.log(request.url) - if (!marketplaceDialog.navigationRequested(request.url)) { - console.log("Application absorbed the request") - request.action = WebView.IgnoreRequest; + WebView { + objectName: "WebView" + id: webview + url: "https://metaverse.highfidelity.com/marketplace" + anchors.fill: parent + onNavigationRequested: { + console.log(request.url) + if (!marketplaceDialog.navigationRequested(request.url)) { + console.log("Application absorbed the request") + request.action = WebView.IgnoreRequest; + return; + } + console.log("Application passed on the request") + request.action = WebView.AcceptRequest; return; - } - console.log("Application passed on the request") - request.action = WebView.AcceptRequest; - return; + } } - } - } + } + + } } diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml deleted file mode 100644 index 9664c0edb8..0000000000 --- a/interface/resources/qml/QmlWebWindow.qml +++ /dev/null @@ -1,63 +0,0 @@ - -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtWebEngine 1.1 -import QtWebChannel 1.0 -import QtWebSockets 1.0 - -import "qwebchannel.js" as WebChannel -import "controls" -import "styles" - -VrDialog { - id: root - HifiConstants { id: hifi } - title: "WebWindow" - resizable: true - contentImplicitWidth: clientArea.implicitWidth - contentImplicitHeight: clientArea.implicitHeight - backgroundColor: "#7f000000" - property url source: "about:blank" - - signal navigating(string url) - - Component.onCompleted: { - enabled = true - console.log("Web Window Created " + root); - webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); - }); - - webview.loadingChanged.connect(handleWebviewLoading) - } - - - function handleWebviewLoading(loadRequest) { - var HIFI_URL_PATTERN = /^hifi:\/\//; - if (WebEngineView.LoadStartedStatus == loadRequest.status) { - var newUrl = loadRequest.url.toString(); - if (newUrl.match(HIFI_URL_PATTERN)) { - root.navigating(newUrl); - } - } - } - - Item { - id: clientArea - implicitHeight: 600 - implicitWidth: 800 - x: root.clientX - y: root.clientY - width: root.clientWidth - height: root.clientHeight - - WebEngineView { - id: webview - url: root.source - anchors.fill: parent - profile: WebEngineProfile { - httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)" - } - } - } // item -} // dialog diff --git a/interface/resources/qml/TestMenu.qml b/interface/resources/qml/TestMenu.qml index fe8a26e234..4d109e6298 100644 --- a/interface/resources/qml/TestMenu.qml +++ b/interface/resources/qml/TestMenu.qml @@ -4,7 +4,116 @@ import Hifi 1.0 // Currently for testing a pure QML replacement menu Item { + Item { + objectName: "AllActions" + Action { + id: aboutApp + objectName: "HifiAction_" + MenuConstants.AboutApp + text: qsTr("About Interface") + } + + // + // File Menu + // + Action { + id: login + objectName: "HifiAction_" + MenuConstants.Login + text: qsTr("Login") + } + Action { + id: quit + objectName: "HifiAction_" + MenuConstants.Quit + text: qsTr("Quit") + //shortcut: StandardKey.Quit + shortcut: "Ctrl+Q" + } + + + // + // Edit menu + // + Action { + id: undo + text: "Undo" + shortcut: StandardKey.Undo + } + + Action { + id: redo + text: "Redo" + shortcut: StandardKey.Redo + } + + Action { + id: animations + objectName: "HifiAction_" + MenuConstants.Animations + text: qsTr("Animations...") + } + Action { + id: attachments + text: qsTr("Attachments...") + } + Action { + id: explode + text: qsTr("Explode on quit") + checkable: true + checked: true + } + Action { + id: freeze + text: qsTr("Freeze on quit") + checkable: true + checked: false + } + ExclusiveGroup { + Action { + id: visibleToEveryone + objectName: "HifiAction_" + MenuConstants.VisibleToEveryone + text: qsTr("Everyone") + checkable: true + checked: true + } + Action { + id: visibleToFriends + objectName: "HifiAction_" + MenuConstants.VisibleToFriends + text: qsTr("Friends") + checkable: true + } + Action { + id: visibleToNoOne + objectName: "HifiAction_" + MenuConstants.VisibleToNoOne + text: qsTr("No one") + checkable: true + } + } + } + Menu { objectName: "rootMenu"; + Menu { + title: "File" + MenuItem { action: login } + MenuItem { action: explode } + MenuItem { action: freeze } + MenuItem { action: quit } + } + Menu { + title: "Tools" + Menu { + title: "I Am Visible To" + MenuItem { action: visibleToEveryone } + MenuItem { action: visibleToFriends } + MenuItem { action: visibleToNoOne } + } + MenuItem { action: animations } + } + Menu { + title: "Long menu name top menu" + MenuItem { action: aboutApp } + } + Menu { + title: "Help" + MenuItem { action: aboutApp } + } } } diff --git a/interface/resources/qml/WebEntity.qml b/interface/resources/qml/WebEntity.qml index ae94105672..0eb943cac7 100644 --- a/interface/resources/qml/WebEntity.qml +++ b/interface/resources/qml/WebEntity.qml @@ -1,10 +1,10 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtWebEngine 1.1 +import QtWebKit 3.0 -WebEngineView { +WebView { id: root - anchors.fill: parent objectName: "webview" + anchors.fill: parent url: "about:blank" } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e437a05aa3..fa5565417d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -101,7 +101,6 @@ #include #include #include -#include #include "AnimDebugDraw.h" #include "AudioClient.h" @@ -363,17 +362,6 @@ Cube3DOverlay* _keyboardFocusHighlight{ nullptr }; int _keyboardFocusHighlightID{ -1 }; PluginContainer* _pluginContainer; - -// FIXME hack access to the internal share context for the Chromium helper -// Normally we'd want to use QWebEngine::initialize(), but we can't because -// our primary context is a QGLWidget, which can't easily be initialized to share -// from a QOpenGLContext. -// -// So instead we create a new offscreen context to share with the QGLWidget, -// and manually set THAT to be the shared context for the Chromium helper -OffscreenGLCanvas* _chromiumShareContext { nullptr }; -Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); - Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), @@ -635,11 +623,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _glWidget->makeCurrent(); _glWidget->initializeGL(); - _chromiumShareContext = new OffscreenGLCanvas(); - _chromiumShareContext->create(_glWidget->context()->contextHandle()); - _chromiumShareContext->makeCurrent(); - qt_gl_set_global_share_context(_chromiumShareContext->getContext()); - _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->makeCurrent(); diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index 26a564e20b..bddc7d19ae 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -320,13 +320,10 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { void OffscreenQmlSurface::resize(const QSize& newSize) { if (!_renderer || !_renderer->_quickWindow) { - return; - } - - - QSize currentSize = _renderer->_quickWindow->geometry().size(); - if (newSize == currentSize) { - return; + QSize currentSize = _renderer->_quickWindow->geometry().size(); + if (newSize == currentSize) { + return; + } } _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize); @@ -440,9 +437,7 @@ void OffscreenQmlSurface::updateQuick() { } if (_render) { - QMutexLocker lock(&(_renderer->_mutex)); _renderer->post(RENDER); - _renderer->_cond.wait(&(_renderer->_mutex)); _render = false; } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h index d66cbeb285..67315b0783 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.h +++ b/libraries/gl/src/gl/OffscreenQmlSurface.h @@ -40,8 +40,8 @@ public: void create(QOpenGLContext* context); void resize(const QSize& size); QSize size() const; - Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { + QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { return load(QUrl(qmlSourceFile), f); } diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 6397d30e13..3e879df7af 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -39,11 +39,6 @@ void QOpenGLContextWrapper::doneCurrent() { _context->doneCurrent(); } -void QOpenGLContextWrapper::setShareContext(QOpenGLContext* otherContext) { - _context->setShareContext(otherContext); -} - bool isCurrentContext(QOpenGLContext* context) { return QOpenGLContext::currentContext() == context; -} - +} \ No newline at end of file diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.h b/libraries/gl/src/gl/QOpenGLContextWrapper.h index b736253213..832119162c 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.h +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.h @@ -25,12 +25,6 @@ public: void swapBuffers(QSurface* surface); bool makeCurrent(QSurface* surface); void doneCurrent(); - void setShareContext(QOpenGLContext* otherContext); - - QOpenGLContext* getContext() { - return _context; - } - private: QOpenGLContext* _context { nullptr }; diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index c1131765f7..3796abd92a 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME script-engine) setup_hifi_library(Gui Network Script WebSockets Widgets) -link_hifi_libraries(shared networking ui octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) +link_hifi_libraries(shared networking octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5f39bee9fa..ded3db11e9 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -351,8 +350,6 @@ void ScriptEngine::init() { qScriptRegisterSequenceMetaType >(this); qScriptRegisterSequenceMetaType >(this); - - registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor); QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index cc2382926f..140ca87d0d 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME ui) -setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebSockets XmlPatterns) +setup_hifi_library(OpenGL Network Qml Quick Script XmlPatterns) link_hifi_libraries(shared networking gl) diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp deleted file mode 100644 index d5cdc1fde9..0000000000 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ /dev/null @@ -1,240 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015-12-15 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "QmlWebWindowClass.h" - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "OffscreenUi.h" - -QWebSocketServer* QmlWebWindowClass::_webChannelServer { nullptr }; -static QWebChannel webChannel; -static const uint16_t WEB_CHANNEL_PORT = 51016; -static std::atomic nextWindowId; -static const char* const URL_PROPERTY = "source"; -static const char* const TITLE_PROPERTY = "title"; -static const QRegExp HIFI_URL_PATTERN { "^hifi://" }; - -void QmlScriptEventBridge::emitWebEvent(const QString& data) { - QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); -} - -void QmlScriptEventBridge::emitScriptEvent(const QString& data) { - QMetaObject::invokeMethod(this, "scriptEventReceived", Qt::QueuedConnection, - Q_ARG(int, _webWindow->getWindowId()), Q_ARG(QString, data)); -} - -class QmlWebTransport : public QWebChannelAbstractTransport { - Q_OBJECT -public: - QmlWebTransport(QWebSocket* webSocket) : _webSocket(webSocket) { - // Translate from the websocket layer to the webchannel layer - connect(webSocket, &QWebSocket::textMessageReceived, [this](const QString& message) { - QJsonParseError error; - QJsonDocument document = QJsonDocument::fromJson(message.toUtf8(), &error); - if (error.error || !document.isObject()) { - qWarning() << "Unable to parse incoming JSON message" << message; - return; - } - emit messageReceived(document.object(), this); - }); - } - - virtual void sendMessage(const QJsonObject &message) override { - // Translate from the webchannel layer to the websocket layer - _webSocket->sendTextMessage(QJsonDocument(message).toJson(QJsonDocument::Compact)); - } - -private: - QWebSocket* const _webSocket; -}; - - -void QmlWebWindowClass::setupServer() { - if (!_webChannelServer) { - _webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); - if (!_webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { - qFatal("Failed to open web socket server."); - } - - QObject::connect(_webChannelServer, &QWebSocketServer::newConnection, [] { - webChannel.connectTo(new QmlWebTransport(_webChannelServer->nextPendingConnection())); - }); - } -} - -// Method called by Qt scripts to create a new web window in the overlay -QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { - QmlWebWindowClass* retVal { nullptr }; - const QString title = context->argument(0).toString(); - QString url = context->argument(1).toString(); - if (!url.startsWith("http") && !url.startsWith("file://")) { - url = QUrl::fromLocalFile(url).toString(); - } - const int width = std::max(100, std::min(1280, context->argument(2).toInt32()));; - const int height = std::max(100, std::min(720, context->argument(3).toInt32()));; - - // Build the event bridge and wrapper on the main thread - QMetaObject::invokeMethod(DependencyManager::get().data(), "load", Qt::BlockingQueuedConnection, - Q_ARG(const QString&, "QmlWebWindow.qml"), - Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { - setupServer(); - retVal = new QmlWebWindowClass(object); - webChannel.registerObject(url.toLower(), retVal); - retVal->setTitle(title); - retVal->setURL(url); - retVal->setSize(width, height); - })); - connect(engine, &QScriptEngine::destroyed, retVal, &QmlWebWindowClass::deleteLater); - return engine->newQObject(retVal); -} - -QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) - : _windowId(++nextWindowId), _qmlWindow(qmlWindow) -{ - qDebug() << "Created window with ID " << _windowId; - Q_ASSERT(_qmlWindow); - Q_ASSERT(dynamic_cast(_qmlWindow)); - QObject::connect(_qmlWindow, SIGNAL(navigating(QString)), this, SLOT(handleNavigation(QString))); -} - -void QmlWebWindowClass::handleNavigation(const QString& url) { - DependencyManager::get()->handleLookupString(url); -} - -void QmlWebWindowClass::setVisible(bool visible) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); - return; - } - - auto qmlWindow = asQuickItem(); - if (qmlWindow->isEnabled() != visible) { - qmlWindow->setEnabled(visible); - emit visibilityChanged(visible); - } -} - -QQuickItem* QmlWebWindowClass::asQuickItem() const { - return dynamic_cast(_qmlWindow); -} - -bool QmlWebWindowClass::isVisible() const { - if (QThread::currentThread() != thread()) { - bool result; - QMetaObject::invokeMethod(const_cast(this), "isVisible", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); - return result; - } - - return asQuickItem()->isEnabled(); -} - - -glm::vec2 QmlWebWindowClass::getPosition() const { - if (QThread::currentThread() != thread()) { - glm::vec2 result; - QMetaObject::invokeMethod(const_cast(this), "getPosition", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); - return result; - } - - return glm::vec2(asQuickItem()->x(), asQuickItem()->y()); -} - - -void QmlWebWindowClass::setPosition(const glm::vec2& position) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setPosition", Qt::QueuedConnection, Q_ARG(glm::vec2, position)); - return; - } - - asQuickItem()->setPosition(QPointF(position.x, position.y)); -} - -void QmlWebWindowClass::setPosition(int x, int y) { - setPosition(glm::vec2(x, y)); -} - -glm::vec2 QmlWebWindowClass::getSize() const { - if (QThread::currentThread() != thread()) { - glm::vec2 result; - QMetaObject::invokeMethod(const_cast(this), "getSize", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); - return result; - } - - return glm::vec2(asQuickItem()->width(), asQuickItem()->height()); -} - -void QmlWebWindowClass::setSize(const glm::vec2& size) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setSize", Qt::QueuedConnection, Q_ARG(glm::vec2, size)); - } - - asQuickItem()->setSize(QSizeF(size.x, size.y)); -} - -void QmlWebWindowClass::setSize(int width, int height) { - setSize(glm::vec2(width, height)); -} - -QString QmlWebWindowClass::getURL() const { - if (QThread::currentThread() != thread()) { - QString result; - QMetaObject::invokeMethod(const_cast(this), "getURL", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, result)); - return result; - } - return _qmlWindow->property(URL_PROPERTY).toString(); -} - -void QmlWebWindowClass::setURL(const QString& urlString) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setURL", Qt::QueuedConnection, Q_ARG(QString, urlString)); - } - _qmlWindow->setProperty(URL_PROPERTY, urlString); -} - - -void QmlWebWindowClass::setTitle(const QString& title) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setTitle", Qt::QueuedConnection, Q_ARG(QString, title)); - } - - _qmlWindow->setProperty(TITLE_PROPERTY, title); -} - -void QmlWebWindowClass::close() { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); - } - _qmlWindow->setProperty("destroyOnInvisible", true); - _qmlWindow->setProperty("visible", false); - _qmlWindow->deleteLater(); -} - -void QmlWebWindowClass::hasClosed() { -} - -void QmlWebWindowClass::raise() { - // FIXME -} - -#include "QmlWebWindowClass.moc" diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h deleted file mode 100644 index 2b563e68ba..0000000000 --- a/libraries/ui/src/QmlWebWindowClass.h +++ /dev/null @@ -1,104 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015-12-15 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_ui_QmlWebWindowClass_h -#define hifi_ui_QmlWebWindowClass_h - -#include -#include -#include -#include -#include - -class QScriptEngine; -class QScriptContext; -class QmlWebWindowClass; -class QWebSocketServer; -class QWebSocket; - -class QmlScriptEventBridge : public QObject { - Q_OBJECT -public: - QmlScriptEventBridge(const QmlWebWindowClass* webWindow) : _webWindow(webWindow) {} - -public slots : - void emitWebEvent(const QString& data); - void emitScriptEvent(const QString& data); - -signals: - void webEventReceived(const QString& data); - void scriptEventReceived(int windowId, const QString& data); - -private: - const QmlWebWindowClass* _webWindow { nullptr }; - QWebSocket *_socket { nullptr }; -}; - -// FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping -class QmlWebWindowClass : public QObject { - Q_OBJECT - Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) - Q_PROPERTY(int windowId READ getWindowId CONSTANT) - Q_PROPERTY(QString url READ getURL CONSTANT) - Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition) - Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize) - Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) - -public: - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); - QmlWebWindowClass(QObject* qmlWindow); - -public slots: - bool isVisible() const; - void setVisible(bool visible); - - glm::vec2 getPosition() const; - void setPosition(const glm::vec2& position); - void setPosition(int x, int y); - - glm::vec2 getSize() const; - void setSize(const glm::vec2& size); - void setSize(int width, int height); - - QString getURL() const; - void setURL(const QString& url); - - void setTitle(const QString& title); - - // Ugh.... do not want to do - Q_INVOKABLE void raise(); - Q_INVOKABLE void close(); - Q_INVOKABLE int getWindowId() const { return _windowId; }; - Q_INVOKABLE QmlScriptEventBridge* getEventBridge() const { return _eventBridge; }; - -signals: - void visibilityChanged(bool visible); // Tool window - void urlChanged(); - void moved(glm::vec2 position); - void resized(QSizeF size); - void closed(); - -private slots: - void hasClosed(); - void handleNavigation(const QString& url); - -private: - static void setupServer(); - static QWebSocketServer* _webChannelServer; - - QQuickItem* asQuickItem() const; - QmlScriptEventBridge* const _eventBridge { new QmlScriptEventBridge(this) }; - - // FIXME needs to be initialized in the ctor once we have support - // for tool window panes in QML - const bool _isToolWindow { false }; - const int _windowId; - QObject* const _qmlWindow; -}; - -#endif diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt index f94a0b85c0..8fda001e14 100644 --- a/tests/ui/CMakeLists.txt +++ b/tests/ui/CMakeLists.txt @@ -2,32 +2,15 @@ set(TARGET_NAME "ui-test") # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Network OpenGL Qml Quick Script WebChannel WebEngine WebSockets) +setup_hifi_project(Widgets OpenGL Network Qml Quick Script) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") if (WIN32) target_link_libraries(${TARGET_NAME} wsock32.lib opengl32.lib Winmm.lib) - # Issue causes build failure unless we add this directory. - # See https://bugreports.qt.io/browse/QTBUG-43351 - add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) endif() # link in the shared libraries link_hifi_libraries(shared networking gl gpu ui) -# copy the resources files beside the executable -add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${PROJECT_SOURCE_DIR}/qml" - $/qml -) - - -target_glew() - -if (WIN32) - set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/../../interface/resources/qml") -endif() - package_libraries_for_deployment() diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 59e7376f1b..18f62dc016 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -1,91 +1,41 @@ // -// Created by Bradley Austin Davis on 2015-04-22 -// Copyright 2013-2015 High Fidelity, Inc. +// main.cpp +// tests/render-utils/src +// +// Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include +#include "OffscreenUi.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include - -#include -#include -#include #include +#include +#include #include -#include -#include -#include -#include -#include - -const QString& getResourcesDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; - qDebug() << "Resources Path: " << dir; - } - return dir; -} - -const QString& getExamplesDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/"; - qDebug() << "Resources Path: " << dir; - } - return dir; -} - -const QString& getInterfaceQmlDir() { - static QString dir; - if (dir.isEmpty()) { - dir = getResourcesDir() + "qml/"; - qDebug() << "Qml Path: " << dir; - } - return dir; -} - -const QString& getTestQmlDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; - qDebug() << "Qml Test Path: " << dir; - } - return dir; -} - +#include +#include "MessageDialog.h" +#include "VrMenu.h" +#include "InfoView.h" +#include class RateCounter { std::vector times; @@ -124,394 +74,142 @@ public: }; - - -extern QOpenGLContext* qt_gl_global_share_context(); - - -static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { - if (engine.hasUncaughtException()) { - const auto backtrace = engine.uncaughtExceptionBacktrace(); - const auto exception = engine.uncaughtException().toString(); - const auto line = QString::number(engine.uncaughtExceptionLineNumber()); - engine.clearExceptions(); - - auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); - if (!backtrace.empty()) { - static const auto lineSeparator = "\n "; - message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); - } - qWarning() << qPrintable(message); - return true; - } - return false; -} - -const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); - -static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { - QString message = ""; - for (int i = 0; i < context->argumentCount(); i++) { - if (i > 0) { - message += " "; - } - message += context->argument(i).toString(); - } - qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline - - message = message.replace("\\", "\\\\") - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("'", "\\'"); - engine->evaluate("Script.print('" + message + "')"); - - return QScriptValue(); -} - -class ScriptEngine : public QScriptEngine { +class MenuConstants : public QObject{ Q_OBJECT + Q_ENUMS(Item) public: - void loadFile(const QString& scriptPath) { - if (_isRunning) { - return; - } - qDebug() << "Loading script from " << scriptPath; - _fileNameString = scriptPath; + enum Item { + RenderLookAtTargets, + }; + +public: + MenuConstants(QObject* parent = nullptr) : QObject(parent) { - QFile file(scriptPath); - if (file.exists()) { - file.open(QIODevice::ReadOnly); - _scriptContents = file.readAll(); - } else { - qFatal("Missing file "); - } - runInThread(); } - - Q_INVOKABLE void stop() { - if (!_isFinished) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "stop"); - return; - } - _isFinished = true; - if (_wantSignals) { - emit runningStateChanged(); - } - } - } - - Q_INVOKABLE void print(const QString& message) { - if (_wantSignals) { - emit printedMessage(message); - } - } - - Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { - // create the timer, add it to the map, and start it - QTimer* newTimer = new QTimer(this); - newTimer->setSingleShot(isSingleShot); - - connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); - - // make sure the timer stops when the script does - connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); - - _timerFunctionMap.insert(newTimer, function); - - newTimer->start(intervalMS); - return newTimer; - } - - Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) { - return setupTimerWithInterval(function, intervalMS, false); - } - - Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) { - return setupTimerWithInterval(function, timeoutMS, true); - } -private: - - void runInThread() { - QThread* workerThread = new QThread(); - connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); - connect(workerThread, &QThread::started, this, &ScriptEngine::run); - connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); - connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); - moveToThread(workerThread); - workerThread->start(); - } - - void init() { - _isInitialized = true; - registerMetaTypes(this); - registerGlobalObject("Script", this); - qScriptRegisterSequenceMetaType>(this); - qScriptRegisterSequenceMetaType>(this); - globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor)); - QScriptValue printConstructorValue = newFunction(debugPrint); - globalObject().setProperty("print", printConstructorValue); - } - - void timerFired() { - QTimer* callingTimer = reinterpret_cast(sender()); - QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); - - if (!callingTimer->isActive()) { - // this timer is done, we can kill it - _timerFunctionMap.remove(callingTimer); - delete callingTimer; - } - - // call the associated JS function, if it exists - if (timerFunction.isValid()) { - timerFunction.call(); - } - } - - - void run() { - if (!_isInitialized) { - init(); - } - - _isRunning = true; - if (_wantSignals) { - emit runningStateChanged(); - } - - QScriptValue result = evaluate(_scriptContents, _fileNameString); - QElapsedTimer startTime; - startTime.start(); - - int thisFrame = 0; - - qint64 lastUpdate = usecTimestampNow(); - - while (!_isFinished) { - int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec - if (usecToSleep > 0) { - usleep(usecToSleep); - } - - if (_isFinished) { - break; - } - - QCoreApplication::processEvents(); - if (_isFinished) { - break; - } - - qint64 now = usecTimestampNow(); - float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND; - if (!_isFinished) { - if (_wantSignals) { - emit update(deltaTime); - } - } - lastUpdate = now; - - // Debug and clear exceptions - hadUncaughtExceptions(*this, _fileNameString); - } - - if (_wantSignals) { - emit scriptEnding(); - } - - if (_wantSignals) { - emit finished(_fileNameString, this); - } - - _isRunning = false; - - if (_wantSignals) { - emit runningStateChanged(); - emit doneRunning(); - } - } - - void registerGlobalObject(const QString& name, QObject* object) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "registerGlobalObject", - Q_ARG(const QString&, name), - Q_ARG(QObject*, object)); - return; - } - if (!globalObject().property(name).isValid()) { - if (object) { - QScriptValue value = newQObject(object); - globalObject().setProperty(name, value); - } else { - globalObject().setProperty(name, QScriptValue()); - } - } - } - - void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } - QScriptValue scriptFun = newFunction(functionSignature, numArguments); - globalObject().setProperty(name, scriptFun); - } - - void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "registerFunction", - Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), - Q_ARG(int, numArguments)); - return; - } - - QScriptValue object = globalObject().property(parent); - if (object.isValid()) { - QScriptValue scriptFun = newFunction(functionSignature, numArguments); - object.setProperty(name, scriptFun); - } - } - -signals: - void scriptLoaded(const QString& scriptFilename); - void errorLoadingScript(const QString& scriptFilename); - void update(float deltaTime); - void scriptEnding(); - void finished(const QString& fileNameString, ScriptEngine* engine); - void cleanupMenuItem(const QString& menuItemString); - void printedMessage(const QString& message); - void errorMessage(const QString& message); - void runningStateChanged(); - void evaluationFinished(QScriptValue result, bool isException); - void loadScript(const QString& scriptName, bool isUserLoaded); - void reloadScript(const QString& scriptName, bool isUserLoaded); - void doneRunning(); - - -private: - QString _scriptContents; - QString _fileNameString; - QString _parentURL; - bool _isInitialized { false }; - std::atomic _isFinished { false }; - std::atomic _isRunning { false }; - bool _wantSignals { true }; - QHash _timerFunctionMap; }; - - -ScriptEngine* loadScript(const QString& scriptFilename) { - ScriptEngine* scriptEngine = new ScriptEngine(); - scriptEngine->loadFile(scriptFilename); - return scriptEngine; +const QString& getResourcesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; } -OffscreenGLCanvas* _chromiumShareContext { nullptr }; -Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); +const QString& getQmlDir() { + static QString dir; + if (dir.isEmpty()) { + dir = getResourcesDir() + "qml/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} +const QString& getTestQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Qml Test Path: " << dir; + } + return dir; +} // Create a simple OpenGL window that renders text in various ways -class QTestWindow : public QWindow { +class QTestWindow : public QWindow, private QOpenGLFunctions { Q_OBJECT - QOpenGLContextWrapper* _context{ nullptr }; + QOpenGLContext* _context{ nullptr }; QSize _size; bool _altPressed{ false }; RateCounter fps; QTimer _timer; int testQmlTexture{ 0 }; - ProgramPtr _program; - ShapeWrapperPtr _plane; - QScriptEngine* _scriptEngine { nullptr }; public: QObject* rootMenu; QTestWindow() { - _scriptEngine = new ScriptEngine(); _timer.setInterval(1); - QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw); + connect(&_timer, &QTimer::timeout, [=] { + draw(); + }); - _chromiumShareContext = new OffscreenGLCanvas(); - _chromiumShareContext->create(); - _chromiumShareContext->makeCurrent(); - qt_gl_set_global_share_context(_chromiumShareContext->getContext()); + DependencyManager::set(); + setSurfaceType(QSurface::OpenGLSurface); - { - setSurfaceType(QSurface::OpenGLSurface); - QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); - setFormat(format); - _context = new QOpenGLContextWrapper(); - _context->setFormat(format); - _context->setShareContext(_chromiumShareContext->getContext()); - } + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + format.setVersion(4, 1); + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); + format.setOption(QSurfaceFormat::DebugContext); + setFormat(format); + _context = new QOpenGLContext; + _context->setFormat(format); if (!_context->create()) { qFatal("Could not create OpenGL context"); } show(); + makeCurrent(); + initializeOpenGLFunctions(); + + { + QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); + // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); + } + + qDebug() << (const char*)this->glGetString(GL_VERSION); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0.2f, 0.2f, 0.2f, 1); + glDisable(GL_DEPTH_TEST); + + MessageDialog::registerType(); + VrMenu::registerType(); + InfoView::registerType(); + + + auto offscreenUi = DependencyManager::get(); + offscreenUi->create(_context); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + testQmlTexture = textureId; + }); makeCurrent(); - glewExperimental = true; - glewInit(); - glGetError(); - - using namespace oglplus; - Context::Enable(Capability::Blend); - Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); - Context::Disable(Capability::DepthTest); - Context::Disable(Capability::CullFace); - Context::ClearColor(0.2f, 0.2f, 0.2f, 1); - - MessageDialog::registerType(); - InfoView::registerType(); - - auto offscreenUi = DependencyManager::set(); - { - offscreenUi->create(_context->getContext()); - offscreenUi->setProxyWindow(this); - - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { - testQmlTexture = textureId; - }); - - makeCurrent(); - } - - - auto primaryScreen = QGuiApplication::primaryScreen(); - auto targetScreen = primaryScreen; - auto screens = QGuiApplication::screens(); - if (screens.size() > 1) { - for (auto screen : screens) { - if (screen != targetScreen) { - targetScreen = screen; - break; - } - } - } - auto rect = targetScreen->availableGeometry(); - rect.setWidth(rect.width() * 0.8f); - rect.setHeight(rect.height() * 0.8f); - rect.moveTo(QPoint(20, 20)); + offscreenUi->setProxyWindow(this); + QDesktopWidget* desktop = QApplication::desktop(); + QRect rect = desktop->availableGeometry(desktop->screenCount() - 1); + int height = rect.height(); + //rect.setHeight(height / 2); + rect.setY(rect.y() + height / 2); setGeometry(rect); +// setFramePosition(QPoint(-1000, 0)); +// resize(QSize(800, 600)); #ifdef QML_CONTROL_GALLERY offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); offscreenUi->load(QUrl("main.qml")); #else - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir())); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); + offscreenUi->load(QUrl("TestMenu.qml")); + // Requires a root menu to have been loaded before it can load + VrMenu::load(); #endif installEventFilter(offscreenUi.data()); offscreenUi->resume(); @@ -529,35 +227,16 @@ private: } makeCurrent(); - auto error = glGetError(); - if (error != GL_NO_ERROR) { - qDebug() << "GL error in entering draw " << error; - } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); - using namespace oglplus; - Context::Clear().ColorBuffer().DepthBuffer(); - ivec2 size(_size.width(), _size.height()); - size *= devicePixelRatio(); - size = glm::max(size, ivec2(100, 100)); - Context::Viewport(size.x, size.y); - if (!_program) { - _program = loadDefaultShader(); - _plane = loadPlane(_program); - } + renderQml(); - if (testQmlTexture > 0) { - glBindTexture(GL_TEXTURE_2D, testQmlTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - _program->Bind(); - _plane->Use(); - _plane->Draw(); _context->swapBuffers(this); + glFinish(); fps.increment(); - if (fps.elapsed() >= 10.0f) { + if (fps.elapsed() >= 2.0f) { qDebug() << "FPS: " << fps.rate(); fps.reset(); } @@ -567,6 +246,8 @@ private: _context->makeCurrent(this); } + void renderQml(); + void resizeWindow(const QSize & size) { _size = size; DependencyManager::get()->resize(_size); @@ -588,13 +269,11 @@ protected: offscreenUi->load("Browser.qml"); } break; - - case Qt::Key_J: + case Qt::Key_L: if (event->modifiers() & Qt::CTRL) { - loadScript(getExamplesDir() + "tests/qmlWebTest.js"); + InfoView::show(getResourcesDir() + "html/interface-welcome.html", true); } break; - case Qt::Key_K: if (event->modifiers() & Qt::CTRL) { OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ @@ -602,9 +281,22 @@ protected: }); } break; + case Qt::Key_J: + if (event->modifiers() & Qt::CTRL) { + auto offscreenUi = DependencyManager::get(); + rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); + QMetaObject::invokeMethod(rootMenu, "popup"); + } + break; } QWindow::keyPressEvent(event); } + QQmlContext* menuContext{ nullptr }; + void keyReleaseEvent(QKeyEvent *event) override { + if (_altPressed && Qt::Key_Alt == event->key()) { + VrMenu::toggle(); + } + } void moveEvent(QMoveEvent* event) override { static qreal oldPixelRatio = 0.0; @@ -616,26 +308,40 @@ protected: } }; +void QTestWindow::renderQml() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (testQmlTexture > 0) { + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + glBegin(GL_QUADS); + { + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + } + glEnd(); +} + + const char * LOG_FILTER_RULES = R"V0G0N( hifi.offscreen.focus.debug=false qt.quick.mouse.debug=false )V0G0N"; -void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = message; - -#ifdef Q_OS_WIN - if (!logMessage.isEmpty()) { - OutputDebugStringA(logMessage.toLocal8Bit().constData()); - OutputDebugStringA("\n"); - } -#endif -} - - int main(int argc, char** argv) { - QGuiApplication app(argc, argv); - qInstallMessageHandler(messageHandler); + QApplication app(argc, argv); QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow window; app.exec(); From 6098c4a1d67ebb5725c7c5ebec3280df5e3baad9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Dec 2015 17:18:46 -0800 Subject: [PATCH 222/318] Revert "Revert "Migrate QML based web views to Qt WebEngine"" This reverts commit 1f3adeb66622a0d527e4f4b2307330e60593728d. --- .../PackageLibrariesForDeployment.cmake | 2 +- examples/directory.js | 2 +- examples/html/eventBridgeLoader.js | 59 ++ examples/html/qmlWebTest.html | 31 + examples/tests/qmlWebTest.js | 32 + interface/CMakeLists.txt | 18 +- interface/resources/qml/Browser.qml | 28 +- interface/resources/qml/InfoView.qml | 16 +- interface/resources/qml/MarketplaceDialog.qml | 37 +- interface/resources/qml/QmlWebWindow.qml | 63 ++ interface/resources/qml/TestMenu.qml | 109 --- interface/resources/qml/WebEntity.qml | 6 +- interface/src/Application.cpp | 17 + libraries/gl/src/gl/OffscreenQmlSurface.cpp | 13 +- libraries/gl/src/gl/OffscreenQmlSurface.h | 4 +- libraries/gl/src/gl/QOpenGLContextWrapper.cpp | 7 +- libraries/gl/src/gl/QOpenGLContextWrapper.h | 6 + libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 3 + libraries/ui/CMakeLists.txt | 2 +- libraries/ui/src/QmlWebWindowClass.cpp | 240 +++++++ libraries/ui/src/QmlWebWindowClass.h | 104 +++ tests/ui/CMakeLists.txt | 19 +- tests/ui/src/main.cpp | 626 +++++++++++++----- 24 files changed, 1107 insertions(+), 339 deletions(-) create mode 100644 examples/html/eventBridgeLoader.js create mode 100644 examples/html/qmlWebTest.html create mode 100644 examples/tests/qmlWebTest.js create mode 100644 interface/resources/qml/QmlWebWindow.qml create mode 100644 libraries/ui/src/QmlWebWindowClass.cpp create mode 100644 libraries/ui/src/QmlWebWindowClass.h diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index bb0b268dd4..17b5d5f49d 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -40,7 +40,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} $<$,$,$>:--release> $" + COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release> $" ) elseif (DEFINED BUILD_BUNDLE AND BUILD_BUNDLE AND APPLE) find_program(MACDEPLOYQT_COMMAND macdeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH) diff --git a/examples/directory.js b/examples/directory.js index b1fac19e8b..d2a3768051 100644 --- a/examples/directory.js +++ b/examples/directory.js @@ -62,7 +62,7 @@ var directory = (function () { function setUp() { viewport = Controller.getViewportDimensions(); - directoryWindow = new WebWindow('Directory', DIRECTORY_URL, 900, 700, false); + directoryWindow = new OverlayWebWindow('Directory', DIRECTORY_URL, 900, 700, false); directoryWindow.setVisible(false); directoryButton = Overlays.addOverlay("image", { diff --git a/examples/html/eventBridgeLoader.js b/examples/html/eventBridgeLoader.js new file mode 100644 index 0000000000..b62e7d9384 --- /dev/null +++ b/examples/html/eventBridgeLoader.js @@ -0,0 +1,59 @@ + +//public slots: +// void emitWebEvent(const QString& data); +// void emitScriptEvent(const QString& data); +// +//signals: +// void webEventReceived(const QString& data); +// void scriptEventReceived(const QString& data); +// + +EventBridgeConnectionProxy = function(parent) { + this.parent = parent; + this.realSignal = this.parent.realBridge.scriptEventReceived + this.webWindowId = this.parent.webWindow.windowId; +} + +EventBridgeConnectionProxy.prototype.connect = function(callback) { + var that = this; + this.realSignal.connect(function(id, message) { + if (id === that.webWindowId) { callback(message); } + }); +} + +EventBridgeProxy = function(webWindow) { + this.webWindow = webWindow; + this.realBridge = this.webWindow.eventBridge; + this.scriptEventReceived = new EventBridgeConnectionProxy(this); +} + +EventBridgeProxy.prototype.emitWebEvent = function(data) { + this.realBridge.emitWebEvent(data); +} + +openEventBridge = function(callback) { + EVENT_BRIDGE_URI = "ws://localhost:51016"; + socket = new WebSocket(this.EVENT_BRIDGE_URI); + + socket.onclose = function() { + console.error("web channel closed"); + }; + + socket.onerror = function(error) { + console.error("web channel error: " + error); + }; + + socket.onopen = function() { + channel = new QWebChannel(socket, function(channel) { + console.log("Document url is " + document.URL); + for(var key in channel.objects){ + console.log("registered object: " + key); + } + var webWindow = channel.objects[document.URL.toLowerCase()]; + console.log("WebWindow is " + webWindow) + eventBridgeProxy = new EventBridgeProxy(webWindow); + if (callback) { callback(eventBridgeProxy); } + }); + } +} + diff --git a/examples/html/qmlWebTest.html b/examples/html/qmlWebTest.html new file mode 100644 index 0000000000..e59535701d --- /dev/null +++ b/examples/html/qmlWebTest.html @@ -0,0 +1,31 @@ + + +Properties + + + + + + + + + + + + + diff --git a/examples/tests/qmlWebTest.js b/examples/tests/qmlWebTest.js new file mode 100644 index 0000000000..f905e494dc --- /dev/null +++ b/examples/tests/qmlWebTest.js @@ -0,0 +1,32 @@ +print("Launching web window"); + +webWindow = new OverlayWebWindow('Test Event Bridge', "file:///C:/Users/bdavis/Git/hifi/examples/html/qmlWebTest.html", 320, 240, false); +print("JS Side window: " + webWindow); +print("JS Side bridge: " + webWindow.eventBridge); +webWindow.eventBridge.webEventReceived.connect(function(data) { + print("JS Side event received: " + data); +}); + +var titles = ["A", "B", "C"]; +var titleIndex = 0; + +Script.setInterval(function() { + webWindow.eventBridge.emitScriptEvent("JS Event sent"); + var size = webWindow.size; + var position = webWindow.position; + print("Window url: " + webWindow.url) + print("Window visible: " + webWindow.visible) + print("Window size: " + size.x + "x" + size.y) + print("Window pos: " + position.x + "x" + position.y) + webWindow.setVisible(!webWindow.visible); + webWindow.setTitle(titles[titleIndex]); + webWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100); + titleIndex += 1; + titleIndex %= titles.length; +}, 2 * 1000); + +Script.setTimeout(function() { + print("Closing script"); + webWindow.close(); + Script.stop(); +}, 15 * 1000) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 87cf1a384c..1d9557a835 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -45,7 +45,9 @@ else () list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP}) endif () -find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets WebSockets) +find_package(Qt5 COMPONENTS + Gui Multimedia Network OpenGL Qml Quick Script Svg + WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets) # grab the ui files in resources/ui file (GLOB_RECURSE QT_UI_FILES ui/*.ui) @@ -175,9 +177,17 @@ include_directories("${PROJECT_SOURCE_DIR}/src") target_link_libraries( ${TARGET_NAME} - Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets + Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL + Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg + Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets ) +# Issue causes build failure unless we add this directory. +# See https://bugreports.qt.io/browse/QTBUG-43351 +if (WIN32) + add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) +endif() + # assume we are using a Qt build without bearer management add_definitions(-DQT_NO_BEARERMANAGEMENT) @@ -209,5 +219,9 @@ else (APPLE) endif() endif (APPLE) +if (WIN32) + set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/resources/qml") +endif() + package_libraries_for_deployment() consolidate_stack_components() diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 947bf739fc..8f3cd0e1e7 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,6 +1,6 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtWebKit 3.0 +import QtWebEngine 1.1 import "controls" import "styles" @@ -39,9 +39,10 @@ VrDialog { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.bottom: scrollView.top + anchors.bottom: webview.top color: "white" } + Row { id: buttons spacing: 4 @@ -112,26 +113,22 @@ VrDialog { } } - ScrollView { - id: scrollView + WebEngineView { + id: webview + url: "http://highfidelity.com" anchors.top: buttons.bottom anchors.topMargin: 8 anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right - WebView { - id: webview - url: "http://highfidelity.com" - anchors.fill: parent - onLoadingChanged: { - if (loadRequest.status == WebView.LoadSucceededStarted) { - addressBar.text = loadRequest.url - } - } - onIconChanged: { - barIcon.source = icon + onLoadingChanged: { + if (loadRequest.status == WebEngineView.LoadSucceededStatus) { + addressBar.text = loadRequest.url } } + onIconChanged: { + console.log("New icon: " + icon) + } } } // item @@ -146,5 +143,4 @@ VrDialog { break; } } - } // dialog diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 012f04f1fd..75b82342ca 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -2,7 +2,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -import QtWebKit 3.0 +import QtWebEngine 1.1 import "controls" VrDialog { @@ -18,15 +18,11 @@ VrDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - ScrollView { + WebEngineView { + id: webview + objectName: "WebView" anchors.fill: parent - WebView { - objectName: "WebView" - id: webview - url: infoView.url - anchors.fill: parent - } - } - + url: infoView.url + } } } diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml index 946f32e84a..3a66c5340f 100644 --- a/interface/resources/qml/MarketplaceDialog.qml +++ b/interface/resources/qml/MarketplaceDialog.qml @@ -2,7 +2,7 @@ import Hifi 1.0 import QtQuick 2.3 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.3 -import QtWebKit 3.0 +import QtWebEngine 1.1 import "controls" VrDialog { @@ -24,27 +24,22 @@ VrDialog { anchors.margins: parent.margins anchors.topMargin: parent.topMargin - - ScrollView { + WebEngineView { + objectName: "WebView" + id: webview + url: "https://metaverse.highfidelity.com/marketplace" anchors.fill: parent - WebView { - objectName: "WebView" - id: webview - url: "https://metaverse.highfidelity.com/marketplace" - anchors.fill: parent - onNavigationRequested: { - console.log(request.url) - if (!marketplaceDialog.navigationRequested(request.url)) { - console.log("Application absorbed the request") - request.action = WebView.IgnoreRequest; - return; - } - console.log("Application passed on the request") - request.action = WebView.AcceptRequest; + onNavigationRequested: { + console.log(request.url) + if (!marketplaceDialog.navigationRequested(request.url)) { + console.log("Application absorbed the request") + request.action = WebView.IgnoreRequest; return; - } + } + console.log("Application passed on the request") + request.action = WebView.AcceptRequest; + return; } - } - - } + } + } } diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml new file mode 100644 index 0000000000..9664c0edb8 --- /dev/null +++ b/interface/resources/qml/QmlWebWindow.qml @@ -0,0 +1,63 @@ + +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtWebEngine 1.1 +import QtWebChannel 1.0 +import QtWebSockets 1.0 + +import "qwebchannel.js" as WebChannel +import "controls" +import "styles" + +VrDialog { + id: root + HifiConstants { id: hifi } + title: "WebWindow" + resizable: true + contentImplicitWidth: clientArea.implicitWidth + contentImplicitHeight: clientArea.implicitHeight + backgroundColor: "#7f000000" + property url source: "about:blank" + + signal navigating(string url) + + Component.onCompleted: { + enabled = true + console.log("Web Window Created " + root); + webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); + }); + + webview.loadingChanged.connect(handleWebviewLoading) + } + + + function handleWebviewLoading(loadRequest) { + var HIFI_URL_PATTERN = /^hifi:\/\//; + if (WebEngineView.LoadStartedStatus == loadRequest.status) { + var newUrl = loadRequest.url.toString(); + if (newUrl.match(HIFI_URL_PATTERN)) { + root.navigating(newUrl); + } + } + } + + Item { + id: clientArea + implicitHeight: 600 + implicitWidth: 800 + x: root.clientX + y: root.clientY + width: root.clientWidth + height: root.clientHeight + + WebEngineView { + id: webview + url: root.source + anchors.fill: parent + profile: WebEngineProfile { + httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)" + } + } + } // item +} // dialog diff --git a/interface/resources/qml/TestMenu.qml b/interface/resources/qml/TestMenu.qml index 4d109e6298..fe8a26e234 100644 --- a/interface/resources/qml/TestMenu.qml +++ b/interface/resources/qml/TestMenu.qml @@ -4,116 +4,7 @@ import Hifi 1.0 // Currently for testing a pure QML replacement menu Item { - Item { - objectName: "AllActions" - Action { - id: aboutApp - objectName: "HifiAction_" + MenuConstants.AboutApp - text: qsTr("About Interface") - } - - // - // File Menu - // - Action { - id: login - objectName: "HifiAction_" + MenuConstants.Login - text: qsTr("Login") - } - Action { - id: quit - objectName: "HifiAction_" + MenuConstants.Quit - text: qsTr("Quit") - //shortcut: StandardKey.Quit - shortcut: "Ctrl+Q" - } - - - // - // Edit menu - // - Action { - id: undo - text: "Undo" - shortcut: StandardKey.Undo - } - - Action { - id: redo - text: "Redo" - shortcut: StandardKey.Redo - } - - Action { - id: animations - objectName: "HifiAction_" + MenuConstants.Animations - text: qsTr("Animations...") - } - Action { - id: attachments - text: qsTr("Attachments...") - } - Action { - id: explode - text: qsTr("Explode on quit") - checkable: true - checked: true - } - Action { - id: freeze - text: qsTr("Freeze on quit") - checkable: true - checked: false - } - ExclusiveGroup { - Action { - id: visibleToEveryone - objectName: "HifiAction_" + MenuConstants.VisibleToEveryone - text: qsTr("Everyone") - checkable: true - checked: true - } - Action { - id: visibleToFriends - objectName: "HifiAction_" + MenuConstants.VisibleToFriends - text: qsTr("Friends") - checkable: true - } - Action { - id: visibleToNoOne - objectName: "HifiAction_" + MenuConstants.VisibleToNoOne - text: qsTr("No one") - checkable: true - } - } - } - Menu { objectName: "rootMenu"; - Menu { - title: "File" - MenuItem { action: login } - MenuItem { action: explode } - MenuItem { action: freeze } - MenuItem { action: quit } - } - Menu { - title: "Tools" - Menu { - title: "I Am Visible To" - MenuItem { action: visibleToEveryone } - MenuItem { action: visibleToFriends } - MenuItem { action: visibleToNoOne } - } - MenuItem { action: animations } - } - Menu { - title: "Long menu name top menu" - MenuItem { action: aboutApp } - } - Menu { - title: "Help" - MenuItem { action: aboutApp } - } } } diff --git a/interface/resources/qml/WebEntity.qml b/interface/resources/qml/WebEntity.qml index 0eb943cac7..ae94105672 100644 --- a/interface/resources/qml/WebEntity.qml +++ b/interface/resources/qml/WebEntity.qml @@ -1,10 +1,10 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 -import QtWebKit 3.0 +import QtWebEngine 1.1 -WebView { +WebEngineView { id: root - objectName: "webview" anchors.fill: parent + objectName: "webview" url: "about:blank" } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fa5565417d..e437a05aa3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -101,6 +101,7 @@ #include #include #include +#include #include "AnimDebugDraw.h" #include "AudioClient.h" @@ -362,6 +363,17 @@ Cube3DOverlay* _keyboardFocusHighlight{ nullptr }; int _keyboardFocusHighlightID{ -1 }; PluginContainer* _pluginContainer; + +// FIXME hack access to the internal share context for the Chromium helper +// Normally we'd want to use QWebEngine::initialize(), but we can't because +// our primary context is a QGLWidget, which can't easily be initialized to share +// from a QOpenGLContext. +// +// So instead we create a new offscreen context to share with the QGLWidget, +// and manually set THAT to be the shared context for the Chromium helper +OffscreenGLCanvas* _chromiumShareContext { nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); + Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _dependencyManagerIsSetup(setupEssentials(argc, argv)), @@ -623,6 +635,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : _glWidget->makeCurrent(); _glWidget->initializeGL(); + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->create(_glWidget->context()->contextHandle()); + _chromiumShareContext->makeCurrent(); + qt_gl_set_global_share_context(_chromiumShareContext->getContext()); + _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->makeCurrent(); diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index bddc7d19ae..26a564e20b 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -320,10 +320,13 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { void OffscreenQmlSurface::resize(const QSize& newSize) { if (!_renderer || !_renderer->_quickWindow) { - QSize currentSize = _renderer->_quickWindow->geometry().size(); - if (newSize == currentSize) { - return; - } + return; + } + + + QSize currentSize = _renderer->_quickWindow->geometry().size(); + if (newSize == currentSize) { + return; } _qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize); @@ -437,7 +440,9 @@ void OffscreenQmlSurface::updateQuick() { } if (_render) { + QMutexLocker lock(&(_renderer->_mutex)); _renderer->post(RENDER); + _renderer->_cond.wait(&(_renderer->_mutex)); _render = false; } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.h b/libraries/gl/src/gl/OffscreenQmlSurface.h index 67315b0783..d66cbeb285 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.h +++ b/libraries/gl/src/gl/OffscreenQmlSurface.h @@ -40,8 +40,8 @@ public: void create(QOpenGLContext* context); void resize(const QSize& size); QSize size() const; - QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { + Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { return load(QUrl(qmlSourceFile), f); } diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp index 3e879df7af..6397d30e13 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.cpp +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.cpp @@ -39,6 +39,11 @@ void QOpenGLContextWrapper::doneCurrent() { _context->doneCurrent(); } +void QOpenGLContextWrapper::setShareContext(QOpenGLContext* otherContext) { + _context->setShareContext(otherContext); +} + bool isCurrentContext(QOpenGLContext* context) { return QOpenGLContext::currentContext() == context; -} \ No newline at end of file +} + diff --git a/libraries/gl/src/gl/QOpenGLContextWrapper.h b/libraries/gl/src/gl/QOpenGLContextWrapper.h index 832119162c..b736253213 100644 --- a/libraries/gl/src/gl/QOpenGLContextWrapper.h +++ b/libraries/gl/src/gl/QOpenGLContextWrapper.h @@ -25,6 +25,12 @@ public: void swapBuffers(QSurface* surface); bool makeCurrent(QSurface* surface); void doneCurrent(); + void setShareContext(QOpenGLContext* otherContext); + + QOpenGLContext* getContext() { + return _context; + } + private: QOpenGLContext* _context { nullptr }; diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 3796abd92a..c1131765f7 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME script-engine) setup_hifi_library(Gui Network Script WebSockets Widgets) -link_hifi_libraries(shared networking octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) +link_hifi_libraries(shared networking ui octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ded3db11e9..5f39bee9fa 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -350,6 +351,8 @@ void ScriptEngine::init() { qScriptRegisterSequenceMetaType >(this); qScriptRegisterSequenceMetaType >(this); + + registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor); QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 140ca87d0d..cc2382926f 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME ui) -setup_hifi_library(OpenGL Network Qml Quick Script XmlPatterns) +setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebSockets XmlPatterns) link_hifi_libraries(shared networking gl) diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp new file mode 100644 index 0000000000..d5cdc1fde9 --- /dev/null +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -0,0 +1,240 @@ +// +// Created by Bradley Austin Davis on 2015-12-15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QmlWebWindowClass.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "OffscreenUi.h" + +QWebSocketServer* QmlWebWindowClass::_webChannelServer { nullptr }; +static QWebChannel webChannel; +static const uint16_t WEB_CHANNEL_PORT = 51016; +static std::atomic nextWindowId; +static const char* const URL_PROPERTY = "source"; +static const char* const TITLE_PROPERTY = "title"; +static const QRegExp HIFI_URL_PATTERN { "^hifi://" }; + +void QmlScriptEventBridge::emitWebEvent(const QString& data) { + QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); +} + +void QmlScriptEventBridge::emitScriptEvent(const QString& data) { + QMetaObject::invokeMethod(this, "scriptEventReceived", Qt::QueuedConnection, + Q_ARG(int, _webWindow->getWindowId()), Q_ARG(QString, data)); +} + +class QmlWebTransport : public QWebChannelAbstractTransport { + Q_OBJECT +public: + QmlWebTransport(QWebSocket* webSocket) : _webSocket(webSocket) { + // Translate from the websocket layer to the webchannel layer + connect(webSocket, &QWebSocket::textMessageReceived, [this](const QString& message) { + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(message.toUtf8(), &error); + if (error.error || !document.isObject()) { + qWarning() << "Unable to parse incoming JSON message" << message; + return; + } + emit messageReceived(document.object(), this); + }); + } + + virtual void sendMessage(const QJsonObject &message) override { + // Translate from the webchannel layer to the websocket layer + _webSocket->sendTextMessage(QJsonDocument(message).toJson(QJsonDocument::Compact)); + } + +private: + QWebSocket* const _webSocket; +}; + + +void QmlWebWindowClass::setupServer() { + if (!_webChannelServer) { + _webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); + if (!_webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { + qFatal("Failed to open web socket server."); + } + + QObject::connect(_webChannelServer, &QWebSocketServer::newConnection, [] { + webChannel.connectTo(new QmlWebTransport(_webChannelServer->nextPendingConnection())); + }); + } +} + +// Method called by Qt scripts to create a new web window in the overlay +QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { + QmlWebWindowClass* retVal { nullptr }; + const QString title = context->argument(0).toString(); + QString url = context->argument(1).toString(); + if (!url.startsWith("http") && !url.startsWith("file://")) { + url = QUrl::fromLocalFile(url).toString(); + } + const int width = std::max(100, std::min(1280, context->argument(2).toInt32()));; + const int height = std::max(100, std::min(720, context->argument(3).toInt32()));; + + // Build the event bridge and wrapper on the main thread + QMetaObject::invokeMethod(DependencyManager::get().data(), "load", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, "QmlWebWindow.qml"), + Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { + setupServer(); + retVal = new QmlWebWindowClass(object); + webChannel.registerObject(url.toLower(), retVal); + retVal->setTitle(title); + retVal->setURL(url); + retVal->setSize(width, height); + })); + connect(engine, &QScriptEngine::destroyed, retVal, &QmlWebWindowClass::deleteLater); + return engine->newQObject(retVal); +} + +QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) + : _windowId(++nextWindowId), _qmlWindow(qmlWindow) +{ + qDebug() << "Created window with ID " << _windowId; + Q_ASSERT(_qmlWindow); + Q_ASSERT(dynamic_cast(_qmlWindow)); + QObject::connect(_qmlWindow, SIGNAL(navigating(QString)), this, SLOT(handleNavigation(QString))); +} + +void QmlWebWindowClass::handleNavigation(const QString& url) { + DependencyManager::get()->handleLookupString(url); +} + +void QmlWebWindowClass::setVisible(bool visible) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible)); + return; + } + + auto qmlWindow = asQuickItem(); + if (qmlWindow->isEnabled() != visible) { + qmlWindow->setEnabled(visible); + emit visibilityChanged(visible); + } +} + +QQuickItem* QmlWebWindowClass::asQuickItem() const { + return dynamic_cast(_qmlWindow); +} + +bool QmlWebWindowClass::isVisible() const { + if (QThread::currentThread() != thread()) { + bool result; + QMetaObject::invokeMethod(const_cast(this), "isVisible", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, result)); + return result; + } + + return asQuickItem()->isEnabled(); +} + + +glm::vec2 QmlWebWindowClass::getPosition() const { + if (QThread::currentThread() != thread()) { + glm::vec2 result; + QMetaObject::invokeMethod(const_cast(this), "getPosition", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); + return result; + } + + return glm::vec2(asQuickItem()->x(), asQuickItem()->y()); +} + + +void QmlWebWindowClass::setPosition(const glm::vec2& position) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setPosition", Qt::QueuedConnection, Q_ARG(glm::vec2, position)); + return; + } + + asQuickItem()->setPosition(QPointF(position.x, position.y)); +} + +void QmlWebWindowClass::setPosition(int x, int y) { + setPosition(glm::vec2(x, y)); +} + +glm::vec2 QmlWebWindowClass::getSize() const { + if (QThread::currentThread() != thread()) { + glm::vec2 result; + QMetaObject::invokeMethod(const_cast(this), "getSize", Qt::BlockingQueuedConnection, Q_RETURN_ARG(glm::vec2, result)); + return result; + } + + return glm::vec2(asQuickItem()->width(), asQuickItem()->height()); +} + +void QmlWebWindowClass::setSize(const glm::vec2& size) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setSize", Qt::QueuedConnection, Q_ARG(glm::vec2, size)); + } + + asQuickItem()->setSize(QSizeF(size.x, size.y)); +} + +void QmlWebWindowClass::setSize(int width, int height) { + setSize(glm::vec2(width, height)); +} + +QString QmlWebWindowClass::getURL() const { + if (QThread::currentThread() != thread()) { + QString result; + QMetaObject::invokeMethod(const_cast(this), "getURL", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, result)); + return result; + } + return _qmlWindow->property(URL_PROPERTY).toString(); +} + +void QmlWebWindowClass::setURL(const QString& urlString) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setURL", Qt::QueuedConnection, Q_ARG(QString, urlString)); + } + _qmlWindow->setProperty(URL_PROPERTY, urlString); +} + + +void QmlWebWindowClass::setTitle(const QString& title) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setTitle", Qt::QueuedConnection, Q_ARG(QString, title)); + } + + _qmlWindow->setProperty(TITLE_PROPERTY, title); +} + +void QmlWebWindowClass::close() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); + } + _qmlWindow->setProperty("destroyOnInvisible", true); + _qmlWindow->setProperty("visible", false); + _qmlWindow->deleteLater(); +} + +void QmlWebWindowClass::hasClosed() { +} + +void QmlWebWindowClass::raise() { + // FIXME +} + +#include "QmlWebWindowClass.moc" diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h new file mode 100644 index 0000000000..2b563e68ba --- /dev/null +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -0,0 +1,104 @@ +// +// Created by Bradley Austin Davis on 2015-12-15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ui_QmlWebWindowClass_h +#define hifi_ui_QmlWebWindowClass_h + +#include +#include +#include +#include +#include + +class QScriptEngine; +class QScriptContext; +class QmlWebWindowClass; +class QWebSocketServer; +class QWebSocket; + +class QmlScriptEventBridge : public QObject { + Q_OBJECT +public: + QmlScriptEventBridge(const QmlWebWindowClass* webWindow) : _webWindow(webWindow) {} + +public slots : + void emitWebEvent(const QString& data); + void emitScriptEvent(const QString& data); + +signals: + void webEventReceived(const QString& data); + void scriptEventReceived(int windowId, const QString& data); + +private: + const QmlWebWindowClass* _webWindow { nullptr }; + QWebSocket *_socket { nullptr }; +}; + +// FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping +class QmlWebWindowClass : public QObject { + Q_OBJECT + Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) + Q_PROPERTY(int windowId READ getWindowId CONSTANT) + Q_PROPERTY(QString url READ getURL CONSTANT) + Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) + +public: + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + QmlWebWindowClass(QObject* qmlWindow); + +public slots: + bool isVisible() const; + void setVisible(bool visible); + + glm::vec2 getPosition() const; + void setPosition(const glm::vec2& position); + void setPosition(int x, int y); + + glm::vec2 getSize() const; + void setSize(const glm::vec2& size); + void setSize(int width, int height); + + QString getURL() const; + void setURL(const QString& url); + + void setTitle(const QString& title); + + // Ugh.... do not want to do + Q_INVOKABLE void raise(); + Q_INVOKABLE void close(); + Q_INVOKABLE int getWindowId() const { return _windowId; }; + Q_INVOKABLE QmlScriptEventBridge* getEventBridge() const { return _eventBridge; }; + +signals: + void visibilityChanged(bool visible); // Tool window + void urlChanged(); + void moved(glm::vec2 position); + void resized(QSizeF size); + void closed(); + +private slots: + void hasClosed(); + void handleNavigation(const QString& url); + +private: + static void setupServer(); + static QWebSocketServer* _webChannelServer; + + QQuickItem* asQuickItem() const; + QmlScriptEventBridge* const _eventBridge { new QmlScriptEventBridge(this) }; + + // FIXME needs to be initialized in the ctor once we have support + // for tool window panes in QML + const bool _isToolWindow { false }; + const int _windowId; + QObject* const _qmlWindow; +}; + +#endif diff --git a/tests/ui/CMakeLists.txt b/tests/ui/CMakeLists.txt index 8fda001e14..f94a0b85c0 100644 --- a/tests/ui/CMakeLists.txt +++ b/tests/ui/CMakeLists.txt @@ -2,15 +2,32 @@ set(TARGET_NAME "ui-test") # This is not a testcase -- just set it up as a regular hifi project -setup_hifi_project(Widgets OpenGL Network Qml Quick Script) +setup_hifi_project(Network OpenGL Qml Quick Script WebChannel WebEngine WebSockets) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") if (WIN32) target_link_libraries(${TARGET_NAME} wsock32.lib opengl32.lib Winmm.lib) + # Issue causes build failure unless we add this directory. + # See https://bugreports.qt.io/browse/QTBUG-43351 + add_paths_to_fixup_libs(${Qt5_DIR}/../../../plugins/qtwebengine) endif() # link in the shared libraries link_hifi_libraries(shared networking gl gpu ui) +# copy the resources files beside the executable +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory + "${PROJECT_SOURCE_DIR}/qml" + $/qml +) + + +target_glew() + +if (WIN32) + set(EXTRA_DEPLOY_OPTIONS "--qmldir ${PROJECT_SOURCE_DIR}/../../interface/resources/qml") +endif() + package_libraries_for_deployment() diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index 18f62dc016..59e7376f1b 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -1,41 +1,91 @@ // -// main.cpp -// tests/render-utils/src -// -// Copyright 2014 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015-04-22 +// Copyright 2013-2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "OffscreenUi.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include -#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include #include -#include -#include "MessageDialog.h" -#include "VrMenu.h" -#include "InfoView.h" -#include +#include +#include +#include +#include +#include +#include + +const QString& getResourcesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; +} + +const QString& getExamplesDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/"; + qDebug() << "Resources Path: " << dir; + } + return dir; +} + +const QString& getInterfaceQmlDir() { + static QString dir; + if (dir.isEmpty()) { + dir = getResourcesDir() + "qml/"; + qDebug() << "Qml Path: " << dir; + } + return dir; +} + +const QString& getTestQmlDir() { + static QString dir; + if (dir.isEmpty()) { + QDir path(__FILE__); + path.cdUp(); + dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; + qDebug() << "Qml Test Path: " << dir; + } + return dir; +} + class RateCounter { std::vector times; @@ -74,142 +124,394 @@ public: }; -class MenuConstants : public QObject{ - Q_OBJECT - Q_ENUMS(Item) -public: - enum Item { - RenderLookAtTargets, - }; -public: - MenuConstants(QObject* parent = nullptr) : QObject(parent) { +extern QOpenGLContext* qt_gl_global_share_context(); + +static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) { + if (engine.hasUncaughtException()) { + const auto backtrace = engine.uncaughtExceptionBacktrace(); + const auto exception = engine.uncaughtException().toString(); + const auto line = QString::number(engine.uncaughtExceptionLineNumber()); + engine.clearExceptions(); + + auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); + if (!backtrace.empty()) { + static const auto lineSeparator = "\n "; + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); + } + qWarning() << qPrintable(message); + return true; } + return false; +} + +const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f); + +static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) { + QString message = ""; + for (int i = 0; i < context->argumentCount(); i++) { + if (i > 0) { + message += " "; + } + message += context->argument(i).toString(); + } + qDebug().noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline + + message = message.replace("\\", "\\\\") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("'", "\\'"); + engine->evaluate("Script.print('" + message + "')"); + + return QScriptValue(); +} + +class ScriptEngine : public QScriptEngine { + Q_OBJECT + +public: + void loadFile(const QString& scriptPath) { + if (_isRunning) { + return; + } + qDebug() << "Loading script from " << scriptPath; + _fileNameString = scriptPath; + + QFile file(scriptPath); + if (file.exists()) { + file.open(QIODevice::ReadOnly); + _scriptContents = file.readAll(); + } else { + qFatal("Missing file "); + } + runInThread(); + } + + Q_INVOKABLE void stop() { + if (!_isFinished) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "stop"); + return; + } + _isFinished = true; + if (_wantSignals) { + emit runningStateChanged(); + } + } + } + + Q_INVOKABLE void print(const QString& message) { + if (_wantSignals) { + emit printedMessage(message); + } + } + + Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { + // create the timer, add it to the map, and start it + QTimer* newTimer = new QTimer(this); + newTimer->setSingleShot(isSingleShot); + + connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); + + // make sure the timer stops when the script does + connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); + + _timerFunctionMap.insert(newTimer, function); + + newTimer->start(intervalMS); + return newTimer; + } + + Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) { + return setupTimerWithInterval(function, intervalMS, false); + } + + Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) { + return setupTimerWithInterval(function, timeoutMS, true); + } +private: + + void runInThread() { + QThread* workerThread = new QThread(); + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + connect(workerThread, &QThread::started, this, &ScriptEngine::run); + connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater); + connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); + moveToThread(workerThread); + workerThread->start(); + } + + void init() { + _isInitialized = true; + registerMetaTypes(this); + registerGlobalObject("Script", this); + qScriptRegisterSequenceMetaType>(this); + qScriptRegisterSequenceMetaType>(this); + globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor)); + QScriptValue printConstructorValue = newFunction(debugPrint); + globalObject().setProperty("print", printConstructorValue); + } + + void timerFired() { + QTimer* callingTimer = reinterpret_cast(sender()); + QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); + + if (!callingTimer->isActive()) { + // this timer is done, we can kill it + _timerFunctionMap.remove(callingTimer); + delete callingTimer; + } + + // call the associated JS function, if it exists + if (timerFunction.isValid()) { + timerFunction.call(); + } + } + + + void run() { + if (!_isInitialized) { + init(); + } + + _isRunning = true; + if (_wantSignals) { + emit runningStateChanged(); + } + + QScriptValue result = evaluate(_scriptContents, _fileNameString); + QElapsedTimer startTime; + startTime.start(); + + int thisFrame = 0; + + qint64 lastUpdate = usecTimestampNow(); + + while (!_isFinished) { + int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec + if (usecToSleep > 0) { + usleep(usecToSleep); + } + + if (_isFinished) { + break; + } + + QCoreApplication::processEvents(); + if (_isFinished) { + break; + } + + qint64 now = usecTimestampNow(); + float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND; + if (!_isFinished) { + if (_wantSignals) { + emit update(deltaTime); + } + } + lastUpdate = now; + + // Debug and clear exceptions + hadUncaughtExceptions(*this, _fileNameString); + } + + if (_wantSignals) { + emit scriptEnding(); + } + + if (_wantSignals) { + emit finished(_fileNameString, this); + } + + _isRunning = false; + + if (_wantSignals) { + emit runningStateChanged(); + emit doneRunning(); + } + } + + void registerGlobalObject(const QString& name, QObject* object) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerGlobalObject", + Q_ARG(const QString&, name), + Q_ARG(QObject*, object)); + return; + } + if (!globalObject().property(name).isValid()) { + if (object) { + QScriptValue value = newQObject(object); + globalObject().setProperty(name, value); + } else { + globalObject().setProperty(name, QScriptValue()); + } + } + } + + void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } + QScriptValue scriptFun = newFunction(functionSignature, numArguments); + globalObject().setProperty(name, scriptFun); + } + + void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "registerFunction", + Q_ARG(const QString&, name), + Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(int, numArguments)); + return; + } + + QScriptValue object = globalObject().property(parent); + if (object.isValid()) { + QScriptValue scriptFun = newFunction(functionSignature, numArguments); + object.setProperty(name, scriptFun); + } + } + +signals: + void scriptLoaded(const QString& scriptFilename); + void errorLoadingScript(const QString& scriptFilename); + void update(float deltaTime); + void scriptEnding(); + void finished(const QString& fileNameString, ScriptEngine* engine); + void cleanupMenuItem(const QString& menuItemString); + void printedMessage(const QString& message); + void errorMessage(const QString& message); + void runningStateChanged(); + void evaluationFinished(QScriptValue result, bool isException); + void loadScript(const QString& scriptName, bool isUserLoaded); + void reloadScript(const QString& scriptName, bool isUserLoaded); + void doneRunning(); + + +private: + QString _scriptContents; + QString _fileNameString; + QString _parentURL; + bool _isInitialized { false }; + std::atomic _isFinished { false }; + std::atomic _isRunning { false }; + bool _wantSignals { true }; + QHash _timerFunctionMap; }; -const QString& getResourcesDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/"; - qDebug() << "Resources Path: " << dir; - } - return dir; + + +ScriptEngine* loadScript(const QString& scriptFilename) { + ScriptEngine* scriptEngine = new ScriptEngine(); + scriptEngine->loadFile(scriptFilename); + return scriptEngine; } -const QString& getQmlDir() { - static QString dir; - if (dir.isEmpty()) { - dir = getResourcesDir() + "qml/"; - qDebug() << "Qml Path: " << dir; - } - return dir; -} +OffscreenGLCanvas* _chromiumShareContext { nullptr }; +Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); -const QString& getTestQmlDir() { - static QString dir; - if (dir.isEmpty()) { - QDir path(__FILE__); - path.cdUp(); - dir = path.cleanPath(path.absoluteFilePath("../")) + "/"; - qDebug() << "Qml Test Path: " << dir; - } - return dir; -} // Create a simple OpenGL window that renders text in various ways -class QTestWindow : public QWindow, private QOpenGLFunctions { +class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; + QOpenGLContextWrapper* _context{ nullptr }; QSize _size; bool _altPressed{ false }; RateCounter fps; QTimer _timer; int testQmlTexture{ 0 }; + ProgramPtr _program; + ShapeWrapperPtr _plane; + QScriptEngine* _scriptEngine { nullptr }; public: QObject* rootMenu; QTestWindow() { + _scriptEngine = new ScriptEngine(); _timer.setInterval(1); - connect(&_timer, &QTimer::timeout, [=] { - draw(); - }); + QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw); - DependencyManager::set(); - setSurfaceType(QSurface::OpenGLSurface); + _chromiumShareContext = new OffscreenGLCanvas(); + _chromiumShareContext->create(); + _chromiumShareContext->makeCurrent(); + qt_gl_set_global_share_context(_chromiumShareContext->getContext()); - QSurfaceFormat format; - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - format.setVersion(4, 1); - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); - format.setOption(QSurfaceFormat::DebugContext); + { + setSurfaceType(QSurface::OpenGLSurface); + QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); + setFormat(format); + _context = new QOpenGLContextWrapper(); + _context->setFormat(format); + _context->setShareContext(_chromiumShareContext->getContext()); + } - setFormat(format); - _context = new QOpenGLContext; - _context->setFormat(format); if (!_context->create()) { qFatal("Could not create OpenGL context"); } show(); + makeCurrent(); - initializeOpenGLFunctions(); - { - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - logger->enableMessages(); - connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { - qDebug() << debugMessage; - }); - // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); - } + glewExperimental = true; + glewInit(); + glGetError(); - qDebug() << (const char*)this->glGetString(GL_VERSION); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glClearColor(0.2f, 0.2f, 0.2f, 1); - glDisable(GL_DEPTH_TEST); + using namespace oglplus; + Context::Enable(Capability::Blend); + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); + Context::Disable(Capability::DepthTest); + Context::Disable(Capability::CullFace); + Context::ClearColor(0.2f, 0.2f, 0.2f, 1); MessageDialog::registerType(); - VrMenu::registerType(); InfoView::registerType(); + auto offscreenUi = DependencyManager::set(); + { + offscreenUi->create(_context->getContext()); + offscreenUi->setProxyWindow(this); - auto offscreenUi = DependencyManager::get(); - offscreenUi->create(_context); - connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { - testQmlTexture = textureId; - }); + connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) { + testQmlTexture = textureId; + }); - makeCurrent(); + makeCurrent(); + } - offscreenUi->setProxyWindow(this); - QDesktopWidget* desktop = QApplication::desktop(); - QRect rect = desktop->availableGeometry(desktop->screenCount() - 1); - int height = rect.height(); - //rect.setHeight(height / 2); - rect.setY(rect.y() + height / 2); + + auto primaryScreen = QGuiApplication::primaryScreen(); + auto targetScreen = primaryScreen; + auto screens = QGuiApplication::screens(); + if (screens.size() > 1) { + for (auto screen : screens) { + if (screen != targetScreen) { + targetScreen = screen; + break; + } + } + } + auto rect = targetScreen->availableGeometry(); + rect.setWidth(rect.width() * 0.8f); + rect.setHeight(rect.height() * 0.8f); + rect.moveTo(QPoint(20, 20)); setGeometry(rect); -// setFramePosition(QPoint(-1000, 0)); -// resize(QSize(800, 600)); #ifdef QML_CONTROL_GALLERY offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir())); offscreenUi->load(QUrl("main.qml")); #else - offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir())); + offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir())); offscreenUi->load(QUrl("TestRoot.qml")); - offscreenUi->load(QUrl("TestMenu.qml")); - // Requires a root menu to have been loaded before it can load - VrMenu::load(); #endif installEventFilter(offscreenUi.data()); offscreenUi->resume(); @@ -227,16 +529,35 @@ private: } makeCurrent(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); + auto error = glGetError(); + if (error != GL_NO_ERROR) { + qDebug() << "GL error in entering draw " << error; + } - renderQml(); + using namespace oglplus; + Context::Clear().ColorBuffer().DepthBuffer(); + ivec2 size(_size.width(), _size.height()); + size *= devicePixelRatio(); + size = glm::max(size, ivec2(100, 100)); + Context::Viewport(size.x, size.y); + if (!_program) { + _program = loadDefaultShader(); + _plane = loadPlane(_program); + } + if (testQmlTexture > 0) { + glBindTexture(GL_TEXTURE_2D, testQmlTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + _program->Bind(); + _plane->Use(); + _plane->Draw(); _context->swapBuffers(this); - glFinish(); fps.increment(); - if (fps.elapsed() >= 2.0f) { + if (fps.elapsed() >= 10.0f) { qDebug() << "FPS: " << fps.rate(); fps.reset(); } @@ -246,8 +567,6 @@ private: _context->makeCurrent(this); } - void renderQml(); - void resizeWindow(const QSize & size) { _size = size; DependencyManager::get()->resize(_size); @@ -269,11 +588,13 @@ protected: offscreenUi->load("Browser.qml"); } break; - case Qt::Key_L: + + case Qt::Key_J: if (event->modifiers() & Qt::CTRL) { - InfoView::show(getResourcesDir() + "html/interface-welcome.html", true); + loadScript(getExamplesDir() + "tests/qmlWebTest.js"); } break; + case Qt::Key_K: if (event->modifiers() & Qt::CTRL) { OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){ @@ -281,22 +602,9 @@ protected: }); } break; - case Qt::Key_J: - if (event->modifiers() & Qt::CTRL) { - auto offscreenUi = DependencyManager::get(); - rootMenu = offscreenUi->getRootItem()->findChild("rootMenu"); - QMetaObject::invokeMethod(rootMenu, "popup"); - } - break; } QWindow::keyPressEvent(event); } - QQmlContext* menuContext{ nullptr }; - void keyReleaseEvent(QKeyEvent *event) override { - if (_altPressed && Qt::Key_Alt == event->key()) { - VrMenu::toggle(); - } - } void moveEvent(QMoveEvent* event) override { static qreal oldPixelRatio = 0.0; @@ -308,40 +616,26 @@ protected: } }; -void QTestWindow::renderQml() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (testQmlTexture > 0) { - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, testQmlTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - glBegin(GL_QUADS); - { - glTexCoord2f(0, 0); - glVertex2f(-1, -1); - glTexCoord2f(0, 1); - glVertex2f(-1, 1); - glTexCoord2f(1, 1); - glVertex2f(1, 1); - glTexCoord2f(1, 0); - glVertex2f(1, -1); - } - glEnd(); -} - - const char * LOG_FILTER_RULES = R"V0G0N( hifi.offscreen.focus.debug=false qt.quick.mouse.debug=false )V0G0N"; +void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + QString logMessage = message; + +#ifdef Q_OS_WIN + if (!logMessage.isEmpty()) { + OutputDebugStringA(logMessage.toLocal8Bit().constData()); + OutputDebugStringA("\n"); + } +#endif +} + + int main(int argc, char** argv) { - QApplication app(argc, argv); + QGuiApplication app(argc, argv); + qInstallMessageHandler(messageHandler); QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow window; app.exec(); From ae6cf131f55c6629347c3cd449bd15dbb7158cf1 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 18 Dec 2015 17:16:56 -0800 Subject: [PATCH 223/318] Fixing crash bug --- interface/resources/qml/QmlWebWindow.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 9664c0edb8..3eb01aa9ba 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -5,7 +5,6 @@ import QtWebEngine 1.1 import QtWebChannel 1.0 import QtWebSockets 1.0 -import "qwebchannel.js" as WebChannel import "controls" import "styles" From 1beec0dbe7c46327bc0553734fa5871bbf3fc90d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 18 Dec 2015 18:15:05 -0800 Subject: [PATCH 224/318] balls --- examples/controllers/handControllerGrab.js | 21 ++++++---- examples/flowArts/arcBall/arcBall.js | 11 ++++- .../flowArts/arcBall/arcBallEntityScript.js | 42 ++++++++++++------- 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 07894b46d1..fb7ba8a4f6 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -861,20 +861,25 @@ function MyController(hand) { var handPosition = this.getHandPosition(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - + var objectRotation = grabbedProperties.rotation; + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + if (grabbableData.spatialKey.relativePosition) { + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + } else { + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + if (grabbableData.spatialKey.relativeRotation) { + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + } } else { this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 736920ddd5..f779f65643 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -26,7 +26,7 @@ ArcBall = function(spawnPosition) { var containerBall = Entities.addEntity({ - type: "Box", + type: "Sphere", name: "Arc Ball", script: scriptURL, position: Vec3.sum(spawnPosition, { @@ -37,7 +37,7 @@ ArcBall = function(spawnPosition) { dimensions: { x: .1, y: .1, - z: .2 + z: .1 }, color: { red: 15, @@ -48,6 +48,13 @@ ArcBall = function(spawnPosition) { collisionsWillMove: true, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.5 + }, + }, invertSolidWhileHeld: true } }) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 4ad0d66257..7cae0a9cb0 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -25,6 +25,7 @@ entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + _this.target = entity; _this.createBeam(position, props.position); } }); @@ -32,21 +33,13 @@ }, createBeam: function(startPosition, endPosition) { - print("CREATE BEAM") // Creates particle arc from start position to end position var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - testBox = Entities.addEntity({ - type: "Box", - dimensions: {x: .1, y: .1, z: 1}, - color: {red: 200, green: 10, blue: 10}, - position: startPosition, - rotation: emitOrientation, - visible: false - }); + var color = { red: 200, green: 10, @@ -57,7 +50,7 @@ name: "Particle Arc", parentID: this.entityID, parentJointIndex: -1, - position: startPosition, + // position: startPosition, isEmitting: true, colorStart: color, color: { @@ -67,7 +60,7 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 6, + lifespan: 5, emitRate: 1000, emitOrientation: emitOrientation, emitSpeed: .4, @@ -103,13 +96,32 @@ this.particleArc = Entities.addEntity(props); }, - continueNearGrab: function() {}, + updateBeam: function(startPosition) { + var targetPosition = Entities.getEntityProperties(this.target, "position").position; + print("TARGET position " + JSON.stringify(this.target)); + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); + Entities.editEntity(this.particleArc, {emitOrientation: emitOrientation}); + Entities.editEntity(this.testBox, {rotation: emitOrientation}); + }, - releaseGrab: function() {}, + continueNearGrab: function() { + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + this.updateBeam(startPosition); + }, + + releaseGrab: function() { + Entities.editEntity(this.particleArc, { + isEmitting: false + }); + }, unload: function() { - Entities.deleteEntity(this.particleArc); - Entities.deleteEntity(testBox); + if (this.particleArc) { + Entities.deleteEntity(this.particleArc); + } }, preload: function(entityID) { From e929e3f789f94b4305e3801c1a3fb74755b6d3c0 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 18 Dec 2015 19:18:39 -0800 Subject: [PATCH 225/318] more work on angular velocity tests --- ...t.js => reticleHandAngularVelocityTest.js} | 60 +++++++++++++------ libraries/script-engine/src/Quat.cpp | 4 ++ libraries/script-engine/src/Quat.h | 1 + 3 files changed, 48 insertions(+), 17 deletions(-) rename examples/controllers/{reticleHandTest.js => reticleHandAngularVelocityTest.js} (57%) diff --git a/examples/controllers/reticleHandTest.js b/examples/controllers/reticleHandAngularVelocityTest.js similarity index 57% rename from examples/controllers/reticleHandTest.js rename to examples/controllers/reticleHandAngularVelocityTest.js index 4132c80d85..94288b7bfb 100644 --- a/examples/controllers/reticleHandTest.js +++ b/examples/controllers/reticleHandAngularVelocityTest.js @@ -1,5 +1,5 @@ // -// reticleTest.js +// reticleHandAngularVelocityTest.js // examples/controllers // // Created by Brad Hefta-Gaub on 2015/12/15 @@ -9,6 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// If you set this to true, you will get the raw instantaneous angular velocity. +// note: there is a LOT of noise in the hydra rotation, you will probably be very +// frustrated with the level of jitter. +var USE_INSTANTANEOUS_ANGULAR_VELOCITY = false; +var whichHand = Controller.Standard.RightHand; +var whichTrigger = Controller.Standard.RT; + + function msecTimestampNow() { var d = new Date(); @@ -30,7 +38,7 @@ function moveReticle(dX, dY) { // some debugging to see if position is jumping around on us... var distanceSinceLastMove = length(lastPos, globalPos); if (distanceSinceLastMove > EXPECTED_CHANGE) { - print("distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); + print("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); } if (Math.abs(dX) > EXPECTED_CHANGE) { @@ -48,12 +56,25 @@ function moveReticle(dX, dY) { lastPos = globalPos; } +var firstTime = true; var lastTime = msecTimestampNow(); +var previousRotation; var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand"; var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from(Controller.Standard.RightHand).peek().to(function(pose) { +mapping.from(whichTrigger).peek().constrainToInteger().to(Controller.Actions.ReticleClick); +mapping.from(whichHand).peek().to(function(pose) { + var MSECS_PER_SECOND = 1000; + var now = msecTimestampNow(); + var deltaMsecs = (now - lastTime); + var deltaTime = deltaMsecs / MSECS_PER_SECOND; + + if (firstTime) { + previousRotation = pose.rotation; + lastTime = msecTimestampNow(); + firstTime = false; + } // pose.angularVelocity - is the angularVelocity in a "physics" sense, that // means the direction of the vector is the axis of symetry of rotation @@ -67,29 +88,34 @@ mapping.from(Controller.Standard.RightHand).peek().to(function(pose) { var xPart = -pose.angularVelocity.y; var yPart = -pose.angularVelocity.x; + // pose.angularVelocity is "smoothed", we can calculate our own instantaneous + // angular velocity as such: + if (USE_INSTANTANEOUS_ANGULAR_VELOCITY) { + var previousConjugate = Quat.conjugate(previousRotation); + var deltaRotation = Quat.multiply(pose.rotation, previousConjugate); + var normalizedDeltaRotation = Quat.normalize(deltaRotation); + var axis = Quat.axis(normalizedDeltaRotation); + var speed = Quat.angle(normalizedDeltaRotation) / deltaTime; + var instantaneousAngularVelocity = Vec3.multiply(speed, axis); + + xPart = -instantaneousAngularVelocity.y; + yPart = -instantaneousAngularVelocity.x; + + previousRotation = pose.rotation; + } var MOVE_SCALE = 1; - var MSECS_PER_SECOND = 1000; - var now = msecTimestampNow(); - var secondsSinceLast = (now - lastTime) / MSECS_PER_SECOND; lastTime = now; - //print("secondsSinceLast:" + secondsSinceLast); - - //print("x part:" + xPart); - //print("y part:" + yPart); - - var dX = (xPart * MOVE_SCALE) / secondsSinceLast; - var dY = (yPart * MOVE_SCALE) / secondsSinceLast; - - //print("dX:" + dX); - //print("dY:" + dY); + var dX = (xPart * MOVE_SCALE) / deltaTime; + var dY = (yPart * MOVE_SCALE) / deltaTime; moveReticle(dX, dY); }); mapping.enable(); - Script.scriptEnding.connect(function(){ mapping.disable(); }); + + diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index bb74b20be0..f6b1726770 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -22,6 +22,10 @@ quat Quat::normalize(const glm::quat& q) { return glm::normalize(q); } +quat Quat::conjugate(const glm::quat& q) { + return glm::conjugate(q); +} + glm::quat Quat::rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { return ::rotationBetween(v1, v2); } diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 543c93401f..bc7f11ab01 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -26,6 +26,7 @@ class Quat : public QObject { public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); glm::quat normalize(const glm::quat& q); + glm::quat conjugate(const glm::quat& q); glm::quat lookAt(const glm::vec3& eye, const glm::vec3& center, const glm::vec3& up); glm::quat lookAtSimple(const glm::vec3& eye, const glm::vec3& center); glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); From 8b9de716f137706423b8bd29418aea32f80e6a61 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 19 Dec 2015 08:08:10 -0800 Subject: [PATCH 226/318] fix bad pointer juju --- assignment-client/src/octree/OctreeQueryNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 044b44a165..edb737ddd5 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -33,7 +33,7 @@ bool OctreeQueryNode::packetIsDuplicate() const { // of the entire packet, we need to compare only the packet content... if (_lastOctreePacketLength == _octreePacket->getPayloadSize()) { - if (memcmp(&_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE, + if (memcmp(_lastOctreePayload.data() + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getPayload() + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getPayloadSize() - OCTREE_PACKET_EXTRA_HEADERS_SIZE) == 0) { return true; From 9271209d8907d01a5365540e46791137efe7dadf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 19 Dec 2015 08:13:53 -0800 Subject: [PATCH 227/318] another --- assignment-client/src/octree/OctreeQueryNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index edb737ddd5..78a049edd6 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -101,7 +101,7 @@ void OctreeQueryNode::resetOctreePacket() { // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing // packet send rate. _lastOctreePacketLength = _octreePacket->getPayloadSize(); - memcpy(&_lastOctreePayload, _octreePacket->getPayload(), _lastOctreePacketLength); + memcpy(_lastOctreePayload.data(), _octreePacket->getPayload(), _lastOctreePacketLength); // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. From eb03dcd8215aa92737b10ae5371eb181795ebe92 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 12:47:44 -0800 Subject: [PATCH 228/318] keep parent of lights that already have parents --- examples/light_modifier/lightModifier.js | 36 +++++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 0d07f2c011..e82897e049 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -47,10 +47,6 @@ if (SHOW_OVERLAYS === true) { lightOverlayManager.setVisible(true); } -// var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking -// var pickRay = Camera.computePickRay(event.x, event.y); -// var lightResult = lightOverlayManager.findRayIntersection(pickRay) - var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}' var AXIS_SCALE = 1; @@ -408,7 +404,7 @@ function makeSliders(light) { }; -function createLightModel(position,rotation) { +function createLightModel(position, rotation) { var blockProperties = { name: 'Hifi-Spotlight-Model', type: 'Model', @@ -417,7 +413,7 @@ function createLightModel(position,rotation) { dimensions: LIGHT_MODEL_DIMENSIONS, collisionsWillMove: true, position: position, - rotation:rotation, + rotation: rotation, script: PARENT_SCRIPT_URL, userData: JSON.stringify({ handControllerKey: { @@ -529,6 +525,7 @@ function handleValueMessages(channel, message, sender) { var currentLight; var block; +var hasParent = false; function handleLightOverlayRayCheckMessages(channel, message, sender) { if (channel !== 'Hifi-Light-Overlay-Ray-Check') { @@ -553,7 +550,16 @@ function handleLightOverlayRayCheckMessages(channel, message, sender) { currentLight = lightID; var lightProperties = Entities.getEntityProperties(lightID); - block = createLightModel(lightProperties.position,lightProperties.rotation); + if (lightProperties.parentID !== DEFAULT_PARENT_ID) { + //this light has a parent already. so lets call our block the parent and then make sure not to delete it at the end; + hasParent = true; + block = lightProperties.parentID; + if (lightProperties.parentJointIndex !== -1) { + //should make sure to retain the parent too. but i don't actually know what the + } + } else { + block = createLightModel(lightProperties.position, lightProperties.rotation); + } var light = { id: lightID, @@ -604,18 +610,20 @@ function cleanup(fromMessage) { parentID: null, }); - if(fromMessage!==true){ - Messages.messageReceived.disconnect(handleLightModMessages); - Messages.messageReceived.disconnect(handleValueMessages); - Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages); - lightOverlayManager.setVisible(false); + if (fromMessage !== true) { + Messages.messageReceived.disconnect(handleLightModMessages); + Messages.messageReceived.disconnect(handleValueMessages); + Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages); + lightOverlayManager.setVisible(false); } selectionManager.clearSelections(); Script.update.disconnect(rotateCloseButtons); - - Entities.deleteEntity(block); + if (hasParent === false) { + Entities.deleteEntity(block); + } + hasParent = false; currentLight = null; From 378d50d8a3174086ae451e3a048ff3aa96e7ac62 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 12:49:42 -0800 Subject: [PATCH 229/318] update overlays when cutoff slider is used --- examples/light_modifier/slider.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/light_modifier/slider.js b/examples/light_modifier/slider.js index dc02e0bdba..6c67d35204 100644 --- a/examples/light_modifier/slider.js +++ b/examples/light_modifier/slider.js @@ -95,6 +95,9 @@ sliderValue: _t.sliderValue } Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message)); + if (_t.userData.sliderType === 'cutoff') { + Messages.sendMessage('entityToolUpdates', 'callUpdate'); + } } }; From 05467bd5e1a356afca087c151f0c77f29aa5e238 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 18:19:00 -0800 Subject: [PATCH 230/318] create panel entity and parent panel to it --- examples/light_modifier/lightModifier.js | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index e82897e049..14053c7974 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -363,6 +363,10 @@ var light = null; function makeSliders(light) { + if (USE_PARENTED_PANEL === true) { + createPanelEntity(MyAvatar.position); + } + if (light.type === 'spotlight') { var USE_COLOR_SLIDER = true; var USE_INTENSITY_SLIDER = true; @@ -398,12 +402,55 @@ function makeSliders(light) { sliders.push(slidersRef.exponent); } + + createCloseButton(slidersRef.exponent.endOfAxis); subscribeToSliderMessages(); + + if (USE_PARENTED_PANEL === true) { + parentEntitiesToPanel(); + } }; +function parentEntitiesToPanel(panel) { + slidersRef.forEach(function(slider) { + Entities.editEntity(slider.axis, { + parentID: panel + }) + Entities.editEntity(slider.sliderIndicator, { + parentID: panel + }) + }) + + closeButtons.forEach(function(button) { + Entities.editEntity(slider.sliderIndicator, { + parentID: panel + }) + }) +} + +function createPanelEntity(position) { + + var panelProperties = { + name: 'Hifi-Slider-Panel', + type: 'Box', + dimensions: { + x: 0.1, + y: 0.1, + z: 0.1 + }, + visible: false, + collisionsWillMove: false, + ignoreForCollisions: true + } + + var panel = Entities.addEntity(panelProperties); + return panel +} + + function createLightModel(position, rotation) { var blockProperties = { name: 'Hifi-Spotlight-Model', From 9f0d254739df2a9a158c01a138a85717dcad0812 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 19:11:17 -0800 Subject: [PATCH 231/318] panel entity, readme --- examples/light_modifier/README.md | 16 ++++++------- examples/light_modifier/lightModifier.js | 29 ++++++++++++++++-------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 73c2199ec9..b12ff7550b 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -1,6 +1,8 @@ -This PR demonstrates one way in-world editing of objects might work. We start with a spotlight. When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. +This PR demonstrates one way in-world editing of objects might work. -Enter edit mode by running your distance beam through a light overlay. Exit using the red X. +Running this script will show light overlay icons in-world. Enter edit mode by running your distance beam through a light overlay. Exit using the red X. + +When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached. To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js @@ -8,14 +10,12 @@ To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: - handControllerGrab.js (custom) - lightModifier.js (listens for message to create sliders for a given light) -- lightModifierTestScene.js (creates a light and parents it to a block, then sends a message ^^) +- lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) -- lightParent.js (attached to the entity to which a light is parented, so you can move it around) +- lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent) - closeButton.js (for closing the ui) -- ../libraries/lightOverlayManager.js (custom) -- ../libraries/entitySelectionTool.js - - +- ../libraries/lightOverlayManager.js (shows 2d overlays for lights in the world) +- ../libraries/entitySelectionTool.js (visualizes volume of the lights) Current sliders are (top to bottom): red diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 14053c7974..30f004c922 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -16,13 +16,14 @@ var SLIDERS_SHOULD_STAY_WITH_AVATAR = false; var VERTICAL_SLIDERS = false; var SHOW_OVERLAYS = true; var SHOW_LIGHT_VOLUME = true; +var USE_PARENTED_PANEL = false; //variables for managing overlays var selectionDisplay; var selectionManager; var lightOverlayManager; -//for when we make a block parent for the light +//for when we make a 3d model of a light a parent for the light var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100)); if (SHOW_OVERLAYS === true) { @@ -362,9 +363,9 @@ var slidersRef = { var light = null; function makeSliders(light) { - + var panel; if (USE_PARENTED_PANEL === true) { - createPanelEntity(MyAvatar.position); + panel = createPanelEntity(MyAvatar.position); } if (light.type === 'spotlight') { @@ -409,10 +410,21 @@ function makeSliders(light) { subscribeToSliderMessages(); if (USE_PARENTED_PANEL === true) { - parentEntitiesToPanel(); + parentEntitiesToPanel(panel); + } + + if () { + parentPanelToAvatar(panel) } }; +function parentPanelToAvatar(panel) { + Entities.editEntity(panel, { + parentID: MyAvatar.sessionUUID, + //actually figure out which one to parent it to -- probably a spine or something. + parentJointIndex: 1, + }) +} function parentEntitiesToPanel(panel) { slidersRef.forEach(function(slider) { @@ -493,11 +505,10 @@ function createCloseButton(endOfAxis) { ignoreForCollisions: true, script: CLOSE_BUTTON_SCRIPT_URL, userData: JSON.stringify({ - grabbableKey: { - wantsTrigger: true - } - }) - //need to add wantsTrigger stuff so we can interact with it with our beamz + grabbableKey: { + wantsTrigger: true + } + }) } var button = Entities.addEntity(buttonProperties); From daa262af7d33d18866d304a5c3b9d1c5e33aeb55 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 19:14:19 -0800 Subject: [PATCH 232/318] readme --- examples/light_modifier/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index b12ff7550b..4a2690cd91 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -8,7 +8,7 @@ To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: -- handControllerGrab.js (custom) +- handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end) - lightModifier.js (listens for message to create sliders for a given light) - lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) From 485bb4ee3f3948f505fdffda30bc67bafa1c3428 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 19 Dec 2015 19:14:56 -0800 Subject: [PATCH 233/318] slider should stay with avatr --- examples/light_modifier/lightModifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 30f004c922..02d764e7e2 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -413,7 +413,7 @@ function makeSliders(light) { parentEntitiesToPanel(panel); } - if () { + if (SLIDERS_SHOULD_STAY_WITH_AVATAR) { parentPanelToAvatar(panel) } }; From da57e29096069c06f841aa4e6d6fdbed27989e71 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 20 Dec 2015 16:40:41 -0800 Subject: [PATCH 234/318] start options, cleanup --- examples/light_modifier/README.md | 2 +- examples/light_modifier/slider.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/light_modifier/README.md b/examples/light_modifier/README.md index 4a2690cd91..1358fbe917 100644 --- a/examples/light_modifier/README.md +++ b/examples/light_modifier/README.md @@ -9,7 +9,7 @@ To reset, I recommend stopping all scripts then re-loading lightLoader.js When you run the lightLoader.js script, several scripts will be loaded: - handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end) -- lightModifier.js (listens for message to create sliders for a given light) +- lightModifier.js (listens for message to create sliders for a given light. will start with slider set to the light's initial properties) - lightModifierTestScene.js (creates a light) - slider.js (attached to each slider entity) - lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent) diff --git a/examples/light_modifier/slider.js b/examples/light_modifier/slider.js index 6c67d35204..e1dfea4e87 100644 --- a/examples/light_modifier/slider.js +++ b/examples/light_modifier/slider.js @@ -50,16 +50,16 @@ var distance = Vec3.distance(this.userData.axisStart, currentPosition); if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, COLOR_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, COLOR_MAX); } if (this.userData.sliderType === 'intensity') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, INTENSITY_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, INTENSITY_MAX); } if (this.userData.sliderType === 'cutoff') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, CUTOFF_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, CUTOFF_MAX); } if (this.userData.sliderType === 'exponent') { - this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, EXPONENT_MAX); + this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, EXPONENT_MAX); }; this.sendValueToSlider(); @@ -80,10 +80,10 @@ this.sendValueToSlider(); }, - scaleValueBasedOnDistanceFromStart: function(value, max2) { + scaleValueBasedOnDistanceFromStart: function(value, min2, max2) { var min1 = 0; var max1 = AXIS_SCALE; - var min2 = 0; + var min2 = min2; var max2 = max2; return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); }, From aef748b894041d5745dfcf76e20a7a5524bbe5fa Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Dec 2015 10:40:29 -0800 Subject: [PATCH 235/318] Adding linear color in Particule system --- .../src/RenderableParticleEffectEntityItem.cpp | 8 ++++---- libraries/entities-renderer/src/untextured_particle.slv | 5 ++--- libraries/entities/src/ParticleEffectEntityItem.h | 6 ++++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 4abd8dbafd..379d1cc4a3 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -223,10 +223,10 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { particleUniforms.radius.middle = getParticleRadius(); particleUniforms.radius.finish = getRadiusFinish(); particleUniforms.radius.spread = getRadiusSpread(); - particleUniforms.color.start = toGlm(getColorStart(), getAlphaStart()); - particleUniforms.color.middle = toGlm(getXColor(), getAlpha()); - particleUniforms.color.finish = toGlm(getColorFinish(), getAlphaFinish()); - particleUniforms.color.spread = toGlm(getColorSpread(), getAlphaSpread()); + particleUniforms.color.start = glm::vec4(getColorStartRGB(), getAlphaStart()); + particleUniforms.color.middle = glm::vec4(getColorRGB(), getAlpha()); + particleUniforms.color.finish = glm::vec4(getColorFinishRGB(), getAlphaFinish()); + particleUniforms.color.spread = glm::vec4(getColorSpreadRGB(), getAlphaSpread()); particleUniforms.lifespan = getLifespan(); // Build particle primitives diff --git a/libraries/entities-renderer/src/untextured_particle.slv b/libraries/entities-renderer/src/untextured_particle.slv index 3d1d99c0dc..ab0ea15219 100644 --- a/libraries/entities-renderer/src/untextured_particle.slv +++ b/libraries/entities-renderer/src/untextured_particle.slv @@ -9,16 +9,15 @@ // <@include gpu/Inputs.slh@> - +<@include gpu/Color.slh@> <@include gpu/Transform.slh@> - <$declareStandardTransform()$> out vec4 _color; void main(void) { // pass along the diffuse color - _color = inColor; + _color = colorToLinearRGBA(inColor); TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index c35a45baeb..cae9340b6d 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -15,6 +15,8 @@ #include "EntityItem.h" +#include "ColorUtils.h" + class ParticleEffectEntityItem : public EntityItem { public: ALLOW_INSTANTIATION // This class can be instantiated @@ -47,6 +49,7 @@ public: const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } + glm::vec3 getColorRGB() const { return ColorUtils::toLinearVec3(toGlm(getXColor())); } static const xColor DEFAULT_COLOR; void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } @@ -59,14 +62,17 @@ public: bool _isColorStartInitialized = false; void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; } xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); } + glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorStart)) : getColorRGB(); } bool _isColorFinishInitialized = false; void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; } xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); } + glm::vec3 getColorFinishRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorFinish)) : getColorRGB(); } static const xColor DEFAULT_COLOR_SPREAD; void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; } xColor getColorSpread() const { return _colorSpread; } + glm::vec3 getColorSpreadRGB() const { return ColorUtils::toLinearVec3(toGlm(_colorSpread)); } static const float MAXIMUM_ALPHA; static const float MINIMUM_ALPHA; From 7a7befafb9e4afc78039d4a4f99da1b53763ea5f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 10:43:59 -0800 Subject: [PATCH 236/318] arc balls working --- examples/controllers/handControllerGrab.js | 54 ++++++++++++------- examples/flowArts/arcBall/arcBall.js | 27 ++++++---- .../flowArts/arcBall/arcBallEntityScript.js | 47 ++++++++++------ 3 files changed, 81 insertions(+), 47 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 07894b46d1..6cacc2e80a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -218,6 +218,7 @@ function getSpatialOffsetPosition(hand, spatialKey) { } var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); + function getSpatialOffsetRotation(hand, spatialKey) { var rotation = Quat.IDENTITY; @@ -261,9 +262,9 @@ function MyController(hand) { this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; this.rawBumperValue = 0; - + this.overlayLine = null; - + this.ignoreIK = false; this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; @@ -819,8 +820,16 @@ function MyController(hand) { // mix in head motion if (MOVE_WITH_HEAD) { var objDistance = Vec3.length(objectToAvatar); - var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); - var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); + var after = Vec3.multiplyQbyV(Camera.orientation, { + x: 0.0, + y: 0.0, + z: objDistance + }); var change = Vec3.subtract(before, after); this.currentCameraOrientation = Camera.orientation; this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); @@ -861,20 +870,25 @@ function MyController(hand) { var handPosition = this.getHandPosition(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - + var objectRotation = grabbedProperties.rotation; + var currentObjectPosition = grabbedProperties.position; + var offset = Vec3.subtract(currentObjectPosition, handPosition); if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + if (grabbableData.spatialKey.relativePosition) { + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + } else { + this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); + } + if (grabbableData.spatialKey.relativeRotation) { + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + } else { + this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); + } } else { this.ignoreIK = false; - - var objectRotation = grabbedProperties.rotation; this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - - var currentObjectPosition = grabbedProperties.position; - var offset = Vec3.subtract(currentObjectPosition, handPosition); this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } @@ -1304,10 +1318,10 @@ Controller.enableMapping(MAPPING_NAME); var handToDisable = 'none'; function update() { - if (handToDisable !== LEFT_HAND && handToDisable!=='both') { + if (handToDisable !== LEFT_HAND && handToDisable !== 'both') { leftController.update(); } - if (handToDisable !== RIGHT_HAND && handToDisable!=='both') { + if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') { rightController.update(); } } @@ -1315,7 +1329,7 @@ function update() { Messages.subscribe('Hifi-Hand-Disabler'); handleHandDisablerMessages = function(channel, message, sender) { - + if (sender === MyAvatar.sessionUUID) { if (message === 'left') { handToDisable = LEFT_HAND; @@ -1323,11 +1337,11 @@ handleHandDisablerMessages = function(channel, message, sender) { if (message === 'right') { handToDisable = RIGHT_HAND; } - if(message==='both'){ - handToDisable='both'; + if (message === 'both') { + handToDisable = 'both'; } - if(message==='none'){ - handToDisable='none'; + if (message === 'none') { + handToDisable = 'none'; } } @@ -1342,4 +1356,4 @@ function cleanup() { } Script.scriptEnding.connect(cleanup); -Script.update.connect(update); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 736920ddd5..54cb16fe15 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -26,7 +26,7 @@ ArcBall = function(spawnPosition) { var containerBall = Entities.addEntity({ - type: "Box", + type: "Sphere", name: "Arc Ball", script: scriptURL, position: Vec3.sum(spawnPosition, { @@ -35,12 +35,12 @@ ArcBall = function(spawnPosition) { z: 0 }), dimensions: { - x: .1, - y: .1, - z: .2 + x: .05, + y: .05, + z: .05 }, color: { - red: 15, + red: 100, green: 10, blue: 150 }, @@ -48,6 +48,13 @@ ArcBall = function(spawnPosition) { collisionsWillMove: true, userData: JSON.stringify({ grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0, + z: -0.5 + }, + }, invertSolidWhileHeld: true } }) @@ -127,11 +134,11 @@ ArcBall = function(spawnPosition) { - function cleanup() { - Entities.deleteEntity(arcBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } + function cleanup() { + Entities.deleteEntity(arcBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } this.cleanup = cleanup; } \ No newline at end of file diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 4ad0d66257..7bb8472ce9 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -25,6 +25,7 @@ entities.forEach(function(entity) { var props = Entities.getEntityProperties(entity, ["position", "name"]); if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + _this.target = entity; _this.createBeam(position, props.position); } }); @@ -32,21 +33,13 @@ }, createBeam: function(startPosition, endPosition) { - print("CREATE BEAM") - // Creates particle arc from start position to end position + // Creates particle arc from start position to end position var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - testBox = Entities.addEntity({ - type: "Box", - dimensions: {x: .1, y: .1, z: 1}, - color: {red: 200, green: 10, blue: 10}, - position: startPosition, - rotation: emitOrientation, - visible: false - }); + var color = { red: 200, green: 10, @@ -57,7 +50,7 @@ name: "Particle Arc", parentID: this.entityID, parentJointIndex: -1, - position: startPosition, + // position: startPosition, isEmitting: true, colorStart: color, color: { @@ -67,7 +60,7 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 6, + lifespan: 5, emitRate: 1000, emitOrientation: emitOrientation, emitSpeed: .4, @@ -98,18 +91,38 @@ alphaStart: 0.5, alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: false + emitterShouldTrail: true } this.particleArc = Entities.addEntity(props); }, - continueNearGrab: function() {}, + updateBeam: function(startPosition) { + var targetPosition = Entities.getEntityProperties(this.target, "position").position; + print("TARGET position " + JSON.stringify(this.target)); + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); + Entities.editEntity(this.particleArc, { + emitOrientation: emitOrientation + }); + }, - releaseGrab: function() {}, + continueNearGrab: function() { + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + this.updateBeam(startPosition); + }, + + releaseGrab: function() { + Entities.editEntity(this.particleArc, { + isEmitting: false + }); + }, unload: function() { - Entities.deleteEntity(this.particleArc); - Entities.deleteEntity(testBox); + if (this.particleArc) { + Entities.deleteEntity(this.particleArc); + } }, preload: function(entityID) { From 45ba7a3d35c12e55207acbee615757f022e655e1 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 10:46:54 -0800 Subject: [PATCH 237/318] merged --- examples/controllers/handControllerGrab.js | 10 --------- .../flowArts/arcBall/arcBallEntityScript.js | 21 ------------------- 2 files changed, 31 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 6337079dc5..6cacc2e80a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -877,24 +877,14 @@ function MyController(hand) { // if an object is "equipped" and has a spatialKey, use it. this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; if (grabbableData.spatialKey.relativePosition) { -<<<<<<< HEAD this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); -======= - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); ->>>>>>> origin/polylineOptimizations } else { this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } if (grabbableData.spatialKey.relativeRotation) { -<<<<<<< HEAD this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); } else { this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); -======= - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); - } else { - this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); ->>>>>>> origin/polylineOptimizations } } else { this.ignoreIK = false; diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 539bdd7cf0..7bb8472ce9 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -33,21 +33,13 @@ }, createBeam: function(startPosition, endPosition) { -<<<<<<< HEAD // Creates particle arc from start position to end position -======= - // Creates particle arc from start position to end position ->>>>>>> origin/polylineOptimizations var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); -<<<<<<< HEAD -======= - ->>>>>>> origin/polylineOptimizations var color = { red: 200, green: 10, @@ -110,7 +102,6 @@ var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); -<<<<<<< HEAD // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); Entities.editEntity(this.particleArc, { emitOrientation: emitOrientation @@ -122,18 +113,6 @@ this.updateBeam(startPosition); }, -======= - emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - Entities.editEntity(this.particleArc, {emitOrientation: emitOrientation}); - Entities.editEntity(this.testBox, {rotation: emitOrientation}); - }, - - continueNearGrab: function() { - var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - this.updateBeam(startPosition); - }, - ->>>>>>> origin/polylineOptimizations releaseGrab: function() { Entities.editEntity(this.particleArc, { isEmitting: false From 248b3d09ace2a887283b255194a429c087e7a981 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 21 Dec 2015 10:49:49 -0800 Subject: [PATCH 238/318] add absolute rotation based hand reticle movement --- .../controllers/reticleHandRotationTest.js | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 examples/controllers/reticleHandRotationTest.js diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js new file mode 100644 index 0000000000..d413e531df --- /dev/null +++ b/examples/controllers/reticleHandRotationTest.js @@ -0,0 +1,103 @@ +// +// reticleHandRotationTest.js +// examples/controllers +// +// Created by Brad Hefta-Gaub on 2015/12/15 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Math.clamp=function(a,b,c) { + return Math.max(b,Math.min(c,a)); +} + +var whichHand = Controller.Standard.RightHand; +var whichTrigger = Controller.Standard.RT; + +function length(posA, posB) { + var dx = posA.x - posB.x; + var dy = posA.y - posB.y; + var length = Math.sqrt((dx*dx) + (dy*dy)) + return length; +} + +var EXPECTED_CHANGE = 50; +var lastPos = Controller.getReticlePosition(); +function moveReticleAbsolute(x, y) { + var globalPos = Controller.getReticlePosition(); + var dX = x - globalPos.x; + var dY = y - globalPos.y; + + // some debugging to see if position is jumping around on us... + var distanceSinceLastMove = length(lastPos, globalPos); + if (distanceSinceLastMove > EXPECTED_CHANGE) { + print("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); + } + + if (Math.abs(dX) > EXPECTED_CHANGE) { + print("surpressing unexpectedly large change dX:" + dX + "----------------------------"); + } + if (Math.abs(dY) > EXPECTED_CHANGE) { + print("surpressing unexpectedly large change dY:" + dY + "----------------------------"); + } + + globalPos.x = x; + globalPos.y = y; + Controller.setReticlePosition(globalPos); + lastPos = globalPos; +} + + +var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; +var mapping = Controller.newMapping(MAPPING_NAME); +mapping.from(whichTrigger).peek().constrainToInteger().to(Controller.Actions.ReticleClick); +mapping.from(whichHand).peek().to(function(pose) { + + // NOTE: hack for now + var screenSizeX = 1920; + var screenSizeY = 1080; + + var rotated = Vec3.multiplyQbyV(pose.rotation, Vec3.UNIT_NEG_Y); // + var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again... + var absoluteYaw = rotated.z; // from -1 left to 1 right + //print("absolutePitch:" + absolutePitch); + //print("absoluteYaw:" + absoluteYaw); + //Vec3.print("rotated:", rotated); + + var ROTATION_BOUND = 0.6; + var clampYaw = Math.clamp(absoluteYaw, -ROTATION_BOUND, ROTATION_BOUND); + var clampPitch = Math.clamp(absolutePitch, -ROTATION_BOUND, ROTATION_BOUND); + //var clampYaw = absoluteYaw; + //print("clampYaw:" + clampYaw); + //print("clampPitch:" + clampPitch); + + // if using entire span... + //var xRatio = (absoluteYaw + 1) / 2; + //var yRatio = (absolutePitch + 1) / 2; + + // if using only from -0.5 to 0.5 + var xRatio = (clampYaw + ROTATION_BOUND) / (2 * ROTATION_BOUND); + var yRatio = (clampPitch + ROTATION_BOUND) / (2 * ROTATION_BOUND); + + //print("xRatio:" + xRatio); + //print("yRatio:" + yRatio); + + //print("ratio x:" + xRatio + " y:" + yRatio); + + var x = screenSizeX * xRatio; + var y = screenSizeY * yRatio; + + //print("position x:" + x + " y:" + y); + if (!(xRatio == 0.5 && yRatio == 0)) { + moveReticleAbsolute(x, y); + } +}); +mapping.enable(); + +Script.scriptEnding.connect(function(){ + mapping.disable(); +}); + + From 48ab99c34864f5ecd2734900e4d89b29f964288d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:00:10 -0800 Subject: [PATCH 239/318] rotation fix --- examples/flowArts/arcBall/arcBall.js | 8 +- .../flowArts/arcBall/arcBallEntityScript.js | 112 +++++++++--------- 2 files changed, 63 insertions(+), 57 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 54cb16fe15..f6860b54c6 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -31,7 +31,7 @@ ArcBall = function(spawnPosition) { script: scriptURL, position: Vec3.sum(spawnPosition, { x: 0, - y: .5, + y: .7, z: 0 }), dimensions: { @@ -51,8 +51,8 @@ ArcBall = function(spawnPosition) { spatialKey: { relativePosition: { x: 0, - y: 0, - z: -0.5 + y: -0.5, + z: 0.0 }, }, invertSolidWhileHeld: true @@ -97,7 +97,7 @@ ArcBall = function(spawnPosition) { }, maxParticles: 100000, lifespan: 2, - emitRate: 1000, + emitRate: 400, emitSpeed: .1, lifetime: -1, speedSpread: 0.0, diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 7bb8472ce9..7edf22ecdb 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -14,6 +14,15 @@ var _this; var ArcBall = function() { _this = this; + this.colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }, { + red: 200, + green: 10, + blue: 10 + }]; }; ArcBall.prototype = { @@ -40,59 +49,56 @@ emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - var color = { - red: 200, - green: 10, - blue: 10 - }; - var props = { - type: "ParticleEffect", - name: "Particle Arc", - parentID: this.entityID, - parentJointIndex: -1, - // position: startPosition, - isEmitting: true, - colorStart: color, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 5, - emitRate: 1000, - emitOrientation: emitOrientation, - emitSpeed: .4, - speedSpread: 0.0, - emitDimensions: { - x: 0, - y: 0, - z: 0 - }, - polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.03, - adiusFinish: 0.025, - alpha: 0.7, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.5, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: true - } + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + parentJointIndex: -1, + // position: startPosition, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 500, + emitOrientation: emitOrientation, + emitSpeed: .4, + speedSpread: 0.1, + emitDimensions: { + x: 0, + y: 0, + z: 0 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.03, + radiusFinish: 0.025, + radiusSpread: .01, + alpha: 0.7, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.5, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: true + } this.particleArc = Entities.addEntity(props); }, From 3c66e3826830a2f9bc84697da5e4d7b61dc77423 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:12:59 -0800 Subject: [PATCH 240/318] test --- examples/flowArts/arcBall/arcBall.js | 7 +++--- .../flowArts/arcBall/arcBallEntityScript.js | 22 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index f6860b54c6..e67dffddff 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -44,6 +44,7 @@ ArcBall = function(spawnPosition) { green: 10, blue: 150 }, + ignoreForCollisions: true, damping: 0.8, collisionsWillMove: true, userData: JSON.stringify({ @@ -51,11 +52,11 @@ ArcBall = function(spawnPosition) { spatialKey: { relativePosition: { x: 0, - y: -0.5, - z: 0.0 + y: 0.0, + z: -0.5 }, }, - invertSolidWhileHeld: true + // invertSolidWhileHeld: true } }) }); diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 7edf22ecdb..0906b90b53 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -65,15 +65,15 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 2, - emitRate: 500, + lifespan: 1, + emitRate: 1000, emitOrientation: emitOrientation, - emitSpeed: .4, + emitSpeed: .2, speedSpread: 0.1, emitDimensions: { - x: 0, - y: 0, - z: 0 + x: .1, + y: .1, + z: .1 }, polarStart: 0, polarFinish: .0, @@ -89,13 +89,13 @@ y: .00, z: .00 }, - radiusStart: 0.03, - radiusFinish: 0.025, - radiusSpread: .01, - alpha: 0.7, + radiusStart: 0.01, + radiusFinish: 0.005, + radiusSpread: .005, + alpha: 0.5, alphaSpread: .1, alphaStart: 0.5, - alphaFinish: 0.5, + alphaFinish: 0.0, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: true } From 05b7fcc9573dd43a9df57df4d901b618767918b0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 21 Dec 2015 11:19:05 -0800 Subject: [PATCH 241/318] Remove script -> qt::webchannel dependency --- interface/src/Application.cpp | 1 + libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 3 --- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e22b3913d0..f4fe919780 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4183,6 +4183,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri LocationScriptingInterface::locationSetter); scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1); + scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index c1131765f7..3796abd92a 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -1,3 +1,3 @@ set(TARGET_NAME script-engine) setup_hifi_library(Gui Network Script WebSockets Widgets) -link_hifi_libraries(shared networking ui octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) +link_hifi_libraries(shared networking octree gpu procedural model model-networking recording avatars fbx entities controllers animation audio physics) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5f39bee9fa..ded3db11e9 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -351,8 +350,6 @@ void ScriptEngine::init() { qScriptRegisterSequenceMetaType >(this); qScriptRegisterSequenceMetaType >(this); - - registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor); QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); From ba3633710a9dfb0663f386a8f532fd5bd83e1c5f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:29:59 -0800 Subject: [PATCH 242/318] name fixes --- examples/flowArts/arcBall/arcBall.js | 258 +++++++++--------- examples/flowArts/flowArtsHutSpawner.js | 8 +- .../{LightSaber.js => lightSaber.js} | 0 .../raveStick/{RaveStick.js => raveStick.js} | 0 4 files changed, 130 insertions(+), 136 deletions(-) rename examples/flowArts/lightSaber/{LightSaber.js => lightSaber.js} (100%) rename examples/flowArts/raveStick/{RaveStick.js => raveStick.js} (100%) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index e67dffddff..0906b90b53 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -1,145 +1,139 @@ -// -// arcBall.js -// examples/arcBall -// +// arcBallEntityScript.js +// +// Script Type: Entity // Created by Eric Levin on 12/17/15. -// Copyright 2014 High Fidelity, Inc. -// -// This script creats a particle light ball which makes particle trails as you move it. -// +// Copyright 2015 High Fidelity, Inc. // +// This entity script handles the logic for the arcBall rave toy // 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 scriptURL = Script.resolvePath("arcBallEntityScript.js"); -ArcBall = function(spawnPosition) { - - var colorPalette = [{ - red: 25, - green: 20, - blue: 162 - }]; - - - var containerBall = Entities.addEntity({ - type: "Sphere", - name: "Arc Ball", - script: scriptURL, - position: Vec3.sum(spawnPosition, { - x: 0, - y: .7, - z: 0 - }), - dimensions: { - x: .05, - y: .05, - z: .05 - }, - color: { - red: 100, - green: 10, - blue: 150 - }, - ignoreForCollisions: true, - damping: 0.8, - collisionsWillMove: true, - userData: JSON.stringify({ - grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 0.0, - z: -0.5 - }, - }, - // invertSolidWhileHeld: true - } - }) - }); - - - var light = Entities.addEntity({ - type: 'Light', - name: "ballLight", - parentID: containerBall, - dimensions: { - x: 30, - y: 30, - z: 30 - }, - color: colorPalette[randInt(0, colorPalette.length)], - intensity: 5 - }); - - - var arcBall = Entities.addEntity({ - type: "ParticleEffect", - parentID: containerBall, - isEmitting: true, - name: "Arc Ball Particle Effect", - colorStart: { - red: 200, - green: 20, - blue: 40 - }, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: { +(function() { + Script.include("../../libraries/utils.js"); + var _this; + var ArcBall = function() { + _this = this; + this.colorPalette = [{ red: 25, green: 20, - blue: 255 + blue: 162 + }, { + red: 200, + green: 10, + blue: 10 + }]; + }; + + ArcBall.prototype = { + isGrabbed: false, + startNearGrab: function() { + //Search for nearby balls and create an arc to it if one is found + var position = Entities.getEntityProperties(this.entityID, "position").position + var entities = Entities.findEntities(position, 10); + entities.forEach(function(entity) { + var props = Entities.getEntityProperties(entity, ["position", "name"]); + if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { + _this.target = entity; + _this.createBeam(position, props.position); + } + }); + }, - maxParticles: 100000, - lifespan: 2, - emitRate: 400, - emitSpeed: .1, - lifetime: -1, - speedSpread: 0.0, - emitDimensions: { - x: 0, - y: 0, - z: 0 - }, - polarStart: 0, - polarFinish: Math.PI, - azimuthStart: -Math.PI, - azimuthFinish: Math.PI, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - particleRadius: 0.02, - radiusSpread: 0, - radiusStart: 0.03, - radiusFinish: 0.0003, - alpha: 0, - alphaSpread: .5, - alphaStart: 0, - alphaFinish: 0.5, - textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", - emitterShouldTrail: true - }) + + createBeam: function(startPosition, endPosition) { + // Creates particle arc from start position to end position + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); + var color = this.colorPalette[randInt(0, this.colorPalette.length)]; + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + parentJointIndex: -1, + // position: startPosition, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 1, + emitRate: 1000, + emitOrientation: emitOrientation, + emitSpeed: .2, + speedSpread: 0.1, + emitDimensions: { + x: .1, + y: .1, + z: .1 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .1, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.01, + radiusFinish: 0.005, + radiusSpread: .005, + alpha: 0.5, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.0, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: true + } + this.particleArc = Entities.addEntity(props); + }, - function cleanup() { - Entities.deleteEntity(arcBall); - Entities.deleteEntity(containerBall); - Entities.deleteEntity(light); - } + updateBeam: function(startPosition) { + var targetPosition = Entities.getEntityProperties(this.target, "position").position; + print("TARGET position " + JSON.stringify(this.target)); + var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; + var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); + // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); + Entities.editEntity(this.particleArc, { + emitOrientation: emitOrientation + }); + }, - this.cleanup = cleanup; -} \ No newline at end of file + continueNearGrab: function() { + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + this.updateBeam(startPosition); + }, + + releaseGrab: function() { + Entities.editEntity(this.particleArc, { + isEmitting: false + }); + }, + + unload: function() { + if (this.particleArc) { + Entities.deleteEntity(this.particleArc); + } + }, + + preload: function(entityID) { + this.entityID = entityID; + }, + }; + return new ArcBall(); +}); \ No newline at end of file diff --git a/examples/flowArts/flowArtsHutSpawner.js b/examples/flowArts/flowArtsHutSpawner.js index 39dcf15698..2c87a27c15 100644 --- a/examples/flowArts/flowArtsHutSpawner.js +++ b/examples/flowArts/flowArtsHutSpawner.js @@ -14,10 +14,10 @@ Script.include("../../libraries/utils.js"); -Script.include("lightBall/LightBall.js"); -Script.include("raveStick/RaveStick.js"); -Script.include("lightSaber/LightSaber.js"); -Script.include("arcBall/ArcBall.js"); +Script.include("lightBall/lightBall.js"); +Script.include("raveStick/raveStick.js"); +Script.include("lightSaber/lightSaber.js"); +Script.include("arcBall/arcBall.js"); diff --git a/examples/flowArts/lightSaber/LightSaber.js b/examples/flowArts/lightSaber/lightSaber.js similarity index 100% rename from examples/flowArts/lightSaber/LightSaber.js rename to examples/flowArts/lightSaber/lightSaber.js diff --git a/examples/flowArts/raveStick/RaveStick.js b/examples/flowArts/raveStick/raveStick.js similarity index 100% rename from examples/flowArts/raveStick/RaveStick.js rename to examples/flowArts/raveStick/raveStick.js From 6ef77bc46aeab1fb17186855271fd16284da9102 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 17 Dec 2015 15:46:44 -0800 Subject: [PATCH 243/318] Support the marketplace in QML --- examples/edit.js | 47 ++++++++++++------- interface/resources/qml/QmlWebWindow.qml | 16 ++++--- interface/src/Application.cpp | 2 +- interface/src/Application.h | 7 +-- libraries/networking/src/AbstractUriHandler.h | 19 ++++++++ libraries/octree/src/Octree.cpp | 2 +- libraries/ui/src/QmlWebWindowClass.cpp | 43 +++++++++++++++-- 7 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 libraries/networking/src/AbstractUriHandler.h diff --git a/examples/edit.js b/examples/edit.js index 59b6ae3e7d..074b43c8c1 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -140,9 +140,33 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", { }); var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace"; -var marketplaceWindow = new WebWindow('Marketplace', MARKETPLACE_URL, 900, 700, false); +var marketplaceWindow = new OverlayWebWindow('Marketplace', "about:blank", 900, 700, false); marketplaceWindow.setVisible(false); +function showMarketplace(marketplaceID) { + var url = MARKETPLACE_URL; + if (marketplaceID) { + url = url + "/items/" + marketplaceID; + } + print("setting marketplace URL to " + url); + marketplaceWindow.setURL(url); + marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); +} + +function hideMarketplace() { + marketplaceWindow.setVisible(false); + marketplaceWindow.setURL("about:blank"); +} + +function toggleMarketplace() { + if (marketplaceWindow.visible) { + hideMarketplace(); + } else { + showMarketplace(); + } +} + var toolBar = (function() { var that = {}, toolBar, @@ -413,12 +437,9 @@ var toolBar = (function() { newModelButtonDown = true; return true; } + if (browseMarketplaceButton === toolBar.clicked(clickedOverlay)) { - if (marketplaceWindow.url != MARKETPLACE_URL) { - marketplaceWindow.setURL(MARKETPLACE_URL); - } - marketplaceWindow.setVisible(true); - marketplaceWindow.raise(); + toggleMarketplace(); return true; } @@ -1336,6 +1357,7 @@ function getPositionToCreateEntity() { } function importSVO(importURL) { + print("Import URL requested: " + importURL) if (!Entities.canAdjustLocks()) { Window.alert(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG); return; @@ -1574,11 +1596,7 @@ PropertiesTool = function(opts) { pushCommandForSelections(); selectionManager._update(); } else if (data.type == "showMarketplace") { - if (marketplaceWindow.url != data.url) { - marketplaceWindow.setURL(data.url); - } - marketplaceWindow.setVisible(true); - marketplaceWindow.raise(); + showMarketplace(); } else if (data.type == "action") { if (data.action == "moveSelectionToGrid") { if (selectionManager.hasSelection()) { @@ -1859,12 +1877,7 @@ var propertyMenu = PopupMenu(); propertyMenu.onSelectMenuItem = function(name) { if (propertyMenu.marketplaceID) { - var url = MARKETPLACE_URL + "/items/" + propertyMenu.marketplaceID; - if (marketplaceWindow.url != url) { - marketplaceWindow.setURL(url); - } - marketplaceWindow.setVisible(true); - marketplaceWindow.raise(); + showMarketplace(propertyMenu.marketplaceID); } }; diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 3eb01aa9ba..029d50519a 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -13,12 +13,18 @@ VrDialog { HifiConstants { id: hifi } title: "WebWindow" resizable: true + // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer + destroyOnCloseButton: false contentImplicitWidth: clientArea.implicitWidth contentImplicitHeight: clientArea.implicitHeight backgroundColor: "#7f000000" property url source: "about:blank" signal navigating(string url) + function stop() { + webview.stop(); + } + Component.onCompleted: { enabled = true @@ -26,18 +32,14 @@ VrDialog { webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); }); - webview.loadingChanged.connect(handleWebviewLoading) } function handleWebviewLoading(loadRequest) { - var HIFI_URL_PATTERN = /^hifi:\/\//; if (WebEngineView.LoadStartedStatus == loadRequest.status) { var newUrl = loadRequest.url.toString(); - if (newUrl.match(HIFI_URL_PATTERN)) { - root.navigating(newUrl); - } + root.navigating(newUrl) } } @@ -55,8 +57,10 @@ VrDialog { url: root.source anchors.fill: parent profile: WebEngineProfile { + id: webviewProfile httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)" - } + storageName: "qmlWebEngine" + } } } // item } // dialog diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e22b3913d0..7f27d97416 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4215,7 +4215,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget()); } -bool Application::canAcceptURL(const QString& urlString) { +bool Application::canAcceptURL(const QString& urlString) const { QUrl url(urlString); if (urlString.startsWith(HIFI_URL_SCHEME)) { return true; diff --git a/interface/src/Application.h b/interface/src/Application.h index a665e925a9..0953aedd8c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -38,6 +38,7 @@ #include #include #include +#include #include "avatar/AvatarUpdate.h" #include "avatar/MyAvatar.h" @@ -88,7 +89,7 @@ class Application; #endif #define qApp (static_cast(QCoreApplication::instance())) -class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface { +class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler { Q_OBJECT // TODO? Get rid of those @@ -219,8 +220,8 @@ public: QString getScriptsLocation(); void setScriptsLocation(const QString& scriptsLocation); - bool canAcceptURL(const QString& url); - bool acceptURL(const QString& url, bool defaultUpload = false); + virtual bool canAcceptURL(const QString& url) const override; + virtual bool acceptURL(const QString& url, bool defaultUpload = false) override; void setMaxOctreePacketsPerSecond(int maxOctreePPS); int getMaxOctreePacketsPerSecond(); diff --git a/libraries/networking/src/AbstractUriHandler.h b/libraries/networking/src/AbstractUriHandler.h new file mode 100644 index 0000000000..3d6ed472ec --- /dev/null +++ b/libraries/networking/src/AbstractUriHandler.h @@ -0,0 +1,19 @@ +// +// Created by Bradley Austin Davis on 2015/12/17 +// Copyright 2013-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 +// + +#pragma once +#ifndef hifi_network_AbstractUriHandler_h +#define hifi_network_AbstractUriHandler_h + +class AbstractUriHandler { +public: + virtual bool canAcceptURL(const QString& url) const = 0; + virtual bool acceptURL(const QString& url, bool defaultUpload = false) = 0; +}; + +#endif diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 636d1a9a1a..652089ebb1 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1867,7 +1867,7 @@ bool Octree::readJSONFromStream(unsigned long streamLength, QDataStream& inputSt QByteArray jsonBuffer; char* rawData = new char[READ_JSON_BUFFER_SIZE]; - while (true) { + while (!inputStream.atEnd()) { int got = inputStream.readRawData(rawData, READ_JSON_BUFFER_SIZE - 1); if (got < 0) { qCritical() << "error while reading from json stream"; diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index d5cdc1fde9..68a45a5bff 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -10,7 +10,10 @@ #include +#include #include +#include +#include #include #include @@ -22,6 +25,7 @@ #include #include +#include #include #include @@ -88,7 +92,7 @@ QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngi QmlWebWindowClass* retVal { nullptr }; const QString title = context->argument(0).toString(); QString url = context->argument(1).toString(); - if (!url.startsWith("http") && !url.startsWith("file://")) { + if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:")) { url = QUrl::fromLocalFile(url).toString(); } const int width = std::max(100, std::min(1280, context->argument(2).toInt32()));; @@ -119,7 +123,23 @@ QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) } void QmlWebWindowClass::handleNavigation(const QString& url) { - DependencyManager::get()->handleLookupString(url); + bool handled = false; + + if (url.contains(HIFI_URL_PATTERN)) { + DependencyManager::get()->handleLookupString(url); + handled = true; + } else { + static auto handler = dynamic_cast(qApp); + if (handler) { + if (handler->canAcceptURL(url)) { + handled = handler->acceptURL(url); + } + } + } + + if (handled) { + QMetaObject::invokeMethod(_qmlWindow, "stop", Qt::AutoConnection); + } } void QmlWebWindowClass::setVisible(bool visible) { @@ -202,6 +222,7 @@ QString QmlWebWindowClass::getURL() const { QMetaObject::invokeMethod(const_cast(this), "getURL", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, result)); return result; } + return _qmlWindow->property(URL_PROPERTY).toString(); } @@ -209,7 +230,23 @@ void QmlWebWindowClass::setURL(const QString& urlString) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setURL", Qt::QueuedConnection, Q_ARG(QString, urlString)); } - _qmlWindow->setProperty(URL_PROPERTY, urlString); + + static const QString ACCESS_TOKEN_PARAMETER = "access_token"; + static const QString ALLOWED_HOST = "metaverse.highfidelity.com"; + + QUrl url(urlString); + qDebug() << "Url: " << urlString; + qDebug() << "Host: " << url.host(); + if (url.host() == ALLOWED_HOST) { + QUrlQuery query(url); + if (query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) { + AccountManager& accountManager = AccountManager::getInstance(); + query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager.getAccountInfo().getAccessToken().token); + url.setQuery(query.query()); + qDebug() << "New URL " << url; + } + } + _qmlWindow->setProperty(URL_PROPERTY, url.toString()); } From b89e25f8f7f6fe1138c9521c9b309111f164838d Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 11:35:57 -0800 Subject: [PATCH 244/318] correct file --- examples/flowArts/arcBall/arcBall.js | 256 ++++++++++++++------------- 1 file changed, 131 insertions(+), 125 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index 0906b90b53..e67dffddff 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -1,139 +1,145 @@ -// arcBallEntityScript.js -// -// Script Type: Entity -// Created by Eric Levin on 12/17/15. -// Copyright 2015 High Fidelity, Inc. // -// This entity script handles the logic for the arcBall rave toy +// arcBall.js +// examples/arcBall +// +// Created by Eric Levin on 12/17/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script creats a particle light ball which makes particle trails as you move it. +// +// // 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 _this; - var ArcBall = function() { - _this = this; - this.colorPalette = [{ +Script.include("../../libraries/utils.js"); + + +var scriptURL = Script.resolvePath("arcBallEntityScript.js"); +ArcBall = function(spawnPosition) { + + var colorPalette = [{ + red: 25, + green: 20, + blue: 162 + }]; + + + var containerBall = Entities.addEntity({ + type: "Sphere", + name: "Arc Ball", + script: scriptURL, + position: Vec3.sum(spawnPosition, { + x: 0, + y: .7, + z: 0 + }), + dimensions: { + x: .05, + y: .05, + z: .05 + }, + color: { + red: 100, + green: 10, + blue: 150 + }, + ignoreForCollisions: true, + damping: 0.8, + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0, + y: 0.0, + z: -0.5 + }, + }, + // invertSolidWhileHeld: true + } + }) + }); + + + var light = Entities.addEntity({ + type: 'Light', + name: "ballLight", + parentID: containerBall, + dimensions: { + x: 30, + y: 30, + z: 30 + }, + color: colorPalette[randInt(0, colorPalette.length)], + intensity: 5 + }); + + + var arcBall = Entities.addEntity({ + type: "ParticleEffect", + parentID: containerBall, + isEmitting: true, + name: "Arc Ball Particle Effect", + colorStart: { + red: 200, + green: 20, + blue: 40 + }, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: { red: 25, green: 20, - blue: 162 - }, { - red: 200, - green: 10, - blue: 10 - }]; - }; - - ArcBall.prototype = { - isGrabbed: false, - startNearGrab: function() { - //Search for nearby balls and create an arc to it if one is found - var position = Entities.getEntityProperties(this.entityID, "position").position - var entities = Entities.findEntities(position, 10); - entities.forEach(function(entity) { - var props = Entities.getEntityProperties(entity, ["position", "name"]); - if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { - _this.target = entity; - _this.createBeam(position, props.position); - } - }); - + blue: 255 }, - - createBeam: function(startPosition, endPosition) { - // Creates particle arc from start position to end position - var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; - var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); - var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); - emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - - - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; - var props = { - type: "ParticleEffect", - name: "Particle Arc", - parentID: this.entityID, - parentJointIndex: -1, - // position: startPosition, - isEmitting: true, - colorStart: color, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 1, - emitRate: 1000, - emitOrientation: emitOrientation, - emitSpeed: .2, - speedSpread: 0.1, - emitDimensions: { - x: .1, - y: .1, - z: .1 - }, - polarStart: 0, - polarFinish: .0, - azimuthStart: .1, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.01, - radiusFinish: 0.005, - radiusSpread: .005, - alpha: 0.5, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.0, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: true - } - this.particleArc = Entities.addEntity(props); + maxParticles: 100000, + lifespan: 2, + emitRate: 400, + emitSpeed: .1, + lifetime: -1, + speedSpread: 0.0, + emitDimensions: { + x: 0, + y: 0, + z: 0 }, - - updateBeam: function(startPosition) { - var targetPosition = Entities.getEntityProperties(this.target, "position").position; - print("TARGET position " + JSON.stringify(this.target)); - var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; - var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); - var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); - // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); - Entities.editEntity(this.particleArc, { - emitOrientation: emitOrientation - }); + polarStart: 0, + polarFinish: Math.PI, + azimuthStart: -Math.PI, + azimuthFinish: Math.PI, + emitAcceleration: { + x: 0, + y: 0, + z: 0 }, - - continueNearGrab: function() { - var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - this.updateBeam(startPosition); + accelerationSpread: { + x: .00, + y: .00, + z: .00 }, + particleRadius: 0.02, + radiusSpread: 0, + radiusStart: 0.03, + radiusFinish: 0.0003, + alpha: 0, + alphaSpread: .5, + alphaStart: 0, + alphaFinish: 0.5, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + emitterShouldTrail: true + }) - releaseGrab: function() { - Entities.editEntity(this.particleArc, { - isEmitting: false - }); - }, - unload: function() { - if (this.particleArc) { - Entities.deleteEntity(this.particleArc); - } - }, - preload: function(entityID) { - this.entityID = entityID; - }, - }; - return new ArcBall(); -}); \ No newline at end of file + function cleanup() { + Entities.deleteEntity(arcBall); + Entities.deleteEntity(containerBall); + Entities.deleteEntity(light); + } + + this.cleanup = cleanup; +} \ No newline at end of file From ae124ebede205b3caa81905f676af44aae90cc6f Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Dec 2015 12:00:30 -0800 Subject: [PATCH 245/318] Tuning the proedural shader support to work with the current default: gamma corrected emissive --- libraries/procedural/src/procedural/ProceduralSkybox.slf | 3 ++- libraries/render-utils/src/RenderDeferredTask.cpp | 1 - libraries/render-utils/src/ToneMappingEffect.cpp | 2 -- libraries/render-utils/src/simple.slf | 2 ++ 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.slf b/libraries/procedural/src/procedural/ProceduralSkybox.slf index 8705278bee..7ad6f6b5a1 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.slf +++ b/libraries/procedural/src/procedural/ProceduralSkybox.slf @@ -35,6 +35,8 @@ void main(void) { #ifdef PROCEDURAL vec3 color = getSkyboxColor(); + // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline + color = pow(color, vec3(2.2)); _fragColor = vec4(color, 0.0); #else @@ -42,7 +44,6 @@ void main(void) { vec3 coord = normalize(_normal); vec3 texel = texture(cubeMap, coord).rgb; vec3 color = texel * _skybox._color.rgb; - // vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction _fragColor = vec4(color, 0.0); #endif diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ddfb6bc7a3..7fced1bdf3 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -54,7 +54,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) { context->getItemsConfig().opaque.numFeed = count; - auto& opaque = context->getItemsConfig().opaque; }) ))); _jobs.push_back(Job(new CullItemsOpaque::JobModel("CullOpaque", _jobs.back().getOutput()))); diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index a00a66fe69..2583719424 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -141,7 +141,5 @@ void ToneMappingEffect::render(RenderArgs* args) { batch.setUniformBuffer(3, _parametersBuffer); batch.setResourceTexture(0, lightingBuffer); batch.draw(gpu::TRIANGLE_STRIP, 4); - - args->_context->render(batch); }); } \ No newline at end of file diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index 576acf9340..8c93ee564e 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -40,6 +40,8 @@ void main(void) { #ifdef PROCEDURAL_V1 specular = getProceduralColor().rgb; + // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline + specular = pow(specular, vec3(2.2)); emissiveAmount = 1.0; #else emissiveAmount = getProceduralColors(diffuse, specular, shininess); From 4f54b85c9208fb2d64c5cf76dcbbd6e1057d39ed Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Dec 2015 12:05:19 -0800 Subject: [PATCH 246/318] Remove warnings --- libraries/render-utils/src/RenderDeferredTask.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 7fced1bdf3..4dcda425a1 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -104,12 +104,12 @@ RenderDeferredTask::RenderDeferredTask() : Task() { // Lighting Buffer ready for tone mapping _jobs.push_back(Job(new ToneMappingDeferred::JobModel("ToneMapping"))); - _toneMappingJobIndex = _jobs.size() - 1; + _toneMappingJobIndex = (int)_jobs.size() - 1; // Debugging Deferred buffer job _jobs.push_back(Job(new DebugDeferredBuffer::JobModel("DebugDeferredBuffer"))); _jobs.back().setEnabled(false); - _drawDebugDeferredBufferIndex = _jobs.size() - 1; + _drawDebugDeferredBufferIndex = (int)_jobs.size() - 1; // Status icon rendering job { @@ -118,7 +118,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath); _jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap)))); _jobs.back().setEnabled(false); - _drawStatusJobIndex = _jobs.size() - 1; + _drawStatusJobIndex = (int)_jobs.size() - 1; } _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); From b59b8db5c935884238d6c5f269cbc922ccbf2322 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 21 Dec 2015 12:09:18 -0800 Subject: [PATCH 247/318] set defaults --- examples/light_modifier/lightModifier.js | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/light_modifier/lightModifier.js b/examples/light_modifier/lightModifier.js index 02d764e7e2..e8a9f39903 100644 --- a/examples/light_modifier/lightModifier.js +++ b/examples/light_modifier/lightModifier.js @@ -120,6 +120,17 @@ var PER_ROW_OFFSET = { y: -0.2, z: 0 }; +var sliders = []; +var slidersRef = { + 'color_red': null, + 'color_green': null, + 'color_blue': null, + intensity: null, + cutoff: null, + exponent: null +}; +var light = null; + function entitySlider(light, color, sliderType, row) { this.light = light; @@ -351,17 +362,6 @@ entitySlider.prototype = { }; -var sliders = []; -var slidersRef = { - 'color_red': null, - 'color_green': null, - 'color_blue': null, - intensity: null, - cutoff: null, - exponent: null -} -var light = null; - function makeSliders(light) { var panel; if (USE_PARENTED_PANEL === true) { @@ -403,8 +403,6 @@ function makeSliders(light) { sliders.push(slidersRef.exponent); } - - createCloseButton(slidersRef.exponent.endOfAxis); subscribeToSliderMessages(); @@ -413,12 +411,13 @@ function makeSliders(light) { parentEntitiesToPanel(panel); } - if (SLIDERS_SHOULD_STAY_WITH_AVATAR) { - parentPanelToAvatar(panel) + if (SLIDERS_SHOULD_STAY_WITH_AVATAR === true) { + parentPanelToAvatar(panel); } }; function parentPanelToAvatar(panel) { + //this is going to need some more work re: the sliders actually being grabbable. probably something to do with updating axis movement Entities.editEntity(panel, { parentID: MyAvatar.sessionUUID, //actually figure out which one to parent it to -- probably a spine or something. @@ -427,7 +426,8 @@ function parentPanelToAvatar(panel) { } function parentEntitiesToPanel(panel) { - slidersRef.forEach(function(slider) { + + sliders.forEach(function(slider) { Entities.editEntity(slider.axis, { parentID: panel }) @@ -437,14 +437,14 @@ function parentEntitiesToPanel(panel) { }) closeButtons.forEach(function(button) { - Entities.editEntity(slider.sliderIndicator, { + Entities.editEntity(button, { parentID: panel }) }) } function createPanelEntity(position) { - + print('CREATING PANEL at ' + JSON.stringify(position)); var panelProperties = { name: 'Hifi-Slider-Panel', type: 'Box', From 4b4fe96b64808321652b4ca0e2a8d9ea056d5331 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 12:47:31 -0800 Subject: [PATCH 248/318] tweaks --- examples/flowArts/arcBall/arcBallEntityScript.js | 14 +++++++------- examples/flowArts/lightSaber/lightSaber.js | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 0906b90b53..84208bf559 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -65,19 +65,19 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 1, + lifespan: 2, emitRate: 1000, emitOrientation: emitOrientation, - emitSpeed: .2, - speedSpread: 0.1, + emitSpeed: .1, + speedSpread: 0.02, emitDimensions: { - x: .1, - y: .1, - z: .1 + x: .01, + y: .01, + z: .01 }, polarStart: 0, polarFinish: .0, - azimuthStart: .1, + azimuthStart: .02, azimuthFinish: .01, emitAcceleration: { x: 0, diff --git a/examples/flowArts/lightSaber/lightSaber.js b/examples/flowArts/lightSaber/lightSaber.js index 50984110bc..a42f81d196 100644 --- a/examples/flowArts/lightSaber/lightSaber.js +++ b/examples/flowArts/lightSaber/lightSaber.js @@ -23,6 +23,7 @@ LightSaber = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', + collisionsWillMove: true, script: scriptURL, dimensions: { x: 0.06, From 4110630d1f074fdf4c710f804d10d14539424a00 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 13:15:37 -0800 Subject: [PATCH 249/318] fixed ravestick fargrab --- examples/flowArts/raveStick/raveStick.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/flowArts/raveStick/raveStick.js b/examples/flowArts/raveStick/raveStick.js index 3e4cf16136..bcbe44168c 100644 --- a/examples/flowArts/raveStick/raveStick.js +++ b/examples/flowArts/raveStick/raveStick.js @@ -30,7 +30,8 @@ RaveStick = function(spawnPosition) { modelURL: modelURL, position: spawnPosition, shapeType: 'box', - script: scriptURL, + collisionsWillMove: true, + // script: scriptURL, dimensions: { x: 0.06, y: 0.06, From cabc47e7a9914e9e2985e932de6f74310d3bb71f Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 13:30:52 -0800 Subject: [PATCH 250/318] lightsaber immediately turns off on release --- .../flowArts/arcBall/arcBallEntityScript.js | 128 ++++++++++-------- .../lightSaber/lightSaberEntityScript.js | 4 +- 2 files changed, 76 insertions(+), 56 deletions(-) diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 84208bf559..1952209c95 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -27,7 +27,16 @@ ArcBall.prototype = { isGrabbed: false, - startNearGrab: function() { + startDistanceGrab: function() { + this.searchForNearbyArcBalls(); + + }, + + startFarGrab: function() { + this.searchForNearbyArcBalls(); + }, + + searchForNearbyArcBalls: function() { //Search for nearby balls and create an arc to it if one is found var position = Entities.getEntityProperties(this.entityID, "position").position var entities = Entities.findEntities(position, 10); @@ -36,12 +45,13 @@ if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) { _this.target = entity; _this.createBeam(position, props.position); + } }); - }, createBeam: function(startPosition, endPosition) { + // Creates particle arc from start position to end position var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(endPosition, startPosition); @@ -50,61 +60,65 @@ var color = this.colorPalette[randInt(0, this.colorPalette.length)]; - var props = { - type: "ParticleEffect", - name: "Particle Arc", - parentID: this.entityID, - parentJointIndex: -1, - // position: startPosition, - isEmitting: true, - colorStart: color, - color: { - red: 200, - green: 200, - blue: 255 - }, - colorFinish: color, - maxParticles: 100000, - lifespan: 2, - emitRate: 1000, - emitOrientation: emitOrientation, - emitSpeed: .1, - speedSpread: 0.02, - emitDimensions: { - x: .01, - y: .01, - z: .01 - }, - polarStart: 0, - polarFinish: .0, - azimuthStart: .02, - azimuthFinish: .01, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - accelerationSpread: { - x: .00, - y: .00, - z: .00 - }, - radiusStart: 0.01, - radiusFinish: 0.005, - radiusSpread: .005, - alpha: 0.5, - alphaSpread: .1, - alphaStart: 0.5, - alphaFinish: 0.0, - textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", - emitterShouldTrail: true - } + var props = { + type: "ParticleEffect", + name: "Particle Arc", + parentID: this.entityID, + parentJointIndex: -1, + // position: startPosition, + isEmitting: true, + colorStart: color, + color: { + red: 200, + green: 200, + blue: 255 + }, + colorFinish: color, + maxParticles: 100000, + lifespan: 2, + emitRate: 1000, + emitOrientation: emitOrientation, + emitSpeed: .1, + speedSpread: 0.02, + emitDimensions: { + x: .01, + y: .01, + z: .01 + }, + polarStart: 0, + polarFinish: .0, + azimuthStart: .02, + azimuthFinish: .01, + emitAcceleration: { + x: 0, + y: 0, + z: 0 + }, + accelerationSpread: { + x: .00, + y: .00, + z: .00 + }, + radiusStart: 0.01, + radiusFinish: 0.005, + radiusSpread: .005, + alpha: 0.5, + alphaSpread: .1, + alphaStart: 0.5, + alphaFinish: 0.0, + textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", + emitterShouldTrail: true + } this.particleArc = Entities.addEntity(props); }, - updateBeam: function(startPosition) { + updateBeam: function() { + if(!this.target) { + return; + } + var startPosition = Entities.getEntityProperties(this.entityID, "position").position; + var targetPosition = Entities.getEntityProperties(this.target, "position").position; - print("TARGET position " + JSON.stringify(this.target)); var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); @@ -115,14 +129,18 @@ }, continueNearGrab: function() { - var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - this.updateBeam(startPosition); + this.updateBeam(); + }, + + continueDistanceGrab: function() { + this.updateBeam(); }, releaseGrab: function() { Entities.editEntity(this.particleArc, { isEmitting: false }); + this.target = null; }, unload: function() { diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index 794e241924..cbbcd8a0bf 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -31,12 +31,14 @@ startNearGrab: function() { Entities.editEntity(this.beam, { - isEmitting: true + isEmitting: true, + visible: true }); }, releaseGrab: function() { Entities.editEntity(this.beam, { + visible: false, isEmitting: false }); }, From 876d8ab6b25a427ae16acbe459ea3e4f01b05348 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Mon, 21 Dec 2015 13:59:00 -0800 Subject: [PATCH 251/318] far grabbing arc balls --- examples/flowArts/arcBall/arcBall.js | 12 ++++++------ examples/flowArts/arcBall/arcBallEntityScript.js | 16 ++++++---------- .../lightSaber/lightSaberEntityScript.js | 1 - 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/examples/flowArts/arcBall/arcBall.js b/examples/flowArts/arcBall/arcBall.js index e67dffddff..5a6b1b47f3 100644 --- a/examples/flowArts/arcBall/arcBall.js +++ b/examples/flowArts/arcBall/arcBall.js @@ -15,7 +15,7 @@ Script.include("../../libraries/utils.js"); -var scriptURL = Script.resolvePath("arcBallEntityScript.js"); +var scriptURL = Script.resolvePath("arcBallEntityScript.js?v1" + Math.random()); ArcBall = function(spawnPosition) { var colorPalette = [{ @@ -50,11 +50,11 @@ ArcBall = function(spawnPosition) { userData: JSON.stringify({ grabbableKey: { spatialKey: { - relativePosition: { - x: 0, - y: 0.0, - z: -0.5 - }, + // relativePosition: { + // x: 0, + // y: -0.5, + // z: 0.0 + // }, }, // invertSolidWhileHeld: true } diff --git a/examples/flowArts/arcBall/arcBallEntityScript.js b/examples/flowArts/arcBall/arcBallEntityScript.js index 1952209c95..102ceca40c 100644 --- a/examples/flowArts/arcBall/arcBallEntityScript.js +++ b/examples/flowArts/arcBall/arcBallEntityScript.js @@ -27,12 +27,11 @@ ArcBall.prototype = { isGrabbed: false, - startDistanceGrab: function() { + startDistantGrab: function() { this.searchForNearbyArcBalls(); - }, - startFarGrab: function() { + startNearGrab: function() { this.searchForNearbyArcBalls(); }, @@ -58,7 +57,6 @@ var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation); - var color = this.colorPalette[randInt(0, this.colorPalette.length)]; var props = { type: "ParticleEffect", @@ -75,10 +73,10 @@ }, colorFinish: color, maxParticles: 100000, - lifespan: 2, + lifespan: 1, emitRate: 1000, emitOrientation: emitOrientation, - emitSpeed: .1, + emitSpeed: 1, speedSpread: 0.02, emitDimensions: { x: .01, @@ -105,7 +103,7 @@ alpha: 0.5, alphaSpread: .1, alphaStart: 0.5, - alphaFinish: 0.0, + alphaFinish: 0.5, textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png", emitterShouldTrail: true } @@ -117,12 +115,10 @@ return; } var startPosition = Entities.getEntityProperties(this.entityID, "position").position; - var targetPosition = Entities.getEntityProperties(this.target, "position").position; var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation; var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition); var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec); - // emitOrientation = Quat.multiply(emitOrientation,Quat.inverse(rotation)); Entities.editEntity(this.particleArc, { emitOrientation: emitOrientation }); @@ -132,7 +128,7 @@ this.updateBeam(); }, - continueDistanceGrab: function() { + continueDistantGrab: function() { this.updateBeam(); }, diff --git a/examples/flowArts/lightSaber/lightSaberEntityScript.js b/examples/flowArts/lightSaber/lightSaberEntityScript.js index cbbcd8a0bf..fd55916cc6 100644 --- a/examples/flowArts/lightSaber/lightSaberEntityScript.js +++ b/examples/flowArts/lightSaber/lightSaberEntityScript.js @@ -54,7 +54,6 @@ createBeam: function() { - this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]); var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0))); // forwardVec = Vec3.normalize(forwardVec); From 5a86f0c23fbe4f1e3c64cfe3bec987f76ea650dd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 21 Dec 2015 12:12:13 -0800 Subject: [PATCH 252/318] Nest JS props in SceneScriptingInterface --- .../src/EntityTreeRenderer.cpp | 61 ++--- libraries/model/src/model/Stage.cpp | 15 ++ libraries/model/src/model/Stage.h | 3 + .../src/SceneScriptingInterface.cpp | 211 ++++++++++-------- .../src/SceneScriptingInterface.h | 155 +++++++++---- 5 files changed, 279 insertions(+), 166 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index e3618d0e2a..996a8f3e1d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -256,33 +256,38 @@ void EntityTreeRenderer::forceRecheckEntities() { void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr zone) { QSharedPointer scene = DependencyManager::get(); + auto sceneStage = scene->getStage(); + auto sceneKeyLight = sceneStage->getKeyLight(); + auto sceneLocation = sceneStage->getLocation(); + auto sceneTime = sceneStage->getTime(); + if (zone) { if (!_hasPreviousZone) { - _previousKeyLightColor = scene->getKeyLightColor(); - _previousKeyLightIntensity = scene->getKeyLightIntensity(); - _previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity(); - _previousKeyLightDirection = scene->getKeyLightDirection(); - _previousStageSunModelEnabled = scene->isStageSunModelEnabled(); - _previousStageLongitude = scene->getStageLocationLongitude(); - _previousStageLatitude = scene->getStageLocationLatitude(); - _previousStageAltitude = scene->getStageLocationAltitude(); - _previousStageHour = scene->getStageDayTime(); - _previousStageDay = scene->getStageYearTime(); + _previousKeyLightColor = sceneKeyLight->getColor(); + _previousKeyLightIntensity = sceneKeyLight->getIntensity(); + _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity(); + _previousKeyLightDirection = sceneKeyLight->getDirection(); + _previousStageSunModelEnabled = sceneStage->isSunModelEnabled(); + _previousStageLongitude = sceneLocation->getLongitude(); + _previousStageLatitude = sceneLocation->getLatitude(); + _previousStageAltitude = sceneLocation->getAltitude(); + _previousStageHour = sceneTime->getHour(); + _previousStageDay = sceneTime->getDay(); _hasPreviousZone = true; } - scene->setKeyLightColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); - scene->setKeyLightIntensity(zone->getKeyLightProperties().getIntensity()); - scene->setKeyLightAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); - scene->setKeyLightDirection(zone->getKeyLightProperties().getDirection()); - scene->setStageSunModelEnable(zone->getStageProperties().getSunModelEnabled()); - scene->setStageLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(), + sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor())); + sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity()); + sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity()); + sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection()); + sceneStage->setSunModelEnable(zone->getStageProperties().getSunModelEnabled()); + sceneStage->setLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(), zone->getStageProperties().getAltitude()); - scene->setStageDayTime(zone->getStageProperties().calculateHour()); - scene->setStageYearTime(zone->getStageProperties().calculateDay()); + sceneTime->setHour(zone->getStageProperties().calculateHour()); + sceneTime->setDay(zone->getStageProperties().calculateDay()); if (zone->getBackgroundMode() == BACKGROUND_MODE_ATMOSPHERE) { EnvironmentData data = zone->getEnvironmentData(); - glm::vec3 keyLightDirection = scene->getKeyLightDirection(); + glm::vec3 keyLightDirection = sceneKeyLight->getDirection(); glm::vec3 inverseKeyLightDirection = keyLightDirection * -1.0f; // NOTE: is this right? It seems like the "sun" should be based on the center of the @@ -293,7 +298,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetKeyLightIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO; + float sunBrightness = sceneKeyLight->getIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO; data.setSunBrightness(sunBrightness); _viewState->overrideEnvironmentData(data); @@ -339,15 +344,15 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrsetKeyLightColor(_previousKeyLightColor); - scene->setKeyLightIntensity(_previousKeyLightIntensity); - scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity); - scene->setKeyLightDirection(_previousKeyLightDirection); - scene->setStageSunModelEnable(_previousStageSunModelEnabled); - scene->setStageLocation(_previousStageLongitude, _previousStageLatitude, + sceneKeyLight->setColor(_previousKeyLightColor); + sceneKeyLight->setIntensity(_previousKeyLightIntensity); + sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity); + sceneKeyLight->setDirection(_previousKeyLightDirection); + sceneStage->setSunModelEnable(_previousStageSunModelEnabled); + sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude, _previousStageAltitude); - scene->setStageDayTime(_previousStageHour); - scene->setStageYearTime(_previousStageDay); + sceneTime->setHour(_previousStageHour); + sceneTime->setDay(_previousStageDay); _hasPreviousZone = false; } _viewState->endOverrideEnvironmentData(); diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 67f0262b61..47d3ba3063 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -225,6 +225,21 @@ void SunSkyStage::setOriginOrientation(const Quat& orientation) { invalidate(); } +void SunSkyStage::setOriginLongitude(float longitude) { + _earthSunModel.setLongitude(longitude); + invalidate(); +} + +void SunSkyStage::setOriginLatitude(float latitude) { + _earthSunModel.setLatitude(latitude); + invalidate(); +} + +void SunSkyStage::setOriginSurfaceAltitude(float altitude) { + _earthSunModel.setAltitude(altitude); + invalidate(); +} + void SunSkyStage::setOriginLocation(float longitude, float latitude, float altitude) { _earthSunModel.setLongitude(longitude); _earthSunModel.setLatitude(latitude); diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 978c308ac6..bf586b6b55 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -184,6 +184,9 @@ public: const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); } // Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km] + void setOriginLatitude(float latitude); + void setOriginLongitude(float longitude); + void setOriginSurfaceAltitude(float surfaceAltitude); void setOriginLocation(float longitude, float latitude, float surfaceAltitude); float getOriginLatitude() const { return _earthSunModel.getLatitude(); } float getOriginLongitude() const { return _earthSunModel.getLongitude(); } diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 39bceba9d9..e3d16912f4 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -13,7 +13,118 @@ #include -SceneScriptingInterface::SceneScriptingInterface() { +float SceneScripting::Location::getLongitude() const { + return _skyStage->getOriginLongitude(); +} + +float SceneScripting::Location::getLatitude() const { + return _skyStage->getOriginLatitude(); +} + +float SceneScripting::Location::getAltitude() const { + return _skyStage->getOriginSurfaceAltitude(); +} + +void SceneScripting::Location::setLongitude(float longitude) { + _skyStage->setOriginLongitude(longitude); +} + +void SceneScripting::Location::setLatitude(float latitude) { + _skyStage->setOriginLatitude(latitude); +} + +void SceneScripting::Location::setAltitude(float altitude) { + _skyStage->setOriginSurfaceAltitude(altitude); +} + +void SceneScripting::Time::setHour(float hour) { + _skyStage->setDayTime(hour); +} + +float SceneScripting::Time::getHour() const { + return _skyStage->getDayTime(); +} + +void SceneScripting::Time::setDay(int day) { + _skyStage->setYearTime(day); +} + +int SceneScripting::Time::getDay() const { + return _skyStage->getYearTime(); +} + +glm::vec3 SceneScripting::KeyLight::getColor() const { + return _skyStage->getSunColor(); +} + +void SceneScripting::KeyLight::setColor(const glm::vec3& color) { + _skyStage->setSunColor(color); +} + +float SceneScripting::KeyLight::getIntensity() const { + return _skyStage->getSunIntensity(); +} + +void SceneScripting::KeyLight::setIntensity(float intensity) { + _skyStage->setSunIntensity(intensity); +} + +float SceneScripting::KeyLight::getAmbientIntensity() const { + return _skyStage->getSunAmbientIntensity(); +} + +void SceneScripting::KeyLight::setAmbientIntensity(float intensity) { + _skyStage->setSunAmbientIntensity(intensity); +} + +glm::vec3 SceneScripting::KeyLight::getDirection() const { + return _skyStage->getSunDirection(); +} + +void SceneScripting::KeyLight::setDirection(const glm::vec3& direction) { + _skyStage->setSunDirection(direction); +} + +void SceneScripting::Stage::setOrientation(const glm::quat& orientation) const { + _skyStage->setOriginOrientation(orientation); +} + +void SceneScripting::Stage::setLocation(float longitude, float latitude, float altitude) { + _skyStage->setOriginLocation(longitude, latitude, altitude); +} + +void SceneScripting::Stage::setSunModelEnable(bool isEnabled) { + _skyStage->setSunModelEnable(isEnabled); +} + +bool SceneScripting::Stage::isSunModelEnabled() const { + return _skyStage->isSunModelEnabled(); +} + +void SceneScripting::Stage::setBackgroundMode(const QString& mode) { + if (mode == QString("inherit")) { + _skyStage->setBackgroundMode(model::SunSkyStage::NO_BACKGROUND); + } else if (mode == QString("atmosphere")) { + _skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); + } else if (mode == QString("skybox")) { + _skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + } +} + +QString SceneScripting::Stage::getBackgroundMode() const { + switch (_skyStage->getBackgroundMode()) { + case model::SunSkyStage::NO_BACKGROUND: + return QString("inherit"); + case model::SunSkyStage::SKY_DOME: + return QString("atmosphere"); + case model::SunSkyStage::SKY_BOX: + return QString("skybox"); + default: + return QString("inherit"); + }; +} + +SceneScriptingInterface::SceneScriptingInterface() : _stage{ std::make_unique(_skyStage) } { // Let's make sure the sunSkyStage is using a proceduralSkybox _skyStage->setSkybox(model::SkyboxPointer(new ProceduralSkybox())); } @@ -32,102 +143,6 @@ void SceneScriptingInterface::setShouldRenderEntities(bool shouldRenderEntities) } } -void SceneScriptingInterface::setStageOrientation(const glm::quat& orientation) { - _skyStage->setOriginOrientation(orientation); -} -void SceneScriptingInterface::setStageLocation(float longitude, float latitude, float altitude) { - _skyStage->setOriginLocation(longitude, latitude, altitude); -} - -float SceneScriptingInterface::getStageLocationLongitude() const { - return _skyStage->getOriginLongitude(); -} -float SceneScriptingInterface::getStageLocationLatitude() const { - return _skyStage->getOriginLatitude(); -} -float SceneScriptingInterface::getStageLocationAltitude() const { - return _skyStage->getOriginSurfaceAltitude(); -} - -void SceneScriptingInterface::setStageDayTime(float hour) { - _skyStage->setDayTime(hour); -} - -float SceneScriptingInterface::getStageDayTime() const { - return _skyStage->getDayTime(); -} - -void SceneScriptingInterface::setStageYearTime(int day) { - _skyStage->setYearTime(day); -} - -int SceneScriptingInterface::getStageYearTime() const { - return _skyStage->getYearTime(); -} - -void SceneScriptingInterface::setKeyLightColor(const glm::vec3& color) { - _skyStage->setSunColor(color); -} - -glm::vec3 SceneScriptingInterface::getKeyLightColor() const { - return _skyStage->getSunColor(); -} - -void SceneScriptingInterface::setKeyLightIntensity(float intensity) { - _skyStage->setSunIntensity(intensity); -} - -float SceneScriptingInterface::getKeyLightIntensity() const { - return _skyStage->getSunIntensity(); -} - -void SceneScriptingInterface::setKeyLightAmbientIntensity(float intensity) { - _skyStage->setSunAmbientIntensity(intensity); -} - -float SceneScriptingInterface::getKeyLightAmbientIntensity() const { - return _skyStage->getSunAmbientIntensity(); -} - -void SceneScriptingInterface::setKeyLightDirection(const glm::vec3& direction) { - _skyStage->setSunDirection(direction); -} - -glm::vec3 SceneScriptingInterface::getKeyLightDirection() const { - return _skyStage->getSunDirection(); -} - -void SceneScriptingInterface::setStageSunModelEnable(bool isEnabled) { - _skyStage->setSunModelEnable(isEnabled); -} - -bool SceneScriptingInterface::isStageSunModelEnabled() const { - return _skyStage->isSunModelEnabled(); -} - -void SceneScriptingInterface::setBackgroundMode(const QString& mode) { - if (mode == QString("inherit")) { - _skyStage->setBackgroundMode(model::SunSkyStage::NO_BACKGROUND); - } else if (mode == QString("atmosphere")) { - _skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); - } else if (mode == QString("skybox")) { - _skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX); - } -} - -QString SceneScriptingInterface::getBackgroundMode() const { - switch (_skyStage->getBackgroundMode()) { - case model::SunSkyStage::NO_BACKGROUND: - return QString("inherit"); - case model::SunSkyStage::SKY_DOME: - return QString("atmosphere"); - case model::SunSkyStage::SKY_BOX: - return QString("skybox"); - default: - return QString("inherit"); - }; -} - model::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { return _skyStage; -} +} \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index abc4ee68a9..da107b3126 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -17,6 +17,112 @@ #include "model/Stage.h" +// TODO: if QT moc ever supports nested classes, subclass these to the interface instead of namespacing +namespace SceneScripting { + class Location : public QObject { + Q_OBJECT + + public: + Location(model::SunSkyStagePointer skyStage) : _skyStage{ skyStage } {} + + Q_PROPERTY(float longitude READ getLongitude WRITE setLongitude) + Q_PROPERTY(float latitude READ getLatitude WRITE setLatitude) + Q_PROPERTY(float altitude READ getAltitude WRITE setAltitude) + + float getLongitude() const; + float getLatitude() const; + float getAltitude() const; + void setLongitude(float longitude); + void setLatitude(float latitude); + void setAltitude(float altitude); + + protected: + model::SunSkyStagePointer _skyStage; + }; + using LocationPointer = std::unique_ptr; + + class Time : public QObject { + Q_OBJECT + + public: + Time(model::SunSkyStagePointer skyStage) : _skyStage{ skyStage } {} + + Q_PROPERTY(float hour READ getHour WRITE setHour) + Q_PROPERTY(int day READ getDay WRITE setDay) + + float getHour() const; + void setHour(float hour); + int getDay() const; + void setDay(int day); + + protected: + model::SunSkyStagePointer _skyStage; + }; + using TimePointer = std::unique_ptr