From a50c3c1696873d1c7fd2d9c921816f5d04192e3e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 7 Nov 2014 12:04:03 -0800 Subject: [PATCH 01/45] Fix order of wrist and hand joints in Leapmotion controller --- examples/leapHands.js | 4 ++-- interface/src/devices/Leapmotion.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/leapHands.js b/examples/leapHands.js index 437637dc3f..47e4a51552 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -353,7 +353,7 @@ var leapHands = (function () { handOffset.x = -handOffset.x; // Hand rotation in camera coordinates ... - handRotation = wrists[h].controller.getAbsRotation(); + handRotation = hands[h].controller.getAbsRotation(); handRotation = { x: handRotation.z, y: handRotation.y, @@ -386,7 +386,7 @@ var leapHands = (function () { z: hands[h].zeroPosition.z - handOffset.z }; - handRotation = wrists[h].controller.getAbsRotation(); + handRotation = hands[h].controller.getAbsRotation(); handRotation = { x: handRotation.z, y: handRotation.y, diff --git a/interface/src/devices/Leapmotion.cpp b/interface/src/devices/Leapmotion.cpp index a3794123ce..0c1433f216 100644 --- a/interface/src/devices/Leapmotion.cpp +++ b/interface/src/devices/Leapmotion.cpp @@ -70,8 +70,8 @@ Leapmotion::Leapmotion() : std::vector< Semantic > rootBones; rootBones.push_back("elbow"); - rootBones.push_back("hand"); rootBones.push_back("wrist"); + rootBones.push_back("hand"); std::vector< Semantic > fingers; fingers.push_back("thumb"); From 5f259791a30b92b0b3fe0f0ed145aac740a5b512 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 7 Nov 2014 12:07:04 -0800 Subject: [PATCH 02/45] Control "hand" joint with wrist position estimate if no "wrist" joint --- examples/leapHands.js | 127 +++++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 46 deletions(-) diff --git a/examples/leapHands.js b/examples/leapHands.js index 47e4a51552..04253c8ab6 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -17,12 +17,16 @@ var leapHands = (function () { LEAP_ON_HMD_MENU_ITEM = "Leap Motion on HMD", LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip HMD_OFFSET = 0.070, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief + hasHandAndWristJoints, + handToWristOffset = [], // For avatars without a wrist joint we control an estimate of a proper hand joint position + HAND_OFFSET = 0.4, // Relative distance of wrist to hand versus wrist to index finger knuckle hands, wrists, NUM_HANDS = 2, // 0 = left; 1 = right fingers, NUM_FINGERS = 5, // 0 = thumb; ...; 4 = pinky THUMB = 0, + MIDDLE_FINGER = 2, NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal joint MAX_HAND_INACTIVE_COUNT = 20, calibrationStatus, @@ -123,30 +127,41 @@ var leapHands = (function () { function finishCalibration() { var avatarPosition, - avatarOrientation, - avatarHandPosition, + handPosition, + middleFingerPosition, leapHandHeight, h; - if (hands[0].controller.isActive() && hands[1].controller.isActive()) { - leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; - } else { - calibrationStatus = UNCALIBRATED; - return; + if (!isOnHMD) { + if (hands[0].controller.isActive() && hands[1].controller.isActive()) { + leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; + } else { + calibrationStatus = UNCALIBRATED; + return; + } } avatarPosition = MyAvatar.position; - avatarOrientation = MyAvatar.orientation; for (h = 0; h < NUM_HANDS; h += 1) { - avatarHandPosition = MyAvatar.getJointPosition(hands[h].jointName); - hands[h].zeroPosition = { - x: avatarHandPosition.x - avatarPosition.x, - y: avatarHandPosition.y - avatarPosition.y, - z: avatarPosition.z - avatarHandPosition.z - }; - hands[h].zeroPosition = Vec3.multiplyQbyV(MyAvatar.orientation, hands[h].zeroPosition); - hands[h].zeroPosition.y = hands[h].zeroPosition.y - leapHandHeight; + handPosition = MyAvatar.getJointPosition(hands[h].jointName); + if (!hasHandAndWristJoints) { + middleFingerPosition = MyAvatar.getJointPosition(fingers[h][MIDDLE_FINGER][0].jointName); + handToWristOffset[h] = Vec3.multiply(Vec3.subtract(handPosition, middleFingerPosition), 1.0 - HAND_OFFSET); + } + + if (isOnHMD) { + // Offset of Leap Motion origin from physical eye position + hands[h].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; + } else { + hands[h].zeroPosition = { + x: handPosition.x - avatarPosition.x, + y: handPosition.y - avatarPosition.y, + z: avatarPosition.z - handPosition.z + }; + hands[h].zeroPosition = Vec3.multiplyQbyV(MyAvatar.orientation, hands[h].zeroPosition); + hands[h].zeroPosition.y = hands[h].zeroPosition.y - leapHandHeight; + } } MyAvatar.clearJointData("LeftHand"); @@ -161,6 +176,8 @@ var leapHands = (function () { } function calibrate() { + var jointNames, + i; calibrationStatus = CALIBRATING; @@ -168,6 +185,13 @@ var leapHands = (function () { avatarFaceModelURL = MyAvatar.faceModelURL; avatarSkeletonModelURL = MyAvatar.skeletonModelURL; + // Does this skeleton have both wrist and hand joints? + hasHandAndWristJoints = false; + jointNames = MyAvatar.getJointNames(); + for (i = 0; i < jointNames.length; i += 1) { + hasHandAndWristJoints = hasHandAndWristJoints || jointNames[i].toLowerCase() === "leftwrist"; + } + // Set avatar arms vertical, forearms horizontal, as "zero" position for calibration MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, -90.0)); MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0)); @@ -176,6 +200,7 @@ var leapHands = (function () { MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0)); MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); + // Wait for arms to assume their positions before calculating Script.setTimeout(finishCalibration, CALIBRATION_TIME); } @@ -195,37 +220,34 @@ var leapHands = (function () { function setIsOnHMD() { isOnHMD = Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM); - if (isOnHMD) { - print("Leap Motion: Is on HMD"); - - // Offset of Leap Motion origin from physical eye position - hands[0].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; - hands[1].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; - - calibrationStatus = CALIBRATED; - } else { - print("Leap Motion: Is on desk"); - calibrationStatus = UNCALIBRATED; - } + print("Leap Motion: " + (isOnHMD ? "Is on HMD" : "Is on desk")); } function checkSettings() { - // There is no "scale changed" event so we need check periodically. - if (!isOnHMD && calibrationStatus > UNCALIBRATED && (MyAvatar.scale !== avatarScale + if (calibrationStatus > UNCALIBRATED && (MyAvatar.scale !== avatarScale || MyAvatar.faceModelURL !== avatarFaceModelURL - || MyAvatar.skeletonModelURL !== avatarSkeletonModelURL)) { - print("Leap Motion: Recalibrate because avatar body or scale changed"); + || MyAvatar.skeletonModelURL !== avatarSkeletonModelURL + || Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM) !== isOnHMD)) { + print("Leap Motion: Recalibrate..."); calibrationStatus = UNCALIBRATED; - } - // There is a "menu changed" event but we may as well check here. - if (isOnHMD !== Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM)) { setIsOnHMD(); } } function setUp() { + wrists = [ + { + jointName: "LeftWrist", + controller: Controller.createInputController("Spatial", "joint_L_wrist") + }, + { + jointName: "RightWrist", + controller: Controller.createInputController("Spatial", "joint_R_wrist") + } + ]; + hands = [ { jointName: "LeftHand", @@ -239,11 +261,6 @@ var leapHands = (function () { } ]; - wrists = [ - { controller: Controller.createInputController("Spatial", "joint_L_wrist") }, - { controller: Controller.createInputController("Spatial", "joint_R_wrist") } - ]; - // The Leap controller's first joint is the hand-metacarpal joint but this joint's data is not used because it's too // dependent on the model skeleton exactly matching the Leap skeleton; using just the second and subsequent joints // seems to work better over all. @@ -306,6 +323,8 @@ var leapHands = (function () { setIsOnHMD(); settingsTimer = Script.setInterval(checkSettings, 2000); + + calibrationStatus = UNCALIBRATED; } function moveHands() { @@ -314,6 +333,7 @@ var leapHands = (function () { j, side, handOffset, + wristOffset, handRotation, locRotation, cameraOrientation, @@ -330,10 +350,18 @@ var leapHands = (function () { } // Hand position ... + handOffset = hands[h].controller.getAbsTranslation(); + handRotation = hands[h].controller.getAbsRotation(); + if (isOnHMD) { + // Adjust to control wrist position if "hand" joint is at wrist ... + if (!hasHandAndWristJoints) { + wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]); + handOffset = Vec3.sum(handOffset, wristOffset); + } + // Hand offset in camera coordinates ... - handOffset = hands[h].controller.getAbsTranslation(); handOffset = { x: hands[h].zeroPosition.x - handOffset.x, y: hands[h].zeroPosition.y - handOffset.z, @@ -353,7 +381,6 @@ var leapHands = (function () { handOffset.x = -handOffset.x; // Hand rotation in camera coordinates ... - handRotation = hands[h].controller.getAbsRotation(); handRotation = { x: handRotation.z, y: handRotation.y, @@ -361,6 +388,7 @@ var leapHands = (function () { w: handRotation.w }; + // Hand rotation in avatar coordinates ... if (h === 0) { handRotation.x = -handRotation.x; handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); @@ -371,7 +399,6 @@ var leapHands = (function () { handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation); } - // Hand rotation in avatar coordinates ... cameraOrientation.x = -cameraOrientation.x; cameraOrientation.z = -cameraOrientation.z; handRotation = Quat.multiply(cameraOrientation, handRotation); @@ -379,14 +406,20 @@ var leapHands = (function () { } else { - handOffset = hands[h].controller.getAbsTranslation(); + // Adjust to control wrist position if "hand" joint is at wrist ... + if (!hasHandAndWristJoints) { + wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]); + handOffset = Vec3.sum(handOffset, wristOffset); + } + + // Hand offset in camera coordinates ... handOffset = { x: -handOffset.x, y: hands[h].zeroPosition.y + handOffset.y, z: hands[h].zeroPosition.z - handOffset.z }; - handRotation = hands[h].controller.getAbsRotation(); + // Hand rotation in camera coordinates ... handRotation = { x: handRotation.z, y: handRotation.y, @@ -394,6 +427,7 @@ var leapHands = (function () { w: handRotation.w }; + // Hand rotation in avatar coordinates ... if (h === 0) { handRotation.x = -handRotation.x; handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), @@ -405,9 +439,10 @@ var leapHands = (function () { } } + // Set hand position and orientation ... MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true); - // Finger joints ... + // Set finger joints ... for (i = 0; i < NUM_FINGERS; i += 1) { for (j = 0; j < NUM_FINGER_JOINTS; j += 1) { if (fingers[h][i][j].controller !== null) { From 6cf833cf987e6c424ddd21bdc2f15529dac61997 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 11 Nov 2014 17:31:49 -0800 Subject: [PATCH 03/45] Add text overlay textWidth() method --- interface/src/ui/overlays/Overlays.cpp | 16 ++++++++++++++++ interface/src/ui/overlays/Overlays.h | 4 ++++ interface/src/ui/overlays/Text3DOverlay.cpp | 12 +++++++++--- interface/src/ui/overlays/Text3DOverlay.h | 2 ++ interface/src/ui/overlays/TextOverlay.cpp | 10 +++++++--- interface/src/ui/overlays/TextOverlay.h | 3 +++ 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index df7a5fbcea..b65fe6d286 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -9,6 +9,7 @@ // #include +#include #include #include @@ -357,3 +358,18 @@ bool Overlays::isLoaded(unsigned int id) { return overlay->isLoaded(); } +float Overlays::textWidth(unsigned int id, const QString& text) { + if (_overlays2D.contains(id)) { + Overlay* thisOverlay = _overlays2D[id]; + if (typeid(*thisOverlay) == typeid(TextOverlay)) { + return static_cast(thisOverlay)->textWidth(text); + } + } + if (_overlays3D.contains(id)) { + Overlay* thisOverlay = _overlays3D[id]; + if (typeid(*thisOverlay) == typeid(Text3DOverlay)) { + return static_cast(thisOverlay)->textWidth(text); + } + } + return 0.f; +} diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 686b998267..dcda9a8ed7 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -65,6 +65,10 @@ public slots: /// returns whether the overlay's assets are loaded or not bool isLoaded(unsigned int id); + /// returns the width of the given text in the specified overlay if it is a text overlay: in pixels if it is a 2D text + /// overlay; in meters if it is a 3D text overlay + float textWidth(unsigned int id, const QString& text); + private: QMap _overlays2D; QMap _overlays3D; diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index d8febbf0eb..5928e328ba 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -17,6 +17,8 @@ const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 }; const float DEFAULT_MARGIN = 0.1f; +const int FIXED_FONT_POINT_SIZE = 40; +const float LINE_SCALE_RATIO = 1.2f; Text3DOverlay::Text3DOverlay() : _backgroundColor(DEFAULT_BACKGROUND_COLOR), @@ -87,11 +89,10 @@ void Text3DOverlay::render(RenderArgs* args) { glVertex3f(-halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); glEnd(); - const int FIXED_FONT_POINT_SIZE = 40; const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 40.0f; // this is a ratio determined through experimentation + // Same font properties as textWidth() TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); - float LINE_SCALE_RATIO = 1.2f; float maxHeight = (float)textRenderer->calculateHeight("Xy") * LINE_SCALE_RATIO; float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight; @@ -179,4 +180,9 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) { } - +float Text3DOverlay::textWidth(const QString& text) { + QFont font(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); // Same font properties as render() + QFontMetrics fontMetrics(font); + float scaleFactor = _lineHeight * LINE_SCALE_RATIO / (float)FIXED_FONT_POINT_SIZE; + return scaleFactor * (float)fontMetrics.width(qPrintable(text)); +} diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index 45e311c554..f0369b4206 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -48,6 +48,8 @@ public: virtual void setProperties(const QScriptValue& properties); + float textWidth(const QString& text); // Meters + private: void enableClipPlane(GLenum plane, float x, float y, float z, float w); diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 530b30a856..9f194b75dd 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -66,9 +66,8 @@ void TextOverlay::render(RenderArgs* args) { glVertex2f(_bounds.left(), _bounds.bottom()); glEnd(); - //TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false, - // EffectType effect = NO_EFFECT, int effectThickness = 1); - TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, 50); + // Same font properties as textWidth() + TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); const int leftAdjust = -1; // required to make text render relative to left edge of bounds const int topAdjust = -2; // required to make text render relative to top edge of bounds @@ -126,3 +125,8 @@ void TextOverlay::setProperties(const QScriptValue& properties) { } +float TextOverlay::textWidth(const QString& text) { + QFont font(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); // Same font properties as render() + QFontMetrics fontMetrics(font); + return fontMetrics.width(qPrintable(text)); +} diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index f7ff83e542..2922d747ca 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -30,6 +30,7 @@ const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 }; const int DEFAULT_MARGIN = 10; const int DEFAULT_FONTSIZE = 11; +const int DEFAULT_FONT_WEIGHT = 50; class TextOverlay : public Overlay2D { Q_OBJECT @@ -53,6 +54,8 @@ public: virtual void setProperties(const QScriptValue& properties); + float textWidth(const QString& text); // Pixels + private: QString _text; From f0f12b047951eaf9bfdbdb6c622dfa98b78a38ca Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 11 Nov 2014 17:32:37 -0800 Subject: [PATCH 04/45] Auto-size load URL and file menu items in editModels and newEditEntities And fix a couple of typos --- examples/editModels.js | 15 +++++++++------ examples/newEditEntities.js | 15 +++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index d26a6e14b0..7538a83fef 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1125,12 +1125,12 @@ var toolBar = (function () { browseModelsButton, loadURLMenuItem, loadFileMenuItem, - menuItemWidth = 125, + menuItemWidth, menuItemOffset, menuItemHeight, menuItemMargin = 5, menuTextColor = { red: 255, green: 255, blue: 255 }, - menuBackgoundColor = { red: 18, green: 66, blue: 66 }; + menuBackgroundColor = { red: 18, green: 66, blue: 66 }; function initialize() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); @@ -1167,9 +1167,8 @@ var toolBar = (function () { loadURLMenuItem = Overlays.addOverlay("text", { x: newModelButton.x - menuItemWidth, y: newModelButton.y + menuItemOffset, - width: menuItemWidth, height: menuItemHeight, - backgroundColor: menuBackgoundColor, + backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, text: "Model URL", alpha: 0.9, @@ -1179,15 +1178,19 @@ var toolBar = (function () { loadFileMenuItem = Overlays.addOverlay("text", { x: newModelButton.x - menuItemWidth, y: newModelButton.y + menuItemOffset + menuItemHeight, - width: menuItemWidth, height: menuItemHeight, - backgroundColor: menuBackgoundColor, + backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, text: "Model File", alpha: 0.9, visible: false }); + menuItemWidth = Math.max(Overlays.textWidth(loadURLMenuItem, "Model URL"), + Overlays.textWidth(loadFileMenuItem, "Model File")) + 20; + Overlays.editOverlay(loadURLMenuItem, { width: menuItemWidth }); + Overlays.editOverlay(loadFileMenuItem, { width: menuItemWidth }); + newCubeButton = toolBar.addTool({ imageURL: toolIconUrl + "add-cube.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 57f3f29670..20359d9718 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -83,12 +83,12 @@ var toolBar = (function () { browseModelsButton, loadURLMenuItem, loadFileMenuItem, - menuItemWidth = 125, + menuItemWidth, menuItemOffset, menuItemHeight, menuItemMargin = 5, menuTextColor = { red: 255, green: 255, blue: 255 }, - menuBackgoundColor = { red: 18, green: 66, blue: 66 }; + menuBackgroundColor = { red: 18, green: 66, blue: 66 }; function initialize() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); @@ -125,9 +125,8 @@ var toolBar = (function () { loadURLMenuItem = Overlays.addOverlay("text", { x: newModelButton.x - menuItemWidth, y: newModelButton.y + menuItemOffset, - width: menuItemWidth, height: menuItemHeight, - backgroundColor: menuBackgoundColor, + backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, text: "Model URL", alpha: 0.9, @@ -137,15 +136,19 @@ var toolBar = (function () { loadFileMenuItem = Overlays.addOverlay("text", { x: newModelButton.x - menuItemWidth, y: newModelButton.y + menuItemOffset + menuItemHeight, - width: menuItemWidth, height: menuItemHeight, - backgroundColor: menuBackgoundColor, + backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, text: "Model File", alpha: 0.9, visible: false }); + menuItemWidth = Math.max(Overlays.textWidth(loadURLMenuItem, "Model URL"), + Overlays.textWidth(loadFileMenuItem, "Model File")) + 20; + Overlays.editOverlay(loadURLMenuItem, { width: menuItemWidth }); + Overlays.editOverlay(loadFileMenuItem, { width: menuItemWidth }); + newCubeButton = toolBar.addTool({ imageURL: toolIconUrl + "add-cube.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, From 4fa5447c85a10a9a67623c7a66bf3f12cd63cbb8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 12 Nov 2014 12:13:57 -0800 Subject: [PATCH 05/45] Add overlay getProperty() for text overlay "text" property --- examples/overlaysExample.js | 3 +++ interface/src/ui/overlays/Overlay.cpp | 4 ++++ interface/src/ui/overlays/Overlay.h | 1 + interface/src/ui/overlays/Overlay2D.cpp | 4 ++++ interface/src/ui/overlays/Overlay2D.h | 1 + interface/src/ui/overlays/Overlays.cpp | 14 ++++++++++++++ interface/src/ui/overlays/Overlays.h | 3 +++ interface/src/ui/overlays/TextOverlay.cpp | 9 +++++++++ interface/src/ui/overlays/TextOverlay.h | 1 + 9 files changed, 40 insertions(+) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index fef502c761..e087bd3e3a 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -166,6 +166,9 @@ var clipboardPreview = Overlays.addOverlay("clipboard", { visible: true }); +// Demonstrate retrieving overlay properties +print("Text overlay text property value =\n" + Overlays.getProperty(text, "text")); +print("Text overlay unknown property vale =\n" + Overlays.getProperty(text, "unknown")); // value = undefined // When our script shuts down, we should clean up all of our overlays function scriptEnding() { diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 215119374e..762cf28dfd 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -104,6 +104,10 @@ void Overlay::setProperties(const QScriptValue& properties) { } } +QScriptValue Overlay::getProperty(const QString& property) { + return QScriptValue(); +} + xColor Overlay::getColor() { if (_colorPulse == 0.0f) { return _color; diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 81ddaf1a91..4752b33a4e 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -77,6 +77,7 @@ public: void setAlphaPulse(float value) { _alphaPulse = value; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); protected: float updatePulse(); diff --git a/interface/src/ui/overlays/Overlay2D.cpp b/interface/src/ui/overlays/Overlay2D.cpp index 0bdb8790cc..5a42a4fc2b 100644 --- a/interface/src/ui/overlays/Overlay2D.cpp +++ b/interface/src/ui/overlays/Overlay2D.cpp @@ -64,3 +64,7 @@ void Overlay2D::setProperties(const QScriptValue& properties) { //qDebug() << "set bounds to " << getBounds(); } } + +QScriptValue Overlay2D::getProperty(const QString& property) { + return Overlay::getProperty(property); +} diff --git a/interface/src/ui/overlays/Overlay2D.h b/interface/src/ui/overlays/Overlay2D.h index 283e7b7b23..d0d75c9397 100644 --- a/interface/src/ui/overlays/Overlay2D.h +++ b/interface/src/ui/overlays/Overlay2D.h @@ -47,6 +47,7 @@ public: void setBounds(const QRect& bounds) { _bounds = bounds; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); protected: QRect _bounds; // where on the screen to draw diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 0192f9c216..5315a37f5d 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -241,6 +241,20 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { return 0; // not found } +QScriptValue Overlays::getProperty(unsigned int id, const QString& property) { + Overlay* thisOverlay = NULL; + QReadLocker lock(&_lock); + if (_overlays2D.contains(id)) { + thisOverlay = _overlays2D[id]; + } else if (_overlays3D.contains(id)) { + thisOverlay = _overlays3D[id]; + } + if (thisOverlay) { + return thisOverlay->getProperty(property); + } + return QScriptValue(); +} + RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) { float bestDistance = std::numeric_limits::max(); RayToOverlayIntersectionResult result; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 686b998267..9c1efe3a64 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -59,6 +59,9 @@ public slots: /// returns the top most 2D overlay at the screen point, or 0 if not overlay at that point unsigned int getOverlayAtPoint(const glm::vec2& point); + /// returns the value of specified property, or null if there is no such property + QScriptValue getProperty(unsigned int id, const QString& property); + /// returns details about the closest 3D Overlay hit by the pick ray RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray); diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 530b30a856..3bbdd70388 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -126,3 +126,12 @@ void TextOverlay::setProperties(const QScriptValue& properties) { } +QScriptValue TextOverlay::getProperty(const QString& property) { + if (property == "text") { + return _text; + } + + return Overlay::getProperty(property); +} + + diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index f7ff83e542..d43c701582 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -52,6 +52,7 @@ public: void setFontSize(int fontSize) { _fontSize = fontSize; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); private: From 8c3bedae9d1443b6c4737351642af5a958bf27f4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 12 Nov 2014 14:33:52 -0800 Subject: [PATCH 06/45] Add position vector and color object script value examples OverlayPropertyResult type is needed to successfully move QScriptValue objects from QScriptEngine in Overlays to QScriptEngine in script. --- examples/overlaysExample.js | 13 +++++++ interface/src/Application.cpp | 4 +- interface/src/ui/overlays/Base3DOverlay.cpp | 7 ++++ interface/src/ui/overlays/Base3DOverlay.h | 1 + interface/src/ui/overlays/Overlay.cpp | 6 ++- interface/src/ui/overlays/Overlay.h | 5 ++- interface/src/ui/overlays/Overlays.cpp | 41 +++++++++++++++++++-- interface/src/ui/overlays/Overlays.h | 15 +++++++- 8 files changed, 84 insertions(+), 8 deletions(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index e087bd3e3a..1dcb088d78 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -169,6 +169,19 @@ var clipboardPreview = Overlays.addOverlay("clipboard", { // Demonstrate retrieving overlay properties print("Text overlay text property value =\n" + Overlays.getProperty(text, "text")); print("Text overlay unknown property vale =\n" + Overlays.getProperty(text, "unknown")); // value = undefined +var cubePosition = Overlays.getProperty(cube, "position"); +print("Cube overlay position =\n" + + "x: " + cubePosition.x + "\n" + + "y: " + cubePosition.y + "\n" + + "z: " + cubePosition.z + ); +var cubeColor = Overlays.getProperty(cube, "color"); +print("Cube overlay color =\n" + + "red: " + cubeColor.red + "\n" + + "green: " + cubeColor.green + "\n" + + "blue: " + cubeColor.blue + ); +print("Unknown overlay property =\n" + Overlays.getProperty(1000, "text")); // value = undefined // When our script shuts down, we should clean up all of our overlays function scriptEnding() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bb19ce3ca5..cf64bd55d6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3888,7 +3888,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool))); scriptEngine->registerGlobalObject("Overlays", &_overlays); - qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); + qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue); + qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, + RayToOverlayIntersectionResultFromScriptValue); QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", WindowScriptingInterface::getInstance()); scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 89dd4d4b01..8c26bc1493 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -118,6 +118,13 @@ void Base3DOverlay::setProperties(const QScriptValue& properties) { } } +QScriptValue Base3DOverlay::getProperty(const QString& property) { + if (property == "position") { + return vec3toScriptValue(_scriptEngine, _position); + } + return Overlay::getProperty(property); +} + bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { return false; diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 75ce6b303d..7b7fa1a8f4 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -45,6 +45,7 @@ public: void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 762cf28dfd..ba7269c5dc 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -39,8 +39,9 @@ Overlay::Overlay() : { } -void Overlay::init(QGLWidget* parent) { +void Overlay::init(QGLWidget* parent, QScriptEngine* scriptEngine) { _parent = parent; + _scriptEngine = scriptEngine; } @@ -105,6 +106,9 @@ void Overlay::setProperties(const QScriptValue& properties) { } QScriptValue Overlay::getProperty(const QString& property) { + if (property == "color") { + return xColorToScriptValue(_scriptEngine, _color); + } return QScriptValue(); } diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 4752b33a4e..192bb5fd40 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -19,6 +19,7 @@ #include #include +#include #include // for xColor #include @@ -36,7 +37,7 @@ public: Overlay(); ~Overlay(); - void init(QGLWidget* parent); + void init(QGLWidget* parent, QScriptEngine* scriptEngine); virtual void update(float deltatime) {} virtual void render(RenderArgs* args) = 0; @@ -101,6 +102,8 @@ protected: xColor _color; bool _visible; // should the overlay be drawn at all Anchor _anchor; + + QScriptEngine* _scriptEngine; }; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5315a37f5d..6fdd4e75d2 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "BillboardOverlay.h" #include "Circle3DOverlay.h" @@ -55,6 +56,7 @@ Overlays::~Overlays() { void Overlays::init(QGLWidget* parent) { _parent = parent; + _scriptEngine = new QScriptEngine(); } void Overlays::update(float deltatime) { @@ -179,7 +181,7 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope } unsigned int Overlays::addOverlay(Overlay* overlay) { - overlay->init(_parent); + overlay->init(_parent, _scriptEngine); QWriteLocker lock(&_lock); unsigned int thisID = _nextOverlayID; @@ -241,7 +243,8 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { return 0; // not found } -QScriptValue Overlays::getProperty(unsigned int id, const QString& property) { +OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) { + OverlayPropertyResult result; Overlay* thisOverlay = NULL; QReadLocker lock(&_lock); if (_overlays2D.contains(id)) { @@ -250,9 +253,39 @@ QScriptValue Overlays::getProperty(unsigned int id, const QString& property) { thisOverlay = _overlays3D[id]; } if (thisOverlay) { - return thisOverlay->getProperty(property); + result.value = thisOverlay->getProperty(property); } - return QScriptValue(); + return result; +} + +OverlayPropertyResult::OverlayPropertyResult() : + value(QScriptValue()) +{ +} + +QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& result) +{ + if (!result.value.isValid()) { + return QScriptValue::UndefinedValue; + } + + QScriptValue object = engine->newObject(); + if (result.value.isObject()) { + QScriptValueIterator it(result.value); + while (it.hasNext()) { + it.next(); + object.setProperty(it.name(), QScriptValue(it.value().toString())); + } + + } else { + object = result.value; + } + return object; +} + +void OverlayPropertyResultFromScriptValue(const QScriptValue& value, OverlayPropertyResult& result) +{ + result.value = value; } RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 9c1efe3a64..ae48428bca 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -16,6 +16,17 @@ #include "Overlay.h" +class OverlayPropertyResult { +public: + OverlayPropertyResult(); + QScriptValue value; +}; + +Q_DECLARE_METATYPE(OverlayPropertyResult); + +QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value); +void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value); + class RayToOverlayIntersectionResult { public: RayToOverlayIntersectionResult(); @@ -27,6 +38,7 @@ public: QString extraInfo; }; + Q_DECLARE_METATYPE(RayToOverlayIntersectionResult); QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value); @@ -60,7 +72,7 @@ public slots: unsigned int getOverlayAtPoint(const glm::vec2& point); /// returns the value of specified property, or null if there is no such property - QScriptValue getProperty(unsigned int id, const QString& property); + OverlayPropertyResult getProperty(unsigned int id, const QString& property); /// returns details about the closest 3D Overlay hit by the pick ray RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray); @@ -76,6 +88,7 @@ private: QGLWidget* _parent; QReadWriteLock _lock; QReadWriteLock _deleteLock; + QScriptEngine* _scriptEngine; }; From 725d56d41f23dbe8a7af73e3dc79e778e90971a2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 12 Nov 2014 16:50:13 -0800 Subject: [PATCH 07/45] Add property getting for all 2D overlays --- examples/overlaysExample.js | 14 +++++++++- interface/src/ui/overlays/ImageOverlay.cpp | 14 ++++++++++ interface/src/ui/overlays/ImageOverlay.h | 1 + interface/src/ui/overlays/Overlay.cpp | 31 ++++++++++++++++++++++ interface/src/ui/overlays/Overlay2D.cpp | 21 +++++++++++++++ interface/src/ui/overlays/TextOverlay.cpp | 17 ++++++++++-- 6 files changed, 95 insertions(+), 3 deletions(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index 1dcb088d78..d64a29046a 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -168,7 +168,19 @@ var clipboardPreview = Overlays.addOverlay("clipboard", { // Demonstrate retrieving overlay properties print("Text overlay text property value =\n" + Overlays.getProperty(text, "text")); -print("Text overlay unknown property vale =\n" + Overlays.getProperty(text, "unknown")); // value = undefined +print("Text overlay alpha =\n" + Overlays.getProperty(text, "alpha")); +print("Text overlay visible =\n" + Overlays.getProperty(text, "visible")); +print("Text overlay font size =\n" + Overlays.getProperty(text, "font").size); +print("Text overlay anchor =\n" + Overlays.getProperty(text, "anchor")); +print("Text overlay unknown property value =\n" + Overlays.getProperty(text, "unknown")); // value = undefined +var sliderBounds = Overlays.getProperty(slider, "bounds"); +print("Slider overlay bounds =\n" + + "x: " + sliderBounds.x + "\n" + + "y: " + sliderBounds.y + "\n" + + "width: " + sliderBounds.width + "\n" + + "height: " + sliderBounds.height + ); + var cubePosition = Overlays.getProperty(cube, "position"); print("Cube overlay position =\n" + "x: " + cubePosition.x + "\n" diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 3b9d95af2e..f2e93c2e0e 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -151,4 +151,18 @@ void ImageOverlay::setProperties(const QScriptValue& properties) { } } +QScriptValue ImageOverlay::getProperty(const QString& property) { + if (property == "subImage") { + QScriptValue subImage = _scriptEngine->newObject(); + subImage.setProperty("x", _fromImage.x()); + subImage.setProperty("y", _fromImage.y()); + subImage.setProperty("width", _fromImage.width()); + subImage.setProperty("height", _fromImage.height()); + return subImage; + } + if (property == "imageURL") { + return _imageURL.toString(); + } + return Overlay2D::getProperty(property); +} diff --git a/interface/src/ui/overlays/ImageOverlay.h b/interface/src/ui/overlays/ImageOverlay.h index ef1ead8c02..bf4f2860ad 100644 --- a/interface/src/ui/overlays/ImageOverlay.h +++ b/interface/src/ui/overlays/ImageOverlay.h @@ -44,6 +44,7 @@ public: void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; } void setImageURL(const QUrl& url); virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); private slots: void replyFinished(); // we actually want to hide this... diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index ba7269c5dc..a7c38946b7 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -109,6 +109,37 @@ QScriptValue Overlay::getProperty(const QString& property) { if (property == "color") { return xColorToScriptValue(_scriptEngine, _color); } + if (property == "alpha") { + return _alpha; + } + if (property == "glowLevel") { + return _glowLevel; + } + if (property == "pulseMax") { + return _pulseMax; + } + if (property == "pulseMin") { + return _pulseMin; + } + if (property == "pulsePeriod") { + return _pulsePeriod; + } + if (property == "glowLevelPulse") { + return _glowLevelPulse; + } + if (property == "alphaPulse") { + return _alphaPulse; + } + if (property == "colorPulse") { + return _colorPulse; + } + if (property == "visible") { + return _visible; + } + if (property == "anchor") { + return _anchor == MY_AVATAR ? "MyAvatar" : ""; + } + return QScriptValue(); } diff --git a/interface/src/ui/overlays/Overlay2D.cpp b/interface/src/ui/overlays/Overlay2D.cpp index 5a42a4fc2b..d71f8cac05 100644 --- a/interface/src/ui/overlays/Overlay2D.cpp +++ b/interface/src/ui/overlays/Overlay2D.cpp @@ -66,5 +66,26 @@ void Overlay2D::setProperties(const QScriptValue& properties) { } QScriptValue Overlay2D::getProperty(const QString& property) { + if (property == "bounds") { + QScriptValue bounds = _scriptEngine->newObject(); + bounds.setProperty("x", _bounds.x()); + bounds.setProperty("y", _bounds.y()); + bounds.setProperty("width", _bounds.width()); + bounds.setProperty("height", _bounds.height()); + return bounds; + } + if (property == "x") { + return _bounds.x(); + } + if (property == "y") { + return _bounds.y(); + } + if (property == "width") { + return _bounds.width(); + } + if (property == "height") { + return _bounds.height(); + } + return Overlay::getProperty(property); } diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 3bbdd70388..a17d381a85 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -125,13 +125,26 @@ void TextOverlay::setProperties(const QScriptValue& properties) { } } - QScriptValue TextOverlay::getProperty(const QString& property) { + if (property == "font") { + QScriptValue font = _scriptEngine->newObject(); + font.setProperty("size", _fontSize); + return font; + } if (property == "text") { return _text; } + if (property == "backgroundColor") { + return xColorToScriptValue(_scriptEngine, _backgroundColor); + } + if (property == "leftMargin") { + return _leftMargin; + } + if (property == "topMargin") { + return _topMargin; + } - return Overlay::getProperty(property); + return Overlay2D::getProperty(property); } From 9e19641a1d8987fef54eb907a3710e0e1365d561 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 12 Nov 2014 21:05:44 -0800 Subject: [PATCH 08/45] Add property getting for all 3D overlays --- examples/overlaysExample.js | 14 +++++++ interface/src/ui/overlays/Base3DOverlay.cpp | 21 +++++++++- .../src/ui/overlays/BillboardOverlay.cpp | 22 +++++++++++ interface/src/ui/overlays/BillboardOverlay.h | 1 + interface/src/ui/overlays/Circle3DOverlay.cpp | 39 +++++++++++++++++++ interface/src/ui/overlays/Circle3DOverlay.h | 1 + interface/src/ui/overlays/Grid3DOverlay.cpp | 11 ++++++ interface/src/ui/overlays/Grid3DOverlay.h | 1 + interface/src/ui/overlays/Line3DOverlay.cpp | 8 ++++ interface/src/ui/overlays/Line3DOverlay.h | 1 + .../src/ui/overlays/LocalVoxelsOverlay.cpp | 11 ++++++ .../src/ui/overlays/LocalVoxelsOverlay.h | 3 +- interface/src/ui/overlays/ModelOverlay.cpp | 31 +++++++++++++++ interface/src/ui/overlays/ModelOverlay.h | 2 + interface/src/ui/overlays/Planar3DOverlay.cpp | 8 ++++ interface/src/ui/overlays/Planar3DOverlay.h | 1 + interface/src/ui/overlays/Text3DOverlay.cpp | 27 +++++++++++++ interface/src/ui/overlays/Text3DOverlay.h | 1 + interface/src/ui/overlays/Volume3DOverlay.cpp | 8 ++++ interface/src/ui/overlays/Volume3DOverlay.h | 1 + 20 files changed, 210 insertions(+), 2 deletions(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index d64a29046a..5c7793185b 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -193,6 +193,20 @@ print("Cube overlay color =\n" + "green: " + cubeColor.green + "\n" + "blue: " + cubeColor.blue ); +var modelOverlayProperties = { + textures: { + filename1: "http://url1", + filename2: "http://url2" + } +} +var modelOverlay = Overlays.addOverlay("model", modelOverlayProperties); +var textures = Overlays.getProperty(modelOverlay, "textures"); +var textureValues = ""; +for (key in textures) { + textureValues += "\n" + key + ": " + textures[key]; +} +print("Model overlay textures =" + textureValues); +Overlays.deleteOverlay(modelOverlay); print("Unknown overlay property =\n" + Overlays.getProperty(1000, "text")); // value = undefined // When our script shuts down, we should clean up all of our overlays diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 8c26bc1493..a83772d01b 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -119,9 +119,28 @@ void Base3DOverlay::setProperties(const QScriptValue& properties) { } QScriptValue Base3DOverlay::getProperty(const QString& property) { - if (property == "position") { + if (property == "position" || property == "start" || property == "p1" || property == "point") { return vec3toScriptValue(_scriptEngine, _position); } + if (property == "lineWidth") { + return _lineWidth; + } + if (property == "rotation") { + return quatToScriptValue(_scriptEngine, _rotation); + } + if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") { + return _isSolid; + } + if (property == "isWire" || property == "wire") { + return !_isSolid; + } + if (property == "isDashedLine" || property == "dashed") { + return _isDashedLine; + } + if (property == "ignoreRayIntersection") { + return _ignoreRayIntersection; + } + return Overlay::getProperty(property); } diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index c8d4877bb5..87b6dcc1c8 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -157,6 +157,28 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) { } } +QScriptValue BillboardOverlay::getProperty(const QString& property) { + if (property == "url") { + return _url; + } + if (property == "subImage") { + QScriptValue subImage = _scriptEngine->newObject(); + subImage.setProperty("x", _fromImage.x()); + subImage.setProperty("y", _fromImage.y()); + subImage.setProperty("width", _fromImage.width()); + subImage.setProperty("height", _fromImage.height()); + return subImage; + } + if (property == "scale") { + return _scale; + } + if (property == "isFacingAvatar") { + return _isFacingAvatar; + } + + return Base3DOverlay::getProperty(property); +} + void BillboardOverlay::setURL(const QString& url) { setBillboardURL(url); } diff --git a/interface/src/ui/overlays/BillboardOverlay.h b/interface/src/ui/overlays/BillboardOverlay.h index 018ca5f5cf..3a22a247f0 100644 --- a/interface/src/ui/overlays/BillboardOverlay.h +++ b/interface/src/ui/overlays/BillboardOverlay.h @@ -32,6 +32,7 @@ public: virtual void setProperties(const QScriptValue& properties); void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } + virtual QScriptValue getProperty(const QString& property); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 144119c450..986088cebb 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -299,6 +299,45 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) { } } +QScriptValue Circle3DOverlay::getProperty(const QString& property) { + if (property == "startAt") { + return _startAt; + } + if (property == "endAt") { + return _endAt; + } + if (property == "outerRadius") { + return _outerRadius; + } + if (property == "innerRadius") { + return _innerRadius; + } + if (property == "hasTickMarks") { + return _hasTickMarks; + } + if (property == "majorTickMarksAngle") { + return _majorTickMarksAngle; + } + if (property == "minorTickMarksAngle") { + return _minorTickMarksAngle; + } + if (property == "majorTickMarksLength") { + return _majorTickMarksLength; + } + if (property == "minorTickMarksLength") { + return _minorTickMarksLength; + } + if (property == "majorTickMarksColor") { + return xColorToScriptValue(_scriptEngine, _majorTickMarksColor); + } + if (property == "minorTickMarksColor") { + return xColorToScriptValue(_scriptEngine, _minorTickMarksColor); + } + + return Planar3DOverlay::getProperty(property); +} + + bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index 191a0d3100..816ed280f9 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -21,6 +21,7 @@ public: ~Circle3DOverlay(); virtual void render(RenderArgs* args); virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); float getStartAt() const { return _startAt; } float getEndAt() const { return _endAt; } diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index c628199fe3..dee5d5d60a 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -116,3 +116,14 @@ void Grid3DOverlay::setProperties(const QScriptValue& properties) { _majorGridEvery = properties.property("majorGridEvery").toVariant().toInt(); } } + +QScriptValue Grid3DOverlay::getProperty(const QString& property) { + if (property == "minorGridWidth") { + return _minorGridWidth; + } + if (property == "majorGridEvery") { + return _majorGridEvery; + } + + return Base3DOverlay::getProperty(property); +} diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h index b1675f15d7..3e6a235d54 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.h +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -33,6 +33,7 @@ public: virtual void render(RenderArgs* args); virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); private: float _minorGridWidth; diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 18671ea074..896ebd1e68 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -79,3 +79,11 @@ void Line3DOverlay::setProperties(const QScriptValue& properties) { } } } + +QScriptValue Line3DOverlay::getProperty(const QString& property) { + if (property == "end" || property == "endPoint" || property == "p2") { + return vec3toScriptValue(_scriptEngine, _end); + } + + return Base3DOverlay::getProperty(property); +} diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index f9c4e0d6d6..0148648c35 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -28,6 +28,7 @@ public: void setEnd(const glm::vec3& end) { _end = end; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); protected: glm::vec3 _end; diff --git a/interface/src/ui/overlays/LocalVoxelsOverlay.cpp b/interface/src/ui/overlays/LocalVoxelsOverlay.cpp index dcfc79f3b4..3ca79d548c 100644 --- a/interface/src/ui/overlays/LocalVoxelsOverlay.cpp +++ b/interface/src/ui/overlays/LocalVoxelsOverlay.cpp @@ -103,3 +103,14 @@ void LocalVoxelsOverlay::setProperties(const QScriptValue &properties) { } } +QScriptValue LocalVoxelsOverlay::getProperty(const QString& property) { + if (property == "scale") { + return vec3toScriptValue(_scriptEngine, getDimensions()); + } + if (property == "name") { + return _treeName; + } + + return Volume3DOverlay::getProperty(property); +} + diff --git a/interface/src/ui/overlays/LocalVoxelsOverlay.h b/interface/src/ui/overlays/LocalVoxelsOverlay.h index 46a88407af..25ad4738b9 100644 --- a/interface/src/ui/overlays/LocalVoxelsOverlay.h +++ b/interface/src/ui/overlays/LocalVoxelsOverlay.h @@ -38,7 +38,8 @@ public: virtual void render(RenderArgs* args); virtual void setProperties(const QScriptValue& properties); - + virtual QScriptValue getProperty(const QString& property); + private: static QMap _voxelSystemMap; // treeName/voxelSystem diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 150d40f15a..a2abfe77b1 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -14,6 +14,7 @@ ModelOverlay::ModelOverlay() : _model(), + _modelTextures(QVariantMap()), _scale(1.0f), _updateModel(false) { @@ -114,6 +115,8 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { QMetaObject::invokeMethod(&_model, "setTextureWithNameToURL", Qt::AutoConnection, Q_ARG(const QString&, key), Q_ARG(const QUrl&, newTextureURL)); + + _modelTextures[key] = newTextureURL; // Keep local track of textures for getProperty() } } @@ -122,6 +125,34 @@ void ModelOverlay::setProperties(const QScriptValue &properties) { } } +QScriptValue ModelOverlay::getProperty(const QString& property) { + if (property == "url") { + return _url.toString(); + } + if (property == "scale") { + return _scale; + } + if (property == "rotation") { + return quatToScriptValue(_scriptEngine, _rotation); + } + if (property == "dimensions") { + return vec3toScriptValue(_scriptEngine, _model.getScaleToFitDimensions()); + } + if (property == "textures") { + if (_modelTextures.size() > 0) { + QScriptValue textures = _scriptEngine->newObject(); + foreach(const QString& key, _modelTextures.keys()) { + textures.setProperty(key, _modelTextures[key].toString()); + } + return textures; + } else { + return QScriptValue(); + } + } + + return Base3DOverlay::getProperty(property); +} + bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 26471a79e1..c9f6799e8c 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -24,6 +24,7 @@ public: virtual void update(float deltatime); virtual void render(RenderArgs* args); virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo) const; @@ -31,6 +32,7 @@ public: private: Model _model; + QVariantMap _modelTextures; QUrl _url; glm::quat _rotation; diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index 91a3a023f7..b2de7bdaad 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -77,6 +77,14 @@ void Planar3DOverlay::setProperties(const QScriptValue& properties) { } } +QScriptValue Planar3DOverlay::getProperty(const QString& property) { + if (property == "dimensions" || property == "scale" || property == "size") { + return vec2toScriptValue(_scriptEngine, _dimensions); + } + + Base3DOverlay::getProperty(property); +} + bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { diff --git a/interface/src/ui/overlays/Planar3DOverlay.h b/interface/src/ui/overlays/Planar3DOverlay.h index ee4bb3e05a..fe73cfbe08 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.h +++ b/interface/src/ui/overlays/Planar3DOverlay.h @@ -36,6 +36,7 @@ public: void setDimensions(const glm::vec2& value) { _dimensions = value; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index d8febbf0eb..ae21e4a8d4 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -179,4 +179,31 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) { } +QScriptValue Text3DOverlay::getProperty(const QString& property) { + if (property == "text") { + return _text; + } + if (property == "backgroundColor") { + return xColorToScriptValue(_scriptEngine, _backgroundColor); + } + if (property == "lineHeight") { + return _lineHeight; + } + if (property == "leftMargin") { + return _leftMargin; + } + if (property == "topMargin") { + return _topMargin; + } + if (property == "rightMargin") { + return _rightMargin; + } + if (property == "bottomMargin") { + return _bottomMargin; + } + if (property == "isFacingAvatar") { + return _isFacingAvatar; + } + return Planar3DOverlay::getProperty(property); +} diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index 45e311c554..ff5575c20c 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -47,6 +47,7 @@ public: void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); private: void enableClipPlane(GLenum plane, float x, float y, float z, float w); diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index cc12d41e2e..0940caea04 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -85,6 +85,14 @@ void Volume3DOverlay::setProperties(const QScriptValue& properties) { } } +QScriptValue Volume3DOverlay::getProperty(const QString& property) { + if (property == "dimensions" || property == "scale" || property == "size") { + return vec3toScriptValue(_scriptEngine, _dimensions); + } + + return Base3DOverlay::getProperty(property); +} + bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { diff --git a/interface/src/ui/overlays/Volume3DOverlay.h b/interface/src/ui/overlays/Volume3DOverlay.h index 7cde169c30..8787759022 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.h +++ b/interface/src/ui/overlays/Volume3DOverlay.h @@ -38,6 +38,7 @@ public: void setDimensions(const glm::vec3& value) { _dimensions = value; } virtual void setProperties(const QScriptValue& properties); + virtual QScriptValue getProperty(const QString& property); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; From fac6b6b4267717c53b2270138bcfe2a715c4c532 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 12 Nov 2014 21:32:55 -0800 Subject: [PATCH 09/45] Refactor QRect conversion to QScriptValue --- interface/src/ui/overlays/BillboardOverlay.cpp | 7 +------ interface/src/ui/overlays/ImageOverlay.cpp | 7 +------ interface/src/ui/overlays/Overlay2D.cpp | 7 +------ libraries/shared/src/RegisteredMetaTypes.cpp | 18 ++++++++++++++++++ libraries/shared/src/RegisteredMetaTypes.h | 3 +++ 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 87b6dcc1c8..b36202cb04 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -162,12 +162,7 @@ QScriptValue BillboardOverlay::getProperty(const QString& property) { return _url; } if (property == "subImage") { - QScriptValue subImage = _scriptEngine->newObject(); - subImage.setProperty("x", _fromImage.x()); - subImage.setProperty("y", _fromImage.y()); - subImage.setProperty("width", _fromImage.width()); - subImage.setProperty("height", _fromImage.height()); - return subImage; + return qRectToScriptValue(_scriptEngine, _fromImage); } if (property == "scale") { return _scale; diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index f2e93c2e0e..615872e6ef 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -153,12 +153,7 @@ void ImageOverlay::setProperties(const QScriptValue& properties) { QScriptValue ImageOverlay::getProperty(const QString& property) { if (property == "subImage") { - QScriptValue subImage = _scriptEngine->newObject(); - subImage.setProperty("x", _fromImage.x()); - subImage.setProperty("y", _fromImage.y()); - subImage.setProperty("width", _fromImage.width()); - subImage.setProperty("height", _fromImage.height()); - return subImage; + return qRectToScriptValue(_scriptEngine, _fromImage); } if (property == "imageURL") { return _imageURL.toString(); diff --git a/interface/src/ui/overlays/Overlay2D.cpp b/interface/src/ui/overlays/Overlay2D.cpp index d71f8cac05..b7c0a3a3e4 100644 --- a/interface/src/ui/overlays/Overlay2D.cpp +++ b/interface/src/ui/overlays/Overlay2D.cpp @@ -67,12 +67,7 @@ void Overlay2D::setProperties(const QScriptValue& properties) { QScriptValue Overlay2D::getProperty(const QString& property) { if (property == "bounds") { - QScriptValue bounds = _scriptEngine->newObject(); - bounds.setProperty("x", _bounds.x()); - bounds.setProperty("y", _bounds.y()); - bounds.setProperty("width", _bounds.width()); - bounds.setProperty("height", _bounds.height()); - return bounds; + return qRectToScriptValue(_scriptEngine, _bounds); } if (property == "x") { return _bounds.x(); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 5867e2ef43..02b9d5c927 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -30,6 +31,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); + qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue); qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); @@ -96,6 +98,22 @@ void quatFromScriptValue(const QScriptValue &object, glm::quat& quat) { quat.w = object.property("w").toVariant().toFloat(); } +QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", rect.x()); + obj.setProperty("y", rect.y()); + obj.setProperty("width", rect.width()); + obj.setProperty("height", rect.height()); + return obj; +} + +void qRectFromScriptValue(const QScriptValue &object, QRect& rect) { + rect.setX(object.property("x").toVariant().toInt()); + rect.setY(object.property("y").toVariant().toInt()); + rect.setWidth(object.property("width").toVariant().toInt()); + rect.setHeight(object.property("height").toVariant().toInt()); +} + QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) { QScriptValue obj = engine->newObject(); obj.setProperty("red", color.red); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index b8884be845..0fd3138b06 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -42,6 +42,9 @@ void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2); QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat); void quatFromScriptValue(const QScriptValue &object, glm::quat& quat); +QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect); +void qRectFromScriptValue(const QScriptValue& object, QRect& rect); + QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color); void xColorFromScriptValue(const QScriptValue &object, xColor& color); From fd6b9c3550676af1a00dfdccf68ce1ab02961842 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 10:16:42 -0800 Subject: [PATCH 10/45] changes to sound class to allow caching of sounds --- libraries/audio/src/AudioInjector.cpp | 41 +++++++------ libraries/audio/src/AudioInjector.h | 3 +- libraries/audio/src/Sound.cpp | 85 ++------------------------- libraries/audio/src/Sound.h | 24 +++----- libraries/audio/src/SoundCache.cpp | 33 +++++++++++ libraries/audio/src/SoundCache.h | 37 ++++++++++++ libraries/avatars/src/Recording.cpp | 24 ++------ libraries/avatars/src/Recording.h | 9 +-- 8 files changed, 114 insertions(+), 142 deletions(-) create mode 100644 libraries/audio/src/SoundCache.cpp create mode 100644 libraries/audio/src/SoundCache.h diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 1743504883..1c9c93c00e 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -31,7 +31,6 @@ void injectorFromScriptValue(const QScriptValue& object, AudioInjector*& out) { AudioInjector::AudioInjector(QObject* parent) : QObject(parent), - _sound(NULL), _options(), _shouldStop(false), _loudness(0.0f), @@ -42,7 +41,7 @@ AudioInjector::AudioInjector(QObject* parent) : } AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) : - _sound(sound), + _audioData(sound->getByteArray()), _options(injectorOptions), _shouldStop(false), _loudness(0.0f), @@ -52,6 +51,18 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO { } +AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) : + _audioData(audioData), + _options(injectorOptions), + _shouldStop(false), + _loudness(0.0f), + _isFinished(false), + _currentSendPosition(0), + _localBuffer(NULL) +{ + +} + AudioInjector::~AudioInjector() { if (_localBuffer) { _localBuffer->stop(); @@ -76,11 +87,9 @@ void AudioInjector::injectAudio() { void AudioInjector::injectLocally() { bool success = false; - if (_localAudioInterface) { - const QByteArray& soundByteArray = _sound->getByteArray(); - - if (soundByteArray.size() > 0) { - _localBuffer = new AudioInjectorLocalBuffer(_sound->getByteArray(), this); + if (_localAudioInterface) { + if (_audioData.size() > 0) { + _localBuffer = new AudioInjectorLocalBuffer(_audioData, this); _localBuffer->open(QIODevice::ReadOnly); _localBuffer->setShouldLoop(_options.loop); @@ -114,15 +123,13 @@ void AudioInjector::injectLocally() { const uchar MAX_INJECTOR_VOLUME = 0xFF; void AudioInjector::injectToMixer() { - QByteArray soundByteArray = _sound->getByteArray(); - if (_currentSendPosition < 0 || - _currentSendPosition >= soundByteArray.size()) { + _currentSendPosition >= _audioData.size()) { _currentSendPosition = 0; } // make sure we actually have samples downloaded to inject - if (soundByteArray.size()) { + if (_audioData.size()) { // setup the packet for injected audio QByteArray injectAudioPacket = byteArrayWithPopulatedHeader(PacketTypeInjectAudio); @@ -172,15 +179,15 @@ void AudioInjector::injectToMixer() { // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks quint16 outgoingInjectedAudioSequenceNumber = 0; - while (_currentSendPosition < soundByteArray.size() && !_shouldStop) { + while (_currentSendPosition < _audioData.size() && !_shouldStop) { int bytesToCopy = std::min(((_options.stereo) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, - soundByteArray.size() - _currentSendPosition); + _audioData.size() - _currentSendPosition); // Measure the loudness of this frame _loudness = 0.0f; for (int i = 0; i < bytesToCopy; i += sizeof(int16_t)) { - _loudness += abs(*reinterpret_cast(soundByteArray.data() + _currentSendPosition + i)) / + _loudness += abs(*reinterpret_cast(_audioData.data() + _currentSendPosition + i)) / (MAX_SAMPLE_VALUE / 2.0f); } _loudness /= (float)(bytesToCopy / sizeof(int16_t)); @@ -203,7 +210,7 @@ void AudioInjector::injectToMixer() { // copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet memcpy(injectAudioPacket.data() + numPreAudioDataBytes, - soundByteArray.data() + _currentSendPosition, bytesToCopy); + _audioData.data() + _currentSendPosition, bytesToCopy); // grab our audio mixer from the NodeList, if it exists NodeList* nodeList = NodeList::getInstance(); @@ -217,7 +224,7 @@ void AudioInjector::injectToMixer() { // send two packets before the first sleep so the mixer can start playback right away - if (_currentSendPosition != bytesToCopy && _currentSendPosition < soundByteArray.size()) { + if (_currentSendPosition != bytesToCopy && _currentSendPosition < _audioData.size()) { // not the first packet and not done // sleep for the appropriate time int usecToSleep = (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - timer.nsecsElapsed() / 1000; @@ -227,7 +234,7 @@ void AudioInjector::injectToMixer() { } } - if (shouldLoop && _currentSendPosition >= soundByteArray.size()) { + if (shouldLoop && _currentSendPosition >= _audioData.size()) { _currentSendPosition = 0; } } diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 13188c5977..257b538c11 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -29,6 +29,7 @@ class AudioInjector : public QObject { public: AudioInjector(QObject* parent); AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions); + AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions); ~AudioInjector(); bool isFinished() const { return _isFinished; } @@ -51,7 +52,7 @@ private: void injectToMixer(); void injectLocally(); - Sound* _sound; + QByteArray _audioData; AudioInjectorOptions _options; bool _shouldStop; float _loudness; diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 4c520f27ce..8f858e6d3c 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -38,87 +38,17 @@ void soundFromScriptValue(const QScriptValue& object, Sound*& out) { out = qobject_cast(object.toQObject()); } -// procedural audio version of Sound -Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) : - QObject(parent), - _isStereo(false) +Sound::Sound(const QUrl& url, bool isStereo) : + Resource(url), + _isStereo(isStereo) { - static char monoAudioData[MAX_PACKET_SIZE]; - static int16_t* monoAudioSamples = (int16_t*)(monoAudioData); - - float t; - const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; - const float MAX_VOLUME = 32000.f; - const float MAX_DURATION = 2.f; - const float MIN_AUDIBLE_VOLUME = 0.001f; - const float NOISE_MAGNITUDE = 0.02f; - const int MAX_SAMPLE_VALUE = std::numeric_limits::max(); - const int MIN_SAMPLE_VALUE = std::numeric_limits::min(); - int numSamples = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; // we add sounds in chunks of this many samples - int chunkStartingSample = 0; - float waveFrequency = (frequency / SAMPLE_RATE) * TWO_PI; - while (volume > 0.f) { - for (int i = 0; i < numSamples; i++) { - t = (float)chunkStartingSample + (float)i; - float sample = sinf(t * waveFrequency); - sample += ((randFloat() - 0.5f) * NOISE_MAGNITUDE); - sample *= volume * MAX_VOLUME; - - monoAudioSamples[i] = glm::clamp((int)sample, MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); - volume *= (1.f - decay); - } - // add the monoAudioSamples to our actual output Byte Array - _byteArray.append(monoAudioData, numSamples * sizeof(int16_t)); - chunkStartingSample += numSamples; - duration = glm::clamp(duration - (AUDIO_CALLBACK_MSECS / 1000.f), 0.f, MAX_DURATION); - //qDebug() << "decaying... _duration=" << _duration; - if (duration == 0.f || (volume < MIN_AUDIBLE_VOLUME)) { - volume = 0.f; - } - } } -Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) : - QObject(parent), - _isStereo(isStereo), - _hasDownloaded(false) -{ - // assume we have a QApplication or QCoreApplication instance and use the - // QNetworkAccess manager to grab the raw audio file at the given URL - - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - qDebug() << "Requesting audio file" << sampleURL.toDisplayString(); - - QNetworkReply* soundDownload = networkAccessManager.get(QNetworkRequest(sampleURL)); - connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished); - connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(replyError(QNetworkReply::NetworkError))); -} - -Sound::Sound(const QByteArray byteArray, QObject* parent) : - QObject(parent), - _byteArray(byteArray), - _isStereo(false), - _hasDownloaded(true) -{ -} - -void Sound::append(const QByteArray byteArray) { - _byteArray.append(byteArray); -} - -void Sound::replyFinished() { - - QNetworkReply* reply = reinterpret_cast(sender()); - +void Sound::downloadFinished(QNetworkReply* reply) { // replace our byte array with the downloaded data QByteArray rawAudioByteArray = reply->readAll(); - // foreach(QByteArray b, reply->rawHeaderList()) - // qDebug() << b.constData() << ": " << reply->rawHeader(b).constData(); - if (reply->hasRawHeader("Content-Type")) { QByteArray headerContentType = reply->rawHeader("Content-Type"); @@ -140,13 +70,6 @@ void Sound::replyFinished() { } else { qDebug() << "Network reply without 'Content-Type'."; } - - _hasDownloaded = true; -} - -void Sound::replyError(QNetworkReply::NetworkError code) { - QNetworkReply* reply = reinterpret_cast(sender()); - qDebug() << "Error downloading sound file at" << reply->url().toString() << "-" << reply->errorString(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index f7b51891f0..2880781ac6 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -16,38 +16,28 @@ #include #include -class Sound : public QObject { +#include + +class Sound : public Resource { Q_OBJECT - Q_PROPERTY(bool downloaded READ hasDownloaded) + Q_PROPERTY(bool downloaded READ isLoaded) public: - Sound(const QUrl& sampleURL, bool isStereo = false, QObject* parent = NULL); - Sound(float volume, float frequency, float duration, float decay, QObject* parent = NULL); - Sound(const QByteArray byteArray, QObject* parent = NULL); - void append(const QByteArray byteArray); + Sound(const QUrl& url, bool isStereo = false); bool isStereo() const { return _isStereo; } - bool hasDownloaded() const { return _hasDownloaded; } const QByteArray& getByteArray() { return _byteArray; } private: QByteArray _byteArray; bool _isStereo; - bool _hasDownloaded; void trimFrames(); void downSample(const QByteArray& rawAudioByteArray); void interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray); - -private slots: - void replyFinished(); - void replyError(QNetworkReply::NetworkError code); + + virtual void downloadFinished(QNetworkReply* reply); }; -Q_DECLARE_METATYPE(Sound*) - -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in); -void soundFromScriptValue(const QScriptValue& object, Sound*& out); - #endif // hifi_Sound_h diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp new file mode 100644 index 0000000000..09b9cfe330 --- /dev/null +++ b/libraries/audio/src/SoundCache.cpp @@ -0,0 +1,33 @@ +// +// SoundCache.cpp +// libraries/audio/src +// +// Created by Stephen Birarda on 2014-11-13. +// 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 "SoundCache.h" + +SoundCache::SoundCache(QObject* parent) : + ResourceCache(parent) { +} + +SharedSoundPointer SoundCache::getSound(const QUrl& url) { + if (QThread::currentThread() != thread()) { + SharedSoundPointer result; + QMetaObject::invokeMethod(this, "getSound", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); + return result; + } + return getResource(url).staticCast(); +} + +QSharedPointer SoundCache::createResource(const QUrl& url, const QSharedPointer& fallback, + bool delayLoad, const void* extra) { + return QSharedPointer(new Sound(url), &Resource::allReferencesCleared); +} \ No newline at end of file diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h new file mode 100644 index 0000000000..4146171794 --- /dev/null +++ b/libraries/audio/src/SoundCache.h @@ -0,0 +1,37 @@ +// +// SoundCache.h +// libraries/audio/src +// +// Created by Stephen Birarda on 2014-11-13. +// 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_SoundCache_h +#define hifi_SoundCache_h + +#include + +#include "Sound.h" + +typedef QSharedPointer SharedSoundPointer; + +/// Scriptable interface for FBX animation loading. +class SoundCache : public ResourceCache { + Q_OBJECT +public: + SoundCache(QObject* parent = NULL); + + Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); + +protected: + + virtual QSharedPointer createResource(const QUrl& url, + const QSharedPointer& fallback, bool delayLoad, const void* extra); +}; + +Q_DECLARE_METATYPE(SharedSoundPointer) + +#endif // hifi_SoundCache_h \ No newline at end of file diff --git a/libraries/avatars/src/Recording.cpp b/libraries/avatars/src/Recording.cpp index 0d089a2bd2..b39421d03a 100644 --- a/libraries/avatars/src/Recording.cpp +++ b/libraries/avatars/src/Recording.cpp @@ -43,13 +43,6 @@ void RecordingFrame::setBlendshapeCoefficients(QVector blendshapeCoeffici _blendshapeCoefficients = blendshapeCoefficients; } -Recording::Recording() : _audio(NULL) { -} - -Recording::~Recording() { - delete _audio; -} - int Recording::getLength() const { if (_timestamps.isEmpty()) { return 0; @@ -77,19 +70,10 @@ void Recording::addFrame(int timestamp, RecordingFrame &frame) { _frames << frame; } -void Recording::addAudioPacket(const QByteArray& byteArray) { - if (!_audio) { - _audio = new Sound(byteArray); - return; - } - _audio->append(byteArray); -} - void Recording::clear() { _timestamps.clear(); _frames.clear(); - delete _audio; - _audio = NULL; + _audioData.clear(); } void writeVec3(QDataStream& stream, const glm::vec3& value) { @@ -324,7 +308,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) { fileStream << buffer; } - fileStream << recording->_audio->getByteArray(); + fileStream << recording->getAudioData(); qint64 writingTime = timer.restart(); // Write data length and CRC-16 @@ -367,7 +351,7 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) { qDebug() << "Recording:"; qDebug() << "Total frames:" << recording->getFrameNumber(); - qDebug() << "Audio array:" << recording->getAudio()->getByteArray().size(); + qDebug() << "Audio array:" << recording->getAudioData().size(); } qint64 checksumTime = timer.elapsed(); @@ -642,7 +626,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString qDebug() << "Recording:"; qDebug() << "Total frames:" << recording->getFrameNumber(); - qDebug() << "Audio array:" << recording->getAudio()->getByteArray().size(); + qDebug() << "Audio array:" << recording->getAudioData().size(); } diff --git a/libraries/avatars/src/Recording.h b/libraries/avatars/src/Recording.h index aa14dc5d76..d1da77560c 100644 --- a/libraries/avatars/src/Recording.h +++ b/libraries/avatars/src/Recording.h @@ -48,9 +48,6 @@ public: /// Stores a recording class Recording { public: - Recording(); - ~Recording(); - bool isEmpty() const { return _timestamps.isEmpty(); } int getLength() const; // in ms @@ -58,11 +55,11 @@ public: int getFrameNumber() const { return _frames.size(); } qint32 getFrameTimestamp(int i) const; const RecordingFrame& getFrame(int i) const; - Sound* getAudio() const { return _audio; } + const QByteArray& getAudioData() const { return _audioData; } protected: void addFrame(int timestamp, RecordingFrame& frame); - void addAudioPacket(const QByteArray& byteArray); + void addAudioPacket(const QByteArray& byteArray) { _audioData.append(byteArray); } void clear(); private: @@ -70,7 +67,7 @@ private: QVector _timestamps; QVector _frames; - Sound* _audio; + QByteArray _audioData; friend class Recorder; friend class Player; From 7e2c4c05615d9300f26a1182e50f444ece003892 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 13 Nov 2014 10:57:32 -0800 Subject: [PATCH 11/45] SImplified the Transform usage in the gpu::api, no more pointers, just values. Improved the Transform by compressing the memory footprint --- interface/src/Application.cpp | 10 ++--- interface/src/Application.h | 6 +-- interface/src/gpu/Batch.cpp | 6 +-- interface/src/gpu/Batch.h | 40 ++++++++---------- interface/src/gpu/GLBackend.cpp | 36 ++++++---------- interface/src/gpu/GLBackend.h | 12 +++--- interface/src/renderer/Model.cpp | 17 ++++---- interface/src/renderer/Model.h | 2 +- libraries/shared/src/Transform.h | 70 ++++++++++++++++++++------------ 9 files changed, 101 insertions(+), 98 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c3ab4fe115..f11ac14d40 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -160,7 +160,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), - _viewTransform(new gpu::Transform()), + _viewTransform(), _scaleMirror(1.0f), _rotateMirror(0.0f), _raiseMirror(0.0f), @@ -2911,13 +2911,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // Equivalent to what is happening with _untranslatedViewMatrix and the _viewMatrixTranslation // the viewTransofmr object is updatded with the correct values and saved, // this is what is used for rendering the Entities and avatars - gpu::Transform viewTransform; + Transform viewTransform; viewTransform.setTranslation(whichCamera.getPosition()); viewTransform.setRotation(rotation); viewTransform.postTranslate(eyeOffsetPos); viewTransform.postRotate(eyeOffsetOrient); if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { - viewTransform.setScale(gpu::Transform::Vec3(-1.0f, 1.0f, 1.0f)); + viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); } setViewTransform(viewTransform); @@ -3117,8 +3117,8 @@ void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTransl _viewMatrixTranslation = viewMatrixTranslation; } -void Application::setViewTransform(const gpu::Transform& view) { - (*_viewTransform) = view; +void Application::setViewTransform(const Transform& view) { + _viewTransform = view; } void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 9ce857ee8a..cba39317a5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -232,8 +232,8 @@ public: const glm::vec3& getViewMatrixTranslation() const { return _viewMatrixTranslation; } void setViewMatrixTranslation(const glm::vec3& translation) { _viewMatrixTranslation = translation; } - const gpu::TransformPointer& getViewTransform() const { return _viewTransform; } - void setViewTransform(const gpu::Transform& view); + const Transform& getViewTransform() const { return _viewTransform; } + void setViewTransform(const Transform& view); /// if you need to access the application settings, use lockSettings()/unlockSettings() QSettings* lockSettings() { _settingsMutex.lock(); return _settings; } @@ -526,7 +526,7 @@ private: QRect _mirrorViewRect; RearMirrorTools* _rearMirrorTools; - gpu::TransformPointer _viewTransform; + Transform _viewTransform; glm::mat4 _untranslatedViewMatrix; glm::vec3 _viewMatrixTranslation; glm::mat4 _projectionMatrix; diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index 2bf92f43cf..30e591cc60 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -135,19 +135,19 @@ void Batch::setIndexBuffer(Type type, const BufferPointer& buffer, Offset offset _params.push_back(type); } -void Batch::setModelTransform(const TransformPointer& model) { +void Batch::setModelTransform(const Transform& model) { ADD_COMMAND(setModelTransform); _params.push_back(_transforms.cache(model)); } -void Batch::setViewTransform(const TransformPointer& view) { +void Batch::setViewTransform(const Transform& view) { ADD_COMMAND(setViewTransform); _params.push_back(_transforms.cache(view)); } -void Batch::setProjectionTransform(const TransformPointer& proj) { +void Batch::setProjectionTransform(const Transform& proj) { ADD_COMMAND(setProjectionTransform); _params.push_back(_transforms.cache(proj)); diff --git a/interface/src/gpu/Batch.h b/interface/src/gpu/Batch.h index 3c15fef63b..d006473b50 100644 --- a/interface/src/gpu/Batch.h +++ b/interface/src/gpu/Batch.h @@ -50,10 +50,6 @@ enum Primitive { NUM_PRIMITIVES, }; -typedef ::Transform Transform; -typedef QSharedPointer< ::gpu::Transform > TransformPointer; -typedef std::vector< TransformPointer > Transforms; - class Batch { public: typedef Stream::Slot Slot; @@ -87,9 +83,9 @@ public: // finaly projected into the clip space by the projection transform // WARNING: ViewTransform transform from eye space to world space, its inverse is composed // with the ModelTransformu to create the equivalent of the glModelViewMatrix - void setModelTransform(const TransformPointer& model); - void setViewTransform(const TransformPointer& view); - void setProjectionTransform(const TransformPointer& proj); + void setModelTransform(const Transform& model); + void setViewTransform(const Transform& view); + void setProjectionTransform(const Transform& proj); // TODO: As long as we have gl calls explicitely issued from interface @@ -258,35 +254,35 @@ public: template class Cache { public: - typedef QSharedPointer Pointer; - Pointer _pointer; - Cache(const Pointer& pointer) : _pointer(pointer) {} + typedef T Data; + Data _data; + Cache(const Data& data) : _data(data) {} class Vector { public: - std::vector< Cache > _pointers; + std::vector< Cache > _items; - uint32 cache(const Pointer& pointer) { - uint32 offset = _pointers.size(); - _pointers.push_back(Cache(pointer)); + uint32 cache(const Data& data) { + uint32 offset = _items.size(); + _items.push_back(Cache(data)); return offset; } - Pointer get(uint32 offset) { - if (offset >= _pointers.size()) { - return Pointer(); + Data get(uint32 offset) { + if (offset >= _items.size()) { + return Data(); } - return (_pointers.data() + offset)->_pointer; + return (_items.data() + offset)->_data; } void clear() { - _pointers.clear(); + _items.clear(); } }; }; - - typedef Cache::Vector BufferCaches; - typedef Cache::Vector StreamFormatCaches; + + typedef Cache::Vector BufferCaches; + typedef Cache::Vector StreamFormatCaches; typedef Cache::Vector TransformCaches; typedef unsigned char Byte; diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 8921dc6d1c..539ac69b8d 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -430,30 +430,18 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { // Transform Stage void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { - TransformPointer modelTransform = batch._transforms.get(batch._params[paramOffset]._uint); - - if (_transform._model.isNull() || (modelTransform != _transform._model)) { - _transform._model = modelTransform; - _transform._invalidModel = true; - } + _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); + _transform._invalidModel = true; } void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { - TransformPointer viewTransform = batch._transforms.get(batch._params[paramOffset]._uint); - - if (_transform._view.isNull() || (viewTransform != _transform._view)) { - _transform._view = viewTransform; - _transform._invalidView = true; - } + _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); + _transform._invalidView = true; } void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { - TransformPointer projectionTransform = batch._transforms.get(batch._params[paramOffset]._uint); - - if (_transform._projection.isNull() || (projectionTransform != _transform._projection)) { - _transform._projection = projectionTransform; - _transform._invalidProj = true; - } + _transform._projection = batch._transforms.get(batch._params[paramOffset]._uint); + _transform._invalidProj = true; } void GLBackend::updateTransform() { @@ -468,28 +456,28 @@ void GLBackend::updateTransform() { } if (_transform._invalidModel || _transform._invalidView) { - if (!_transform._model.isNull()) { + if (!_transform._model.isIdentity()) { if (_transform._lastMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; - if (!_transform._view.isNull()) { + if (!_transform._view.isIdentity()) { Transform mvx; - Transform::inverseMult(mvx, (*_transform._view), (*_transform._model)); + Transform::inverseMult(mvx, _transform._view, _transform._model); mvx.getMatrix(modelView); } else { - _transform._model->getMatrix(modelView); + _transform._model.getMatrix(modelView); } glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { - if (!_transform._view.isNull()) { + if (!_transform._view.isIdentity()) { if (_transform._lastMode != GL_MODELVIEW) { glMatrixMode(GL_MODELVIEW); _transform._lastMode = GL_MODELVIEW; } Transform::Mat4 modelView; - _transform._view->getInverseMatrix(modelView); + _transform._view.getInverseMatrix(modelView); glLoadMatrixf(reinterpret_cast< const GLfloat* >(&modelView)); } else { // TODO: eventually do something about the matrix when neither view nor model is specified? diff --git a/interface/src/gpu/GLBackend.h b/interface/src/gpu/GLBackend.h index 0f58ec192d..8524722e75 100644 --- a/interface/src/gpu/GLBackend.h +++ b/interface/src/gpu/GLBackend.h @@ -86,9 +86,9 @@ protected: void updateTransform(); struct TransformStageState { - TransformPointer _model; - TransformPointer _view; - TransformPointer _projection; + Transform _model; + Transform _view; + Transform _projection; bool _invalidModel; bool _invalidView; bool _invalidProj; @@ -96,9 +96,9 @@ protected: GLenum _lastMode; TransformStageState() : - _model(0), - _view(0), - _projection(0), + _model(), + _view(), + _projection(), _invalidModel(true), _invalidView(true), _invalidProj(true), diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 8b3c656ae7..8cbcbaa959 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -567,11 +567,11 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { // Capture the view matrix once for the rendering of this model if (_transforms.empty()) { - _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); + _transforms.push_back(Transform()); } - (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); + _transforms[0] = Application::getInstance()->getViewTransform(); // apply entity translation offset to the viewTransform in one go (it's a preTranslate because viewTransform goes from world to eye space) - _transforms[0]->preTranslate(-_translation); + _transforms[0].preTranslate(-_translation); batch.setViewTransform(_transforms[0]); @@ -1493,10 +1493,10 @@ void Model::setupBatchTransform(gpu::Batch& batch) { // Capture the view matrix once for the rendering of this model if (_transforms.empty()) { - _transforms.push_back(gpu::TransformPointer(new gpu::Transform())); + _transforms.push_back(Transform()); } - (*_transforms[0]) = gpu::Transform((*Application::getInstance()->getViewTransform())); - _transforms[0]->preTranslate(-_translation); + _transforms[0] = Application::getInstance()->getViewTransform(); + _transforms[0].preTranslate(-_translation); batch.setViewTransform(_transforms[0]); } @@ -2149,10 +2149,9 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl if (state.clusterMatrices.size() > 1) { GLBATCH(glUniformMatrix4fv)(skinLocations->clusterMatrices, state.clusterMatrices.size(), false, (const float*)state.clusterMatrices.constData()); - batch.setModelTransform(gpu::TransformPointer()); + batch.setModelTransform(Transform()); } else { - gpu::TransformPointer modelTransform(new gpu::Transform(state.clusterMatrices[0])); - batch.setModelTransform(modelTransform); + batch.setModelTransform(Transform(state.clusterMatrices[0])); } if (mesh.blendshapes.isEmpty()) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 8c74b1a222..e6454a964a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -283,7 +283,7 @@ private: QUrl _url; gpu::Buffers _blendedVertexBuffers; - gpu::Transforms _transforms; + std::vector _transforms; gpu::Batch _renderBatch; QVector > > _dilatedTextures; diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 6ad106063f..3c668adcd6 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -20,6 +20,8 @@ #include +#include + class Transform { public: typedef glm::mat4 Mat4; @@ -30,16 +32,16 @@ public: typedef glm::quat Quat; Transform() : - _translation(0), _rotation(1.0f, 0, 0, 0), _scale(1.0f), + _translation(0), _flags(FLAG_CACHE_INVALID_BITSET) // invalid cache { } Transform(const Transform& transform) : - _translation(transform._translation), _rotation(transform._rotation), _scale(transform._scale), + _translation(transform._translation), _flags(transform._flags) { invalidCache(); @@ -49,6 +51,15 @@ public: } ~Transform() {} + Transform& operator=(const Transform& transform) { + _rotation = transform._rotation; + _scale = transform._scale; + _translation = transform._translation; + _flags = transform._flags; + invalidCache(); + return (*this); + } + void setIdentity(); const Vec3& getTranslation() const; @@ -89,7 +100,6 @@ public: // Left will be inversed before the multiplication static Transform& inverseMult(Transform& result, const Transform& left, const Transform& right); - protected: enum Flag { @@ -111,14 +121,15 @@ protected: // TRS - Vec3 _translation; Quat _rotation; Vec3 _scale; + Vec3 _translation; mutable Flags _flags; // Cached transform - mutable Mat4 _matrix; + // TODO: replace this auto ptr by a "unique ptr" as soon as we are compiling in C++11 + mutable std::auto_ptr _matrix; bool isCacheInvalid() const { return _flags[FLAG_CACHE_INVALID]; } void validCache() const { _flags.set(FLAG_CACHE_INVALID, false); } @@ -135,6 +146,7 @@ protected: void flagNonUniform() { _flags.set(FLAG_NON_UNIFORM, true); } void updateCache() const; + Mat4& getCachedMatrix(Mat4& result) const; }; inline void Transform::setIdentity() { @@ -271,8 +283,25 @@ inline void Transform::postScale(const Vec3& scale) { } inline Transform::Mat4& Transform::getMatrix(Transform::Mat4& result) const { - updateCache(); - result = _matrix; + if (isRotating()) { + Mat3 rot = glm::mat3_cast(_rotation); + + if (isScaling()) { + rot[0] *= _scale.x; + rot[1] *= _scale.y; + rot[2] *= _scale.z; + } + + result[0] = Vec4(rot[0], 0.f); + result[1] = Vec4(rot[1], 0.f); + result[2] = Vec4(rot[2], 0.f); + } else { + result[0] = Vec4(_scale.x, 0.f, 0.f, 0.f); + result[1] = Vec4(0.f, _scale.y, 0.f, 0.f); + result[2] = Vec4(0.f, 0.f, _scale.z, 0.f); + } + + result[3] = Vec4(_translation, 1.0f); return result; } @@ -369,27 +398,18 @@ inline Transform& Transform::inverseMult( Transform& result, const Transform& le return result; } +inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result) const { + updateCache(); + result = (*_matrix); + return result; +} + inline void Transform::updateCache() const { if (isCacheInvalid()) { - if (isRotating()) { - Mat3 rot = glm::mat3_cast(_rotation); - - if (isScaling()) { - rot[0] *= _scale.x; - rot[1] *= _scale.y; - rot[2] *= _scale.z; - } - - _matrix[0] = Vec4(rot[0], 0.f); - _matrix[1] = Vec4(rot[1], 0.f); - _matrix[2] = Vec4(rot[2], 0.f); - } else { - _matrix[0] = Vec4(_scale.x, 0.f, 0.f, 0.f); - _matrix[1] = Vec4(0.f, _scale.y, 0.f, 0.f); - _matrix[2] = Vec4(0.f, 0.f, _scale.z, 0.f); + if (!_matrix.get()) { + _matrix.reset(new Mat4()); } - - _matrix[3] = Vec4(_translation, 1.0f); + getMatrix((*_matrix)); validCache(); } } From 8d4cecda6241dd8bdfec6ef29418aa32a50227bb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 13 Nov 2014 11:06:40 -0800 Subject: [PATCH 12/45] Optimization and coding standard --- interface/src/ui/overlays/Overlays.cpp | 19 ++++++++++--------- interface/src/ui/overlays/Overlays.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index b65fe6d286..d208658e8b 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -358,18 +358,19 @@ bool Overlays::isLoaded(unsigned int id) { return overlay->isLoaded(); } -float Overlays::textWidth(unsigned int id, const QString& text) { - if (_overlays2D.contains(id)) { - Overlay* thisOverlay = _overlays2D[id]; +const float Overlays::textWidth(unsigned int id, const QString& text) { + Overlay* thisOverlay = _overlays2D[id]; + if (thisOverlay) { if (typeid(*thisOverlay) == typeid(TextOverlay)) { return static_cast(thisOverlay)->textWidth(text); } - } - if (_overlays3D.contains(id)) { - Overlay* thisOverlay = _overlays3D[id]; - if (typeid(*thisOverlay) == typeid(Text3DOverlay)) { - return static_cast(thisOverlay)->textWidth(text); + } else { + thisOverlay = _overlays3D[id]; + if (thisOverlay) { + if (typeid(*thisOverlay) == typeid(Text3DOverlay)) { + return static_cast(thisOverlay)->textWidth(text); + } } } - return 0.f; + return 0.0f; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index dcda9a8ed7..4e11526f23 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -67,7 +67,7 @@ public slots: /// returns the width of the given text in the specified overlay if it is a text overlay: in pixels if it is a 2D text /// overlay; in meters if it is a 3D text overlay - float textWidth(unsigned int id, const QString& text); + const float textWidth(unsigned int id, const QString& text); private: QMap _overlays2D; From 493455fdacb8edbeb23d6d2d251150a300a93f79 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 13 Nov 2014 11:34:40 -0800 Subject: [PATCH 13/45] Fix const --- interface/src/ui/overlays/Overlays.cpp | 2 +- interface/src/ui/overlays/Overlays.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index d208658e8b..029b0d90a1 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -358,7 +358,7 @@ bool Overlays::isLoaded(unsigned int id) { return overlay->isLoaded(); } -const float Overlays::textWidth(unsigned int id, const QString& text) { +float Overlays::textWidth(unsigned int id, const QString& text) const { Overlay* thisOverlay = _overlays2D[id]; if (thisOverlay) { if (typeid(*thisOverlay) == typeid(TextOverlay)) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 4e11526f23..66232196f2 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -67,7 +67,7 @@ public slots: /// returns the width of the given text in the specified overlay if it is a text overlay: in pixels if it is a 2D text /// overlay; in meters if it is a 3D text overlay - const float textWidth(unsigned int id, const QString& text); + float textWidth(unsigned int id, const QString& text) const; private: QMap _overlays2D; From 6f4952c7d52fe733cc0a7b36c06b0c57f2ebd38d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 13 Nov 2014 12:25:15 -0800 Subject: [PATCH 14/45] More consts --- interface/src/ui/overlays/Text3DOverlay.cpp | 2 +- interface/src/ui/overlays/Text3DOverlay.h | 2 +- interface/src/ui/overlays/TextOverlay.cpp | 2 +- interface/src/ui/overlays/TextOverlay.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 5928e328ba..3a3a23e828 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -180,7 +180,7 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) { } -float Text3DOverlay::textWidth(const QString& text) { +float Text3DOverlay::textWidth(const QString& text) const { QFont font(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); // Same font properties as render() QFontMetrics fontMetrics(font); float scaleFactor = _lineHeight * LINE_SCALE_RATIO / (float)FIXED_FONT_POINT_SIZE; diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index f0369b4206..e9969b1cad 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -48,7 +48,7 @@ public: virtual void setProperties(const QScriptValue& properties); - float textWidth(const QString& text); // Meters + float textWidth(const QString& text) const; // Meters private: void enableClipPlane(GLenum plane, float x, float y, float z, float w); diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 9f194b75dd..356ba419b0 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -125,7 +125,7 @@ void TextOverlay::setProperties(const QScriptValue& properties) { } -float TextOverlay::textWidth(const QString& text) { +float TextOverlay::textWidth(const QString& text) const { QFont font(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); // Same font properties as render() QFontMetrics fontMetrics(font); return fontMetrics.width(qPrintable(text)); diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 2922d747ca..9fc6480eb7 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -54,7 +54,7 @@ public: virtual void setProperties(const QScriptValue& properties); - float textWidth(const QString& text); // Pixels + float textWidth(const QString& text) const; // Pixels private: From 5c9c78e62b2bbbe1b6fdfd128faafac3447efc32 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 13 Nov 2014 12:32:48 -0800 Subject: [PATCH 15/45] Moving all the variables for the Input stage cache into a struct just like for transformStage --- interface/src/gpu/GLBackend.cpp | 68 +++++++++++++++------------------ interface/src/gpu/GLBackend.h | 43 ++++++++++++++------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 539ac69b8d..d6e1a011a3 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -113,15 +113,7 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { GLBackend::GLBackend() : - _needInputFormatUpdate(true), - _inputFormat(0), - _inputBuffersState(0), - _inputBuffers(_inputBuffersState.size(), BufferPointer(0)), - _inputBufferOffsets(_inputBuffersState.size(), 0), - _inputBufferStrides(_inputBuffersState.size(), 0), - _indexBuffer(0), - _indexBufferOffset(0), - _inputAttributeActivation(0), + _input(), _transform() { @@ -203,9 +195,9 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { uint32 numIndices = batch._params[paramOffset + 1]._uint; uint32 startIndex = batch._params[paramOffset + 0]._uint; - GLenum glType = _elementTypeToGLType[_indexBufferType]; + GLenum glType = _elementTypeToGLType[_input._indexBufferType]; - glDrawElements(mode, numIndices, glType, reinterpret_cast(startIndex + _indexBufferOffset)); + glDrawElements(mode, numIndices, glType, reinterpret_cast(startIndex + _input._indexBufferOffset)); CHECK_GL_ERROR(); } @@ -220,9 +212,9 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); - if (format != _inputFormat) { - _inputFormat = format; - _needInputFormatUpdate = true; + if (format != _input._format) { + _input._format = format; + _input._invalidFormat = true; } } @@ -233,10 +225,10 @@ void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { uint32 channel = batch._params[paramOffset + 3]._uint; if (channel < getNumInputBuffers()) { - _inputBuffers[channel] = buffer; - _inputBufferOffsets[channel] = offset; - _inputBufferStrides[channel] = stride; - _inputBuffersState.set(channel); + _input._buffers[channel] = buffer; + _input._bufferOffsets[channel] = offset; + _input._bufferStrides[channel] = stride; + _input._buffersState.set(channel); } } @@ -252,14 +244,14 @@ static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = { #endif void GLBackend::updateInput() { - if (_needInputFormatUpdate || _inputBuffersState.any()) { + if (_input._invalidFormat || _input._buffersState.any()) { - if (_needInputFormatUpdate) { - InputActivationCache newActivation; + if (_input._invalidFormat) { + InputStageState::ActivationCache newActivation; // Check expected activation - if (_inputFormat) { - const Stream::Format::AttributeMap& attributes = _inputFormat->getAttributes(); + if (_input._format) { + const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); for (Stream::Format::AttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++) { const Stream::Attribute& attrib = (*it).second; newActivation.set(attrib._slot); @@ -269,7 +261,7 @@ void GLBackend::updateInput() { // Manage Activation what was and what is expected now for (unsigned int i = 0; i < newActivation.size(); i++) { bool newState = newActivation[i]; - if (newState != _inputAttributeActivation[i]) { + if (newState != _input._attributeActivation[i]) { #if defined(SUPPORT_LEGACY_OPENGL) if (i < NUM_CLASSIC_ATTRIBS) { if (newState) { @@ -290,31 +282,31 @@ void GLBackend::updateInput() { } CHECK_GL_ERROR(); - _inputAttributeActivation.flip(i); + _input._attributeActivation.flip(i); } } } // now we need to bind the buffers and assign the attrib pointers - if (_inputFormat) { - const Buffers& buffers = _inputBuffers; - const Offsets& offsets = _inputBufferOffsets; - const Offsets& strides = _inputBufferStrides; + if (_input._format) { + const Buffers& buffers = _input._buffers; + const Offsets& offsets = _input._bufferOffsets; + const Offsets& strides = _input._bufferStrides; - const Stream::Format::AttributeMap& attributes = _inputFormat->getAttributes(); + const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); - for (Stream::Format::ChannelMap::const_iterator channelIt = _inputFormat->getChannels().begin(); - channelIt != _inputFormat->getChannels().end(); + for (Stream::Format::ChannelMap::const_iterator channelIt = _input._format->getChannels().begin(); + channelIt != _input._format->getChannels().end(); channelIt++) { const Stream::Format::ChannelMap::value_type::second_type& channel = (*channelIt).second; if ((*channelIt).first < buffers.size()) { int bufferNum = (*channelIt).first; - if (_inputBuffersState.test(bufferNum) || _needInputFormatUpdate) { + if (_input._buffersState.test(bufferNum) || _input._invalidFormat) { GLuint vbo = gpu::GLBackend::getBufferID((*buffers[bufferNum])); glBindBuffer(GL_ARRAY_BUFFER, vbo); CHECK_GL_ERROR(); - _inputBuffersState[bufferNum] = false; + _input._buffersState[bufferNum] = false; for (unsigned int i = 0; i < channel._slots.size(); i++) { const Stream::Attribute& attrib = attributes.at(channel._slots[i]); @@ -354,7 +346,7 @@ void GLBackend::updateInput() { } } // everything format related should be in sync now - _needInputFormatUpdate = false; + _input._invalidFormat = false; } /* TODO: Fancy version GL4.4 @@ -415,10 +407,10 @@ void GLBackend::updateInput() { void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { - _indexBufferType = (Type) batch._params[paramOffset + 2]._uint; + _input._indexBufferType = (Type) batch._params[paramOffset + 2]._uint; BufferPointer indexBuffer = batch._buffers.get(batch._params[paramOffset + 1]._uint); - _indexBufferOffset = batch._params[paramOffset + 0]._uint; - _indexBuffer = indexBuffer; + _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; + _input._indexBuffer = indexBuffer; if (indexBuffer) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); } else { diff --git a/interface/src/gpu/GLBackend.h b/interface/src/gpu/GLBackend.h index 8524722e75..71869229fd 100644 --- a/interface/src/gpu/GLBackend.h +++ b/interface/src/gpu/GLBackend.h @@ -48,7 +48,7 @@ public: static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; - uint32 getNumInputBuffers() const { return _inputBuffersState.size(); } + uint32 getNumInputBuffers() const { return _input._buffersState.size(); } protected: @@ -62,22 +62,39 @@ protected: void do_setInputFormat(Batch& batch, uint32 paramOffset); void do_setInputBuffer(Batch& batch, uint32 paramOffset); void do_setIndexBuffer(Batch& batch, uint32 paramOffset); + void updateInput(); - bool _needInputFormatUpdate; - Stream::FormatPointer _inputFormat; - typedef std::bitset InputBuffersState; - InputBuffersState _inputBuffersState; + struct InputStageState { + bool _invalidFormat; + Stream::FormatPointer _format; - Buffers _inputBuffers; - Offsets _inputBufferOffsets; - Offsets _inputBufferStrides; + typedef std::bitset BuffersState; + BuffersState _buffersState; - BufferPointer _indexBuffer; - Offset _indexBufferOffset; - Type _indexBufferType; + Buffers _buffers; + Offsets _bufferOffsets; + Offsets _bufferStrides; - typedef std::bitset InputActivationCache; - InputActivationCache _inputAttributeActivation; + BufferPointer _indexBuffer; + Offset _indexBufferOffset; + Type _indexBufferType; + + typedef std::bitset ActivationCache; + ActivationCache _attributeActivation; + + InputStageState() : + _invalidFormat(true), + _format(0), + _buffersState(0), + _buffers(_buffersState.size(), BufferPointer(0)), + _bufferOffsets(_buffersState.size(), 0), + _bufferStrides(_buffersState.size(), 0), + _indexBuffer(0), + _indexBufferOffset(0), + _indexBufferType(UINT32), + _attributeActivation(0) + {} + } _input; // Transform Stage void do_setModelTransform(Batch& batch, uint32 paramOffset); From 7ba3c74bc0c6840af70ce72e467c8afbd5bef1e0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 14:47:02 -0800 Subject: [PATCH 16/45] more work on render model scenes --- interface/src/renderer/Model.cpp | 260 ++++++++++++++----------------- interface/src/renderer/Model.h | 12 ++ 2 files changed, 125 insertions(+), 147 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 8b3c656ae7..d10ce80126 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1553,46 +1553,18 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int opaqueMeshPartsRendered = 0; // now, for each model in the scene, render the mesh portions - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - opaqueMeshPartsRendered += model->renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); - GLBATCH(glPopMatrix)(); - } + //bool pickProgramsNeeded = true; + //SkinLocations* skinLocations; + //GLenum specularTextureUnit; + + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, args); // render translucent meshes afterwards //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); @@ -1606,46 +1578,14 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int translucentParts = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); - GLBATCH(glPopMatrix)(); - } + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, true, args); GLBATCH(glDisable)(GL_ALPHA_TEST); GLBATCH(glEnable)(GL_BLEND); @@ -1662,46 +1602,14 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); - GLBATCH(glPopMatrix)(); - } - foreach(Model* model, _modelsInScene) { - model->setupBatchTransform(batch); - translucentParts += model->renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); - GLBATCH(glPopMatrix)(); - } + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, true, args); } GLBATCH(glDepthMask)(true); @@ -1981,19 +1889,8 @@ void Model::segregateMeshGroups() { _meshGroupsKnown = true; } -int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { - +QVector* Model::pickMeshList(bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned) { PROFILE_RANGE(__FUNCTION__); - bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); - bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); - bool dontReduceMaterialSwitches = Menu::getInstance()->isOptionChecked(MenuOption::DontReduceMaterialSwitches); - - QString lastMaterialID; - int meshPartsRendered = 0; - updateVisibleJointStates(); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const QVector& networkMeshes = _geometry->getMeshes(); // depending on which parameters we were called with, pick the correct mesh group to render QVector* whichList = NULL; @@ -2032,23 +1929,18 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } else { qDebug() << "unexpected!!! this mesh didn't fall into any or our groups???"; } - - if (!whichList) { - qDebug() << "unexpected!!! we don't know which list of meshes to render..."; - return 0; - } - QVector& list = *whichList; - - // If this list has nothing to render, then don't bother proceeding. This saves us on binding to programs - if (list.size() == 0) { - return 0; - } + return whichList; +} +void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, + SkinLocations*& skinLocations, GLenum& specularTextureUnit) { + ProgramObject* program = &_program; Locations* locations = &_locations; ProgramObject* skinProgram = &_skinProgram; - SkinLocations* skinLocations = &_skinLocations; - GLenum specularTextureUnit = 0; + skinLocations = &_skinLocations; + specularTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { program = &_shadowProgram; skinProgram = &_skinShadowProgram; @@ -2091,8 +1983,84 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl if (!activeProgram->isLinked()) { activeProgram->link(); } + GLBATCH(glUseProgram)(activeProgram->programId()); GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); +} + +int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + + PROFILE_RANGE(__FUNCTION__); + int meshPartsRendered = 0; + + bool pickProgramsNeeded = true; + SkinLocations* skinLocations; + GLenum specularTextureUnit; + + foreach(Model* model, _modelsInScene) { + QVector* whichList = model->pickMeshList(translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned); + if (whichList) { + QVector& list = *whichList; + if (list.size() > 0) { + //if (pickProgramsNeeded) { + pickPrograms(batch, mode, translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned, args, skinLocations, specularTextureUnit); + pickProgramsNeeded = false; + //} + model->setupBatchTransform(batch); + meshPartsRendered += model->renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, skinLocations, specularTextureUnit); + GLBATCH(glPopMatrix)(); + } + } + } + // if we selected a program, then unselect it + if (!pickProgramsNeeded) { + //GLBATCH(glUseProgram)(0); + } + return meshPartsRendered; +} + +int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + + PROFILE_RANGE(__FUNCTION__); + int meshPartsRendered = 0; + + QVector* whichList = pickMeshList(translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned); + + if (!whichList) { + qDebug() << "unexpected!!! we don't know which list of meshes to render..."; + return 0; + } + QVector& list = *whichList; + + // If this list has nothing to render, then don't bother proceeding. This saves us on binding to programs + if (list.size() == 0) { + return 0; + } + + SkinLocations* skinLocations; + GLenum specularTextureUnit; + pickPrograms(batch, mode, translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned, args, skinLocations, specularTextureUnit); + meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, skinLocations, specularTextureUnit); + GLBATCH(glUseProgram)(0); + + return meshPartsRendered; +} + + +int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args, + SkinLocations* skinLocations, GLenum specularTextureUnit) { + PROFILE_RANGE(__FUNCTION__); + bool dontCullOutOfViewMeshParts = Menu::getInstance()->isOptionChecked(MenuOption::DontCullOutOfViewMeshParts); + bool cullTooSmallMeshParts = !Menu::getInstance()->isOptionChecked(MenuOption::DontCullTooSmallMeshParts); + bool dontReduceMaterialSwitches = Menu::getInstance()->isOptionChecked(MenuOption::DontReduceMaterialSwitches); + + QString lastMaterialID; + int meshPartsRendered = 0; + updateVisibleJointStates(); + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const QVector& networkMeshes = _geometry->getMeshes(); // i is the "index" from the original networkMeshes QVector... foreach (int i, list) { @@ -2268,7 +2236,5 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } - GLBATCH(glUseProgram)(0); - return meshPartsRendered; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 8c74b1a222..ab6b990eb2 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -409,6 +409,18 @@ private: int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); void setupBatchTransform(gpu::Batch& batch); + QVector* pickMeshList(bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, bool isSkinned); + + int renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + RenderArgs* args, SkinLocations* skinLocations, GLenum specularTextureUnit); + + static void pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, + SkinLocations*& skinLocations, GLenum& specularTextureUnit); + + static int renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, + bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args); + }; From e10d132f754ced8e0b75f66e523151f3550486cb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 14:47:28 -0800 Subject: [PATCH 17/45] avoid Qt QTimer thread bug by putting SoundCache on same thread --- examples/birdSongs.js | 9 ++-- interface/src/Application.cpp | 2 + .../audio/src/AudioScriptingInterface.cpp | 48 ++++++++++--------- libraries/audio/src/Sound.cpp | 15 +++--- libraries/audio/src/Sound.h | 13 ++++- libraries/audio/src/SoundCache.cpp | 14 +++++- libraries/audio/src/SoundCache.h | 11 ++--- libraries/avatars/src/Player.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 6 ++- libraries/script-engine/src/ScriptEngine.cpp | 13 ----- libraries/shared/src/LogHandler.cpp | 2 - 11 files changed, 74 insertions(+), 61 deletions(-) diff --git a/examples/birdSongs.js b/examples/birdSongs.js index 680cb025ad..267fa20b49 100644 --- a/examples/birdSongs.js +++ b/examples/birdSongs.js @@ -67,7 +67,7 @@ function maybePlaySound(deltaTime) { lifetime: 10 }); } - + playing.push({ audioId: Audio.playSound(birds[whichBird].sound, options), entityId: entityId, lightId: lightId, color: birds[whichBird].color }); } if (playing.length != numPlaying) { @@ -159,8 +159,9 @@ function loadBirds() { var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/"; for (var i = 0; i < sound_filenames.length; i++) { - birds.push({ sound: new Sound(SOUND_BASE_URL + sound_filenames[i]), - color: colors[i] - } ); + birds.push({ + sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]), + color: colors[i] + }); } } \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f11ac14d40..6188811442 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -3916,6 +3917,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); + scriptEngine->registerGlobalObject("SoundCache", &SoundCache::getInstance()); scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels); diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index cb010ef11d..35a11f4dd4 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -43,28 +43,32 @@ void AudioScriptingInterface::stopAllInjectors() { } AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { - - AudioInjector* injector = new AudioInjector(sound, injectorOptions); - injector->setLocalAudioInterface(_localAudioInterface); - - QThread* injectorThread = new QThread(); - - injector->moveToThread(injectorThread); - - // start injecting when the injector thread starts - connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); - - // connect the right slots and signals so that the AudioInjector is killed once the injection is complete - connect(injector, &AudioInjector::finished, injector, &AudioInjector::deleteLater); - connect(injector, &AudioInjector::finished, injectorThread, &QThread::quit); - connect(injector, &AudioInjector::finished, this, &AudioScriptingInterface::injectorStopped); - connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); - - injectorThread->start(); - - _activeInjectors.append(QPointer(injector)); - - return injector; + if (sound) { + AudioInjector* injector = new AudioInjector(sound, injectorOptions); + injector->setLocalAudioInterface(_localAudioInterface); + + QThread* injectorThread = new QThread(); + + injector->moveToThread(injectorThread); + + // start injecting when the injector thread starts + connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); + + // connect the right slots and signals so that the AudioInjector is killed once the injection is complete + connect(injector, &AudioInjector::finished, injector, &AudioInjector::deleteLater); + connect(injector, &AudioInjector::finished, injectorThread, &QThread::quit); + connect(injector, &AudioInjector::finished, this, &AudioScriptingInterface::injectorStopped); + connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); + + injectorThread->start(); + + _activeInjectors.append(QPointer(injector)); + + return injector; + } else { + qDebug() << "AudioScriptingInterface::playSound called with null Sound object."; + return NULL; + } } void AudioScriptingInterface::stopInjector(AudioInjector* injector) { diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 8f858e6d3c..ff54e262f8 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -29,18 +29,19 @@ #include "AudioEditBuffer.h" #include "Sound.h" - -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in) { - return engine->newQObject(in); +QScriptValue soundToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in) { + return engine->newQObject(in.data()); } -void soundFromScriptValue(const QScriptValue& object, Sound*& out) { - out = qobject_cast(object.toQObject()); +void soundFromScriptValue(const QScriptValue &object, SharedSoundPointer &out) { + out = SharedSoundPointer(qobject_cast(object.toQObject())); + qDebug() << "Sound from script value" << out.data(); } Sound::Sound(const QUrl& url, bool isStereo) : Resource(url), - _isStereo(isStereo) + _isStereo(isStereo), + _isReady(false) { } @@ -70,6 +71,8 @@ void Sound::downloadFinished(QNetworkReply* reply) { } else { qDebug() << "Network reply without 'Content-Type'."; } + + _isReady = true; } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 2880781ac6..c78bf72ff7 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -21,17 +21,19 @@ class Sound : public Resource { Q_OBJECT - Q_PROPERTY(bool downloaded READ isLoaded) + Q_PROPERTY(bool downloaded READ isReady) public: Sound(const QUrl& url, bool isStereo = false); bool isStereo() const { return _isStereo; } - + bool isReady() const { return _isReady; } + const QByteArray& getByteArray() { return _byteArray; } private: QByteArray _byteArray; bool _isStereo; + bool _isReady; void trimFrames(); void downSample(const QByteArray& rawAudioByteArray); @@ -40,4 +42,11 @@ private: virtual void downloadFinished(QNetworkReply* reply); }; +typedef QSharedPointer SharedSoundPointer; + +Q_DECLARE_METATYPE(SharedSoundPointer) + +QScriptValue soundToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in); +void soundFromScriptValue(const QScriptValue& object, SharedSoundPointer& out); + #endif // hifi_Sound_h diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 09b9cfe330..68a35e3c48 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -13,8 +13,17 @@ #include "SoundCache.h" +static int soundPointerMetaTypeId = qRegisterMetaType(); + +SoundCache& SoundCache::getInstance() { + static SoundCache staticInstance; + return staticInstance; +} + SoundCache::SoundCache(QObject* parent) : - ResourceCache(parent) { + ResourceCache(parent) +{ + } SharedSoundPointer SoundCache::getSound(const QUrl& url) { @@ -24,10 +33,11 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) { Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); return result; } + qDebug() << "Requesting sound at" << url.toString() << "from SoundCache"; return getResource(url).staticCast(); } QSharedPointer SoundCache::createResource(const QUrl& url, const QSharedPointer& fallback, - bool delayLoad, const void* extra) { + bool delayLoad, const void* extra) { return QSharedPointer(new Sound(url), &Resource::allReferencesCleared); } \ No newline at end of file diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h index 4146171794..f9fbf51c10 100644 --- a/libraries/audio/src/SoundCache.h +++ b/libraries/audio/src/SoundCache.h @@ -16,22 +16,19 @@ #include "Sound.h" -typedef QSharedPointer SharedSoundPointer; - -/// Scriptable interface for FBX animation loading. +/// Scriptable interface for sound loading. class SoundCache : public ResourceCache { Q_OBJECT public: - SoundCache(QObject* parent = NULL); + static SoundCache& getInstance(); Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra); +private: + SoundCache(QObject* parent = NULL); }; -Q_DECLARE_METATYPE(SharedSoundPointer) - #endif // hifi_SoundCache_h \ No newline at end of file diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 63384371bd..9f01e98730 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -168,7 +168,7 @@ void Player::setupAudioThread() { _audioThread = new QThread(); _options.position = _avatar->getPosition(); _options.orientation = _avatar->getOrientation(); - _injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater); + _injector.reset(new AudioInjector(_recording->getAudioData(), _options), &QObject::deleteLater); _injector->moveToThread(_audioThread); _audioThread->start(); QMetaObject::invokeMethod(_injector.data(), "injectAudio", Qt::QueuedConnection); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index bd0f1cae01..097ede23d0 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -22,7 +22,9 @@ ResourceCache::ResourceCache(QObject* parent) : QObject(parent), - _lastLRUKey(0) { + _lastLRUKey(0) +{ + } ResourceCache::~ResourceCache() { @@ -291,7 +293,7 @@ void Resource::makeRequest() { connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); - + _replyTimer = new QTimer(this); connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); _replyTimer->setSingleShot(true); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2691b10273..e6002d7c10 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -47,14 +46,6 @@ VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; EntityScriptingInterface ScriptEngine::_entityScriptingInterface; -static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) { - QUrl soundURL = QUrl(context->argument(0).toString()); - bool isStereo = context->argument(1).toBool(); - QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL, isStereo), QScriptEngine::ScriptOwnership); - - return soundScriptValue; -} - static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ qDebug() << "script:print()<<" << context->argument(0).toString(); QString message = context->argument(0).toString() @@ -263,10 +254,6 @@ void ScriptEngine::init() { QScriptValue printConstructorValue = newFunction(debugPrint); globalObject().setProperty("print", printConstructorValue); - QScriptValue soundConstructorValue = newFunction(soundConstructor); - QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); - globalObject().setProperty("Sound", soundMetaObject); - QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index a13f3a9dad..dfac02b912 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -119,8 +119,6 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont char dateString[100]; strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime); - prefixString.append(QString(" [%1]").arg(dateString)); - if (_shouldOutputPID) { prefixString.append(QString(" [%1").arg(getpid())); From 8a03738c837a0e3ecca0b236dbec92503681d6b3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 14:48:18 -0800 Subject: [PATCH 18/45] give a Sound cache to the assignment-client --- assignment-client/src/Agent.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 60129aa444..f3efccf31a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -217,6 +218,8 @@ void Agent::run() { _scriptEngine.registerGlobalObject("Agent", this); _scriptEngine.init(); // must be done before we set up the viewers + + _scriptEngine.registerGlobalObject("SoundCache", &SoundCache::getInstance()); _scriptEngine.registerGlobalObject("VoxelViewer", &_voxelViewer); // connect the VoxelViewer and the VoxelScriptingInterface to each other From 3ff89be3fdb6fe05fee801c29508ca55c1f6521a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 14:51:47 -0800 Subject: [PATCH 19/45] actually only pick programs once --- interface/src/renderer/Model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d9e29dba7c..997322637c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -2003,10 +2003,10 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool if (whichList) { QVector& list = *whichList; if (list.size() > 0) { - //if (pickProgramsNeeded) { + if (pickProgramsNeeded) { pickPrograms(batch, mode, translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned, args, skinLocations, specularTextureUnit); pickProgramsNeeded = false; - //} + } model->setupBatchTransform(batch); meshPartsRendered += model->renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, skinLocations, specularTextureUnit); GLBATCH(glPopMatrix)(); From 49ef6f8be087f85b146d219b3081a351d9168110 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 14:53:37 -0800 Subject: [PATCH 20/45] some cleanup --- interface/src/renderer/Model.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 997322637c..c007f44f2e 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1553,10 +1553,6 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int opaqueMeshPartsRendered = 0; // now, for each model in the scene, render the mesh portions - //bool pickProgramsNeeded = true; - //SkinLocations* skinLocations; - //GLenum specularTextureUnit; - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, args); opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, args); opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, args); @@ -2015,7 +2011,7 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool } // if we selected a program, then unselect it if (!pickProgramsNeeded) { - //GLBATCH(glUseProgram)(0); + GLBATCH(glUseProgram)(0); } return meshPartsRendered; } From de5881818b06f042de2607d3b5e377dc80518a16 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 14:54:48 -0800 Subject: [PATCH 21/45] update playSound to new sound interface --- examples/playSound.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/playSound.js b/examples/playSound.js index efcda0b42b..bc21204665 100644 --- a/examples/playSound.js +++ b/examples/playSound.js @@ -11,7 +11,7 @@ Script.include("libraries/globals.js"); // First, load a sample sound from a URL -var bird = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw"); +var bird = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw"); function maybePlaySound(deltaTime) { if (Math.random() < 0.01) { From f27367a0c12cda95e88b52daca63f2ab0866dd08 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 15:00:40 -0800 Subject: [PATCH 22/45] fix audio-mixer muting for injectors --- assignment-client/src/audio/AudioMixer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 4173cacfc7..6c8a4fd1c2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -774,7 +774,8 @@ void AudioMixer::run() { nodeData->checkBuffersBeforeFrameSend(); // if the stream should be muted, send mute packet - if (shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())) { + if (nodeData->getAvatarAudioStream() + && shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())) { static const int TIME_BETWEEN_MUTES = 5; // in secs if (usecTimestampNow() - nodeData->getAvatarAudioStream()->getLastMuted() > TIME_BETWEEN_MUTES * USECS_PER_SECOND) { From cfa2912877f15dfd238e1f987ff077850cb70abf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 15:01:45 -0800 Subject: [PATCH 23/45] use new SoundCache across scripts --- examples/airGuitar.js | 24 +++++----- examples/audioBall.js | 2 +- examples/avatarCollision.js | 44 +++++++++---------- examples/bot.js | 2 +- examples/botProceduralWayPoints.js | 4 +- examples/bot_procedural.js | 4 +- examples/clap.js | 20 ++++----- examples/drumStick.js | 4 +- examples/editVoxels.js | 2 +- examples/entityBirds.js | 10 ++--- examples/entityScripts/playSoundOnClick.js | 2 +- .../entityScripts/playSoundOnEnterOrLeave.js | 2 +- examples/frisbee.js | 6 +-- examples/grenadeLauncher.js | 10 ++--- examples/gun.js | 10 ++--- examples/headMove.js | 2 +- examples/inWorldTestTone.js | 2 +- examples/libraries/walkApi.js | 12 ++--- examples/lobby.js | 6 +-- examples/playSoundLoop.js | 6 +-- examples/playSoundOrbit.js | 2 +- examples/playSoundWave.js | 2 +- examples/radio.js | 2 +- examples/spaceInvadersExample.js | 12 ++--- examples/toyball.js | 6 +-- 25 files changed, 99 insertions(+), 99 deletions(-) diff --git a/examples/airGuitar.js b/examples/airGuitar.js index 2c3d0409fa..5a62ee3e7b 100644 --- a/examples/airGuitar.js +++ b/examples/airGuitar.js @@ -34,22 +34,22 @@ var guitarModel = HIFI_PUBLIC_BUCKET + "models/attachments/guitar.fst"; var chords = new Array(); // Nylon string guitar -chords[1] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw"); -chords[2] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+B.raw"); -chords[3] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+E.raw"); -chords[4] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+G.raw"); +chords[1] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw"); +chords[2] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+B.raw"); +chords[3] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+E.raw"); +chords[4] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+G.raw"); // Electric guitar -chords[5] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+A+short.raw"); -chords[6] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+B+short.raw"); -chords[7] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+E+short.raw"); -chords[8] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+G+short.raw"); +chords[5] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+A+short.raw"); +chords[6] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+B+short.raw"); +chords[7] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+E+short.raw"); +chords[8] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Metal+G+short.raw"); // Steel Guitar -chords[9] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+A.raw"); -chords[10] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+B.raw"); -chords[11] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+E.raw"); -chords[12] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+G.raw"); +chords[9] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+A.raw"); +chords[10] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+B.raw"); +chords[11] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+E.raw"); +chords[12] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Steel+G.raw"); var NUM_CHORDS = 4; var NUM_GUITARS = 3; diff --git a/examples/audioBall.js b/examples/audioBall.js index ca666285a9..e0c0ce7976 100644 --- a/examples/audioBall.js +++ b/examples/audioBall.js @@ -15,7 +15,7 @@ Script.include("libraries/globals.js"); -var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw"); +var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw"); var CHANCE_OF_PLAYING_SOUND = 0.01; var FACTOR = 0.05; diff --git a/examples/avatarCollision.js b/examples/avatarCollision.js index 4bd0adf69a..ce13daa50d 100644 --- a/examples/avatarCollision.js +++ b/examples/avatarCollision.js @@ -24,28 +24,28 @@ var audioOptions = { } var hitSounds = new Array(); -hitSounds[0] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw"); -hitSounds[1] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit2.raw"); -hitSounds[2] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit3.raw"); -hitSounds[3] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit4.raw"); -hitSounds[4] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit5.raw"); -hitSounds[5] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit6.raw"); -hitSounds[6] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit7.raw"); -hitSounds[7] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit8.raw"); -hitSounds[8] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit9.raw"); -hitSounds[9] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit10.raw"); -hitSounds[10] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit11.raw"); -hitSounds[11] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit12.raw"); -hitSounds[12] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit13.raw"); -hitSounds[13] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit14.raw"); -hitSounds[14] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit15.raw"); -hitSounds[15] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit16.raw"); -hitSounds[16] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit17.raw"); -hitSounds[17] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit18.raw"); -hitSounds[18] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit19.raw"); -hitSounds[19] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit20.raw"); -hitSounds[20] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit21.raw"); -hitSounds[21] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit22.raw"); +hitSounds[0] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit1.raw"); +hitSounds[1] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit2.raw"); +hitSounds[2] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit3.raw"); +hitSounds[3] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit4.raw"); +hitSounds[4] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit5.raw"); +hitSounds[5] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit6.raw"); +hitSounds[6] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit7.raw"); +hitSounds[7] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit8.raw"); +hitSounds[8] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit9.raw"); +hitSounds[9] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit10.raw"); +hitSounds[10] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit11.raw"); +hitSounds[11] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit12.raw"); +hitSounds[12] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit13.raw"); +hitSounds[13] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit14.raw"); +hitSounds[14] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit15.raw"); +hitSounds[15] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit16.raw"); +hitSounds[16] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit17.raw"); +hitSounds[17] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit18.raw"); +hitSounds[18] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit19.raw"); +hitSounds[19] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit20.raw"); +hitSounds[20] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit21.raw"); +hitSounds[21] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-hitsandslaps/Hit22.raw"); function playHitSound(mySessionID, theirSessionID, collision) { var now = new Date(); diff --git a/examples/bot.js b/examples/bot.js index 09c9a51cdd..aadd038eb6 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -228,6 +228,6 @@ function loadSounds() { var SOUND_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Raws/"; for (var i = 0; i < sound_filenames.length; i++) { - sounds.push(new Sound(SOUND_BASE_URL + sound_filenames[i])); + sounds.push(SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i])); } } diff --git a/examples/botProceduralWayPoints.js b/examples/botProceduralWayPoints.js index 0f8b369470..e20714bd27 100644 --- a/examples/botProceduralWayPoints.js +++ b/examples/botProceduralWayPoints.js @@ -151,11 +151,11 @@ function loadSounds() { var FOOTSTEP_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Footsteps/"; for (var i = 0; i < sound_filenames.length; i++) { - sounds.push(new Sound(SOUND_BASE_URL + sound_filenames[i])); + sounds.push(SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i])); } for (var i = 0; i < footstep_filenames.length; i++) { - footstepSounds.push(new Sound(FOOTSTEP_BASE_URL + footstep_filenames[i])); + footstepSounds.push(SoundCache.getSound(FOOTSTEP_BASE_URL + footstep_filenames[i])); } } diff --git a/examples/bot_procedural.js b/examples/bot_procedural.js index 80f83fcdfa..eec3c8906d 100644 --- a/examples/bot_procedural.js +++ b/examples/bot_procedural.js @@ -113,11 +113,11 @@ function loadSounds() { var FOOTSTEP_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Footsteps/"; for (var i = 0; i < sound_filenames.length; i++) { - sounds.push(new Sound(SOUND_BASE_URL + sound_filenames[i])); + sounds.push(SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i])); } for (var i = 0; i < footstep_filenames.length; i++) { - footstepSounds.push(new Sound(FOOTSTEP_BASE_URL + footstep_filenames[i])); + footstepSounds.push(SoundCache.getSound(FOOTSTEP_BASE_URL + footstep_filenames[i])); } } diff --git a/examples/clap.js b/examples/clap.js index bf71f13cea..2b011404c0 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -28,16 +28,16 @@ var lastClapFrame = 0; var lastAnimFrame = 0; var claps = []; -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap1Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap2Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap3Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap4Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap5Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap6Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap7Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap8Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap9Rvb.wav")); -claps.push(new Sound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap10Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap1Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap2Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap3Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap4Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap5Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap6Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap7Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap8Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap9Rvb.wav")); +claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap10Rvb.wav")); var numberOfSounds = claps.length; var clappingNow = false; diff --git a/examples/drumStick.js b/examples/drumStick.js index 1af9ffc3dd..463b653e5f 100644 --- a/examples/drumStick.js +++ b/examples/drumStick.js @@ -28,8 +28,8 @@ function vMinus(a, b) { // First, load two percussion sounds to be used on the sticks -var drum1 = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Drums/RackTomHi.raw"); -var drum2 = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Drums/RackTomLo.raw"); +var drum1 = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Drums/RackTomHi.raw"); +var drum2 = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Drums/RackTomLo.raw"); // State Machine: // 0 = not triggered diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 0747b9269f..1fa2df0977 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -78,7 +78,7 @@ function SoundArray() { this.audioOptions = audioOptions this.sounds = new Array(); this.addSound = function (soundURL) { - this.sounds[this.sounds.length] = new Sound(soundURL); + this.sounds[this.sounds.length] = SoundCache.getSound(soundURL); } this.play = function (index) { if (0 <= index && index < this.sounds.length) { diff --git a/examples/entityBirds.js b/examples/entityBirds.js index d18513ba49..9512597af9 100644 --- a/examples/entityBirds.js +++ b/examples/entityBirds.js @@ -70,23 +70,23 @@ function addBird() var size; var which = Math.random(); if (which < 0.2) { - tweet = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw"); + tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/bushtit_1.raw"); color = { red: 100, green: 50, blue: 120 }; size = 0.08; } else if (which < 0.4) { - tweet = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/rosyfacedlovebird.raw"); + tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/rosyfacedlovebird.raw"); color = { red: 100, green: 150, blue: 75 }; size = 0.09; } else if (which < 0.6) { - tweet = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/saysphoebe.raw"); + tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/saysphoebe.raw"); color = { red: 84, green: 121, blue: 36 }; size = 0.05; } else if (which < 0.8) { - tweet = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw"); + tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/mexicanWhipoorwill.raw"); color = { red: 23, green: 197, blue: 230 }; size = 0.12; } else { - tweet = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Animals/westernscreechowl.raw"); + tweet = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Animals/westernscreechowl.raw"); color = { red: 50, green: 67, blue: 144 }; size = 0.15; } diff --git a/examples/entityScripts/playSoundOnClick.js b/examples/entityScripts/playSoundOnClick.js index 4ab83a1952..6c1279774b 100644 --- a/examples/entityScripts/playSoundOnClick.js +++ b/examples/entityScripts/playSoundOnClick.js @@ -16,7 +16,7 @@ this.preload = function(entityID) { print("preload("+entityID.id+")"); - bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); }; this.clickDownOnEntity = function(entityID, mouseEvent) { diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index 07be090c31..f82c05c580 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -23,7 +23,7 @@ this.preload = function(entityID) { print("preload("+entityID.id+")"); - bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + bird = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); }; this.enterEntity = function(entityID) { diff --git a/examples/frisbee.js b/examples/frisbee.js index 7e266de34b..cf271f4f04 100644 --- a/examples/frisbee.js +++ b/examples/frisbee.js @@ -160,9 +160,9 @@ var rightMouseControl = new MouseControl("RIGHT"); var mouseControls = [leftMouseControl, middleMouseControl, rightMouseControl]; var currentMouseControl = false; -var newSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); -var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); -var throwSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); +var newSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); +var catchSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); +var throwSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); var simulatedFrisbees = []; diff --git a/examples/grenadeLauncher.js b/examples/grenadeLauncher.js index e95d8dd79d..3907e41ea6 100644 --- a/examples/grenadeLauncher.js +++ b/examples/grenadeLauncher.js @@ -36,11 +36,11 @@ var RELOAD_INTERVAL = 5; var showScore = false; // Load some sound to use for loading and firing -var fireSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw"); -var loadSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw"); -var impactSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw"); -var targetHitSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); -var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); +var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw"); +var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw"); +var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw"); +var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); +var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; diff --git a/examples/gun.js b/examples/gun.js index 76084ce013..fff78496b2 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -35,11 +35,11 @@ var RELOAD_INTERVAL = 5; var showScore = false; // Load some sound to use for loading and firing -var fireSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw"); -var loadSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw"); -var impactSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw"); -var targetHitSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); -var targetLaunchSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); +var fireSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/GUN-SHOT2.raw"); +var loadSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/Gun_Reload_Weapon22.raw"); +var impactSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guns/BulletImpact2.raw"); +var targetHitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); +var targetLaunchSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst"; diff --git a/examples/headMove.js b/examples/headMove.js index 957686bb20..56f42984e4 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -70,7 +70,7 @@ function activateWarp() { var WATCH_AVATAR_DISTANCE = 2.5; -var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); +var sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); function playSound() { Audio.playSound(sound, { position: MyAvatar.position diff --git a/examples/inWorldTestTone.js b/examples/inWorldTestTone.js index b3bf91d14d..4547309faa 100644 --- a/examples/inWorldTestTone.js +++ b/examples/inWorldTestTone.js @@ -13,7 +13,7 @@ Script.include("libraries/globals.js"); -var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/220Sine.wav"); +var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/220Sine.wav"); var soundPlaying = false; diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js index 0175c56e18..e61335f6f0 100644 --- a/examples/libraries/walkApi.js +++ b/examples/libraries/walkApi.js @@ -335,12 +335,12 @@ walkAssets = (function () { // read in the sounds var _footsteps = []; - _footsteps.push(new Sound(_pathToSounds+"FootstepW2Left-12db.wav")); - _footsteps.push(new Sound(_pathToSounds+"FootstepW2Right-12db.wav")); - _footsteps.push(new Sound(_pathToSounds+"FootstepW3Left-12db.wav")); - _footsteps.push(new Sound(_pathToSounds+"FootstepW3Right-12db.wav")); - _footsteps.push(new Sound(_pathToSounds+"FootstepW5Left-12db.wav")); - _footsteps.push(new Sound(_pathToSounds+"FootstepW5Right-12db.wav")); + _footsteps.push(SoundCache.getSound(_pathToSounds+"FootstepW2Left-12db.wav")); + _footsteps.push(SoundCache.getSound(_pathToSounds+"FootstepW2Right-12db.wav")); + _footsteps.push(SoundCache.getSound(_pathToSounds+"FootstepW3Left-12db.wav")); + _footsteps.push(SoundCache.getSound(_pathToSounds+"FootstepW3Right-12db.wav")); + _footsteps.push(SoundCache.getSound(_pathToSounds+"FootstepW5Left-12db.wav")); + _footsteps.push(SoundCache.getSound(_pathToSounds+"FootstepW5Right-12db.wav")); // load the animation datafiles Script.include(pathToAssets+"animations/dd-female-standard-walk-animation.js"); diff --git a/examples/lobby.js b/examples/lobby.js index 1b6596efa7..bb033971b3 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -39,11 +39,11 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" -var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") +var droneSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") var currentDrone = null; -var latinSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") -var elevatorSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.raw") +var latinSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/latin.raw") +var elevatorSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/elevator.raw") var currentMusak = null; function reticlePosition() { diff --git a/examples/playSoundLoop.js b/examples/playSoundLoop.js index b84c475d1a..f7116cb615 100644 --- a/examples/playSoundLoop.js +++ b/examples/playSoundLoop.js @@ -15,9 +15,9 @@ Script.include("libraries/globals.js"); // A few sample files you may want to try: -var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw"); -//var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/220Sine.wav"); -//var sound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Bandcamp.wav"); +var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Guitars/Guitar+-+Nylon+A.raw"); +//var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/220Sine.wav"); +//var sound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Bandcamp.wav"); var soundPlaying = false; var options = { diff --git a/examples/playSoundOrbit.js b/examples/playSoundOrbit.js index d98f7d0768..16ba5e52af 100644 --- a/examples/playSoundOrbit.js +++ b/examples/playSoundOrbit.js @@ -11,7 +11,7 @@ Script.include("libraries/globals.js"); -var soundClip = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Voxels/voxel create 3.raw"); +var soundClip = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Voxels/voxel create 3.raw"); var currentTime = 1.570079; // pi/2 var deltaTime = 0.05; diff --git a/examples/playSoundWave.js b/examples/playSoundWave.js index c5e69f5cd6..0741b72ef0 100644 --- a/examples/playSoundWave.js +++ b/examples/playSoundWave.js @@ -11,7 +11,7 @@ Script.include("libraries/globals.js"); -var soundClip = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav"); +var soundClip = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Cocktail%20Party%20Snippets/Walken1.wav"); function playSound() { Audio.playSound(soundClip, { diff --git a/examples/radio.js b/examples/radio.js index fc09fb184e..0b62d78b0e 100644 --- a/examples/radio.js +++ b/examples/radio.js @@ -23,7 +23,7 @@ var audioOptions = { var injector = null; -var sound = new Sound(soundURL, audioOptions.isStereo); +var sound = SoundCache.getSound(soundURL, audioOptions.isStereo); var entity = null; var properties = null; diff --git a/examples/spaceInvadersExample.js b/examples/spaceInvadersExample.js index dd5ac9e875..832efe7e75 100644 --- a/examples/spaceInvadersExample.js +++ b/examples/spaceInvadersExample.js @@ -84,13 +84,13 @@ var missileFired = false; var myMissile; // sounds -var hitSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); -var shootSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); +var hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/hit.raw"); +var shootSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/shoot.raw"); var moveSounds = new Array(); -moveSounds[0] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo1.raw"); -moveSounds[1] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo2.raw"); -moveSounds[2] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo3.raw"); -moveSounds[3] = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo4.raw"); +moveSounds[0] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo1.raw"); +moveSounds[1] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo2.raw"); +moveSounds[2] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo3.raw"); +moveSounds[3] = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Space%20Invaders/Lo4.raw"); var currentMoveSound = 0; var numberOfSounds = 4; var stepsPerSound = invaderStepsPerCycle / numberOfSounds; diff --git a/examples/toyball.js b/examples/toyball.js index 1cd6de16eb..e39ca9c8b4 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -39,9 +39,9 @@ var rightBallAlreadyInHand = false; var leftHandEntity; var rightHandEntity; -var newSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); -var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); -var throwSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); +var newSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); +var catchSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); +var throwSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); var targetRadius = 1.0; From f47620231e1f7d30a784119eb64e63ef74050628 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Nov 2014 16:16:20 -0800 Subject: [PATCH 24/45] Entities have user data --- libraries/entities/src/EntityItem.cpp | 7 +++++++ libraries/entities/src/EntityItem.h | 6 ++++++ libraries/entities/src/EntityItemProperties.cpp | 8 ++++++++ libraries/entities/src/EntityItemProperties.h | 10 +++++++++- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ef02aafbc8..8228ebc8ce 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -28,6 +28,7 @@ const float EntityItem::DEFAULT_GLOW_LEVEL = 0.0f; const float EntityItem::DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float EntityItem::DEFAULT_MASS = 1.0f; const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL; +const QString EntityItem::DEFAULT_USER_DATA = QString(""); const float EntityItem::DEFAULT_DAMPING = 0.5f; const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0); const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second @@ -71,6 +72,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _gravity = DEFAULT_GRAVITY; _damping = DEFAULT_DAMPING; _lifetime = DEFAULT_LIFETIME; + _userData = DEFAULT_USER_DATA; _registrationPoint = DEFAULT_REGISTRATION_POINT; _angularVelocity = DEFAULT_ANGULAR_VELOCITY; _angularDamping = DEFAULT_ANGULAR_DAMPING; @@ -115,6 +117,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_GRAVITY; requestedProperties += PROP_DAMPING; requestedProperties += PROP_LIFETIME; + requestedProperties += PROP_USER_DATA; requestedProperties += PROP_SCRIPT; requestedProperties += PROP_REGISTRATION_POINT; requestedProperties += PROP_ANGULAR_VELOCITY; @@ -231,6 +234,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, getGravity()); APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping()); APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime()); + APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData()); APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity()); @@ -502,6 +506,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions); READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); + READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, _userData); if (wantDebug) { qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint; @@ -758,6 +763,7 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); properties._defaultSettings = false; @@ -794,6 +800,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index adf72198be..51accd2a4f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -196,6 +196,11 @@ public: static const float DEFAULT_LIFETIME; float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity + + /// User-specified data stored in a variant map + static const QString DEFAULT_USER_DATA; + const QString& getUserData() const { return _userData; } + void setUserData(const QString& value) { _userData = value; } /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return _lifetime == IMMORTAL; } @@ -284,6 +289,7 @@ protected: glm::vec3 _gravity; float _damping; float _lifetime; + QString _userData; QString _script; glm::vec3 _registrationPoint; glm::vec3 _angularVelocity; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 0c184d5e35..86bf81f6e2 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -37,6 +37,7 @@ EntityItemProperties::EntityItemProperties() : _gravity(EntityItem::DEFAULT_GRAVITY), _damping(EntityItem::DEFAULT_DAMPING), _lifetime(EntityItem::DEFAULT_LIFETIME), + _userData(EntityItem::DEFAULT_USER_DATA), _script(EntityItem::DEFAULT_SCRIPT), _registrationPoint(EntityItem::DEFAULT_REGISTRATION_POINT), _angularVelocity(EntityItem::DEFAULT_ANGULAR_VELOCITY), @@ -53,6 +54,7 @@ EntityItemProperties::EntityItemProperties() : _gravityChanged(false), _dampingChanged(false), _lifetimeChanged(false), + _userDataChanged(false), _scriptChanged(false), _registrationPointChanged(false), _angularVelocityChanged(false), @@ -198,6 +200,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity); CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping); CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime); + CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); @@ -247,6 +250,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(damping); COPY_PROPERTY_TO_QSCRIPTVALUE(mass); COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE(userData); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(age, getAge()); // gettable, but not settable COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable COPY_PROPERTY_TO_QSCRIPTVALUE(script); @@ -350,6 +354,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(locked, setLocked); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(textures, setTextures); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(userData, setUserData); _lastEdited = usecTimestampNow(); } @@ -512,6 +517,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, properties.getTextures()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, properties.getAnimationSettings()); + APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, properties.getUserData()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -722,6 +728,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); return valid; } @@ -764,6 +771,7 @@ void EntityItemProperties::markAllChanged() { _gravityChanged = true; _dampingChanged = true; _lifetimeChanged = true; + _userDataChanged = true; _scriptChanged = true; _registrationPointChanged = true; _angularVelocityChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index d6b8181c28..534ed7615f 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -47,6 +47,7 @@ enum EntityPropertyList { PROP_GRAVITY, PROP_DAMPING, PROP_LIFETIME, + PROP_USER_DATA, PROP_SCRIPT, // these properties are supported by some derived classes @@ -156,9 +157,13 @@ public: float getDamping() const { return _damping; } void setDamping(float value) { _damping = value; _dampingChanged = true; } - + float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; _lifetimeChanged = true; } /// set the lifetime in seconds for the entity + + const QString& getUserData() const { return _userData; } + void setUserData(const QString& value) { _userData = value; _userDataChanged = true; } + float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } quint64 getCreated() const { return _created; } void setCreated(quint64 usecTime) { _created = usecTime; } @@ -216,6 +221,7 @@ public: bool gravityChanged() const { return _gravityChanged; } bool dampingChanged() const { return _dampingChanged; } bool lifetimeChanged() const { return _lifetimeChanged; } + bool userDataChanged() const { return _userDataChanged; } bool scriptChanged() const { return _scriptChanged; } bool dimensionsChanged() const { return _dimensionsChanged; } bool registrationPointChanged() const { return _registrationPointChanged; } @@ -315,6 +321,7 @@ private: glm::vec3 _gravity; float _damping; float _lifetime; + QString _userData; QString _script; glm::vec3 _registrationPoint; glm::vec3 _angularVelocity; @@ -331,6 +338,7 @@ private: bool _gravityChanged; bool _dampingChanged; bool _lifetimeChanged; + bool _userDataChanged; bool _scriptChanged; bool _registrationPointChanged; bool _angularVelocityChanged; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index a5fdd86e3d..e200d82e9d 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -75,7 +75,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS; + return VERSION_ENTITIES_HAVE_USER_DATA; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 466aebd36b..d617f2243a 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -125,6 +125,7 @@ const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3; const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU; const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; +const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6; const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From 7630aab96397385b5bf5ab5211f44303b8cbe941 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 16:18:19 -0800 Subject: [PATCH 25/45] only debug request sound if there is a network request --- libraries/audio/src/SoundCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 68a35e3c48..4fbd98fea0 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -33,11 +33,11 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) { Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); return result; } - qDebug() << "Requesting sound at" << url.toString() << "from SoundCache"; return getResource(url).staticCast(); } QSharedPointer SoundCache::createResource(const QUrl& url, const QSharedPointer& fallback, - bool delayLoad, const void* extra) { + bool delayLoad, const void* extra) { + qDebug() << "Requesting sound at" << url.toString(); return QSharedPointer(new Sound(url), &Resource::allReferencesCleared); } \ No newline at end of file From f8be98260cf87984c3bcbbe41de8c354f072d8e6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Nov 2014 16:32:15 -0800 Subject: [PATCH 26/45] String specific macros --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItemProperties.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8228ebc8ce..a73bd486c9 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -506,7 +506,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions); READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); - READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, _userData); + READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA,setUserData); if (wantDebug) { qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 86bf81f6e2..305507ead9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -728,7 +728,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_USER_DATA, setUserData); return valid; } From 40576b3c03d03965d36cf87704f859578c335c68 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Nov 2014 17:02:45 -0800 Subject: [PATCH 27/45] moved append to the end --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a73bd486c9..e17bfb362a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -234,7 +234,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, getGravity()); APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping()); APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime()); - APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData()); APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity()); @@ -243,6 +242,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked()); + APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, From 9fc74515818357755512fe60b5124c29b68940bd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Nov 2014 17:06:57 -0800 Subject: [PATCH 28/45] Move macros to the end --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItemProperties.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e17bfb362a..d5790d88a7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -117,7 +117,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_GRAVITY; requestedProperties += PROP_DAMPING; requestedProperties += PROP_LIFETIME; - requestedProperties += PROP_USER_DATA; requestedProperties += PROP_SCRIPT; requestedProperties += PROP_REGISTRATION_POINT; requestedProperties += PROP_ANGULAR_VELOCITY; @@ -126,6 +125,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_IGNORE_FOR_COLLISIONS; requestedProperties += PROP_COLLISIONS_WILL_MOVE; requestedProperties += PROP_LOCKED; + requestedProperties += PROP_USER_DATA; return requestedProperties; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 305507ead9..75fa05032a 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -200,7 +200,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity); CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping); CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime); - CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); CHECK_PROPERTY_CHANGE(PROP_COLOR, color); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); @@ -226,6 +225,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff); CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); + CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); return changedProperties; } @@ -250,7 +250,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(damping); COPY_PROPERTY_TO_QSCRIPTVALUE(mass); COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime); - COPY_PROPERTY_TO_QSCRIPTVALUE(userData); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(age, getAge()); // gettable, but not settable COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable COPY_PROPERTY_TO_QSCRIPTVALUE(script); @@ -280,6 +279,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff); COPY_PROPERTY_TO_QSCRIPTVALUE(locked); COPY_PROPERTY_TO_QSCRIPTVALUE(textures); + COPY_PROPERTY_TO_QSCRIPTVALUE(userData); // Sitting properties support QScriptValue sittingPoints = engine->newObject(); From c55f76d7efda109c07df0fe01a38ca8df6c0901d Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Thu, 13 Nov 2014 17:27:05 -0800 Subject: [PATCH 29/45] Apply alpha to text from 0 - .9 Apply alpha to text from 0 - .9 --- examples/editVoxels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 1fa2df0977..1dd825d3cf 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -319,7 +319,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, topMargin: 13, text: this.scale.toString(), - alpha: 0.0, + alpha: 0.9, visible: editToolsOn }); this.powerOverlay = Overlays.addOverlay("text", { From 4254d38cddbb3cc18d0807d7180a4f8903a9985d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Nov 2014 17:40:21 -0800 Subject: [PATCH 30/45] Update buttons to grid tool --- examples/html/gridControls.html | 145 +++++++++++++------------------- examples/html/style.css | 95 +++++++++++++++++++++ examples/libraries/gridTool.js | 9 ++ 3 files changed, 163 insertions(+), 86 deletions(-) create mode 100644 examples/html/style.css diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index e7bf1cdf8c..4cb935e600 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -1,5 +1,6 @@ + -
-
+
- -
-
-
- +
+ + + +
- -
-
-
- +
+ + + +
- -
-
-
- +
+ + + +
- -
-
-
- +
+ + + +
- -
-
-
+
+ + + + +
+ +
+ + +
+ +
+ + + +
+
+ + +
diff --git a/examples/html/style.css b/examples/html/style.css new file mode 100644 index 0000000000..1625fd094f --- /dev/null +++ b/examples/html/style.css @@ -0,0 +1,95 @@ +* { +} + +body { + margin: 0; + padding: 0; + + background-color: #efefef; + font-family: Sans-Serif; + font-size: 12px; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +input { + line-height: 2; +} + +.input-left { + display: inline-block; + width: 20px; +} + +.color-box { + display: inline-block; + width: 20px; + height: 20px; + border: 1px solid black; + margin: 2px; + cursor: pointer; +} + +.color-box.highlight { + width: 18px; + height: 18px; + border: 2px solid black; +} + +.section-header { + background: #AAA; + border-bottom: 1px solid #CCC; + background-color: #333333; + color: #999; + padding: 4px; +} + +.section-header label { + font-weight: bold; +} + +.multi-property-section { +} +.property-section { + display: block; + margin: 10 10; + height: 30px; +} + +.property-section label { + font-weight: bold; + vertical-align: middle; +} + +.property-section span { + float: right; +} + +.grid-section { + border-top: 1px solid #DDD; + background-color: #efefef; +} + +input[type=button] { + cursor: pointer; + background-color: #608e96; + border-color: #608e96; + border-radius: 5px; + padding: 5px 10px; + border: 0; + color: #fff; + font-weight: bold; + margin: 0 2px; + margin-top: 5px; + font-size: .9em; +} + +input.coord { + width: 6em; + height: 2em; +} diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 34e25d6733..04547a6918 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -174,6 +174,15 @@ GridTool = function(opts) { for (var i = 0; i < listeners.length; i++) { listeners[i](data); } + } else if (data.type == "action") { + var action = data.action; + if (action == "moveToAvatar") { + grid.setPosition(MyAvatar.position); + } else if (action == "moveToSelection") { + var newPosition = selectionManager.worldPosition; + newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 }); + grid.setPosition(newPosition); + } } }); From 49563dbff7a9c90844e8c837de015f38649a880d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Nov 2014 17:41:51 -0800 Subject: [PATCH 31/45] Add entityProperties tool window --- examples/html/entityProperties.html | 561 ++++++++++++++++++++++ examples/libraries/entitySelectionTool.js | 15 +- examples/newEditEntities.js | 35 +- 3 files changed, 605 insertions(+), 6 deletions(-) create mode 100644 examples/html/entityProperties.html diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html new file mode 100644 index 0000000000..408e83198f --- /dev/null +++ b/examples/html/entityProperties.html @@ -0,0 +1,561 @@ + + + + + + +
+ +
+
+
+ + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + X + Y + Z + +
+ +
+ + + X + Y + Z + +
+ +
+ + + + +
+
+ + + + +
+
+ + + + +
+ +
+ + + X + Y + Z + +
+
+ + + + +
+
+ + + Pitch + Roll + Yaw + +
+
+ + + + +
+ +
+ + + X + Y + Z + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + +
+ + +
+
+ + + Red + Green + Blue + +
+
+ + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + +
+
+ + + + +
+
+ + + Red + Green + Blue + +
+
+ + + Red + Green + Blue + +
+
+ + + Red + Green + Blue + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+ + + diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 22f75cb187..6733ccaf39 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -23,12 +23,13 @@ SelectionManager = (function() { that.savedProperties = {}; - that.eventListener = null; that.selections = []; // These are selections that don't have a known ID yet that.pendingSelections = []; var pendingSelectionTimer = null; + 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 }; @@ -46,8 +47,8 @@ SelectionManager = (function() { } }; - that.setEventListener = function(func) { - that.eventListener = func; + that.addEventListener = function(func) { + listeners.push(func); }; that.hasSelection = function() { @@ -187,8 +188,12 @@ SelectionManager = (function() { SelectionDisplay.setSpaceMode(SPACE_WORLD); } - if (that.eventListener) { - that.eventListener(); + for (var i = 0; i < listeners.length; i++) { + try { + listeners[i](); + } catch (e) { + print("got exception"); + } } }; diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 68e0d0c146..f5af558fa1 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -39,7 +39,7 @@ Script.include("libraries/gridTool.js"); var grid = Grid(); gridTool = GridTool({ horizontalGrid: grid }); -selectionManager.setEventListener(selectionDisplay.updateHandles); +selectionManager.addEventListener(selectionDisplay.updateHandles); var windowDimensions = Controller.getViewportDimensions(); var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; @@ -908,3 +908,36 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) { } UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); } + +PropertiesTool = function(opts) { + var that = {}; + + var url = Script.resolvePath('html/entityProperties.html'); + var webView = new WebWindow('Entity Properties', url, 200, 280); + + webView.setVisible(true); + + selectionManager.addEventListener(function() { + data = { + type: 'update', + }; + if (selectionManager.hasSelection()) { + data.properties = Entities.getEntityProperties(selectionManager.selections[0]); + } + webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + }); + + webView.eventBridge.webEventReceived.connect(function(data) { + print(data); + data = JSON.parse(data); + if (data.type == "update") { + Entities.editEntity(selectionManager.selections[0], data.properties); + selectionManager._update(); + } + }); + + return that; +}; + +propertiesTool = PropertiesTool(); + From f914f02a0b39ad82f07f44a09802a72bb3b0b963 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Nov 2014 17:44:22 -0800 Subject: [PATCH 32/45] Move user data to end of enum --- libraries/entities/src/EntityItem.h | 11 +++++------ libraries/entities/src/EntityItemProperties.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 51accd2a4f..cb153dee60 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -196,11 +196,6 @@ public: static const float DEFAULT_LIFETIME; float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity - - /// User-specified data stored in a variant map - static const QString DEFAULT_USER_DATA; - const QString& getUserData() const { return _userData; } - void setUserData(const QString& value) { _userData = value; } /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return _lifetime == IMMORTAL; } @@ -257,6 +252,10 @@ public: bool getLocked() const { return _locked; } void setLocked(bool value) { _locked = value; } + static const QString DEFAULT_USER_DATA; + const QString& getUserData() const { return _userData; } + void setUserData(const QString& value) { _userData = value; } + // TODO: We need to get rid of these users of getRadius()... float getRadius() const; @@ -289,7 +288,6 @@ protected: glm::vec3 _gravity; float _damping; float _lifetime; - QString _userData; QString _script; glm::vec3 _registrationPoint; glm::vec3 _angularVelocity; @@ -298,6 +296,7 @@ protected: bool _ignoreForCollisions; bool _collisionsWillMove; bool _locked; + QString _userData; // NOTE: Radius support is obsolete, but these private helper functions are available for this class to // parse old data streams diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 534ed7615f..273aedb18a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -47,7 +47,6 @@ enum EntityPropertyList { PROP_GRAVITY, PROP_DAMPING, PROP_LIFETIME, - PROP_USER_DATA, PROP_SCRIPT, // these properties are supported by some derived classes @@ -82,8 +81,9 @@ enum EntityPropertyList { // used by Model entities PROP_TEXTURES, PROP_ANIMATION_SETTINGS, + PROP_USER_DATA, - PROP_LAST_ITEM = PROP_ANIMATION_SETTINGS + PROP_LAST_ITEM = PROP_USER_DATA }; typedef PropertyFlags EntityPropertyFlags; From 55612cc5962f6c2b30445b1a6fdbe6938d4d6f47 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Nov 2014 17:46:20 -0800 Subject: [PATCH 33/45] Add title to WebWindowClass --- examples/libraries/gridTool.js | 2 +- interface/src/scripting/WebWindowClass.cpp | 8 +++++--- interface/src/scripting/WebWindowClass.h | 2 +- interface/src/scripting/WindowScriptingInterface.cpp | 4 ++-- interface/src/scripting/WindowScriptingInterface.h | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 04547a6918..9945fe3e98 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -159,7 +159,7 @@ GridTool = function(opts) { var listeners = []; var url = Script.resolvePath('html/gridControls.html'); - var webView = new WebWindow(url, 200, 280); + var webView = new WebWindow('Grid', url, 200, 280); horizontalGrid.addListener(function(data) { webView.eventBridge.emitScriptEvent(JSON.stringify(data)); diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index d280d8eecf..01a7983098 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -28,7 +28,8 @@ void ScriptEventBridge::emitScriptEvent(const QString& data) { emit scriptEventReceived(data); } -WebWindowClass::WebWindowClass(const QString& url, int width, int height) + +WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height) : QObject(NULL), _window(new QWidget(NULL, Qt::Tool)), _eventBridge(new ScriptEventBridge(this)) { @@ -59,8 +60,9 @@ QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* QMetaObject::invokeMethod(WindowScriptingInterface::getInstance(), "doCreateWebWindow", Qt::BlockingQueuedConnection, Q_RETURN_ARG(WebWindowClass*, retVal), Q_ARG(const QString&, file), - Q_ARG(int, context->argument(1).toInteger()), - Q_ARG(int, context->argument(2).toInteger())); + Q_ARG(QString, context->argument(1).toString()), + Q_ARG(int, context->argument(2).toInteger()), + Q_ARG(int, context->argument(3).toInteger())); connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater); diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index 7b77299774..928b8fb23b 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -34,7 +34,7 @@ class WebWindowClass : public QObject { Q_OBJECT Q_PROPERTY(QObject* eventBridge READ getEventBridge) public: - WebWindowClass(const QString& url, int width, int height); + WebWindowClass(const QString& title, const QString& url, int width, int height); ~WebWindowClass(); static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 8c2066f253..8a79cad6e1 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -34,8 +34,8 @@ WindowScriptingInterface::WindowScriptingInterface() : { } -WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& url, int width, int height) { - return new WebWindowClass(url, width, height); +WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height) { + return new WebWindowClass(title, url, width, height); } QScriptValue WindowScriptingInterface::hasFocus() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 5529d31efd..0b320f23a1 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -78,7 +78,7 @@ private slots: void nonBlockingFormAccepted() { _nonBlockingFormActive = false; _formResult = QDialog::Accepted; emit nonBlockingFormClosed(); } void nonBlockingFormRejected() { _nonBlockingFormActive = false; _formResult = QDialog::Rejected; emit nonBlockingFormClosed(); } - WebWindowClass* doCreateWebWindow(const QString& url, int width, int height); + WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); private: WindowScriptingInterface(); From 03f155bcd8d5f9405563cae5fd43bafa3f2b0779 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Nov 2014 17:47:02 -0800 Subject: [PATCH 34/45] Add tool window --- interface/src/Application.cpp | 4 ++++ interface/src/Application.h | 4 ++++ interface/src/Menu.cpp | 11 +++++++++++ interface/src/Menu.h | 2 ++ interface/src/scripting/WebWindowClass.cpp | 17 ++++++++++------- interface/src/scripting/WebWindowClass.h | 2 +- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b1c969b66f..3958011ba2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -370,6 +370,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); + _toolWindow = new QMainWindow(); + _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint); + _toolWindow->setWindowTitle("Tools"); + // initialization continues in initializeGL when OpenGL context is ready // Tell our voxel edit sender about our known jurisdictions diff --git a/interface/src/Application.h b/interface/src/Application.h index eee2581e2e..a6f94f0ab5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -244,6 +244,8 @@ public: void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); } void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); } + QMainWindow* getToolWindow() { return _toolWindow ; } + GeometryCache* getGeometryCache() { return &_geometryCache; } AnimationCache* getAnimationCache() { return &_animationCache; } TextureCache* getTextureCache() { return &_textureCache; } @@ -457,6 +459,8 @@ private: MainWindow* _window; GLCanvas* _glWidget; // our GLCanvas has a couple extra features + QMainWindow* _toolWindow; + BandwidthMeter _bandwidthMeter; QThread* _nodeThread; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index cd074805b6..fd0db559ff 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -247,6 +247,12 @@ Menu::Menu() : _chatWindow = new ChatWindow(Application::getInstance()->getWindow()); #endif + addActionToQMenuAndActionHash(toolsMenu, + MenuOption::ToolWindow, + Qt::CTRL | Qt::ALT | Qt::Key_T, + this, + SLOT(toggleToolWindow())); + addActionToQMenuAndActionHash(toolsMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, @@ -1461,6 +1467,11 @@ void Menu::toggleConsole() { _jsConsole->setVisible(!_jsConsole->isVisible()); } +void Menu::toggleToolWindow() { + QMainWindow* toolWindow = Application::getInstance()->getToolWindow(); + toolWindow->setVisible(!toolWindow->isVisible()); +} + void Menu::audioMuteToggled() { QAction *muteAction = _actionHash.value(MenuOption::MuteAudio); if (muteAction) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8af91ccae4..badd79759f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -224,6 +224,7 @@ private slots: void showScriptEditor(); void showChat(); void toggleConsole(); + void toggleToolWindow(); void toggleChat(); void audioMuteToggled(); void displayNameLocationResponse(const QString& errorString); @@ -491,6 +492,7 @@ namespace MenuOption { const QString StringHair = "String Hair"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString TestPing = "Test Ping"; + const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; const QString UploadAttachment = "Upload Attachment Model"; diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 01a7983098..1645fe2f56 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -11,9 +11,13 @@ #include #include +#include +#include #include #include +#include +#include "Application.h" #include "WindowScriptingInterface.h" #include "WebWindowClass.h" @@ -31,18 +35,17 @@ void ScriptEventBridge::emitScriptEvent(const QString& data) { WebWindowClass::WebWindowClass(const QString& title, const QString& url, int width, int height) : QObject(NULL), - _window(new QWidget(NULL, Qt::Tool)), _eventBridge(new ScriptEventBridge(this)) { + QMainWindow* toolWindow = Application::getInstance()->getToolWindow(); + + _window = new QDockWidget(title, toolWindow); QWebView* webView = new QWebView(_window); webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); webView->setUrl(url); - QVBoxLayout* layout = new QVBoxLayout(_window); - _window->setLayout(layout); - layout->addWidget(webView); - layout->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - _window->setGeometry(0, 0, width, height); + _window->setWidget(webView); + + toolWindow->addDockWidget(Qt::RightDockWidgetArea, _window); connect(this, &WebWindowClass::destroyed, _window, &QWidget::deleteLater); } diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index 928b8fb23b..c37b7aea48 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -44,7 +44,7 @@ public slots: ScriptEventBridge* getEventBridge() const { return _eventBridge; } private: - QWidget* _window; + QDockWidget* _window; ScriptEventBridge* _eventBridge; }; From a6f027e33aadc9bc22cd1ac74b2f6003ebd7b354 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Nov 2014 18:31:32 -0800 Subject: [PATCH 35/45] Fix entity edit grid not hiding when disabling tools --- examples/libraries/gridTool.js | 8 +++++++- examples/newEditEntities.js | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 9945fe3e98..d8b84babf9 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -31,6 +31,7 @@ Grid = function(opts) { that.getMajorIncrement = function() { return minorGridSpacing * majorGridEvery; }; that.visible = false; + that.enabled = false; that.getOrigin = function() { return origin; @@ -38,6 +39,11 @@ Grid = function(opts) { that.getSnapToGrid = function() { return snapToGrid; }; + that.setEnabled = function(enabled) { + that.enabled = enabled; + updateGrid(); + } + that.setVisible = function(visible, noUpdate) { that.visible = visible; updateGrid(); @@ -127,7 +133,7 @@ Grid = function(opts) { function updateGrid() { Overlays.editOverlay(gridOverlay, { position: { x: origin.y, y: origin.y, z: -origin.y }, - visible: that.visible, + visible: that.visible && that.enabled, minorGridWidth: minorGridSpacing, majorGridEvery: majorGridEvery, color: gridColor, diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 8a2c8a636d..0b8eebfee5 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -272,11 +272,13 @@ var toolBar = (function () { isActive = !isActive; if (!isActive) { gridTool.setVisible(false); + grid.setEnabled(false); selectionManager.clearSelections(); cameraManager.disable(); } else { cameraManager.enable(); gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); + grid.setEnabled(true); } return true; } From 6a4f1c857f3bcae8c8412b496b1a83c96a637fc6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 18:35:04 -0800 Subject: [PATCH 36/45] fix a couple bugs --- interface/src/renderer/Model.cpp | 8 ++++---- libraries/octree/src/OctreeElement.cpp | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c007f44f2e..09aaa63929 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -537,7 +537,7 @@ void Model::renderSetup(RenderArgs* args) { } } - if (!_meshGroupsKnown) { + if (!_meshGroupsKnown && isLoadedWithTextures()) { segregateMeshGroups(); } } @@ -628,7 +628,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, args); // render translucent meshes afterwards //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); @@ -649,7 +649,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, true, args); GLBATCH(glDisable)(GL_ALPHA_TEST); GLBATCH(glEnable)(GL_BLEND); @@ -673,7 +673,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, true, args); } GLBATCH(glDepthMask)(true); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index a0a331beb3..32dafc0b68 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -1159,6 +1160,10 @@ OctreeElement* OctreeElement::addChildAtIndex(int childIndex) { bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) { bool deleteApproved = false; if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return deleteApproved; } From 3658d65028c57945cef9d6376f3814d90fe24a02 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 13 Nov 2014 20:02:19 -0800 Subject: [PATCH 37/45] Remove grid tool from menu --- examples/newEditEntities.js | 25 ++++++++++------------ interface/src/scripting/WebWindowClass.cpp | 13 +++++------ interface/src/scripting/WebWindowClass.h | 2 +- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 0b8eebfee5..cc3c0fceda 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -55,13 +55,11 @@ var wantEntityGlow = false; var SPAWN_DISTANCE = 1; var DEFAULT_DIMENSION = 0.20; -var MENU_GRID_TOOL_ENABLED = 'Grid Tool'; var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled"; var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus"; -var SETTING_GRID_TOOL_ENABLED = 'GridToolEnabled'; var modelURLs = [ HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx", @@ -273,12 +271,14 @@ var toolBar = (function () { if (!isActive) { gridTool.setVisible(false); grid.setEnabled(false); + propertiesTool.setVisible(false); selectionManager.clearSelections(); cameraManager.disable(); } else { cameraManager.enable(); - gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); + gridTool.setVisible(true); grid.setEnabled(true); + propertiesTool.setVisible(true); } return true; } @@ -610,10 +610,6 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); Menu.addMenuItem({ menuName: "Developer", menuItemName: "Debug Ryans Rotation Problems", isCheckable: true }); - Menu.addMenuItem({ menuName: "View", menuItemName: MENU_GRID_TOOL_ENABLED, afterItem: "Edit Entities Help...", isCheckable: true, - isChecked: Settings.getValue(SETTING_GRID_TOOL_ENABLED) == 'true'}); - Menu.addMenuItem({ menuName: "View", menuItemName: MENU_INSPECT_TOOL_ENABLED, afterItem: MENU_GRID_TOOL_ENABLED, - isCheckable: true, isChecked: Settings.getValue(SETTING_INSPECT_TOOL_ENABLED) == "true" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); } @@ -638,8 +634,6 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Import Models"); Menu.removeMenuItem("Developer", "Debug Ryans Rotation Problems"); - Settings.setValue(SETTING_GRID_TOOL_ENABLED, Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); - Menu.removeMenuItem("View", MENU_GRID_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); } @@ -751,10 +745,6 @@ function handeMenuEvent(menuItem) { } } else if (menuItem == "Import Models") { modelImporter.doImport(); - } else if (menuItem == MENU_GRID_TOOL_ENABLED) { - if (isActive) { - gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); - } } tooltip.show(false); } @@ -920,7 +910,14 @@ PropertiesTool = function(opts) { var url = Script.resolvePath('html/entityProperties.html'); var webView = new WebWindow('Entity Properties', url, 200, 280); - webView.setVisible(true); + var visible = false; + + webView.setVisible(visible); + + that.setVisible = function(newVisible) { + visible = newVisible; + webView.setVisible(visible); + }; selectionManager.addEventListener(function() { data = { diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 1645fe2f56..7f11dbe580 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -39,22 +39,23 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid QMainWindow* toolWindow = Application::getInstance()->getToolWindow(); - _window = new QDockWidget(title, toolWindow); - QWebView* webView = new QWebView(_window); + _dockWidget = new QDockWidget(title, toolWindow); + _dockWidget->setFeatures(QDockWidget::DockWidgetMovable); + QWebView* webView = new QWebView(_dockWidget); webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); webView->setUrl(url); - _window->setWidget(webView); + _dockWidget->setWidget(webView); - toolWindow->addDockWidget(Qt::RightDockWidgetArea, _window); + toolWindow->addDockWidget(Qt::RightDockWidgetArea, _dockWidget); - connect(this, &WebWindowClass::destroyed, _window, &QWidget::deleteLater); + connect(this, &WebWindowClass::destroyed, _dockWidget, &QWidget::deleteLater); } WebWindowClass::~WebWindowClass() { } void WebWindowClass::setVisible(bool visible) { - QMetaObject::invokeMethod(_window, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); + QMetaObject::invokeMethod(_dockWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); } QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index c37b7aea48..ae0d14ae06 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -44,7 +44,7 @@ public slots: ScriptEventBridge* getEventBridge() const { return _eventBridge; } private: - QDockWidget* _window; + QDockWidget* _dockWidget; ScriptEventBridge* _eventBridge; }; From 5da0d1e55a287a965a8c7959d9f00fc7b62c3f2a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 20:53:31 -0800 Subject: [PATCH 38/45] fix regexs for dangerously deep recurssion suppression --- libraries/octree/src/Octree.cpp | 8 ++++---- libraries/octree/src/OctreeElement.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 4450689949..93ee8c95d0 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -74,7 +74,7 @@ void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOp if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( - "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + "Octree::recurseElementWithOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!"); qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; @@ -96,7 +96,7 @@ void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctr if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( - "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + "Octree::recurseElementWithPostOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!"); qDebug() << "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; @@ -126,7 +126,7 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( - "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + "Octree::recurseElementWithOperationDistanceSorted\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!"); qDebug() << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return; @@ -167,7 +167,7 @@ bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOpe if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( - "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + "Octree::recurseElementWithOperator\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!"); qDebug() << "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return false; diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 32dafc0b68..e5db8b24f8 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1162,7 +1162,7 @@ bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCoun if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( - "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + "OctreeElement::safeDeepDeleteChildAtIndex\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!"); qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return deleteApproved; From 744f9bc508960d45cd7f02b4f02c4b4c690754af Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 22:26:18 -0800 Subject: [PATCH 39/45] better handle corrupt packets that would cause unreasonably deep recursion --- libraries/octree/src/Octree.cpp | 52 ++++++++++++++++---------- libraries/octree/src/Octree.h | 2 +- libraries/octree/src/OctreeConstants.h | 3 +- libraries/octree/src/OctreeElement.h | 2 - 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 93ee8c95d0..e9cf1158fa 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -231,8 +231,18 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement, } // returns the element created! -OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach) { +OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount) { + + if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "Octree::createMissingElement\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!"); + + qDebug() << "Octree::createMissingElement() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; + return lastParentElement; + } int indexOfNewChild = branchIndexWithDescendant(lastParentElement->getOctalCode(), codeToReach); + // If this parent element is a leaf, then you know the child path doesn't exist, so deal with // breaking up the leaf first, which will also create a child path if (lastParentElement->requiresSplit()) { @@ -246,7 +256,7 @@ OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, co if (*lastParentElement->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) { return lastParentElement->getChildAtIndex(indexOfNewChild); } else { - return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach); + return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach, recursionCount + 1); } } @@ -255,25 +265,20 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch int bytesLeftToRead = bytesAvailable; int bytesRead = 0; - bool wantDebug = false; // give this destination element the child mask from the packet const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; if ((size_t)bytesLeftToRead < sizeof(unsigned char)) { - if (wantDebug) { - qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. " - "Not enough for meaningful data."; - } + qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. " + "Not enough for meaningful data."; return bytesAvailable; // assume we read the entire buffer... } if (destinationElement->getScale() < SCALE_AT_DANGEROUSLY_DEEP_RECURSION) { - if (wantDebug) { - qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small [" - << destinationElement->getScale() * (float)TREE_SCALE << " meters] " - << " Discarding " << bytesAvailable << " remaining bytes."; - } + qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small [" + << destinationElement->getScale() * (float)TREE_SCALE << " meters] " + << " Discarding " << bytesAvailable << " remaining bytes."; return bytesAvailable; // assume we read the entire buffer... } @@ -322,7 +327,7 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch : sizeof(childInBufferMask); if (bytesLeftToRead < bytesForMasks) { - if (wantDebug) { + if (bytesLeftToRead > 0) { qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. " "Not enough for meaningful data."; } @@ -385,7 +390,6 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long ReadBitstreamToTreeParams& args) { int bytesRead = 0; const unsigned char* bitstreamAt = bitstream; - bool wantDebug = false; // If destination element is not included, set it to root if (!args.destinationElement) { @@ -398,14 +402,24 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long while (bitstreamAt < bitstream + bufferSizeBytes) { OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL); - int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes); + if (numberOfThreeBitSectionsInStream > UNREASONABLY_DEEP_RECURSION) { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex( + "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... " + "numberOfThreeBitSectionsInStream: \\d+ This buffer is corrupt. Returning." + ); + + + qDebug() << "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... " + "numberOfThreeBitSectionsInStream:" << numberOfThreeBitSectionsInStream << + "This buffer is corrupt. Returning."; + return; + } if (numberOfThreeBitSectionsInStream == OVERFLOWED_OCTCODE_BUFFER) { - if (wantDebug) { - qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. " - "This buffer is corrupt. Returning."; - } + qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. " + "This buffer is corrupt. Returning."; return; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 42cbb3c38d..4ac7e22d90 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -373,7 +373,7 @@ protected: static bool countOctreeElementsOperation(OctreeElement* element, void* extraData); OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const; - OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach); + OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount = 0); int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args); diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index 4186b90888..e924676771 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -35,10 +35,11 @@ const int MAX_TREE_SLICE_BYTES = 26; const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f; // These are guards to prevent our voxel tree recursive routines from spinning out of control -const int UNREASONABLY_DEEP_RECURSION = 20; // use this for something that you want to be shallow, but not spin out +const int UNREASONABLY_DEEP_RECURSION = 29; // use this for something that you want to be shallow, but not spin out const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs to go deeper const float SCALE_AT_UNREASONABLY_DEEP_RECURSION = (1.0f / powf(2.0f, UNREASONABLY_DEEP_RECURSION)); const float SCALE_AT_DANGEROUSLY_DEEP_RECURSION = (1.0f / powf(2.0f, DANGEROUSLY_DEEP_RECURSION)); +const float SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE = SCALE_AT_UNREASONABLY_DEEP_RECURSION * 2.0f; // 0.00006103515 meter ~1/10,0000th const int DEFAULT_MAX_OCTREE_PPS = 600; // the default maximum PPS we think any octree based server should send to a client diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 31a9dfddc1..2bd5e3ae1e 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -36,8 +36,6 @@ class ReadBitstreamToTreeParams; class Shape; class VoxelSystem; -const float SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE = (1.0f / TREE_SCALE) / 10000.0f; // 1/10,000th of a meter - // Callers who want delete hook callbacks should implement this class class OctreeElementDeleteHook { public: From 7b69642c67a301e5d75f94b8700dd0e66057f17e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Nov 2014 23:03:12 -0800 Subject: [PATCH 40/45] fix bug in animation jitter on turn --- libraries/entities/src/ModelEntityItem.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 52b8f7e643..f50fe7866b 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -115,7 +115,9 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying); if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) { - setAnimationIsPlaying(animationIsPlaying); + if (animationIsPlaying != getAnimationIsPlaying()) { + setAnimationIsPlaying(animationIsPlaying); + } } if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) { setAnimationFPS(animationFPS); @@ -345,7 +347,6 @@ QVector ModelEntityItem::getAnimationFrame() { if (frameCount > 0) { int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount; - if (animationFrameIndex < 0 || animationFrameIndex > frameCount) { animationFrameIndex = 0; } @@ -427,7 +428,9 @@ void ModelEntityItem::setAnimationSettings(const QString& value) { if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); - setAnimationIsPlaying(running); + if (running != getAnimationIsPlaying()) { + setAnimationIsPlaying(running); + } } if (settingsMap.contains("firstFrame")) { From 5ba213f8d191cc07fc2febe88a0eb783d9635fd6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 14 Nov 2014 09:33:11 -0800 Subject: [PATCH 41/45] fix for function override with no return --- interface/src/ui/overlays/Planar3DOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index b2de7bdaad..ffd7d73531 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -82,7 +82,7 @@ QScriptValue Planar3DOverlay::getProperty(const QString& property) { return vec2toScriptValue(_scriptEngine, _dimensions); } - Base3DOverlay::getProperty(property); + return Base3DOverlay::getProperty(property); } bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, From 20fdd6d8117405296b02e7a383630dc95aab0ae4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 14 Nov 2014 10:31:30 -0800 Subject: [PATCH 42/45] Disable model overlay properties example It causes intermittent crashes in NetworkGeometry::setTextureWithNameToURL() --- examples/overlaysExample.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index 3ab70a0562..0d47f7ca64 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -194,20 +194,23 @@ print("Cube overlay color =\n" + "green: " + cubeColor.green + "\n" + "blue: " + cubeColor.blue ); -var modelOverlayProperties = { - textures: { - filename1: "http://url1", - filename2: "http://url2" - } -} -var modelOverlay = Overlays.addOverlay("model", modelOverlayProperties); -var textures = Overlays.getProperty(modelOverlay, "textures"); -var textureValues = ""; -for (key in textures) { - textureValues += "\n" + key + ": " + textures[key]; -} -print("Model overlay textures =" + textureValues); -Overlays.deleteOverlay(modelOverlay); + +// This model overlay example causes intermittent crashes in NetworkGeometry::setTextureWithNameToURL() +//var modelOverlayProperties = { +// textures: { +// filename1: HIFI_PUBLIC_BUCKET + "images/testing-swatches.svg", +// filename2: HIFI_PUBLIC_BUCKET + "images/hifi-interface-tools.svg" +// } +//} +//var modelOverlay = Overlays.addOverlay("model", modelOverlayProperties); +//var textures = Overlays.getProperty(modelOverlay, "textures"); +//var textureValues = ""; +//for (key in textures) { +// textureValues += "\n" + key + ": " + textures[key]; +//} +//print("Model overlay textures =" + textureValues); +//Overlays.deleteOverlay(modelOverlay); + print("Unknown overlay property =\n" + Overlays.getProperty(1000, "text")); // value = undefined // When our script shuts down, we should clean up all of our overlays From 86284036f1c6d8054c97bef7b43c9ca39b3b2d6a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 14 Nov 2014 10:35:13 -0800 Subject: [PATCH 43/45] put back timestamp in log --- libraries/shared/src/LogHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index dfac02b912..a13f3a9dad 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -119,6 +119,8 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont char dateString[100]; strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime); + prefixString.append(QString(" [%1]").arg(dateString)); + if (_shouldOutputPID) { prefixString.append(QString(" [%1").arg(getpid())); From 903cd05ff83eb1f79c80829ef556ce28788d1b88 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 14 Nov 2014 10:39:45 -0800 Subject: [PATCH 44/45] put newlines back in interface log --- interface/src/Application.cpp | 2 +- interface/src/FileLogger.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 605bd62118..5e158352bb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -124,7 +124,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); if (!logMessage.isEmpty()) { - Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage)); + Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage + "\n")); } } diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index 505cb6a029..4808842036 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -41,7 +41,7 @@ void FileLogger::addMessage(QString message) { QFile file(_fileName); if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { QTextStream out(&file); - out << message << "\n"; + out << message; } } From 604b1b620b628fcb2c9b24699cbe999b79bca0bf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 14 Nov 2014 10:52:08 -0800 Subject: [PATCH 45/45] Move dock window to ToolWindow --- interface/src/Application.cpp | 2 +- interface/src/Application.h | 5 +- interface/src/scripting/WebWindowClass.cpp | 6 +- interface/src/ui/ToolWindow.cpp | 82 ++++++++++++++++++++++ interface/src/ui/ToolWindow.h | 40 +++++++++++ 5 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 interface/src/ui/ToolWindow.cpp create mode 100644 interface/src/ui/ToolWindow.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eefc41cf24..1664cc700e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -373,7 +373,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); - _toolWindow = new QMainWindow(); + _toolWindow = new ToolWindow(); _toolWindow->setWindowFlags(_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint); _toolWindow->setWindowTitle("Tools"); diff --git a/interface/src/Application.h b/interface/src/Application.h index f2a6615cbf..d31833897f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -82,6 +82,7 @@ #include "ui/overlays/Overlays.h" #include "ui/ApplicationOverlay.h" #include "ui/RunningScriptsWidget.h" +#include "ui/ToolWindow.h" #include "ui/VoxelImportDialog.h" #include "voxels/VoxelFade.h" #include "voxels/VoxelHideShowThread.h" @@ -246,7 +247,7 @@ public: void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); } void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); } - QMainWindow* getToolWindow() { return _toolWindow ; } + ToolWindow* getToolWindow() { return _toolWindow ; } GeometryCache* getGeometryCache() { return &_geometryCache; } AnimationCache* getAnimationCache() { return &_animationCache; } @@ -461,7 +462,7 @@ private: MainWindow* _window; GLCanvas* _glWidget; // our GLCanvas has a couple extra features - QMainWindow* _toolWindow; + ToolWindow* _toolWindow; BandwidthMeter _bandwidthMeter; diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 7f11dbe580..cc6f4fbfff 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -37,7 +37,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid : QObject(NULL), _eventBridge(new ScriptEventBridge(this)) { - QMainWindow* toolWindow = Application::getInstance()->getToolWindow(); + ToolWindow* toolWindow = Application::getInstance()->getToolWindow(); _dockWidget = new QDockWidget(title, toolWindow); _dockWidget->setFeatures(QDockWidget::DockWidgetMovable); @@ -55,6 +55,10 @@ WebWindowClass::~WebWindowClass() { } void WebWindowClass::setVisible(bool visible) { + if (visible) { + QMetaObject::invokeMethod( + Application::getInstance()->getToolWindow(), "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); + } QMetaObject::invokeMethod(_dockWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); } diff --git a/interface/src/ui/ToolWindow.cpp b/interface/src/ui/ToolWindow.cpp new file mode 100644 index 0000000000..1375ff1ea5 --- /dev/null +++ b/interface/src/ui/ToolWindow.cpp @@ -0,0 +1,82 @@ +// +// ToolWindow.cpp +// interface/src/ui +// +// Created by Ryan Huffman on 11/13/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Application.h" +#include "ToolWindow.h" +#include "UIUtil.h" + +const int DEFAULT_WIDTH = 300; + +ToolWindow::ToolWindow(QWidget* parent) : + QMainWindow(parent), + _hasShown(false), + _lastGeometry() { +} + +bool ToolWindow::event(QEvent* event) { + QEvent::Type type = event->type(); + if (type == QEvent::Show) { + if (!_hasShown) { + _hasShown = true; + + QMainWindow* mainWindow = Application::getInstance()->getWindow(); + QRect mainGeometry = mainWindow->geometry(); + + int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); + int menuBarHeight = Menu::getInstance()->geometry().height(); + int topMargin = titleBarHeight + menuBarHeight; + + _lastGeometry = QRect(mainGeometry.topLeft().x(), mainGeometry.topLeft().y() + topMargin, + DEFAULT_WIDTH, mainGeometry.height() - topMargin); + } + setGeometry(_lastGeometry); + return true; + } else if (type == QEvent::Hide) { + _lastGeometry = geometry(); + return true; + } + + return QMainWindow::event(event); +} + +void ToolWindow::onChildVisibilityUpdated(bool visible) { + if (visible) { + setVisible(true); + } else { + bool hasVisible = false; + QList dockWidgets = findChildren(); + for (int i = 0; i < dockWidgets.count(); i++) { + if (dockWidgets[i]->isVisible()) { + hasVisible = true; + break; + } + } + setVisible(hasVisible); + } +} + +void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget) { + QMainWindow::addDockWidget(area, dockWidget); + + connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated); +} + +void ToolWindow::addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation) { + QMainWindow::addDockWidget(area, dockWidget, orientation); + + connect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated); +} + +void ToolWindow::removeDockWidget(QDockWidget* dockWidget) { + QMainWindow::removeDockWidget(dockWidget); + + disconnect(dockWidget, &QDockWidget::visibilityChanged, this, &ToolWindow::onChildVisibilityUpdated); +} diff --git a/interface/src/ui/ToolWindow.h b/interface/src/ui/ToolWindow.h new file mode 100644 index 0000000000..87b94d46df --- /dev/null +++ b/interface/src/ui/ToolWindow.h @@ -0,0 +1,40 @@ +// +// ToolWindow.h +// interface/src/ui +// +// Created by Ryan Huffman on 11/13/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 +// + +#ifndef hifi_ToolWindow_h +#define hifi_ToolWindow_h + +#include +#include +#include +#include +#include + +class ToolWindow : public QMainWindow { + Q_OBJECT +public: + ToolWindow(QWidget* parent = NULL); + + virtual bool event(QEvent* event); + virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget); + virtual void addDockWidget(Qt::DockWidgetArea area, QDockWidget* dockWidget, Qt::Orientation orientation); + virtual void removeDockWidget(QDockWidget* dockWidget); + +public slots: + void onChildVisibilityUpdated(bool visible); + + +private: + bool _hasShown; + QRect _lastGeometry; +}; + +#endif // hifi_ToolWindow_h