From e6bafb9bf1a202415540f955fcea739abc108738 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 11 Jun 2015 16:19:54 -0700 Subject: [PATCH 1/7] Draggable toolBar.js, with persistence, and update some scripts for it. --- examples/controllers/hydra/gun.js | 23 ++++++---- examples/dice.js | 24 +++++++---- examples/edit.js | 11 +++++ examples/libraries/toolBars.js | 70 +++++++++++++++++++++++++++++-- examples/pointer.js | 16 +++++-- 5 files changed, 119 insertions(+), 25 deletions(-) diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js index 146f9daca3..7d024e2fd3 100644 --- a/examples/controllers/hydra/gun.js +++ b/examples/controllers/hydra/gun.js @@ -99,6 +99,13 @@ var NUM_BUTTONS = 3; var screenSize = Controller.getViewportDimensions(); var startX = screenSize.x / 2 - (NUM_BUTTONS * (BUTTON_SIZE + PADDING)) / 2; +Script.include(["../../libraries/toolBars.js"]); +const persistKey = "highfidelity.gun.toolbar.position"; +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); +toolBar.save = function () { + Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); +}; +var old = JSON.parse(Settings.getValue(persistKey) || '0'); var reticle = Overlays.addOverlay("image", { x: screenSize.x / 2 - (BUTTON_SIZE / 2), y: screenSize.y / 2 - (BUTTON_SIZE / 2), @@ -108,9 +115,9 @@ var reticle = Overlays.addOverlay("image", { alpha: 1 }); -var offButton = Overlays.addOverlay("image", { - x: startX, - y: screenSize.y - (BUTTON_SIZE + PADDING), +var offButton = toolBar.addOverlay("image", { + x: old ? old[0] : startX, + y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)), width: BUTTON_SIZE, height: BUTTON_SIZE, imageURL: HIFI_PUBLIC_BUCKET + "images/gun/close.svg", @@ -118,7 +125,7 @@ var offButton = Overlays.addOverlay("image", { }); startX += BUTTON_SIZE + PADDING; -var platformButton = Overlays.addOverlay("image", { +var platformButton = toolBar.addOverlay("image", { x: startX, y: screenSize.y - (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, @@ -128,7 +135,7 @@ var platformButton = Overlays.addOverlay("image", { }); startX += BUTTON_SIZE + PADDING; -var gridButton = Overlays.addOverlay("image", { +var gridButton = toolBar.addOverlay("image", { x: startX, y: screenSize.y - (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, @@ -493,10 +500,8 @@ function mousePressEvent(event) { } function scriptEnding() { - Overlays.deleteOverlay(reticle); - Overlays.deleteOverlay(offButton); - Overlays.deleteOverlay(platformButton); - Overlays.deleteOverlay(gridButton); + Overlays.deleteOverlay(reticle); + toolBar.cleanup(); Overlays.deleteOverlay(pointer[0]); Overlays.deleteOverlay(pointer[1]); Overlays.deleteOverlay(text); diff --git a/examples/dice.js b/examples/dice.js index 515019e740..ac5d1b7426 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -3,6 +3,7 @@ // examples // // Created by Philip Rosedale on February 2, 2015 +// Persist toolbar by HRS 6/11/15. // Copyright 2015 High Fidelity, Inc. // // Press the dice button to throw some dice from the center of the screen. @@ -31,9 +32,16 @@ var screenSize = Controller.getViewportDimensions(); var BUTTON_SIZE = 32; var PADDING = 3; -var offButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, - y: screenSize.y - (BUTTON_SIZE + PADDING), +Script.include(["libraries/toolBars.js"]); +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); +const persistKey = "highfidelity.dice.toolbar.position"; +toolBar.save = function () { + Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); +}; +var old = JSON.parse(Settings.getValue(persistKey) || '0'); +var offButton = toolBar.addOverlay("image", { + x: old ? old[0] : (screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING), + y: old ? old[1] : (screenSize.y - (BUTTON_SIZE + PADDING)), width: BUTTON_SIZE, height: BUTTON_SIZE, imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", @@ -45,7 +53,7 @@ var offButton = Overlays.addOverlay("image", { alpha: 1 }); -var deleteButton = Overlays.addOverlay("image", { +var deleteButton = toolBar.addOverlay("image", { x: screenSize.x / 2 - BUTTON_SIZE, y: screenSize.y - (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, @@ -59,7 +67,7 @@ var deleteButton = Overlays.addOverlay("image", { alpha: 1 }); -var diceButton = Overlays.addOverlay("image", { +var diceButton = toolBar.addOverlay("image", { x: screenSize.x / 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, @@ -140,10 +148,8 @@ function mousePressEvent(event) { } function scriptEnding() { - Overlays.deleteOverlay(offButton); - Overlays.deleteOverlay(diceButton); - Overlays.deleteOverlay(deleteButton); + toolBar.cleanup(); } Controller.mousePressEvent.connect(mousePressEvent); -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/edit.js b/examples/edit.js index 6055400289..2974397cde 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -2,6 +2,7 @@ // examples // // Created by Brad Hefta-Gaub on 10/2/14. +// Persist toolbar by HRS 6/11/15. // Copyright 2014 High Fidelity, Inc. // // This script allows you to edit entities with a new UI/UX for mouse and trackpad based editing @@ -320,6 +321,7 @@ var toolBar = (function () { } } + const persistKey = "highfidelity.edit.toolbar.position"; that.move = function () { var newViewPort, toolsX, @@ -330,6 +332,15 @@ var toolBar = (function () { if (toolBar === undefined) { initialize(); + toolBar.save = function () { + Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); + }; + var old = JSON.parse(Settings.getValue(persistKey) || '0'); + if (old) { + windowDimensions = newViewPort; + toolBar.move(old[0], old[1]); + return; + } } else if (windowDimensions.x === newViewPort.x && windowDimensions.y === newViewPort.y) { return; diff --git a/examples/libraries/toolBars.js b/examples/libraries/toolBars.js index 670a69dec7..94bc1c8af0 100644 --- a/examples/libraries/toolBars.js +++ b/examples/libraries/toolBars.js @@ -236,6 +236,7 @@ ToolBar = function(x, y, direction) { y: y - ToolBar.SPACING }); } + this.save(); } this.setAlpha = function(alpha, tool) { @@ -313,9 +314,8 @@ ToolBar = function(x, y, direction) { this.cleanup = function() { for(var tool in this.tools) { this.tools[tool].cleanup(); - delete this.tools[tool]; } - + if (this.back != null) { Overlays.deleteOverlay(this.back); this.back = null; @@ -327,7 +327,71 @@ ToolBar = function(x, y, direction) { this.width = 0; this.height = 0; } + + var that = this; + this.contains = function (xOrPoint, optionalY) { + var x = (optionalY === undefined) ? xOrPoint.x : xOrPoint, + y = (optionalY === undefined) ? xOrPoint.y : optionalY; + return (that.x <= x) && (x <= (that.x + that.width)) && + (that.y <= y) && (y <= (that.y + that.height)); + } + that.hover = function (enable) { + that.isHovering = enable; + if (that.back) { + if (enable) { + that.oldAlpha = Overlays.getProperty(that.back, 'backgroundAlpha'); + } + Overlays.editOverlay(this.back, { + visible: enable, + backgroundAlpha: enable ? 0.5 : that.oldAlpha + }); + } + }; + // These are currently only doing that which is necessary for toolbar hover and toolbar drag. + // They have not yet been extended to tool hover/click/release, etc. + this.mousePressEvent = function (event) { + if (!that.contains(event)) { + that.mightBeDragging = false; + return; + } + that.mightBeDragging = true; + that.dragOffsetX = that.x - event.x; + that.dragOffsetY = that.y - event.y; + }; + this.mouseMove = function (event) { + if (!that.mightBeDragging || !event.isLeftButton) { + that.mightBeDragging = false; + if (!that.contains(event)) { + if (that.isHovering) { + that.hover(false); + } + return; + } + if (!that.isHovering) { + that.hover(true); + } + return; + } + that.move(that.dragOffsetX + event.x, that.dragOffsetY + event.y); + }; + Controller.mousePressEvent.connect(this.mousePressEvent); + Controller.mouseMoveEvent.connect(this.mouseMove); + // Called on move. A different approach would be to have all this on the prototype, + // and let apps extend where needed. Ex. app defines its toolbar.move() to call this.__proto__.move and then save. + this.save = function () { }; + // This compatability hack breaks the model, but makes converting existing scripts easier: + this.addOverlay = function (ignored, oldSchoolProperties) { + var properties = JSON.parse(JSON.stringify(oldSchoolProperties)); // a copy + if (that.numberOfTools() === 0) { + that.move(properties.x, properties.y); + } + delete properties.x; + delete properties.y; + var index = that.addTool(properties); + var id = that.tools[index].overlay(); + return id; + } } ToolBar.SPACING = 4; ToolBar.VERTICAL = 0; -ToolBar.HORIZONTAL = 1; \ No newline at end of file +ToolBar.HORIZONTAL = 1; diff --git a/examples/pointer.js b/examples/pointer.js index cca46709ee..ea6b0c233f 100644 --- a/examples/pointer.js +++ b/examples/pointer.js @@ -3,6 +3,7 @@ // // Created by Seth Alves on May 15th // Modified by Eric Levin on June 4 +// Persist toolbar by HRS 6/11/15. // Copyright 2015 High Fidelity, Inc. // // Provides a pointer with option to draw on surfaces @@ -31,9 +32,16 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var screenSize = Controller.getViewportDimensions(); var userCanPoint = false; -var pointerButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, - y: screenSize.y - (BUTTON_SIZE + PADDING), +Script.include(["libraries/toolBars.js"]); +const persistKey = "highfidelity.pointer.toolbar.position"; +var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); +toolBar.save = function () { + Settings.setValue(persistKey, JSON.stringify([toolBar.x, toolBar.y])); +}; +var old = JSON.parse(Settings.getValue(persistKey) || '0'); +var pointerButton = toolBar.addOverlay("image", { + x: old ? old[0] : screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, + y: old ? old[1] : screenSize.y - (BUTTON_SIZE + PADDING), width: BUTTON_SIZE, height: BUTTON_SIZE, imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png", @@ -150,4 +158,4 @@ Script.scriptEnding.connect(cleanup); Controller.mouseMoveEvent.connect(mouseMoveEvent); Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); \ No newline at end of file +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); From 3cb4ee183e615a2fcf9192c5a1802cac70cbc100 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 11 Jun 2015 16:24:22 -0700 Subject: [PATCH 2/7] Update header. --- examples/libraries/toolBars.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/libraries/toolBars.js b/examples/libraries/toolBars.js index 94bc1c8af0..6e72795ea5 100644 --- a/examples/libraries/toolBars.js +++ b/examples/libraries/toolBars.js @@ -3,6 +3,7 @@ // examples // // Created by Clément Brisset on 5/7/14. +// Persistable drag position by HRS 6/11/15. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. From 7ee609396c5045ae976b8b72dee5fddbacdb974c Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Fri, 12 Jun 2015 11:58:43 -0700 Subject: [PATCH 3/7] added lifetime to painted lines to prevent huge model.json files when lots of people draw in one domain. Got rid of gaps in lines when switching line entities --- examples/paint.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/paint.js b/examples/paint.js index 8bba4e2571..c0cc93afc7 100644 --- a/examples/paint.js +++ b/examples/paint.js @@ -12,8 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // Script.include('lineRider.js') -var MAX_POINTS_PER_LINE = 80; - +var MAX_POINTS_PER_LINE = 30; +var LINE_LIFETIME = 60 * 5 //5 minute lifetime var colorPalette = [{ red: 236, @@ -120,10 +120,12 @@ function MousePaint() { y: 10, z: 10 }, - lineWidth: LINE_WIDTH + lineWidth: LINE_WIDTH, + lifetime: LINE_LIFETIME }); points = []; if (point) { + points.push(point); path.push(point); } @@ -133,22 +135,22 @@ function MousePaint() { function mouseMoveEvent(event) { + if (!isDrawing) { + return; + } var pickRay = Camera.computePickRay(event.x, event.y); var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); var point = Vec3.sum(Camera.getPosition(), addVector); + points.push(point); + path.push(point); Entities.editEntity(line, { linePoints: points }); Entities.editEntity(brush, { position: point }); - if (!isDrawing) { - return; - } - points.push(point); - path.push(point); if (points.length === MAX_POINTS_PER_LINE) { //We need to start a new line! @@ -253,7 +255,6 @@ function HydraPaint() { var maxLineWidth = 10; var currentLineWidth = minLineWidth; var MIN_PAINT_TRIGGER_THRESHOLD = .01; - var LINE_LIFETIME = 20; var COLOR_CHANGE_TIME_FACTOR = 0.1; var RIGHT_BUTTON_1 = 7 @@ -330,7 +331,7 @@ function HydraPaint() { z: 10 }, lineWidth: 5, - // lifetime: LINE_LIFETIME + lifetime: LINE_LIFETIME }); this.points = []; if (point) { From 648f9bebdf8676ea31c5aa2d00ead97958c0eca3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Jun 2015 15:58:26 -0700 Subject: [PATCH 4/7] add LOD stats to the default stats --- interface/src/ui/Stats.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 8d098b4dc8..8359480b03 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -464,7 +464,7 @@ void Stats::display( verticalOffset = STATS_PELS_INITIALOFFSET; horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3; - lines = _expanded ? 10 : 2; + lines = _expanded ? 10 : 3; drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset, (lines + 1) * STATS_PELS_PER_LINE); @@ -612,12 +612,10 @@ void Stats::display( } // LOD Details - if (_expanded) { - octreeStats.str(""); - QString displayLODDetails = DependencyManager::get()->getLODFeedbackText(); - octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed()); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); - } + octreeStats.str(""); + QString displayLODDetails = DependencyManager::get()->getLODFeedbackText(); + octreeStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed()); + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); } From c1668553fd46dfc24b57c4e123ee0ab13a902f3b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 15 Jun 2015 11:22:07 -0700 Subject: [PATCH 5/7] make sure that the root node always appends an entity count (even if it's zero). This keeps the unreasonably-deep-recursion warnings from happening --- libraries/entities/src/EntityTreeElement.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 5a59636fe7..5ccac49728 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -350,6 +350,8 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } } else { // we we couldn't add the entity count, then we couldn't add anything for this element and we're in a NONE state + if (this == _myTree->getRoot()) + qDebug() << "OctreeElement::NONE 0";; appendElementState = OctreeElement::NONE; } @@ -392,17 +394,20 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData // If we wrote fewer entities than we expected, update the number of entities in our packet bool successUpdateEntityCount = true; - if (!noEntitiesFit && numberOfEntities != actualNumberOfEntities) { + if (numberOfEntities != actualNumberOfEntities) { successUpdateEntityCount = packetData->updatePriorBytes(numberOfEntitiesOffset, (const unsigned char*)&actualNumberOfEntities, sizeof(actualNumberOfEntities)); } // If we weren't able to update our entity count, or we couldn't fit any entities, then // we should discard our element and return a result of NONE - if (!successUpdateEntityCount || noEntitiesFit) { + if (!successUpdateEntityCount) { packetData->discardLevel(elementLevel); appendElementState = OctreeElement::NONE; } else { + if (noEntitiesFit) { + appendElementState = OctreeElement::PARTIAL; + } packetData->endLevel(elementLevel); } return appendElementState; From 5f3b9027986b6e6de6ed43468deced53826abc51 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 15 Jun 2015 11:24:29 -0700 Subject: [PATCH 6/7] remove debugging print --- libraries/entities/src/EntityTreeElement.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 5ccac49728..80333a44e5 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -350,8 +350,6 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } } else { // we we couldn't add the entity count, then we couldn't add anything for this element and we're in a NONE state - if (this == _myTree->getRoot()) - qDebug() << "OctreeElement::NONE 0";; appendElementState = OctreeElement::NONE; } From 1c3b48446659703005cc0de28634eae752ee1895 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 15 Jun 2015 12:48:51 -0700 Subject: [PATCH 7/7] fix detailed ray picking against models --- libraries/render-utils/src/Model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 145f352658..71178070c6 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1761,7 +1761,7 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) { } AABox Model::getPartBounds(int meshIndex, int partIndex) { - if (!_calculatedMeshPartBoxesValid) { + if (!_calculatedMeshPartBoxesValid || !_calculatedMeshBoxesValid) { recalculateMeshBoxes(true); } @@ -1802,7 +1802,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran // we always need these properly calculated before we can render, this will likely already have been done // since the engine will call our getPartBounds() before rendering us. - if (!_calculatedMeshPartBoxesValid) { + if (!_calculatedMeshPartBoxesValid || !_calculatedMeshBoxesValid) { recalculateMeshBoxes(true); } auto textureCache = DependencyManager::get();