From 8b0d859686e0f61589eae5db6f2c7cecc76094f2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 6 Jan 2015 15:54:07 -0800 Subject: [PATCH 01/30] Add method to access downloads information in JavaScript --- examples/example/downloadInfoExample.js | 25 +++++++++++ interface/src/Application.cpp | 1 + .../GlobalServicesScriptingInterface.cpp | 41 +++++++++++++++++++ .../GlobalServicesScriptingInterface.h | 14 +++++++ 4 files changed, 81 insertions(+) create mode 100644 examples/example/downloadInfoExample.js diff --git a/examples/example/downloadInfoExample.js b/examples/example/downloadInfoExample.js new file mode 100644 index 0000000000..399c83b5cf --- /dev/null +++ b/examples/example/downloadInfoExample.js @@ -0,0 +1,25 @@ +// +// downloadInfoExample.js +// examples/example +// +// Created by David Rowe on 5 Jan 2015 +// Copyright 2015 High Fidelity, Inc. +// +// Display downloads information the same as in the stats. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// Get and log the current downloads info ... + +var downloadInfo, + downloadInfoString; + +downloadInfo = GlobalServices.getDownloadInfo(); +downloadInfoString = "Downloads: "; +if (downloadInfo.downloading.length > 0) { + downloadInfoString += downloadInfo.downloading.join("% ") + "% "; +} +downloadInfoString += "(" + downloadInfo.pending.toFixed(0) + " pending)"; +print(downloadInfoString); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bbcf90312e..776fef71ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3669,6 +3669,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels); scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance()); + qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue); scriptEngine->registerGlobalObject("AvatarManager", &_avatarManager); diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 26fa7c564b..24c2008603 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -11,6 +11,7 @@ #include "AccountManager.h" #include "XmppClient.h" +#include "ResourceCache.h" #include "GlobalServicesScriptingInterface.h" @@ -113,3 +114,43 @@ void GlobalServicesScriptingInterface::messageReceived(const QXmppMessage& messa emit GlobalServicesScriptingInterface::incomingMessage(message.from().right(message.from().count() - 1 - publicChatRoom->jid().count()), message.body()); } #endif // HAVE_QXMPP + +DownloadInfoResult GlobalServicesScriptingInterface::getDownloadInfo() { + DownloadInfoResult result; + foreach(Resource* resource, ResourceCache::getLoadingRequests()) { + result.downloading.append(resource->getProgress() * 100.0f); + } + result.pending = ResourceCache::getPendingRequestCount(); + + return result; +} + + +DownloadInfoResult::DownloadInfoResult() : + downloading(QList()), + pending(0.0f) +{ +} + +QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result) { + QScriptValue object = engine->newObject(); + + QScriptValue array = engine->newArray(result.downloading.count()); + for (int i = 0; i < result.downloading.count(); i += 1) { + array.setProperty(i, result.downloading[i]); + } + + object.setProperty("downloading", array); + object.setProperty("pending", result.pending); + return object; +} + +void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result) { + QList downloading = object.property("downloading").toVariant().toList(); + result.downloading.clear(); + for (int i = 0; i < downloading.count(); i += 1) { + result.downloading.append(downloading[i].toFloat()); + } + + result.pending = object.property("pending").toVariant().toFloat(); +} diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index 44b2f7c1bf..2e189a9a69 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -26,6 +26,19 @@ #endif // HAVE_QXMPP +class DownloadInfoResult { +public: + DownloadInfoResult(); + QList downloading; // List of percentages + float pending; +}; + +Q_DECLARE_METATYPE(DownloadInfoResult) + +QScriptValue DownloadInfoResultToScriptValue(QScriptEngine* engine, const DownloadInfoResult& result); +void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoResult& result); + + class GlobalServicesScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(bool isConnected READ isConnected) @@ -42,6 +55,7 @@ public: public slots: QScriptValue chat(const QString& message); + DownloadInfoResult getDownloadInfo(); private slots: void loggedOut(); From 40274df2791689eeaf956673fcebb1e8262b62bd Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 7 Jan 2015 11:20:46 -0800 Subject: [PATCH 02/30] Add downloads information changed event for JavaScript --- examples/example/downloadInfoExample.js | 57 ++++++++++++++++--- .../GlobalServicesScriptingInterface.cpp | 40 +++++++++---- .../GlobalServicesScriptingInterface.h | 6 ++ 3 files changed, 84 insertions(+), 19 deletions(-) diff --git a/examples/example/downloadInfoExample.js b/examples/example/downloadInfoExample.js index 399c83b5cf..19995503bc 100644 --- a/examples/example/downloadInfoExample.js +++ b/examples/example/downloadInfoExample.js @@ -11,15 +11,56 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var downloadInfo, + downloadInfoOverlay; + +function formatInfo(info) { + var string = "Downloads: ", + i; + + for (i = 0; i < info.downloading.length; i += 1) { + string += info.downloading[i].toFixed(0) + "% "; + } + + string += "(" + info.pending.toFixed(0) + " pending)"; + + return string; +} + + // Get and log the current downloads info ... -var downloadInfo, - downloadInfoString; - downloadInfo = GlobalServices.getDownloadInfo(); -downloadInfoString = "Downloads: "; -if (downloadInfo.downloading.length > 0) { - downloadInfoString += downloadInfo.downloading.join("% ") + "% "; +print(formatInfo(downloadInfo)); + + +// Display and update the downloads info in an overlay ... + +function setUp() { + downloadInfoOverlay = Overlays.addOverlay("text", { + x: 300, + y: 200, + width: 300, + height: 50, + color: { red: 255, green: 255, blue: 255 }, + alpha: 1.0, + backgroundColor: { red: 127, green: 127, blue: 127 }, + backgroundAlpha: 0.5, + topMargin: 15, + leftMargin: 20, + text: "" + }); } -downloadInfoString += "(" + downloadInfo.pending.toFixed(0) + " pending)"; -print(downloadInfoString); + +function updateInfo(info) { + Overlays.editOverlay(downloadInfoOverlay, { text: formatInfo(info) }); +} + +function tearDown() { + Overlays.deleteOverlay(downloadInfoOverlay); +} + +setUp(); +GlobalServices.downloadInfoChanged.connect(updateInfo); +GlobalServices.updateDownloadInfo(); +Script.scriptEnding.connect(tearDown); diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 24c2008603..94777acbc0 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -10,8 +10,9 @@ // #include "AccountManager.h" -#include "XmppClient.h" +#include "Application.h" #include "ResourceCache.h" +#include "XmppClient.h" #include "GlobalServicesScriptingInterface.h" @@ -26,6 +27,9 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() { const QXmppClient& qxmppClient = XmppClient::getInstance().getXMPPClient(); connect(&qxmppClient, &QXmppClient::messageReceived, this, &GlobalServicesScriptingInterface::messageReceived); #endif // HAVE_QXMPP + + _downloading = false; + connect(Application::getInstance(), &Application::renderingInWorldInterface, this, &GlobalServicesScriptingInterface::checkDownloadInfo); } GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() { @@ -115,16 +119,6 @@ void GlobalServicesScriptingInterface::messageReceived(const QXmppMessage& messa } #endif // HAVE_QXMPP -DownloadInfoResult GlobalServicesScriptingInterface::getDownloadInfo() { - DownloadInfoResult result; - foreach(Resource* resource, ResourceCache::getLoadingRequests()) { - result.downloading.append(resource->getProgress() * 100.0f); - } - result.pending = ResourceCache::getPendingRequestCount(); - - return result; -} - DownloadInfoResult::DownloadInfoResult() : downloading(QList()), @@ -154,3 +148,27 @@ void DownloadInfoResultFromScriptValue(const QScriptValue& object, DownloadInfoR result.pending = object.property("pending").toVariant().toFloat(); } + +DownloadInfoResult GlobalServicesScriptingInterface::getDownloadInfo() { + DownloadInfoResult result; + foreach(Resource* resource, ResourceCache::getLoadingRequests()) { + result.downloading.append(resource->getProgress() * 100.0f); + } + result.pending = ResourceCache::getPendingRequestCount(); + return result; +} + +void GlobalServicesScriptingInterface::checkDownloadInfo() { + DownloadInfoResult downloadInfo = getDownloadInfo(); + bool downloading = downloadInfo.downloading.count() > 0 || downloadInfo.pending > 0; + + // Emit signal if downloading or have just finished. + if (downloading || _downloading) { + _downloading = downloading; + emit downloadInfoChanged(downloadInfo); + } +} + +void GlobalServicesScriptingInterface::updateDownloadInfo() { + emit downloadInfoChanged(getDownloadInfo()); +} diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.h b/interface/src/scripting/GlobalServicesScriptingInterface.h index 2e189a9a69..657cb945c5 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.h +++ b/interface/src/scripting/GlobalServicesScriptingInterface.h @@ -56,6 +56,7 @@ public: public slots: QScriptValue chat(const QString& message); DownloadInfoResult getDownloadInfo(); + void updateDownloadInfo(); private slots: void loggedOut(); @@ -64,6 +65,7 @@ private slots: #ifdef HAVE_QXMPP void messageReceived(const QXmppMessage& message); #endif // HAVE_QXMPP + void checkDownloadInfo(); signals: void connected(); @@ -71,6 +73,10 @@ signals: void incomingMessage(const QString& username, const QString& message); void onlineUsersChanged(const QStringList& usernames); void myUsernameChanged(const QString& username); + void downloadInfoChanged(DownloadInfoResult info); + +private: + bool _downloading; }; #endif // hifi_GlobalServicesScriptingInterface_h From 6c4932f9d0034c210a379d99cb8f631204650377 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 7 Jan 2015 11:24:10 -0800 Subject: [PATCH 03/30] Coding standard --- .../scripting/GlobalServicesScriptingInterface.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/GlobalServicesScriptingInterface.cpp b/interface/src/scripting/GlobalServicesScriptingInterface.cpp index 94777acbc0..1cceec0e01 100644 --- a/interface/src/scripting/GlobalServicesScriptingInterface.cpp +++ b/interface/src/scripting/GlobalServicesScriptingInterface.cpp @@ -29,7 +29,8 @@ GlobalServicesScriptingInterface::GlobalServicesScriptingInterface() { #endif // HAVE_QXMPP _downloading = false; - connect(Application::getInstance(), &Application::renderingInWorldInterface, this, &GlobalServicesScriptingInterface::checkDownloadInfo); + connect(Application::getInstance(), &Application::renderingInWorldInterface, + this, &GlobalServicesScriptingInterface::checkDownloadInfo); } GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() { @@ -43,14 +44,16 @@ GlobalServicesScriptingInterface::~GlobalServicesScriptingInterface() { const QXmppClient& qxmppClient = XmppClient::getInstance().getXMPPClient(); disconnect(&qxmppClient, &QXmppClient::messageReceived, this, &GlobalServicesScriptingInterface::messageReceived); const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom(); - disconnect(publicChatRoom, &QXmppMucRoom::participantsChanged, this, &GlobalServicesScriptingInterface::participantsChanged); + disconnect(publicChatRoom, &QXmppMucRoom::participantsChanged, + this, &GlobalServicesScriptingInterface::participantsChanged); #endif // HAVE_QXMPP } void GlobalServicesScriptingInterface::onConnected() { #ifdef HAVE_QXMPP const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom(); - connect(publicChatRoom, &QXmppMucRoom::participantsChanged, this, &GlobalServicesScriptingInterface::participantsChanged, Qt::UniqueConnection); + connect(publicChatRoom, &QXmppMucRoom::participantsChanged, + this, &GlobalServicesScriptingInterface::participantsChanged, Qt::UniqueConnection); #endif // HAVE_QXMPP } @@ -115,7 +118,8 @@ void GlobalServicesScriptingInterface::messageReceived(const QXmppMessage& messa return; } const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom(); - emit GlobalServicesScriptingInterface::incomingMessage(message.from().right(message.from().count() - 1 - publicChatRoom->jid().count()), message.body()); + QString username = message.from().right(message.from().count() - 1 - publicChatRoom->jid().count()); + emit GlobalServicesScriptingInterface::incomingMessage(username, message.body()); } #endif // HAVE_QXMPP From 9ca0df07967fbc945b16bdf94c59e9ca3955eb9d Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Thu, 8 Jan 2015 16:05:32 -0800 Subject: [PATCH 04/30] Small fixes to scripts -merge duplicate gun scripts -fix url of sit --- examples/controllers/hydra/gun.js | 209 +++++++++++++++++++++--------- examples/gun.js | 3 +- examples/sit.js | 2 +- 3 files changed, 153 insertions(+), 61 deletions(-) diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js index de18317335..18fe9c542d 100644 --- a/examples/controllers/hydra/gun.js +++ b/examples/controllers/hydra/gun.js @@ -14,7 +14,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("../../libraries/globals.js"); +Script.include("libraries/globals.js"); function getRandomFloat(min, max) { return Math.random() * (max - min) + min; @@ -26,14 +26,19 @@ var yawFromMouse = 0; var pitchFromMouse = 0; var isMouseDown = false; -var BULLET_VELOCITY = 5.0; +var BULLET_VELOCITY = 20.0; var MIN_THROWER_DELAY = 1000; var MAX_THROWER_DELAY = 1000; var LEFT_BUTTON_3 = 3; var RELOAD_INTERVAL = 5; +var KICKBACK_ANGLE = 15; +var elbowKickAngle = 0.0; +var rotationBeforeKickback; + var showScore = false; + // Load some sound to use for loading and firing 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"); @@ -48,10 +53,11 @@ var audioOptions = { } var shotsFired = 0; - var shotTime = new Date(); -// initialize our triggers +var activeControllers = 0; + +// initialize our controller triggers var triggerPulled = new Array(); var numberOfTriggers = Controller.getNumberOfTriggers(); for (t = 0; t < numberOfTriggers; t++) { @@ -59,9 +65,11 @@ for (t = 0; t < numberOfTriggers; t++) { } var isLaunchButtonPressed = false; - var score = 0; +var bulletID = false; +var targetID = false; + // Create a reticle image in center of screen var screenSize = Controller.getViewportDimensions(); var reticle = Overlays.addOverlay("image", { @@ -74,6 +82,16 @@ var reticle = Overlays.addOverlay("image", { alpha: 1 }); +var offButton = Overlays.addOverlay("image", { + x: screenSize.x - 48, + y: 96, + width: 32, + height: 32, + imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + if (showScore) { var text = Overlays.addOverlay("text", { x: screenSize.x / 2 - 100, @@ -95,18 +113,20 @@ function printVector(string, vector) { } function shootBullet(position, velocity) { - var BULLET_SIZE = 0.01; - var BULLET_LIFETIME = 20.0; + var BULLET_SIZE = 0.07; + var BULLET_LIFETIME = 10.0; var BULLET_GRAVITY = -0.02; - Entities.addEntity( + bulletID = Entities.addEntity( { type: "Sphere", position: position, dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE }, - color: { red: 10, green: 10, blue: 10 }, + color: { red: 255, green: 0, blue: 0 }, velocity: velocity, lifetime: BULLET_LIFETIME, - gravity: { x: 0, y: BULLET_GRAVITY, z: 0 }, - damping: 0 }); + gravity: { x: 0, y: BULLET_GRAVITY, z: 0 }, + ignoreCollisions: false, + collisionsWillMove: true + }); // Play firing sounds audioOptions.position = position; @@ -115,36 +135,45 @@ function shootBullet(position, velocity) { if ((shotsFired % RELOAD_INTERVAL) == 0) { Audio.playSound(loadSound, audioOptions); } + + // Kickback the arm + rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm"); + var armRotation = MyAvatar.getJointRotation("LeftForeArm"); + armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE)); + MyAvatar.setJointData("LeftForeArm", armRotation); + elbowKickAngle = KICKBACK_ANGLE; } function shootTarget() { - var TARGET_SIZE = 0.25; - var TARGET_GRAVITY = -0.6; + var TARGET_SIZE = 0.50; + var TARGET_GRAVITY = -0.25; var TARGET_LIFETIME = 300.0; - var TARGET_UP_VELOCITY = 3.0; - var TARGET_FWD_VELOCITY = 5.0; + var TARGET_UP_VELOCITY = 0.5; + var TARGET_FWD_VELOCITY = 1.0; var DISTANCE_TO_LAUNCH_FROM = 3.0; + var ANGLE_RANGE_FOR_LAUNCH = 20.0; var camera = Camera.getPosition(); //printVector("camera", camera); - var targetDirection = Quat.angleAxis(getRandomFloat(-20.0, 20.0), { x:0, y:1, z:0 }); + var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 }); targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection); var forwardVector = Quat.getFront(targetDirection); - //printVector("forwardVector", forwardVector); + var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM)); - //printVector("newPosition", newPosition); + var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY); velocity.y += TARGET_UP_VELOCITY; - //printVector("velocity", velocity); - - Entities.addEntity( - { type: "Sphere", + + targetID = Entities.addEntity( + { type: "Box", position: newPosition, dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE }, color: { red: 0, green: 200, blue: 200 }, + //angularVelocity: { x: 1, y: 0, z: 0 }, velocity: velocity, gravity: { x: 0, y: TARGET_GRAVITY, z: 0 }, lifetime: TARGET_LIFETIME, - damping: 0.0001 }); + damping: 0.0001, + collisionsWillMove: true }); // Record start time shotTime = new Date(); @@ -157,24 +186,25 @@ function shootTarget() { function entityCollisionWithEntity(entity1, entity2, collision) { - score++; - if (showScore) { - Overlays.editOverlay(text, { text: "Score: " + score } ); - } - - // Sort out which entity is which - // Record shot time - var endTime = new Date(); - var msecs = endTime.valueOf() - shotTime.valueOf(); - //print("hit, msecs = " + msecs); - //Vec3.print("penetration = ", collision.penetration); - //Vec3.print("contactPoint = ", collision.contactPoint); - Entities.deleteEntity(entity1); - Entities.deleteEntity(entity2); - // play the sound near the camera so the shooter can hear it - audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - Audio.playSound(targetHitSound, audioOptions); + if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) && + ((entity2.id == bulletID.id) || (entity2.id == targetID.id))) { + score++; + if (showScore) { + Overlays.editOverlay(text, { text: "Score: " + score } ); + } + + // We will delete the bullet and target in 1/2 sec, but for now we can see them bounce! + Script.setTimeout(deleteBulletAndTarget, 500); + + // Turn the target and the bullet white + Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }}); + Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }}); + + // play the sound near the camera so the shooter can hear it + audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + Audio.playSound(targetHitSound, audioOptions); + } } function keyPressEvent(event) { @@ -186,12 +216,42 @@ function keyPressEvent(event) { shootFromMouse(); } else if (event.text == "r") { playLoadSound(); + } else if (event.text == "s") { + // Hit this key to dump a posture from hydra to log + Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm")); + Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm")); + Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand")); + } } function playLoadSound() { audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); Audio.playSound(loadSound, audioOptions); + // Raise arm to firing posture + takeFiringPose(); +} + +function clearPose() { + MyAvatar.clearJointData("LeftForeArm"); + MyAvatar.clearJointData("LeftArm"); + MyAvatar.clearJointData("LeftHand"); +} + +function deleteBulletAndTarget() { + Entities.deleteEntity(bulletID); + Entities.deleteEntity(targetID); + bulletID = false; + targetID = false; +} + +function takeFiringPose() { + clearPose(); + if (Controller.getNumberOfSpatialControls() == 0) { + MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843}); + MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219}); + MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333}); + } } MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20); @@ -201,17 +261,49 @@ MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitc Script.setTimeout(playLoadSound, 2000); function update(deltaTime) { + if (bulletID && !bulletID.isKnownID) { + print("Trying to identify bullet"); + bulletID = Entities.identifyEntity(bulletID); + } + if (targetID && !targetID.isKnownID) { + targetID = Entities.identifyEntity(targetID); + } // Check for mouseLook movement, update rotation // rotate body yaw for yaw received from mouse var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); - MyAvatar.orientation = newOrientation; + //MyAvatar.orientation = newOrientation; yawFromMouse = 0; // apply pitch from mouse var newPitch = MyAvatar.headPitch + pitchFromMouse; - MyAvatar.headPitch = newPitch; + //MyAvatar.headPitch = newPitch; pitchFromMouse = 0; + + if (activeControllers == 0) { + if (Controller.getNumberOfSpatialControls() > 0) { + activeControllers = Controller.getNumberOfSpatialControls(); + clearPose(); + } + } + + var KICKBACK_DECAY_RATE = 0.125; + if (elbowKickAngle > 0.0) { + if (elbowKickAngle > 0.5) { + var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE; + elbowKickAngle -= newAngle; + var armRotation = MyAvatar.getJointRotation("LeftForeArm"); + armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle)); + MyAvatar.setJointData("LeftForeArm", armRotation); + } else { + MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback); + if (Controller.getNumberOfSpatialControls() > 0) { + clearPose(); + } + elbowKickAngle = 0.0; + } + } + // Check hydra controller for launch button press if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) { isLaunchButtonPressed = true; @@ -222,15 +314,13 @@ function update(deltaTime) { } - // Check hydra controller for trigger press + // check for trigger press - var numberOfTriggers = Controller.getNumberOfTriggers(); - var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); - var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + var numberOfTriggers = 2; + var controllersPerTrigger = 2; - // this is expected for hydras if (numberOfTriggers == 2 && controllersPerTrigger == 2) { - for (var t = 0; t < numberOfTriggers; t++) { + for (var t = 0; t < 2; t++) { var shootABullet = false; var triggerValue = Controller.getTriggerValue(t); if (triggerPulled[t]) { @@ -239,14 +329,13 @@ function update(deltaTime) { triggerPulled[t] = false; // unpulled } } else { - // must pull to at least 0.9 - if (triggerValue > 0.9) { + // must pull to at least + if (triggerValue > 0.5) { triggerPulled[t] = true; // pulled shootABullet = true; } } - if (shootABullet) { var palmController = t * controllersPerTrigger; var palmPosition = Controller.getSpatialControlPosition(palmController); @@ -263,12 +352,8 @@ function update(deltaTime) { var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2, y: fingerTipPosition.y + palmToFingerTipVector.y/2, z: fingerTipPosition.z + palmToFingerTipVector.z/2}; - - var linearVelocity = 25; - - var velocity = { x: palmToFingerTipVector.x * linearVelocity, - y: palmToFingerTipVector.y * linearVelocity, - z: palmToFingerTipVector.z * linearVelocity }; + + var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector)); shootBullet(position, velocity); } @@ -280,8 +365,12 @@ function mousePressEvent(event) { isMouseDown = true; lastX = event.x; lastY = event.y; - //audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - //Audio.playSound(loadSound, audioOptions); + + if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) { + Script.stop(); + } else { + shootFromMouse(); + } } function shootFromMouse() { @@ -312,8 +401,10 @@ function mouseMoveEvent(event) { function scriptEnding() { Overlays.deleteOverlay(reticle); + Overlays.deleteOverlay(offButton); Overlays.deleteOverlay(text); MyAvatar.detachOne(gunModel); + clearPose(); } Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); diff --git a/examples/gun.js b/examples/gun.js index c5b7b17052..18fe9c542d 100644 --- a/examples/gun.js +++ b/examples/gun.js @@ -254,7 +254,8 @@ function takeFiringPose() { } } -MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); +MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20); +//MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); // Give a bit of time to load before playing sound Script.setTimeout(playLoadSound, 2000); diff --git a/examples/sit.js b/examples/sit.js index 71d909d1e7..196a1a1972 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -10,7 +10,7 @@ // -var buttonImageUrl = "https://public.highfidelity.io/images/tools/sit.svg"; +var buttonImageUrl = "https://s3.amazonaws.com/hifi-public/images/tools/sit.svg"; var windowDimensions = Controller.getViewportDimensions(); From 1d6066c83700e95ef6b518079151188f0d77e2bf Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 10 Jan 2015 01:41:07 +0100 Subject: [PATCH 05/30] replaced GetVersionEx with new Version helpers to resolve deprecation warnings. --- interface/src/Audio.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index bd106d9bc6..7c2586b55c 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #endif #include @@ -179,12 +180,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { #ifdef WIN32 QString deviceName; //Check for Windows Vista or higher, IMMDeviceEnumerator doesn't work below that. - OSVERSIONINFO osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osvi); - const DWORD VISTA_MAJOR_VERSION = 6; - if (osvi.dwMajorVersion < VISTA_MAJOR_VERSION) {// lower then vista + if (!IsWindowsVistaOrGreater()) { // lower then vista if (mode == QAudio::AudioInput) { WAVEINCAPS wic; // first use WAVE_MAPPER to get the default devices manufacturer ID @@ -223,9 +219,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { pPropertyStore->Release(); pPropertyStore = NULL; deviceName = QString::fromWCharArray((wchar_t*)pv.pwszVal); - const DWORD WINDOWS7_MAJOR_VERSION = 6; - const DWORD WINDOWS7_MINOR_VERSION = 1; - if (osvi.dwMajorVersion <= WINDOWS7_MAJOR_VERSION && osvi.dwMinorVersion <= WINDOWS7_MINOR_VERSION) { + if (!IsWindows8OrGreater()) { // Windows 7 provides only the 31 first characters of the device name. const DWORD QT_WIN7_MAX_AUDIO_DEVICENAME_LEN = 31; deviceName = deviceName.left(QT_WIN7_MAX_AUDIO_DEVICENAME_LEN); From e639c5a549ed90b10fec2e7277d0d3c04d5adf0c Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Sun, 11 Jan 2015 11:33:21 -0800 Subject: [PATCH 06/30] playing with the ambient lighting --- interface/src/Application.cpp | 3 ++- libraries/fbx/src/FBXReader.cpp | 11 +++++++++++ .../src/directional_light_cascaded_shadow_map.slf | 6 +++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ecce508acf..52704bc5b0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2658,7 +2658,8 @@ void Application::updateShadowMap() { glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); } -const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; +//const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; +const GLfloat WORLD_AMBIENT_COLOR[] = { 0.2f, 0.2f, 0.3f }; const GLfloat WORLD_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f }; const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f }; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 9532f44acf..d2bda2d747 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -753,6 +753,7 @@ public: float shininess; float opacity; QString id; + model::MaterialPointer _material; }; class Cluster { @@ -1715,6 +1716,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, #endif } material.id = getID(object.properties); + + material._material = model::MaterialPointer(new model::Material()); + material._material->setEmissive(material.emissive); + material._material->setDiffuse(material.diffuse); + material._material->setSpecular(material.specular); + material._material->setShininess(material.shininess); + material._material->setOpacity(material.opacity); + materials.insert(material.id, material); } else if (object.name == "NodeAttribute") { @@ -2138,6 +2147,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { if (extracted.partMaterialTextures.at(j).first == materialIndex) { FBXMeshPart& part = extracted.mesh.parts[j]; + + part._material = material._material; part.diffuseColor = material.diffuse; part.specularColor = material.specular; part.emissiveColor = material.emissive; diff --git a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf index e2a58de14b..08fdc3a908 100644 --- a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf @@ -83,7 +83,7 @@ void main(void) { float facingLight = step(0.0, diffuse) * shadowAttenuation; // compute the base color based on OpenGL lighting model - vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb + + vec3 baseColor = diffuseVal.rgb * (/*gl_FrontLightModelProduct.sceneColor.rgb + */ gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight)); // compute the specular multiplier (sans exponent) @@ -93,5 +93,9 @@ void main(void) { // add specular contribution vec4 specularColor = specularVal; gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normalVal.a); + + if (gl_FragCoord.x > 1024) { + gl_FragColor = vec4( (gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight)), normalVal.a); + } } } From 17925c7a810159536cbfde189ec9f2a057cb89bc Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 12 Jan 2015 11:06:05 -0800 Subject: [PATCH 07/30] Use more appropriate QNetworkReply error code This error code is available now that Interface is built with Qt 5.3. --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index a756b3fe8f..92c9c1856c 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -66,7 +66,7 @@ QScriptValue XMLHttpRequestClass::getStatus() const { return QScriptValue(200); case QNetworkReply::ContentNotFoundError: return QScriptValue(404); - case QNetworkReply::ContentAccessDenied: + case QNetworkReply::ContentConflictError: return QScriptValue(409); case QNetworkReply::TimeoutError: return QScriptValue(408); @@ -89,7 +89,7 @@ QString XMLHttpRequestClass::getStatusText() const { return "OK"; case QNetworkReply::ContentNotFoundError: return "Not Found"; - case QNetworkReply::ContentAccessDenied: + case QNetworkReply::ContentConflictError: return "Conflict"; case QNetworkReply::TimeoutError: return "Timeout"; @@ -196,8 +196,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a } else if (!_file->open(QIODevice::ReadOnly)) { qDebug() << "Can't open file " << _url.fileName(); abortRequest(); - //_errorCode = QNetworkReply::ContentConflictError; // TODO: Use this status when update to Qt 5.3 - _errorCode = QNetworkReply::ContentAccessDenied; + _errorCode = QNetworkReply::ContentConflictError; setReadyState(DONE); emit requestComplete(); } else { From bece05a994cc7cc27894690e96a26fd16c15c5bf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 12 Jan 2015 11:49:31 -0800 Subject: [PATCH 08/30] entity prop defaults move to their own header --- libraries/entities/src/EntityItem.cpp | 58 ++++++++++--------- libraries/entities/src/EntityItem.h | 35 ++--------- .../entities/src/EntityItemProperties.cpp | 36 ++++++------ .../src/EntityItemPropertiesDefaults.h | 51 ++++++++++++++++ 4 files changed, 106 insertions(+), 74 deletions(-) create mode 100644 libraries/entities/src/EntityItemPropertiesDefaults.h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4bf394314b..70fdb86929 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -35,25 +35,25 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _created = UNKNOWN_CREATED_TIME; _changedOnServer = 0; - _position = glm::vec3(0,0,0); - _dimensions = DEFAULT_DIMENSIONS; - _rotation = DEFAULT_ROTATION; - _glowLevel = DEFAULT_GLOW_LEVEL; - _localRenderAlpha = DEFAULT_LOCAL_RENDER_ALPHA; - _mass = DEFAULT_MASS; - _velocity = DEFAULT_VELOCITY; - _gravity = DEFAULT_GRAVITY; - _damping = DEFAULT_DAMPING; - _lifetime = DEFAULT_LIFETIME; - _script = DEFAULT_SCRIPT; - _registrationPoint = DEFAULT_REGISTRATION_POINT; - _angularVelocity = DEFAULT_ANGULAR_VELOCITY; - _angularDamping = DEFAULT_ANGULAR_DAMPING; - _visible = DEFAULT_VISIBLE; - _ignoreForCollisions = DEFAULT_IGNORE_FOR_COLLISIONS; - _collisionsWillMove = DEFAULT_COLLISIONS_WILL_MOVE; - _locked = DEFAULT_LOCKED; - _userData = DEFAULT_USER_DATA; + _position = ENTITY_ITEM_ZERO_VEC3; + _dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS; + _rotation = ENTITY_ITEM_DEFAULT_ROTATION; + _glowLevel = ENTITY_ITEM_DEFAULT_GLOW_LEVEL; + _localRenderAlpha = ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA; + _mass = ENTITY_ITEM_DEFAULT_MASS; + _velocity = ENTITY_ITEM_DEFAULT_VELOCITY; + _gravity = ENTITY_ITEM_DEFAULT_GRAVITY; + _damping = ENTITY_ITEM_DEFAULT_DAMPING; + _lifetime = ENTITY_ITEM_DEFAULT_LIFETIME; + _script = ENTITY_ITEM_DEFAULT_SCRIPT; + _registrationPoint = ENTITY_ITEM_DEFAULT_REGISTRATION_POINT; + _angularVelocity = ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY; + _angularDamping = ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING; + _visible = ENTITY_ITEM_DEFAULT_VISIBLE; + _ignoreForCollisions = ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS; + _collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE; + _locked = ENTITY_ITEM_DEFAULT_LOCKED; + _userData = ENTITY_ITEM_DEFAULT_USER_DATA; recalculateCollisionShape(); } @@ -555,6 +555,8 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s } } +const float ENTITY_ITEM_EPSILON_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE; + // TODO: we probably want to change this to make "down" be the direction of the entity's gravity vector // for now, this is always true DOWN even if entity has non-down gravity. // TODO: the old code had "&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON" --- what was I thinking? @@ -562,7 +564,7 @@ bool EntityItem::isRestingOnSurface() const { glm::vec3 downwardVelocity = glm::vec3(0.0f, _velocity.y, 0.0f); return _position.y <= getDistanceToBottomOfEntity() - && (glm::length(downwardVelocity) <= EPSILON_VELOCITY_LENGTH) + && (glm::length(downwardVelocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) && _gravity.y < 0.0f; } @@ -639,7 +641,7 @@ void EntityItem::simulate(const quint64& now) { const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; // if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { - setAngularVelocity(NO_ANGULAR_VELOCITY); + setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); } else { // NOTE: angularSpeed is currently in degrees/sec!!! // TODO: Andrew to convert to radians/sec @@ -668,7 +670,7 @@ void EntityItem::simulate(const quint64& now) { qDebug() << " damping:" << _damping; qDebug() << " velocity AFTER dampingResistance:" << velocity; qDebug() << " glm::length(velocity):" << glm::length(velocity); - qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; + qDebug() << " velocityEspilon :" << ENTITY_ITEM_EPSILON_VELOCITY_LENGTH; } } @@ -696,7 +698,7 @@ void EntityItem::simulate(const quint64& now) { #ifndef USE_BULLET_PHYSICS // if we've slowed considerably, then just stop moving, but only if no BULLET - if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { + if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } #endif // !USE_BULLET_PHYSICS @@ -720,7 +722,7 @@ void EntityItem::simulate(const quint64& now) { // When Bullet is available we assume that it will tell us when velocities go to zero... #else // !USE_BULLET_PHYSICS // ... otherwise we help things come to rest by clamping small velocities. - if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { + if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } #endif // USE_BULLET_PHYSICS @@ -909,8 +911,8 @@ AACube EntityItem::getMinimumAACube() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; - glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + glm::vec3 unrotatedMinRelativeToEntity = - unrotatedMaxRelativeToEntity; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); @@ -934,8 +936,8 @@ AABox EntityItem::getAABox() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; - glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + glm::vec3 unrotatedMinRelativeToEntity = - unrotatedMaxRelativeToEntity; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); @@ -1055,7 +1057,7 @@ void EntityItem::updateMass(float value) { void EntityItem::updateVelocity(const glm::vec3& value) { if (glm::distance(_velocity, value) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) { if (glm::length(value) * (float)TREE_SCALE < MIN_VELOCITY_DELTA) { - _velocity = glm::vec3(0.0f); + _velocity = ENTITY_ITEM_ZERO_VEC3; } else { _velocity = value; } @@ -1067,7 +1069,7 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) { glm::vec3 velocity = value / (float) TREE_SCALE; if (glm::distance(_velocity, velocity) * (float)TREE_SCALE > MIN_VELOCITY_DELTA) { if (glm::length(value) < MIN_VELOCITY_DELTA) { - _velocity = glm::vec3(0.0f); + _velocity = ENTITY_ITEM_ZERO_VEC3; } else { _velocity = velocity; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 1b8afa930b..b84739e07e 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -26,6 +26,7 @@ #include "EntityItemID.h" #include "EntityItemProperties.h" +#include "EntityItemPropertiesDefaults.h" #include "EntityTypes.h" class EntityTree; @@ -35,30 +36,6 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; -const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f) / (float)TREE_SCALE; -const glm::quat DEFAULT_ROTATION; -const float DEFAULT_GLOW_LEVEL = 0.0f; -const float DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; -const float DEFAULT_MASS = 1.0f; -const glm::vec3 NO_VELOCITY= glm::vec3(0.0f); -const glm::vec3 DEFAULT_VELOCITY = NO_VELOCITY; -const float EPSILON_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE; -const glm::vec3 NO_GRAVITY = glm::vec3(0.0f); -const glm::vec3 DEFAULT_GRAVITY = NO_GRAVITY; -const glm::vec3 REGULAR_GRAVITY = glm::vec3(0, -9.8f / (float)TREE_SCALE, 0); -const float DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) -const float IMMORTAL = -1.0f; /// special lifetime which means the entity lives for ever. default lifetime -const float DEFAULT_LIFETIME = IMMORTAL; -const QString DEFAULT_SCRIPT = QString(""); -const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center -const glm::vec3 NO_ANGULAR_VELOCITY = glm::vec3(0.0f); -const glm::vec3 DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY; -const float DEFAULT_ANGULAR_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) -const bool DEFAULT_VISIBLE = true; -const bool DEFAULT_IGNORE_FOR_COLLISIONS = false; -const bool DEFAULT_COLLISIONS_WILL_MOVE = false; -const bool DEFAULT_LOCKED = false; -const QString DEFAULT_USER_DATA = QString(""); /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -201,13 +178,13 @@ public: glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters - bool hasVelocity() const { return _velocity != NO_VELOCITY; } + bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; } const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared void setGravityInMeters(const glm::vec3& value) { _gravity = value / (float) TREE_SCALE; } /// gravity in meters - bool hasGravity() const { return _gravity != NO_GRAVITY; } + bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; } // TODO: this should eventually be updated to support resting on collisions with other surfaces bool isRestingOnSurface() const; @@ -220,10 +197,10 @@ public: void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted - bool isImmortal() const { return _lifetime == IMMORTAL; } + bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; } /// is this entity mortal, in that it has a lifetime set, and will automatically be deleted when that lifetime expires - bool isMortal() const { return _lifetime != IMMORTAL; } + bool isMortal() const { return _lifetime != ENTITY_ITEM_IMMORTAL_LIFETIME; } /// age of this entity in seconds float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } @@ -247,7 +224,7 @@ public: const glm::vec3& getAngularVelocity() const { return _angularVelocity; } void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; } - bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; } + bool hasAngularVelocity() const { return _angularVelocity != ENTITY_ITEM_ZERO_VEC3; } float getAngularDamping() const { return _angularDamping; } void setAngularDamping(float value) { _angularDamping = value; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index be6fe01841..d50096f752 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -19,32 +19,34 @@ #include "EntityItem.h" #include "EntityItemProperties.h" +#include "EntityItemPropertiesDefaults.h" #include "ModelEntityItem.h" #include "TextEntityItem.h" + EntityItemProperties::EntityItemProperties() : - CONSTRUCT_PROPERTY(visible, DEFAULT_VISIBLE), + CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE), CONSTRUCT_PROPERTY(position, 0), - CONSTRUCT_PROPERTY(dimensions, DEFAULT_DIMENSIONS), - CONSTRUCT_PROPERTY(rotation, DEFAULT_ROTATION), - CONSTRUCT_PROPERTY(mass, DEFAULT_MASS), - CONSTRUCT_PROPERTY(velocity, DEFAULT_VELOCITY), - CONSTRUCT_PROPERTY(gravity, DEFAULT_GRAVITY), - CONSTRUCT_PROPERTY(damping, DEFAULT_DAMPING), - CONSTRUCT_PROPERTY(lifetime, DEFAULT_LIFETIME), - CONSTRUCT_PROPERTY(script, DEFAULT_SCRIPT), + CONSTRUCT_PROPERTY(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS), + CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION), + CONSTRUCT_PROPERTY(mass, ENTITY_ITEM_DEFAULT_MASS), + CONSTRUCT_PROPERTY(velocity, ENTITY_ITEM_DEFAULT_VELOCITY), + CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY), + CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING), + CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME), + CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(color, ), CONSTRUCT_PROPERTY(modelURL, ""), CONSTRUCT_PROPERTY(animationURL, ""), CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS), CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), CONSTRUCT_PROPERTY(animationIsPlaying, ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING), - CONSTRUCT_PROPERTY(registrationPoint, DEFAULT_REGISTRATION_POINT), - CONSTRUCT_PROPERTY(angularVelocity, DEFAULT_ANGULAR_VELOCITY), - CONSTRUCT_PROPERTY(angularDamping, DEFAULT_ANGULAR_DAMPING), - CONSTRUCT_PROPERTY(ignoreForCollisions, DEFAULT_IGNORE_FOR_COLLISIONS), - CONSTRUCT_PROPERTY(collisionsWillMove, DEFAULT_COLLISIONS_WILL_MOVE), + CONSTRUCT_PROPERTY(registrationPoint, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT), + CONSTRUCT_PROPERTY(angularVelocity, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY), + CONSTRUCT_PROPERTY(angularDamping, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING), + CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), + CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), CONSTRUCT_PROPERTY(isSpotlight, false), CONSTRUCT_PROPERTY(diffuseColor, ), CONSTRUCT_PROPERTY(ambientColor, ), @@ -54,10 +56,10 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(quadraticAttenuation, 0.0f), CONSTRUCT_PROPERTY(exponent, 0.0f), CONSTRUCT_PROPERTY(cutoff, PI), - CONSTRUCT_PROPERTY(locked, false), + CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED), CONSTRUCT_PROPERTY(textures, ""), CONSTRUCT_PROPERTY(animationSettings, ""), - CONSTRUCT_PROPERTY(userData, DEFAULT_USER_DATA), + CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA), CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT), CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT), CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR), @@ -858,8 +860,8 @@ AABox EntityItemProperties::getAABoxInMeters() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; - glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + glm::vec3 unrotatedMinRelativeToEntity = - unrotatedMaxRelativeToEntity; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h new file mode 100644 index 0000000000..285788c960 --- /dev/null +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -0,0 +1,51 @@ +// +// EntityItemPropertiesDefaults.h +// libraries/entities/src +// +// Created by Andrew Meadows on 2015.01.12 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_EntityItemPropertiesDefaults_h +#define hifi_EntityItemPropertiesDefaults_h + +#include + +#include + +// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than +// creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization. +const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f); + +const glm::vec3 REGULAR_GRAVITY = glm::vec3(0, -9.8f / (float)TREE_SCALE, 0); + +const bool ENTITY_ITEM_DEFAULT_LOCKED = false; +const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); + +const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; +const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f; +const bool ENTITY_ITEM_DEFAULT_VISIBLE = true; + +const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString(""); +const glm::vec3 ENTITY_ITEM_DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center + +const float ENTITY_ITEM_IMMORTAL_LIFETIME = -1.0f; /// special lifetime which means the entity lives for ever +const float ENTITY_ITEM_DEFAULT_LIFETIME = ENTITY_ITEM_IMMORTAL_LIFETIME; + +const glm::quat ENTITY_ITEM_DEFAULT_ROTATION; +const glm::vec3 ENTITY_ITEM_DEFAULT_DIMENSIONS = glm::vec3(0.1f) / (float)TREE_SCALE; +const float ENTITY_ITEM_DEFAULT_MASS = 1.0f; + +const glm::vec3 ENTITY_ITEM_DEFAULT_VELOCITY = ENTITY_ITEM_ZERO_VEC3; +const glm::vec3 ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY = ENTITY_ITEM_ZERO_VEC3; +const glm::vec3 ENTITY_ITEM_DEFAULT_GRAVITY = ENTITY_ITEM_ZERO_VEC3; +const float ENTITY_ITEM_DEFAULT_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) +const float ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING = 0.39347f; // approx timescale = 2.0 sec (see damping timescale formula in header) + +const bool ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS = false; +const bool ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE = false; + +#endif // hifi_EntityItemPropertiesDefaults_h From 022760be1d3869b24ed5be250b348064b72a5b35 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 12 Jan 2015 11:52:51 -0800 Subject: [PATCH 09/30] Remove menu item for Show Voxel Nodes which is no longer available And change Show Entity Nodes shortcut from Ctrl-Shift-2 to Ctrl-Shift-1. --- interface/src/Menu.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c50c722d4a..e4508ba042 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -354,11 +354,8 @@ Menu::Menu() : QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders"); NodeBounds& nodeBounds = appInstance->getNodeBoundsDisplay(); - addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersVoxelNodes, - Qt::CTRL | Qt::SHIFT | Qt::Key_1, false, - &nodeBounds, SLOT(setShowVoxelNodes(bool))); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes, - Qt::CTRL | Qt::SHIFT | Qt::Key_2, false, + Qt::CTRL | Qt::SHIFT | Qt::Key_1, false, &nodeBounds, SLOT(setShowEntityNodes(bool))); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); From 1562aab6daad021a7ab7d30b681265d0b532cd07 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 12 Jan 2015 12:35:17 -0800 Subject: [PATCH 10/30] intitial pass at lock file --- libraries/octree/src/OctreePersistThread.cpp | 44 +++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index d9ebea0c2b..49372d1141 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include #include @@ -55,6 +57,21 @@ bool OctreePersistThread::process() { _tree->lockForWrite(); { PerformanceWarning warn(true, "Loading Octree File", true); + + // First check to make sure "lock" file doesn't exist. If it does exist, then + // our last save crashed during the save, and we want to load our most recent backup. + QString lockFileName = _filename + ".lock"; + std::ifstream lockFile(qPrintable(lockFileName), std::ios::in|std::ios::binary|std::ios::ate); + if(lockFile.is_open()) { + qDebug() << "WARNING: Octree lock file detected at startup:" << lockFileName + << "-- Attempting to restore from previous backup file."; + + lockFile.close(); + qDebug() << "Loading Octree... lock file closed:" << lockFileName; + remove(qPrintable(lockFileName)); + qDebug() << "Loading Octree... lock file removed:" << lockFileName; + } + persistantFileRead = _tree->readFromSVOFile(_filename.toLocal8Bit().constData()); _tree->pruneTree(); } @@ -142,11 +159,28 @@ void OctreePersistThread::persist() { backup(); // handle backup if requested - qDebug() << "saving Octree to file " << _filename << "..."; - _tree->writeToSVOFile(qPrintable(_filename)); - time(&_lastPersistTime); - _tree->clearDirtyBit(); // tree is clean after saving - qDebug() << "DONE saving Octree to file..."; + + // create our "lock" file to indicate we're saving. + QString lockFileName = _filename + ".lock"; + std::ofstream lockFile(qPrintable(lockFileName), std::ios::out|std::ios::binary); + if(lockFile.is_open()) { + qDebug() << "saving Octree lock file created at:" << lockFileName; + + qDebug() << "saving Octree to file " << _filename << "..."; + + _tree->writeToSVOFile(qPrintable(_filename)); + time(&_lastPersistTime); + _tree->clearDirtyBit(); // tree is clean after saving + qDebug() << "DONE saving Octree to file..."; + + // force crash + //assert(false); + + lockFile.close(); + qDebug() << "saving Octree lock file closed:" << lockFileName; + remove(qPrintable(lockFileName)); + qDebug() << "saving Octree lock file removed:" << lockFileName; + } } } From 7b65c754147b99696ee9dbf70ae079b28c05fdf5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 12 Jan 2015 14:32:13 -0800 Subject: [PATCH 11/30] first cut at restoreFromMostRecentBackup --- libraries/octree/src/OctreePersistThread.cpp | 67 ++++++++++++++++++++ libraries/octree/src/OctreePersistThread.h | 2 + 2 files changed, 69 insertions(+) diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 49372d1141..8c1901e8e4 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -13,7 +13,10 @@ #include #include +#include #include +#include +#include #include #include @@ -65,6 +68,10 @@ bool OctreePersistThread::process() { if(lockFile.is_open()) { qDebug() << "WARNING: Octree lock file detected at startup:" << lockFileName << "-- Attempting to restore from previous backup file."; + + // This is where we should attempt to find the most recent backup and restore from + // that file as our persist file. + restoreFromMostRecentBackup(); lockFile.close(); qDebug() << "Loading Octree... lock file closed:" << lockFileName; @@ -184,6 +191,66 @@ void OctreePersistThread::persist() { } } +void OctreePersistThread::restoreFromMostRecentBackup() { + qDebug() << "Restoring from most recent backup..."; + + // Based on our backup file name, determine the path and file name pattern for backup files + QFileInfo persistFileInfo(_filename); + QString path = persistFileInfo.path(); + QString fileNamePart = persistFileInfo.fileName(); + + // Create a file filter that will find all backup files of this extension format + QString backupExtension = _backupExtensionFormat; + + if (_backupExtensionFormat.contains("%N")) { + backupExtension.replace(QString("%N"), "*"); + } else { + qDebug() << "This backup extension format does not yet support restoring from most recent backup..."; + return; // exit early, unable to restore from backup + } + + QString backupFileNamePart = fileNamePart + backupExtension; + QStringList filters; + filters << backupFileNamePart; + + bool bestBackupFound = false; + QString bestBackupFile; + QDateTime bestBackupFileTime; + + // Iterate over all of the backup files in the persist location + QDirIterator dirIterator(path, filters, QDir::Files|QDir::NoSymLinks, QDirIterator::NoIteratorFlags); + while(dirIterator.hasNext()) { + + dirIterator.next(); + QDateTime lastModified = dirIterator.fileInfo().lastModified(); + + // Based on last modified date, track the most recently modified file as the best backup + if (lastModified > bestBackupFileTime) { + bestBackupFound = true; + bestBackupFile = dirIterator.filePath(); + bestBackupFileTime = lastModified; + } + } + + // If we found a backup file, restore from that file. + if (bestBackupFound) { + qDebug() << "BEST backup file:" << bestBackupFile << " last modified:" << bestBackupFileTime.toString(); + + qDebug() << "Removing old file:" << _filename; + remove(qPrintable(_filename)); + + qDebug() << "Restoring backup file " << bestBackupFile << "..."; + bool result = QFile::copy(bestBackupFile, _filename); + if (result) { + qDebug() << "DONE restoring backup file " << bestBackupFile << "to" << _filename << "..."; + } else { + qDebug() << "ERROR while restoring backup file " << bestBackupFile << "to" << _filename << "..."; + } + } else { + qDebug() << "NO BEST backup file found."; + } +} + void OctreePersistThread::rollOldBackupVersions() { if (!_backupExtensionFormat.contains("%N")) { return; // this backup extension format doesn't support rolling diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index b2093b89c0..70d2d9b747 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -48,6 +48,8 @@ protected: void persist(); void backup(); void rollOldBackupVersions(); + void restoreFromMostRecentBackup(); + private: Octree* _tree; QString _filename; From 7a2ecd27fd8a1696ef6d7a4719dbac26915ac931 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 12 Jan 2015 14:32:32 -0800 Subject: [PATCH 12/30] fix typo --- libraries/entities/src/EntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 70fdb86929..76045d9c15 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -699,7 +699,7 @@ void EntityItem::simulate(const quint64& now) { #ifndef USE_BULLET_PHYSICS // if we've slowed considerably, then just stop moving, but only if no BULLET if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) { - velocity = NO_VELOCITY; + velocity = ENTITY_ITEM_ZERO_VEC3; } #endif // !USE_BULLET_PHYSICS @@ -723,7 +723,7 @@ void EntityItem::simulate(const quint64& now) { #else // !USE_BULLET_PHYSICS // ... otherwise we help things come to rest by clamping small velocities. if (glm::length(velocity) <= ENTITY_ITEM_EPSILON_VELOCITY_LENGTH) { - velocity = NO_VELOCITY; + velocity = ENTITY_ITEM_ZERO_VEC3; } #endif // USE_BULLET_PHYSICS From 8f3aba35852d698441966b78ccdccbf0e83f3b15 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Mon, 12 Jan 2015 14:39:13 -0800 Subject: [PATCH 13/30] Removing double entry of gun.js Removing double entry of gun.js --- examples/gun.js | 419 ------------------------------------------------ 1 file changed, 419 deletions(-) delete mode 100644 examples/gun.js diff --git a/examples/gun.js b/examples/gun.js deleted file mode 100644 index 18fe9c542d..0000000000 --- a/examples/gun.js +++ /dev/null @@ -1,419 +0,0 @@ -// -// gun.js -// examples -// -// Created by Brad Hefta-Gaub on 12/31/13. -// Modified by Philip on 3/3/14 -// Copyright 2013 High Fidelity, Inc. -// -// This is an example script that turns the hydra controllers and mouse into a entity gun. -// It reads the controller, watches for trigger pulls, and launches entities. -// When entities collide with voxels they blow little holes out of the voxels. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include("libraries/globals.js"); - -function getRandomFloat(min, max) { - return Math.random() * (max - min) + min; -} - -var lastX = 0; -var lastY = 0; -var yawFromMouse = 0; -var pitchFromMouse = 0; -var isMouseDown = false; - -var BULLET_VELOCITY = 20.0; -var MIN_THROWER_DELAY = 1000; -var MAX_THROWER_DELAY = 1000; -var LEFT_BUTTON_3 = 3; -var RELOAD_INTERVAL = 5; - -var KICKBACK_ANGLE = 15; -var elbowKickAngle = 0.0; -var rotationBeforeKickback; - -var showScore = false; - - -// Load some sound to use for loading and firing -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"; - -var audioOptions = { - volume: 0.9 -} - -var shotsFired = 0; -var shotTime = new Date(); - -var activeControllers = 0; - -// initialize our controller triggers -var triggerPulled = new Array(); -var numberOfTriggers = Controller.getNumberOfTriggers(); -for (t = 0; t < numberOfTriggers; t++) { - triggerPulled[t] = false; -} - -var isLaunchButtonPressed = false; -var score = 0; - -var bulletID = false; -var targetID = false; - -// Create a reticle image in center of screen -var screenSize = Controller.getViewportDimensions(); -var reticle = Overlays.addOverlay("image", { - x: screenSize.x / 2 - 16, - y: screenSize.y / 2 - 16, - width: 32, - height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/reticle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - -var offButton = Overlays.addOverlay("image", { - x: screenSize.x - 48, - y: 96, - width: 32, - height: 32, - imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - -if (showScore) { - var text = Overlays.addOverlay("text", { - x: screenSize.x / 2 - 100, - y: screenSize.y / 2 - 50, - width: 150, - height: 50, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 0, blue: 0}, - topMargin: 4, - leftMargin: 4, - text: "Score: " + score - }); -} - - - -function printVector(string, vector) { - print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); -} - -function shootBullet(position, velocity) { - var BULLET_SIZE = 0.07; - var BULLET_LIFETIME = 10.0; - var BULLET_GRAVITY = -0.02; - bulletID = Entities.addEntity( - { type: "Sphere", - position: position, - dimensions: { x: BULLET_SIZE, y: BULLET_SIZE, z: BULLET_SIZE }, - color: { red: 255, green: 0, blue: 0 }, - velocity: velocity, - lifetime: BULLET_LIFETIME, - gravity: { x: 0, y: BULLET_GRAVITY, z: 0 }, - ignoreCollisions: false, - collisionsWillMove: true - }); - - // Play firing sounds - audioOptions.position = position; - Audio.playSound(fireSound, audioOptions); - shotsFired++; - if ((shotsFired % RELOAD_INTERVAL) == 0) { - Audio.playSound(loadSound, audioOptions); - } - - // Kickback the arm - rotationBeforeKickback = MyAvatar.getJointRotation("LeftForeArm"); - var armRotation = MyAvatar.getJointRotation("LeftForeArm"); - armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, KICKBACK_ANGLE)); - MyAvatar.setJointData("LeftForeArm", armRotation); - elbowKickAngle = KICKBACK_ANGLE; -} - -function shootTarget() { - var TARGET_SIZE = 0.50; - var TARGET_GRAVITY = -0.25; - var TARGET_LIFETIME = 300.0; - var TARGET_UP_VELOCITY = 0.5; - var TARGET_FWD_VELOCITY = 1.0; - var DISTANCE_TO_LAUNCH_FROM = 3.0; - var ANGLE_RANGE_FOR_LAUNCH = 20.0; - var camera = Camera.getPosition(); - //printVector("camera", camera); - var targetDirection = Quat.angleAxis(getRandomFloat(-ANGLE_RANGE_FOR_LAUNCH, ANGLE_RANGE_FOR_LAUNCH), { x:0, y:1, z:0 }); - targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection); - var forwardVector = Quat.getFront(targetDirection); - - var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM)); - - var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY); - velocity.y += TARGET_UP_VELOCITY; - - targetID = Entities.addEntity( - { type: "Box", - position: newPosition, - dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE }, - color: { red: 0, green: 200, blue: 200 }, - //angularVelocity: { x: 1, y: 0, z: 0 }, - velocity: velocity, - gravity: { x: 0, y: TARGET_GRAVITY, z: 0 }, - lifetime: TARGET_LIFETIME, - damping: 0.0001, - collisionsWillMove: true }); - - // Record start time - shotTime = new Date(); - - // Play target shoot sound - audioOptions.position = newPosition; - Audio.playSound(targetLaunchSound, audioOptions); -} - - - -function entityCollisionWithEntity(entity1, entity2, collision) { - - if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) && - ((entity2.id == bulletID.id) || (entity2.id == targetID.id))) { - score++; - if (showScore) { - Overlays.editOverlay(text, { text: "Score: " + score } ); - } - - // We will delete the bullet and target in 1/2 sec, but for now we can see them bounce! - Script.setTimeout(deleteBulletAndTarget, 500); - - // Turn the target and the bullet white - Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }}); - Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }}); - - // play the sound near the camera so the shooter can hear it - audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - Audio.playSound(targetHitSound, audioOptions); - } -} - -function keyPressEvent(event) { - // if our tools are off, then don't do anything - if (event.text == "t") { - var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY; - Script.setTimeout(shootTarget, time); - } else if (event.text == ".") { - shootFromMouse(); - } else if (event.text == "r") { - playLoadSound(); - } else if (event.text == "s") { - // Hit this key to dump a posture from hydra to log - Quat.print("arm = ", MyAvatar.getJointRotation("LeftArm")); - Quat.print("forearm = ", MyAvatar.getJointRotation("LeftForeArm")); - Quat.print("hand = ", MyAvatar.getJointRotation("LeftHand")); - - } -} - -function playLoadSound() { - audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - Audio.playSound(loadSound, audioOptions); - // Raise arm to firing posture - takeFiringPose(); -} - -function clearPose() { - MyAvatar.clearJointData("LeftForeArm"); - MyAvatar.clearJointData("LeftArm"); - MyAvatar.clearJointData("LeftHand"); -} - -function deleteBulletAndTarget() { - Entities.deleteEntity(bulletID); - Entities.deleteEntity(targetID); - bulletID = false; - targetID = false; -} - -function takeFiringPose() { - clearPose(); - if (Controller.getNumberOfSpatialControls() == 0) { - MyAvatar.setJointData("LeftForeArm", {x: -0.251919, y: -0.0415449, z: 0.499487, w: 0.827843}); - MyAvatar.setJointData("LeftArm", { x: 0.470196, y: -0.132559, z: 0.494033, w: 0.719219}); - MyAvatar.setJointData("LeftHand", { x: -0.0104815, y: -0.110551, z: -0.352111, w: 0.929333}); - } -} - -MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20); -//MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); - -// Give a bit of time to load before playing sound -Script.setTimeout(playLoadSound, 2000); - -function update(deltaTime) { - if (bulletID && !bulletID.isKnownID) { - print("Trying to identify bullet"); - bulletID = Entities.identifyEntity(bulletID); - } - if (targetID && !targetID.isKnownID) { - targetID = Entities.identifyEntity(targetID); - } - // Check for mouseLook movement, update rotation - // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); - //MyAvatar.orientation = newOrientation; - yawFromMouse = 0; - - // apply pitch from mouse - var newPitch = MyAvatar.headPitch + pitchFromMouse; - //MyAvatar.headPitch = newPitch; - pitchFromMouse = 0; - - - if (activeControllers == 0) { - if (Controller.getNumberOfSpatialControls() > 0) { - activeControllers = Controller.getNumberOfSpatialControls(); - clearPose(); - } - } - - var KICKBACK_DECAY_RATE = 0.125; - if (elbowKickAngle > 0.0) { - if (elbowKickAngle > 0.5) { - var newAngle = elbowKickAngle * KICKBACK_DECAY_RATE; - elbowKickAngle -= newAngle; - var armRotation = MyAvatar.getJointRotation("LeftForeArm"); - armRotation = Quat.multiply(armRotation, Quat.fromPitchYawRollDegrees(0.0, 0.0, -newAngle)); - MyAvatar.setJointData("LeftForeArm", armRotation); - } else { - MyAvatar.setJointData("LeftForeArm", rotationBeforeKickback); - if (Controller.getNumberOfSpatialControls() > 0) { - clearPose(); - } - elbowKickAngle = 0.0; - } - } - - // Check hydra controller for launch button press - if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) { - isLaunchButtonPressed = true; - var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY; - Script.setTimeout(shootTarget, time); - } else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) { - isLaunchButtonPressed = false; - - } - - // check for trigger press - - var numberOfTriggers = 2; - var controllersPerTrigger = 2; - - if (numberOfTriggers == 2 && controllersPerTrigger == 2) { - for (var t = 0; t < 2; t++) { - var shootABullet = false; - var triggerValue = Controller.getTriggerValue(t); - if (triggerPulled[t]) { - // must release to at least 0.1 - if (triggerValue < 0.1) { - triggerPulled[t] = false; // unpulled - } - } else { - // must pull to at least - if (triggerValue > 0.5) { - triggerPulled[t] = true; // pulled - shootABullet = true; - } - } - - if (shootABullet) { - var palmController = t * controllersPerTrigger; - var palmPosition = Controller.getSpatialControlPosition(palmController); - - var fingerTipController = palmController + 1; - var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController); - - var palmToFingerTipVector = - { x: (fingerTipPosition.x - palmPosition.x), - y: (fingerTipPosition.y - palmPosition.y), - z: (fingerTipPosition.z - palmPosition.z) }; - - // just off the front of the finger tip - var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2, - y: fingerTipPosition.y + palmToFingerTipVector.y/2, - z: fingerTipPosition.z + palmToFingerTipVector.z/2}; - - var velocity = Vec3.multiply(BULLET_VELOCITY, Vec3.normalize(palmToFingerTipVector)); - - shootBullet(position, velocity); - } - } - } -} - -function mousePressEvent(event) { - isMouseDown = true; - lastX = event.x; - lastY = event.y; - - if (Overlays.getOverlayAtPoint({ x: event.x, y: event.y }) === offButton) { - Script.stop(); - } else { - shootFromMouse(); - } -} - -function shootFromMouse() { - var DISTANCE_FROM_CAMERA = 2.0; - var camera = Camera.getPosition(); - var forwardVector = Quat.getFront(Camera.getOrientation()); - var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA)); - var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY); - shootBullet(newPosition, velocity); -} - -function mouseReleaseEvent(event) { - // position - isMouseDown = false; -} - -function mouseMoveEvent(event) { - if (isMouseDown) { - var MOUSE_YAW_SCALE = -0.25; - var MOUSE_PITCH_SCALE = -12.5; - var FIXED_MOUSE_TIMESTEP = 0.016; - yawFromMouse += ((event.x - lastX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP); - pitchFromMouse += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP); - lastX = event.x; - lastY = event.y; - } -} - -function scriptEnding() { - Overlays.deleteOverlay(reticle); - Overlays.deleteOverlay(offButton); - Overlays.deleteOverlay(text); - MyAvatar.detachOne(gunModel); - clearPose(); -} - -Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); -Script.scriptEnding.connect(scriptEnding); -Script.update.connect(update); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.keyPressEvent.connect(keyPressEvent); - - - From c45f618852dfeeae44cf68f934f8d57609b661a5 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 12 Jan 2015 15:00:35 -0800 Subject: [PATCH 14/30] Factorising the shader code to unpack data from the deferred buffer --- libraries/render-utils/src/DeferredBuffer.slh | 65 +++++++++++++++++++ .../render-utils/src/directional_light.slf | 47 +++----------- .../directional_light_cascaded_shadow_map.slf | 54 ++++----------- .../src/directional_light_shadow_map.slf | 48 +++----------- 4 files changed, 96 insertions(+), 118 deletions(-) create mode 100755 libraries/render-utils/src/DeferredBuffer.slh diff --git a/libraries/render-utils/src/DeferredBuffer.slh b/libraries/render-utils/src/DeferredBuffer.slh new file mode 100755 index 0000000000..c5630c3564 --- /dev/null +++ b/libraries/render-utils/src/DeferredBuffer.slh @@ -0,0 +1,65 @@ + +<@if not DEFERRED_BUFFER_SLH@> +<@def DEFERRED_BUFFER_SLH@> + + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal texture +uniform sampler2D normalMap; + +// the specular texture +uniform sampler2D specularMap; + +// the depth texture +uniform sampler2D depthMap; + +// the distance to the near clip plane +uniform float near; + +// scale factor for depth: (far - near) / far +uniform float depthScale; + +// offset for depth texture coordinates +uniform vec2 depthTexCoordOffset; + +// scale for depth texture coordinates +uniform vec2 depthTexCoordScale; + +struct DeferredFragment { + float depthVal; + vec4 normalVal; + vec4 diffuseVal; + vec4 specularVal; + vec4 position; + vec3 normal; +}; + +DeferredFragment unpackDeferredFragment(vec2 texcoord) { + DeferredFragment frag; + frag.depthVal = texture2D(depthMap, texcoord).r; + frag.normalVal = texture2D(normalMap, texcoord); + frag.diffuseVal = texture2D(diffuseMap, texcoord); + frag.specularVal = texture2D(specularMap, texcoord); + + // compute the view space position using the depth + float z = near / (frag.depthVal * depthScale - 1.0); + frag.position = vec4((depthTexCoordOffset + texcoord * depthTexCoordScale) * z, z, 1.0); + + // Unpack the normal from the map + frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0)); + + return frag; +} + +<@endif@> diff --git a/libraries/render-utils/src/directional_light.slf b/libraries/render-utils/src/directional_light.slf index 7a02e3c3a8..db963be913 100644 --- a/libraries/render-utils/src/directional_light.slf +++ b/libraries/render-utils/src/directional_light.slf @@ -12,56 +12,29 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the diffuse texture -uniform sampler2D diffuseMap; - -// the normal texture -uniform sampler2D normalMap; - -// the specular texture -uniform sampler2D specularMap; - -// the depth texture -uniform sampler2D depthMap; - -// the distance to the near clip plane -uniform float near; - -// scale factor for depth: (far - near) / far -uniform float depthScale; - -// offset for depth texture coordinates -uniform vec2 depthTexCoordOffset; - -// scale for depth texture coordinates -uniform vec2 depthTexCoordScale; +// Everything about deferred buffer +<@include DeferredBuffer.slh@> void main(void) { - float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r; - vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st); - vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st); - vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st); + DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st); + + vec4 normalVal = frag.normalVal; + vec4 diffuseVal = frag.diffuseVal; + vec4 specularVal = frag.specularVal; - // compute the view space position using the depth - float z = near / (depthVal * depthScale - 1.0); - vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 0.0); - // Light mapped or not ? if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) { gl_FragColor = vec4(diffuseVal.rgb * specularVal.rgb, 1.0); } else { - // get the normal from the map - vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0)); - // compute the base color based on OpenGL lighting model - float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz); + float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz); float facingLight = step(0.0, diffuse); vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb + gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight)); // compute the specular multiplier (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)), - normalizedNormal)); + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)), + frag.normal)); // add specular contribution vec4 specularColor = specularVal; diff --git a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf index 08fdc3a908..f7e21252fb 100644 --- a/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_cascaded_shadow_map.slf @@ -12,52 +12,24 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the diffuse texture -uniform sampler2D diffuseMap; - -// the normal texture -uniform sampler2D normalMap; - -// the specular texture -uniform sampler2D specularMap; - -// the depth texture -uniform sampler2D depthMap; +// Everything about deferred buffer +<@include DeferredBuffer.slh@> // Everything about shadow <@include Shadow.slh@> -// the distance to the near clip plane -uniform float near; - -// scale factor for depth: (far - near) / far -uniform float depthScale; - -// offset for depth texture coordinates -uniform vec2 depthTexCoordOffset; - -// scale for depth texture coordinates -uniform vec2 depthTexCoordScale; - void main(void) { - float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r; - vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st); - vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st); - vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st); - - // compute the view space position using the depth - float z = near / (depthVal * depthScale - 1.0); - vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0); + DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st); + vec4 normalVal = frag.normalVal; + vec4 diffuseVal = frag.diffuseVal; + vec4 specularVal = frag.specularVal; // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalCascadedShadowTexcoord(position); + vec4 shadowTexcoord = evalCascadedShadowTexcoord(frag.position); float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - // get the normal from the map - vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0)); - // how much this fragment faces the light direction - float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz); + float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz); // Light mapped or not ? if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) { @@ -83,19 +55,15 @@ void main(void) { float facingLight = step(0.0, diffuse) * shadowAttenuation; // compute the base color based on OpenGL lighting model - vec3 baseColor = diffuseVal.rgb * (/*gl_FrontLightModelProduct.sceneColor.rgb + */ + vec3 baseColor = diffuseVal.rgb * (gl_FrontLightModelProduct.sceneColor.rgb + gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight)); // compute the specular multiplier (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)), - normalizedNormal)); + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)), + frag.normal)); // add specular contribution vec4 specularColor = specularVal; gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normalVal.a); - - if (gl_FragCoord.x > 1024) { - gl_FragColor = vec4( (gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight)), normalVal.a); - } } } diff --git a/libraries/render-utils/src/directional_light_shadow_map.slf b/libraries/render-utils/src/directional_light_shadow_map.slf index 7a34f56f93..1a781af131 100644 --- a/libraries/render-utils/src/directional_light_shadow_map.slf +++ b/libraries/render-utils/src/directional_light_shadow_map.slf @@ -12,52 +12,24 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the diffuse texture -uniform sampler2D diffuseMap; - -// the normal texture -uniform sampler2D normalMap; - -// the specular texture -uniform sampler2D specularMap; - -// the depth texture -uniform sampler2D depthMap; +// Everything about deferred buffer +<@include DeferredBuffer.slh@> // Everything about shadow <@include Shadow.slh@> -// the distance to the near clip plane -uniform float near; - -// scale factor for depth: (far - near) / far -uniform float depthScale; - -// offset for depth texture coordinates -uniform vec2 depthTexCoordOffset; - -// scale for depth texture coordinates -uniform vec2 depthTexCoordScale; - void main(void) { - float depthVal = texture2D(depthMap, gl_TexCoord[0].st).r; - vec4 normalVal = texture2D(normalMap, gl_TexCoord[0].st); - vec4 diffuseVal = texture2D(diffuseMap, gl_TexCoord[0].st); - vec4 specularVal = texture2D(specularMap, gl_TexCoord[0].st); - - // compute the view space position using the depth - float z = near / (depthVal * depthScale - 1.0); - vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0); + DeferredFragment frag = unpackDeferredFragment(gl_TexCoord[0].st); + vec4 normalVal = frag.normalVal; + vec4 diffuseVal = frag.diffuseVal; + vec4 specularVal = frag.specularVal; // Eval shadow Texcoord and then Attenuation - vec4 shadowTexcoord = evalShadowTexcoord(position); + vec4 shadowTexcoord = evalShadowTexcoord(frag.position); float shadowAttenuation = evalShadowAttenuation(shadowTexcoord); - // get the normal from the map - vec3 normalizedNormal = normalize(normalVal.xyz * 2.0 - vec3(1.0)); - // how much this fragment faces the light direction - float diffuse = dot(normalizedNormal, gl_LightSource[0].position.xyz); + float diffuse = dot(frag.normal, gl_LightSource[0].position.xyz); // Light mapped or not ? if ((normalVal.a >= 0.45) && (normalVal.a <= 0.55)) { @@ -86,8 +58,8 @@ void main(void) { gl_FrontLightProduct[0].ambient.rgb + gl_FrontLightProduct[0].diffuse.rgb * (diffuse * facingLight)); // compute the specular multiplier (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(position.xyz)), - normalizedNormal)); + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position.xyz - normalize(frag.position.xyz)), + frag.normal)); // add specular contribution vec4 specularColor = specularVal; From 67da1148ac69476372456fc6860a713d24f4a018 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 12 Jan 2015 15:22:47 -0800 Subject: [PATCH 15/30] global ambient light back --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 89a27b25d7..22a2b6bc22 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2589,8 +2589,7 @@ void Application::updateShadowMap() { glViewport(0, 0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight()); } -//const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; -const GLfloat WORLD_AMBIENT_COLOR[] = { 0.2f, 0.2f, 0.3f }; +const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; const GLfloat WORLD_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f }; const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f }; From 1566157250c919cd541512aa0f5f0002782d2a5f Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Mon, 12 Jan 2015 15:52:31 -0800 Subject: [PATCH 16/30] Use the DeferredBuffer.slh in point and spot lights --- libraries/render-utils/src/point_light.slf | 25 ++-------------------- libraries/render-utils/src/spot_light.slf | 25 ++-------------------- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/libraries/render-utils/src/point_light.slf b/libraries/render-utils/src/point_light.slf index 320dc93f5e..e5142b25ce 100644 --- a/libraries/render-utils/src/point_light.slf +++ b/libraries/render-utils/src/point_light.slf @@ -12,29 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the diffuse texture -uniform sampler2D diffuseMap; - -// the normal texture -uniform sampler2D normalMap; - -// the specular texture -uniform sampler2D specularMap; - -// the depth texture -uniform sampler2D depthMap; - -// the distance to the near clip plane -uniform float near; - -// scale factor for depth: (far - near) / far -uniform float depthScale; - -// offset for depth texture coordinates -uniform vec2 depthTexCoordOffset; - -// scale for depth texture coordinates -uniform vec2 depthTexCoordScale; +// Everything about deferred buffer +<@include DeferredBuffer.slh@> // the radius (hard cutoff) of the light effect uniform float radius; diff --git a/libraries/render-utils/src/spot_light.slf b/libraries/render-utils/src/spot_light.slf index 489802d061..f987760eb8 100644 --- a/libraries/render-utils/src/spot_light.slf +++ b/libraries/render-utils/src/spot_light.slf @@ -12,29 +12,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the diffuse texture -uniform sampler2D diffuseMap; - -// the normal texture -uniform sampler2D normalMap; - -// the specular texture -uniform sampler2D specularMap; - -// the depth texture -uniform sampler2D depthMap; - -// the distance to the near clip plane -uniform float near; - -// scale factor for depth: (far - near) / far -uniform float depthScale; - -// offset for depth texture coordinates -uniform vec2 depthTexCoordOffset; - -// scale for depth texture coordinates -uniform vec2 depthTexCoordScale; +// Everything about deferred buffer +<@include DeferredBuffer.slh@> // the radius (hard cutoff) of the light effect uniform float radius; From ea3a5b7fcdf5c3161b0116b218bd8741093f6ded Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 12 Jan 2015 17:29:10 -0800 Subject: [PATCH 17/30] use last backup files timestamp as last backup time. --- libraries/octree/src/OctreePersistThread.cpp | 80 +++++++++++++++----- libraries/octree/src/OctreePersistThread.h | 2 + 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 8c1901e8e4..79469ade1f 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -49,6 +49,23 @@ OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, { } +quint64 OctreePersistThread::getMostRecentBackupTimeInUsecs() { + + quint64 mostRecentBackupInUsecs = 0; + + QString mostRecentBackupFileName; + QDateTime mostRecentBackupTime; + + bool recentBackup = getMostRecentBackup(mostRecentBackupFileName, mostRecentBackupTime); + + if (recentBackup) { + mostRecentBackupInUsecs = mostRecentBackupTime.toMSecsSinceEpoch() * USECS_PER_MSEC; + } + + return mostRecentBackupInUsecs; +} + + bool OctreePersistThread::process() { if (!_initialLoadComplete) { @@ -109,7 +126,19 @@ bool OctreePersistThread::process() { } _initialLoadComplete = true; - _lastBackup = _lastCheck = usecTimestampNow(); // we just loaded, no need to save again + + // Since we just loaded the persistent file, we can consider ourselves as having "just checked" for persistance. + _lastCheck = usecTimestampNow(); // we just loaded, no need to save again + + // The last backup time, should be the timestamp for most recent backup file. + _lastBackup = getMostRecentBackupTimeInUsecs(); + + qDebug() << "Last Check:" << qPrintable(formatUsecTime(usecTimestampNow() - _lastCheck)) << "ago..."; + qDebug() << "Last Backup:" << qPrintable(formatUsecTime(usecTimestampNow() - _lastBackup)) << "ago..."; + + // This last persist time is not really used until the file is actually persisted. It is only + // used in formatting the backup filename in cases of non-rolling backup names. However, we don't + // want an uninitialized value for this, so we set it to the current time (startup of the server) time(&_lastPersistTime); emit loadCompleted(); @@ -193,6 +222,32 @@ void OctreePersistThread::persist() { void OctreePersistThread::restoreFromMostRecentBackup() { qDebug() << "Restoring from most recent backup..."; + + QString mostRecentBackupFileName; + QDateTime mostRecentBackupTime; + + bool recentBackup = getMostRecentBackup(mostRecentBackupFileName, mostRecentBackupTime); + + // If we found a backup file, restore from that file. + if (recentBackup) { + qDebug() << "BEST backup file:" << mostRecentBackupFileName << " last modified:" << mostRecentBackupTime.toString(); + + qDebug() << "Removing old file:" << _filename; + remove(qPrintable(_filename)); + + qDebug() << "Restoring backup file " << mostRecentBackupFileName << "..."; + bool result = QFile::copy(mostRecentBackupFileName, _filename); + if (result) { + qDebug() << "DONE restoring backup file " << mostRecentBackupFileName << "to" << _filename << "..."; + } else { + qDebug() << "ERROR while restoring backup file " << mostRecentBackupFileName << "to" << _filename << "..."; + } + } else { + qDebug() << "NO BEST backup file found."; + } +} + +bool OctreePersistThread::getMostRecentBackup(QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime) { // Based on our backup file name, determine the path and file name pattern for backup files QFileInfo persistFileInfo(_filename); @@ -206,7 +261,7 @@ void OctreePersistThread::restoreFromMostRecentBackup() { backupExtension.replace(QString("%N"), "*"); } else { qDebug() << "This backup extension format does not yet support restoring from most recent backup..."; - return; // exit early, unable to restore from backup + return false; // exit early, unable to restore from backup } QString backupFileNamePart = fileNamePart + backupExtension; @@ -231,24 +286,13 @@ void OctreePersistThread::restoreFromMostRecentBackup() { bestBackupFileTime = lastModified; } } - - // If we found a backup file, restore from that file. + + // If we found a backup then return the results if (bestBackupFound) { - qDebug() << "BEST backup file:" << bestBackupFile << " last modified:" << bestBackupFileTime.toString(); - - qDebug() << "Removing old file:" << _filename; - remove(qPrintable(_filename)); - - qDebug() << "Restoring backup file " << bestBackupFile << "..."; - bool result = QFile::copy(bestBackupFile, _filename); - if (result) { - qDebug() << "DONE restoring backup file " << bestBackupFile << "to" << _filename << "..."; - } else { - qDebug() << "ERROR while restoring backup file " << bestBackupFile << "to" << _filename << "..."; - } - } else { - qDebug() << "NO BEST backup file found."; + mostRecentBackupFileName = bestBackupFile; + mostRecentBackupTime = bestBackupFileTime; } + return bestBackupFound; } void OctreePersistThread::rollOldBackupVersions() { diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index 70d2d9b747..6f08b63197 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -49,6 +49,8 @@ protected: void backup(); void rollOldBackupVersions(); void restoreFromMostRecentBackup(); + bool getMostRecentBackup(QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime); + quint64 getMostRecentBackupTimeInUsecs(); private: Octree* _tree; From 80351a768e9ca319ff52eed6e243b7a802ddbe86 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 08:26:11 -0800 Subject: [PATCH 18/30] Enable camera tool --- examples/libraries/entityCameraTool.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index b6a86e7a4d..cd8aa3656b 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -243,9 +243,9 @@ CameraManager = function() { } that.mousePressEvent = function(event) { - // if (cameraTool.mousePressEvent(event)) { - // return true; - // } + if (cameraTool.mousePressEvent(event)) { + return true; + } if (!that.enabled) return; @@ -291,7 +291,7 @@ CameraManager = function() { that.updateCamera = function() { if (!that.enabled || Camera.mode != "independent") { - // cameraTool.update(); + cameraTool.update(); return; } @@ -313,7 +313,7 @@ CameraManager = function() { Camera.setOrientation(q); - // cameraTool.update(); + cameraTool.update(); } function normalizeDegrees(degrees) { @@ -383,7 +383,7 @@ CameraManager = function() { Controller.wheelEvent.connect(that.wheelEvent); - // var cameraTool = new CameraTool(that); + var cameraTool = new CameraTool(that); return that; } From aad49e4404ff8526c4578dd7ef71b3b31d100e6f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 08:26:32 -0800 Subject: [PATCH 19/30] Update camera tool to only show when edit entities is enabled --- examples/libraries/entityCameraTool.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index cd8aa3656b..ecc8935f26 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -105,6 +105,8 @@ CameraManager = function() { Camera.mode = "independent"; that.updateCamera(); + + cameraTool.setVisible(true); } that.disable = function(ignoreCamera) { @@ -115,6 +117,7 @@ CameraManager = function() { if (!ignoreCamera) { Camera.mode = that.previousCameraMode; } + cameraTool.setVisible(false); } that.focus = function(position, dimensions, easeOrientation) { From e873df9680fd11d7d632417330552a4936fb0bb6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 08:39:59 -0800 Subject: [PATCH 20/30] Remove mode buttons from camera tool and increase size --- examples/libraries/entityCameraTool.js | 122 +++++++++---------------- examples/libraries/overlayUtils.js | 2 +- 2 files changed, 46 insertions(+), 78 deletions(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index ecc8935f26..078ce0bbca 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -398,43 +398,21 @@ CameraTool = function(cameraManager) { var GREEN = { red: 26, green: 193, blue: 105 }; var BLUE = { red: 0, green: 131, blue: 204 }; - var ORIENTATION_OVERLAY_SIZE = 20; + var BORDER_WIDTH = 1; + + var ORIENTATION_OVERLAY_SIZE = 26; var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2; - var ORIENTATION_OVERLAY_CUBE_SIZE = 8, + var ORIENTATION_OVERLAY_CUBE_SIZE = 11, var ORIENTATION_OVERLAY_OFFSET = { - x: 96, + x: 30, y: 30, } - var UI_URL = HIFI_PUBLIC_BUCKET + "images/tools/camera-controls.svg"; - - var UI_WIDTH = 128; - var UI_HEIGHT = 61; + var UI_WIDTH = 70; + var UI_HEIGHT = 70; var UI_PADDING = 10; - var UI_BUTTON_WIDTH = 64; - var UI_BUTTON_HEIGHT = 30; - - var UI_SUBIMAGE_FIRST_PERSON = { - x: 0, - y: 0, - width: UI_WIDTH, - height: UI_HEIGHT - }, - var UI_SUBIMAGE_THIRD_PERSON = { - x: 0, - y: UI_HEIGHT, - width: UI_WIDTH, - height: UI_HEIGHT - }, - var UI_SUBIMAGE_OTHER = { - x: 0, - y: UI_HEIGHT * 2, - width: UI_WIDTH, - height: UI_HEIGHT - }, - var lastKnownWidth = Window.innerWidth; var uiPosition = { @@ -442,20 +420,28 @@ CameraTool = function(cameraManager) { y: UI_PADDING, }; - var ui = Overlays.addOverlay("image", { - imageURL: UI_URL, + var backgroundBorder = Overlays.addOverlay("text", { + x: uiPosition.x - BORDER_WIDTH, + y: uiPosition.y - BORDER_WIDTH, + width: UI_WIDTH + BORDER_WIDTH * 2, + height: UI_HEIGHT + BORDER_WIDTH * 2, + alpha: 0, + text: "", + backgroundColor: { red: 101, green: 101, blue: 101 }, + backgroundAlpha: 1.0, + visible: false, + }); + + var background = Overlays.addOverlay("text", { x: uiPosition.x, y: uiPosition.y, - subImage: { - x: 0, - y: 0, - width: UI_WIDTH, - height: UI_HEIGHT - }, width: UI_WIDTH, height: UI_HEIGHT, - alpha: 1.0, - visible: true + alpha: 0, + text: "", + backgroundColor: { red: 51, green: 51, blue: 51 }, + backgroundAlpha: 1.0, + visible: false, }); var defaultCubeProps = { @@ -473,15 +459,16 @@ CameraTool = function(cameraManager) { start: { x: 0, y: 0, z: 0 }, end: { x: 0, y: 0, z: 0 }, color: { red: 255, green: 0, blue: 0 }, - visible: true, + visible: false, drawOnHUD: true, }; var orientationOverlay = OverlayGroup({ position: { - x: uiPosition.x + ORIENTATION_OVERLAY_OFFSET.x, - y: uiPosition.y + ORIENTATION_OVERLAY_OFFSET.y, - } + x: uiPosition.x + UI_WIDTH / 2, + y: uiPosition.y + UI_HEIGHT / 2, + }, + visible: false, }); var OOHS = ORIENTATION_OVERLAY_HALF_SIZE; @@ -515,7 +502,8 @@ CameraTool = function(cameraManager) { Script.scriptEnding.connect(function() { orientationOverlay.destroy(); - Overlays.deleteOverlay(ui); + Overlays.deleteOverlay(background); + Overlays.deleteOverlay(backgroundBorder); }); var flip = Quat.fromPitchYawRollDegrees(0, 180, 0); @@ -530,16 +518,20 @@ CameraTool = function(cameraManager) { x: lastKnownWidth - UI_WIDTH - UI_PADDING, y: UI_PADDING, }; - Overlays.editOverlay(ui, { - x: uiPosition.x, - y: uiPosition.y - }); orientationOverlay.setProperties({ position: { x: uiPosition.x + ORIENTATION_OVERLAY_OFFSET.x, y: uiPosition.y + ORIENTATION_OVERLAY_OFFSET.y, } }); + Overlays.editOverlay(backgroundBorder, { + x: uiPosition.x - BORDER_WIDTH, + y: uiPosition.y - BORDER_WIDTH, + }); + Overlays.editOverlay(background, { + x: uiPosition.x, + y: uiPosition.y, + }); } } @@ -561,40 +553,16 @@ CameraTool = function(cameraManager) { targetYaw = event.isLeftButton ? 0 : 180; cameraManager.setTargetPitchYaw(targetPitch, targetYaw); return true; - } else if (clickedOverlay == ui) { - var x = event.x - uiPosition.x; - var y = event.y - uiPosition.y; - - // Did we hit a button? - if (x < UI_BUTTON_WIDTH) { - if (y < UI_BUTTON_HEIGHT) { - Camera.mode = "first person"; - } else { - Camera.mode = "third person"; - } - } - return true; } }; - function updateMode() { - var mode = Camera.mode; - - var subImage = UI_SUBIMAGE_OTHER; - if (mode == "first person") { - subImage = UI_SUBIMAGE_FIRST_PERSON; - } else if (mode == "third person") { - subImage = UI_SUBIMAGE_THIRD_PERSON; - } - - Overlays.editOverlay(ui, { subImage: subImage }); - } - - Camera.modeUpdated.connect(updateMode); - updateMode(); - that.setVisible = function(visible) { + orientationOverlay.setProperties({ visible: visible }); + Overlays.editOverlay(background, { visible: visible }); + Overlays.editOverlay(backgroundBorder, { visible: visible }); }; + that.setVisible(false); + return that; }; diff --git a/examples/libraries/overlayUtils.js b/examples/libraries/overlayUtils.js index 7623bfbb30..636ea40825 100644 --- a/examples/libraries/overlayUtils.js +++ b/examples/libraries/overlayUtils.js @@ -9,7 +9,7 @@ OverlayGroup = function(opts) { var rootPosition = opts.position || { x: 0, y: 0, z: 0 }; var rootRotation = opts.rotation || Quat.fromPitchYawRollRadians(0, 0, 0); - var visible = true; + var visible = opts.visible == true; function updateOverlays() { for (overlayID in overlays) { From 0c58572d3283527c4b045f29d2a3837851ee2c1d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 08:45:11 -0800 Subject: [PATCH 21/30] Reduce size of camera tool cubes --- examples/libraries/entityCameraTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index 078ce0bbca..b9170dc25d 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -402,7 +402,7 @@ CameraTool = function(cameraManager) { var ORIENTATION_OVERLAY_SIZE = 26; var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2; - var ORIENTATION_OVERLAY_CUBE_SIZE = 11, + var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5, var ORIENTATION_OVERLAY_OFFSET = { x: 30, From 96f75df8318d52925d0a6ad16c432470f5a25340 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 10:09:05 -0800 Subject: [PATCH 22/30] Add missing model properties to entity property window --- examples/html/entityProperties.html | 35 +++++++++++++++++++++++++++-- examples/html/style.css | 7 +++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index d7f097966a..c23a3cd5ab 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -31,8 +31,13 @@ } function createEmitTextPropertyUpdateFunction(propertyName) { return function() { + var properties = {}; + properties[propertyName] = this.value; EventBridge.emitWebEvent( - '{ "type":"update", "properties":{"' + propertyName + '":"' + this.value + '"}}' + JSON.stringify({ + type: "update", + properties: properties, + }) ); }; } @@ -146,6 +151,9 @@ var elModelAnimationPlaying = document.getElementById("property-model-animation-playing"); var elModelAnimationFPS = document.getElementById("property-model-animation-fps"); var elModelAnimationFrame = document.getElementById("property-model-animation-frame"); + var elModelAnimationSettings = document.getElementById("property-model-animation-settings"); + var elModelTextures = document.getElementById("property-model-textures"); + var elModelOriginalTextures = document.getElementById("property-model-original-textures"); var elTextSections = document.querySelectorAll(".text-section"); var elTextText = document.getElementById("property-text-text"); @@ -244,6 +252,10 @@ elModelAnimationURL.value = properties.animationURL; elModelAnimationPlaying.checked = properties.animationIsPlaying; elModelAnimationFPS.value = properties.animationFPS; + elModelAnimationFrame.value = properties.animationFrameIndex; + elModelAnimationSettings.value = properties.animationSettings; + elModelTextures.value = properties.textures; + elModelOriginalTextures.value = properties.originalTextures; } if (properties.type != "Text") { @@ -387,6 +399,8 @@ elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying')); elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS')); elModelAnimationFrame.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFrameIndex')); + elModelAnimationSettings.addEventListener('change', createEmitTextPropertyUpdateFunction('animationSettings')); + elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures')); elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight')); @@ -429,7 +443,6 @@ })); }); - var resizing = false; var startX = 0; var originalWidth = 0; @@ -679,6 +692,24 @@ + + Animation Settings + + + + + + Textures + + + + + + Original Textures + + + + diff --git a/examples/html/style.css b/examples/html/style.css index 2f43b1c356..7ffbacb15e 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -90,12 +90,17 @@ input[type=button] { font-size: .9em; } -input { +textarea, input { padding: 2px; border: 1px solid #999; background-color: #eee; } +textarea { + width: 100%; + resize: vertical; +} + input.url { width: 100%; } From 00f7bf7efeb58646bbc376b234c0bee3dae98330 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 10:12:15 -0800 Subject: [PATCH 23/30] Remove 'Edit Properties...' in favor of properties window --- examples/editEntities.js | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 2462c30854..172089ed62 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -662,8 +662,6 @@ function setupModelMenus() { print("setupModelMenus()"); // adj our menuitems Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", - shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); if (!Menu.menuItemExists("Edit", "Delete")) { print("no delete... adding ours"); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", @@ -674,7 +672,7 @@ function setupModelMenus() { } Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Model List..." }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true, isChecked: true }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", @@ -696,7 +694,6 @@ setupModelMenus(); // do this when first running our script. function cleanupModelMenus() { Menu.removeSeparator("Edit", "Models"); - Menu.removeMenuItem("Edit", "Edit Properties..."); if (modelMenuAddedDelete) { // delete our menuitems Menu.removeMenuItem("Edit", "Delete"); @@ -798,22 +795,6 @@ function handeMenuEvent(menuItem) { MyAvatar.position = selectedModel.properties.position; } } - } else if (menuItem == "Edit Properties...") { - // good place to put the properties dialog - - editModelID = -1; - if (selectionManager.selections.length == 1) { - print(" Edit Properties.... selectedEntityID="+ selectedEntityID); - editModelID = selectionManager.selections[0]; - } else { - print(" Edit Properties.... not holding..."); - } - if (editModelID != -1) { - print(" Edit Properties.... about to edit properties..."); - entityPropertyDialogBox.openDialog(editModelID); - selectionManager._update(); - } - } else if (menuItem == "Paste Models") { modelImporter.paste(); } else if (menuItem == "Export Models") { @@ -841,9 +822,6 @@ Controller.keyPressEvent.connect(function(event) { Controller.keyReleaseEvent.connect(function (event) { // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items - if (event.text == "`") { - handeMenuEvent("Edit Properties..."); - } if (event.text == "BACKSPACE" || event.text == "DELETE") { handeMenuEvent("Delete"); } else if (event.text == "TAB") { From 60aec8ac000887b648a97305b3fd123944c85ca3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 13 Jan 2015 13:41:32 -0800 Subject: [PATCH 24/30] add support for multiple backup rules --- assignment-client/src/octree/OctreeServer.cpp | 21 +- assignment-client/src/octree/OctreeServer.h | 1 + .../resources/describe-settings.json | 88 ++++---- libraries/octree/src/OctreePersistThread.cpp | 204 +++++++++++------- libraries/octree/src/OctreePersistThread.h | 33 +-- 5 files changed, 200 insertions(+), 147 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index cb206f626e..3ac094ff7a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include @@ -978,6 +979,7 @@ void OctreeServer::readConfiguration() { const QJsonObject& settingsObject = domainHandler.getSettingsObject(); QString settingsKey = getMyDomainSettingsKey(); QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject(); + _settings = settingsSectionObject; // keep this for later if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) { _statusHost = getLocalAddress().toString(); @@ -1042,20 +1044,8 @@ void OctreeServer::readConfiguration() { _wantBackup = !noBackup; qDebug() << "wantBackup=" << _wantBackup; - if (_wantBackup) { - _backupExtensionFormat = OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT; - readOptionString(QString("backupExtensionFormat"), settingsSectionObject, _backupExtensionFormat); - qDebug() << "backupExtensionFormat=" << _backupExtensionFormat; - - _backupInterval = OctreePersistThread::DEFAULT_BACKUP_INTERVAL; - readOptionInt(QString("backupInterval"), settingsSectionObject, _backupInterval); - qDebug() << "backupInterval=" << _backupInterval; - - _maxBackupVersions = OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS; - readOptionInt(QString("maxBackupVersions"), settingsSectionObject, _maxBackupVersions); - qDebug() << "maxBackupVersions=" << _maxBackupVersions; - } - + //qDebug() << "settingsSectionObject:" << settingsSectionObject; + } else { qDebug("persistFilename= DISABLED"); } @@ -1140,8 +1130,7 @@ void OctreeServer::run() { // now set up PersistThread _persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval, - _wantBackup, _backupInterval, _backupExtensionFormat, - _maxBackupVersions, _debugTimestampNow); + _wantBackup, _settings, _debugTimestampNow); if (_persistThread) { _persistThread->initialize(true); } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index a467a8a650..0f90c2941e 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -150,6 +150,7 @@ protected: int _argc; const char** _argv; char** _parsedArgV; + QJsonObject _settings; HTTPManager* _httpManager; int _statusPort; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 3435f49b71..3ee62634c8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -308,70 +308,86 @@ "label": "Persistant Filename", "help": "the filename for your entities", "placeholder": "resources/models.svo", - "default": "resources/models.svo", - "advanced": true + "default": "resources/models.svo" }, { "name": "persistInterval", "label": "Persist Interval", "help": "Interval between persist checks in msecs.", "placeholder": "30000", - "default": "30000", - "advanced": true + "default": "30000" + }, + { + "name": "backups", + "type": "table", + "label": "Backup Rules", + "help": "In this table you can define a set of rules for how frequently to backup copies of your content file.", + "numbered": false, + "default": [ + {"Name":"Half Hourly Rolling","backupInterval":1800,"format":".backup.halfhourly.%N","maxBackupVersions":5}, + {"Name":"Daily Rolling","backupInterval":86400,"format":".backup.daily.%N","maxBackupVersions":7}, + {"Name":"Weekly Rolling","backupInterval":604800,"format":".backup.weekly.%N","maxBackupVersions":4}, + {"Name":"Thirty Day Rolling","backupInterval":2592000,"format":".backup.thirtyday.%N","maxBackupVersions":12} + ], + "columns": [ + { + "name": "Name", + "label": "Name", + "can_set": true, + "placeholder": "Example", + "default": "Example" + }, + { + "name": "format", + "label": "Rule Format", + "can_set": true, + "help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z", + "placeholder": ".backup.example.%N", + "default": ".backup.example.%N" + }, + { + "name": "backupInterval", + "label": "Backup Interval", + "help": "Interval between backup checks in seconds.", + "placeholder": 1800, + "default": 1800, + "can_set": true + }, + { + "name": "maxBackupVersions", + "label": "Max Rolled Backup Versions", + "help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?", + "placeholder": 5, + "default": 5, + "can_set": true + } + ] }, { "name": "NoPersist", "type": "checkbox", "help": "Don't persist your entities to a file.", - "default": false, - "advanced": true - }, - { - "name": "backupExtensionFormat", - "label": "Backup File Extension Format:", - "help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z", - "placeholder": ".backup.%N", - "default": ".backup.%N", - "advanced": true - }, - { - "name": "backupInterval", - "label": "Backup Interval", - "help": "Interval between backup checks in msecs.", - "placeholder": "1800000", - "default": "1800000", - "advanced": true - }, - { - "name": "maxBackupVersions", - "label": "Max Rolled Backup Versions", - "help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?", - "placeholder": "5", - "default": "5", - "advanced": true + "default": false }, { "name": "NoBackup", "type": "checkbox", "help": "Don't regularly backup your persisted entities to a backup file.", - "default": false, - "advanced": true + "default": false }, { "name": "statusHost", "label": "Status Hostname", "help": "host name or IP address of the server for accessing the status page", "placeholder": "", - "default": "", - "advanced": true + "default": "" }, { "name": "statusPort", "label": "Status Port", "help": "port of the server for accessing the status page", "placeholder": "", - "default": "", - "advanced": true + "default": "" }, { "name": "verboseDebug", diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 79469ade1f..9b54a3ab25 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -25,38 +27,68 @@ #include "OctreePersistThread.h" const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds -const int OctreePersistThread::DEFAULT_BACKUP_INTERVAL = 1000 * 60 * 30; // every 30 minutes -const QString OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT(".backup.%N"); -const int OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS = 5; - OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval, - bool wantBackup, int backupInterval, const QString& backupExtensionFormat, - int maxBackupVersions, bool debugTimestampNow) : + bool wantBackup, const QJsonObject& settings, bool debugTimestampNow) : _tree(tree), _filename(filename), - _backupExtensionFormat(backupExtensionFormat), - _maxBackupVersions(maxBackupVersions), _persistInterval(persistInterval), - _backupInterval(backupInterval), _initialLoadComplete(false), _loadTimeUSecs(0), _lastCheck(0), - _lastBackup(0), _wantBackup(wantBackup), _debugTimestampNow(debugTimestampNow), _lastTimeDebug(0) { + parseSettings(settings); } -quint64 OctreePersistThread::getMostRecentBackupTimeInUsecs() { +void OctreePersistThread::parseSettings(const QJsonObject& settings) { + qDebug() << "settings[backups]:" << settings["backups"]; + + if (settings["backups"].isArray()) { + const QJsonArray& backupRules = settings["backups"].toArray(); + qDebug() << "BACKUP RULES:" << backupRules; + + foreach (const QJsonValue& value, backupRules) { + QJsonObject obj = value.toObject(); + qDebug() << " Name:" << obj["Name"].toString(); + qDebug() << " format:" << obj["format"].toString(); + qDebug() << " interval:" << obj["backupInterval"].toInt(); + qDebug() << " count:" << obj["maxBackupVersions"].toInt(); + + BackupRule newRule = { obj["Name"].toString(), obj["backupInterval"].toInt(), + obj["format"].toString(), obj["maxBackupVersions"].toInt(), 0}; + + newRule.lastBackup = getMostRecentBackupTimeInUsecs(obj["format"].toString()); + + if (newRule.lastBackup > 0) { + quint64 now = usecTimestampNow(); + quint64 sinceLastBackup = now - newRule.lastBackup; + qDebug() << " now:" << now; + qDebug() << "newRule.lastBackup:" << newRule.lastBackup; + qDebug() << " sinceLastBackup:" << sinceLastBackup; + + qDebug() << " lastBackup:" << qPrintable(formatUsecTime(sinceLastBackup)) << "ago"; + } else { + qDebug() << " lastBackup: NEVER"; + } + + _backupRules << newRule; + } + } else { + qDebug() << "BACKUP RULES: NONE"; + } +} + +quint64 OctreePersistThread::getMostRecentBackupTimeInUsecs(const QString& format) { quint64 mostRecentBackupInUsecs = 0; QString mostRecentBackupFileName; QDateTime mostRecentBackupTime; - bool recentBackup = getMostRecentBackup(mostRecentBackupFileName, mostRecentBackupTime); + bool recentBackup = getMostRecentBackup(format, mostRecentBackupFileName, mostRecentBackupTime); if (recentBackup) { mostRecentBackupInUsecs = mostRecentBackupTime.toMSecsSinceEpoch() * USECS_PER_MSEC; @@ -130,12 +162,6 @@ bool OctreePersistThread::process() { // Since we just loaded the persistent file, we can consider ourselves as having "just checked" for persistance. _lastCheck = usecTimestampNow(); // we just loaded, no need to save again - // The last backup time, should be the timestamp for most recent backup file. - _lastBackup = getMostRecentBackupTimeInUsecs(); - - qDebug() << "Last Check:" << qPrintable(formatUsecTime(usecTimestampNow() - _lastCheck)) << "ago..."; - qDebug() << "Last Backup:" << qPrintable(formatUsecTime(usecTimestampNow() - _lastBackup)) << "ago..."; - // This last persist time is not really used until the file is actually persisted. It is only // used in formatting the backup filename in cases of non-rolling backup names. However, we don't // want an uninitialized value for this, so we set it to the current time (startup of the server) @@ -226,7 +252,7 @@ void OctreePersistThread::restoreFromMostRecentBackup() { QString mostRecentBackupFileName; QDateTime mostRecentBackupTime; - bool recentBackup = getMostRecentBackup(mostRecentBackupFileName, mostRecentBackupTime); + bool recentBackup = getMostRecentBackup(QString(""), mostRecentBackupFileName, mostRecentBackupTime); // If we found a backup file, restore from that file. if (recentBackup) { @@ -247,27 +273,31 @@ void OctreePersistThread::restoreFromMostRecentBackup() { } } -bool OctreePersistThread::getMostRecentBackup(QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime) { +bool OctreePersistThread::getMostRecentBackup(const QString& format, + QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime) { // Based on our backup file name, determine the path and file name pattern for backup files QFileInfo persistFileInfo(_filename); QString path = persistFileInfo.path(); QString fileNamePart = persistFileInfo.fileName(); - // Create a file filter that will find all backup files of this extension format - QString backupExtension = _backupExtensionFormat; - - if (_backupExtensionFormat.contains("%N")) { - backupExtension.replace(QString("%N"), "*"); + QStringList filters; + + if (format.isEmpty()) { + // Create a file filter that will find all backup files of this extension format + foreach(const BackupRule& rule, _backupRules) { + QString backupExtension = rule.extensionFormat; + backupExtension.replace(QRegExp("%."), "*"); + QString backupFileNamePart = fileNamePart + backupExtension; + filters << backupFileNamePart; + } } else { - qDebug() << "This backup extension format does not yet support restoring from most recent backup..."; - return false; // exit early, unable to restore from backup + QString backupExtension = format; + backupExtension.replace(QRegExp("%."), "*"); + QString backupFileNamePart = fileNamePart + backupExtension; + filters << backupFileNamePart; } - QString backupFileNamePart = fileNamePart + backupExtension; - QStringList filters; - filters << backupFileNamePart; - bool bestBackupFound = false; QString bestBackupFile; QDateTime bestBackupFileTime; @@ -295,74 +325,88 @@ bool OctreePersistThread::getMostRecentBackup(QString& mostRecentBackupFileName, return bestBackupFound; } -void OctreePersistThread::rollOldBackupVersions() { - if (!_backupExtensionFormat.contains("%N")) { - return; // this backup extension format doesn't support rolling - } +void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { - qDebug() << "Rolling old backup versions..."; - for(int n = _maxBackupVersions - 1; n > 0; n--) { - QString backupExtensionN = _backupExtensionFormat; - QString backupExtensionNplusOne = _backupExtensionFormat; - backupExtensionN.replace(QString("%N"), QString::number(n)); - backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1)); - - QString backupFilenameN = _filename + backupExtensionN; - QString backupFilenameNplusOne = _filename + backupExtensionNplusOne; + if (rule.extensionFormat.contains("%N")) { + qDebug() << "Rolling old backup versions for rule" << rule.name << "..."; + for(int n = rule.maxBackupVersions - 1; n > 0; n--) { + QString backupExtensionN = rule.extensionFormat; + QString backupExtensionNplusOne = rule.extensionFormat; + backupExtensionN.replace(QString("%N"), QString::number(n)); + backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1)); + + QString backupFilenameN = _filename + backupExtensionN; + QString backupFilenameNplusOne = _filename + backupExtensionNplusOne; - QFile backupFileN(backupFilenameN); + QFile backupFileN(backupFilenameN); - if (backupFileN.exists()) { - qDebug() << "rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; - int result = rename(qPrintable(backupFilenameN), qPrintable(backupFilenameNplusOne)); - if (result == 0) { - qDebug() << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; - } else { - qDebug() << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + if (backupFileN.exists()) { + qDebug() << "rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + int result = rename(qPrintable(backupFilenameN), qPrintable(backupFilenameNplusOne)); + if (result == 0) { + qDebug() << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + } else { + qDebug() << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + } } } + qDebug() << "Done rolling old backup versions..."; } - qDebug() << "Done rolling old backup versions..."; } void OctreePersistThread::backup() { if (_wantBackup) { quint64 now = usecTimestampNow(); - quint64 sinceLastBackup = now - _lastBackup; - quint64 MSECS_TO_USECS = 1000; - quint64 intervalToBackup = _backupInterval * MSECS_TO_USECS; + qDebug() << "OctreePersistThread::backup() - now:" << now; - if (sinceLastBackup > intervalToBackup) { - qDebug() << "Time since last backup [" << sinceLastBackup << "] exceeds backup interval [" - << intervalToBackup << "] doing backup now..."; + // TODO: add a loop over all backup rules, we need to keep track of the last backup for each rule + // because we need to know when each backup rule has "elapsed" + for(int i = 0; i < _backupRules.count(); i++) { + BackupRule& rule = _backupRules[i]; - struct tm* localTime = localtime(&_lastPersistTime); + quint64 sinceLastBackup = now - rule.lastBackup; - QString backupFileName; + qDebug() << " now:" << now; + qDebug() << "newRule.lastBackup:" << rule.lastBackup; + qDebug() << " sinceLastBackup:" << sinceLastBackup; + + qDebug() << " lastBackup:" << qPrintable(formatUsecTime(sinceLastBackup)) << "ago"; + + quint64 SECS_TO_USECS = 1000 * 1000; + quint64 intervalToBackup = rule.interval * SECS_TO_USECS; + + if (sinceLastBackup > intervalToBackup) { + qDebug() << "Time since last backup [" << sinceLastBackup << "] for rule [" << rule.name + << "] exceeds backup interval [" << intervalToBackup << "] doing backup now..."; + + struct tm* localTime = localtime(&_lastPersistTime); + + QString backupFileName; - // check to see if they asked for version rolling format - if (_backupExtensionFormat.contains("%N")) { - rollOldBackupVersions(); // rename all the old backup files accordingly - QString backupExtension = _backupExtensionFormat; - backupExtension.replace(QString("%N"), QString("1")); - backupFileName = _filename + backupExtension; - } else { - char backupExtension[256]; - strftime(backupExtension, sizeof(backupExtension), qPrintable(_backupExtensionFormat), localTime); - backupFileName = _filename + backupExtension; - } + // check to see if they asked for version rolling format + if (rule.extensionFormat.contains("%N")) { + rollOldBackupVersions(rule); // rename all the old backup files accordingly + QString backupExtension = rule.extensionFormat; + backupExtension.replace(QString("%N"), QString("1")); + backupFileName = _filename + backupExtension; + } else { + char backupExtension[256]; + strftime(backupExtension, sizeof(backupExtension), qPrintable(rule.extensionFormat), localTime); + backupFileName = _filename + backupExtension; + } - qDebug() << "backing up persist file " << _filename << "to" << backupFileName << "..."; - int result = rename(qPrintable(_filename), qPrintable(backupFileName)); - if (result == 0) { - qDebug() << "DONE backing up persist file..."; - } else { - qDebug() << "ERROR in backing up persist file..."; - } + qDebug() << "backing up persist file " << _filename << "to" << backupFileName << "..."; + bool result = QFile::copy(_filename, backupFileName); + if (result) { + qDebug() << "DONE backing up persist file..."; + } else { + qDebug() << "ERROR in backing up persist file..."; + } - _lastBackup = now; + rule.lastBackup = now; + } } } } diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index 6f08b63197..374de79f0a 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -22,15 +22,19 @@ class OctreePersistThread : public GenericThread { Q_OBJECT public: + class BackupRule { + public: + QString name; + int interval; + QString extensionFormat; + int maxBackupVersions; + quint64 lastBackup; + }; + static const int DEFAULT_PERSIST_INTERVAL; - static const int DEFAULT_BACKUP_INTERVAL; - static const QString DEFAULT_BACKUP_EXTENSION_FORMAT; - static const int DEFAULT_MAX_BACKUP_VERSIONS; OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL, - bool wantBackup = false, int backupInterval = DEFAULT_BACKUP_INTERVAL, - const QString& backupExtensionFormat = DEFAULT_BACKUP_EXTENSION_FORMAT, - int maxBackupVersions = DEFAULT_MAX_BACKUP_VERSIONS, + bool wantBackup = false, const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false); bool isInitialLoadComplete() const { return _initialLoadComplete; } @@ -47,25 +51,24 @@ protected: void persist(); void backup(); - void rollOldBackupVersions(); + void rollOldBackupVersions(const BackupRule& rule); void restoreFromMostRecentBackup(); - bool getMostRecentBackup(QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime); - quint64 getMostRecentBackupTimeInUsecs(); + bool getMostRecentBackup(const QString& format, QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime); + quint64 getMostRecentBackupTimeInUsecs(const QString& format); + void parseSettings(const QJsonObject& settings); private: Octree* _tree; QString _filename; - QString _backupExtensionFormat; - int _maxBackupVersions; int _persistInterval; - int _backupInterval; bool _initialLoadComplete; quint64 _loadTimeUSecs; - quint64 _lastCheck; - quint64 _lastBackup; - bool _wantBackup; + time_t _lastPersistTime; + quint64 _lastCheck; + bool _wantBackup; + QVector _backupRules; bool _debugTimestampNow; quint64 _lastTimeDebug; From 0e19e1f8a5a982abd37701b096134eb94a12508e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 13 Jan 2015 13:48:28 -0800 Subject: [PATCH 25/30] cleanup some dead code --- libraries/octree/src/OctreePersistThread.cpp | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index 9b54a3ab25..f0612cc9b1 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -44,11 +44,9 @@ OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, } void OctreePersistThread::parseSettings(const QJsonObject& settings) { - qDebug() << "settings[backups]:" << settings["backups"]; - if (settings["backups"].isArray()) { const QJsonArray& backupRules = settings["backups"].toArray(); - qDebug() << "BACKUP RULES:" << backupRules; + qDebug() << "BACKUP RULES:"; foreach (const QJsonValue& value, backupRules) { QJsonObject obj = value.toObject(); @@ -65,10 +63,6 @@ void OctreePersistThread::parseSettings(const QJsonObject& settings) { if (newRule.lastBackup > 0) { quint64 now = usecTimestampNow(); quint64 sinceLastBackup = now - newRule.lastBackup; - qDebug() << " now:" << now; - qDebug() << "newRule.lastBackup:" << newRule.lastBackup; - qDebug() << " sinceLastBackup:" << sinceLastBackup; - qDebug() << " lastBackup:" << qPrintable(formatUsecTime(sinceLastBackup)) << "ago"; } else { qDebug() << " lastBackup: NEVER"; @@ -235,9 +229,6 @@ void OctreePersistThread::persist() { _tree->clearDirtyBit(); // tree is clean after saving qDebug() << "DONE saving Octree to file..."; - // force crash - //assert(false); - lockFile.close(); qDebug() << "saving Octree lock file closed:" << lockFileName; remove(qPrintable(lockFileName)); @@ -358,21 +349,12 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) { void OctreePersistThread::backup() { if (_wantBackup) { quint64 now = usecTimestampNow(); - qDebug() << "OctreePersistThread::backup() - now:" << now; - // TODO: add a loop over all backup rules, we need to keep track of the last backup for each rule - // because we need to know when each backup rule has "elapsed" for(int i = 0; i < _backupRules.count(); i++) { BackupRule& rule = _backupRules[i]; quint64 sinceLastBackup = now - rule.lastBackup; - qDebug() << " now:" << now; - qDebug() << "newRule.lastBackup:" << rule.lastBackup; - qDebug() << " sinceLastBackup:" << sinceLastBackup; - - qDebug() << " lastBackup:" << qPrintable(formatUsecTime(sinceLastBackup)) << "ago"; - quint64 SECS_TO_USECS = 1000 * 1000; quint64 intervalToBackup = rule.interval * SECS_TO_USECS; From dcca5d532aae3b2dbbe5d5a094fe24c1c6874b52 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 13 Jan 2015 14:00:37 -0800 Subject: [PATCH 26/30] fix for glitchy physics updates The main problem was: ObjectMotionState::_sentPosition and friends were not being updated when the EntityServer update arrives. --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 62 +++++++++++++++++---- libraries/physics/src/EntityMotionState.h | 4 +- libraries/physics/src/ObjectMotionState.cpp | 6 +- libraries/physics/src/ObjectMotionState.h | 7 ++- libraries/physics/src/PhysicsEngine.cpp | 46 ++++----------- libraries/physics/src/PhysicsEngine.h | 6 -- 7 files changed, 71 insertions(+), 62 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 76045d9c15..a18f8fc71d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1000,7 +1000,7 @@ void EntityItem::recalculateCollisionShape() { const float MIN_POSITION_DELTA = 0.0001f; const float MIN_ALIGNMENT_DOT = 0.9999f; const float MIN_MASS_DELTA = 0.001f; -const float MIN_VELOCITY_DELTA = 0.025f; +const float MIN_VELOCITY_DELTA = 0.01f; const float MIN_DAMPING_DELTA = 0.001f; const float MIN_GRAVITY_DELTA = 0.001f; const float MIN_SPIN_DELTA = 0.0003f; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 7aa43f944c..019f00fb48 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -79,21 +79,59 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { } #endif // USE_BULLET_PHYSICS -void EntityMotionState::applyVelocities() const { +void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) { #ifdef USE_BULLET_PHYSICS - if (_body) { - setVelocity(_entity->getVelocityInMeters()); - // DANGER! EntityItem stores angularVelocity in degrees/sec!!! - setAngularVelocity(glm::radians(_entity->getAngularVelocity())); - _body->setActivationState(ACTIVE_TAG); - } -#endif // USE_BULLET_PHYSICS -} + if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { + if (flags & EntityItem::DIRTY_POSITION) { + _sentPosition = _entity->getPositionInMeters() - ObjectMotionState::getWorldOffset(); + btTransform worldTrans; + worldTrans.setOrigin(glmToBullet(_sentPosition)); -void EntityMotionState::applyGravity() const { + _sentRotation = _entity->getRotation(); + worldTrans.setRotation(glmToBullet(_sentRotation)); + + _body->setWorldTransform(worldTrans); + } + if (flags & EntityItem::DIRTY_VELOCITY) { + updateObjectVelocities(); + } + _sentFrame = frame; + } + + // TODO: entity support for friction and restitution + //_restitution = _entity->getRestitution(); + _body->setRestitution(_restitution); + //_friction = _entity->getFriction(); + _body->setFriction(_friction); + + _linearDamping = _entity->getDamping(); + _angularDamping = _entity->getAngularDamping(); + _body->setDamping(_linearDamping, _angularDamping); + + if (flags & EntityItem::DIRTY_MASS) { + float mass = getMass(); + btVector3 inertia(0.0f, 0.0f, 0.0f); + _body->getCollisionShape()->calculateLocalInertia(mass, inertia); + _body->setMassProps(mass, inertia); + _body->updateInertiaTensor(); + } + _body->activate(); +#endif // USE_BULLET_PHYSICS +}; + +void EntityMotionState::updateObjectVelocities() { #ifdef USE_BULLET_PHYSICS if (_body) { - setGravity(_entity->getGravityInMeters()); + _sentVelocity = _entity->getVelocityInMeters(); + setVelocity(_sentVelocity); + + // DANGER! EntityItem stores angularVelocity in degrees/sec!!! + _sentAngularVelocity = glm::radians(_entity->getAngularVelocity()); + setAngularVelocity(_sentAngularVelocity); + + _sentAcceleration = _entity->getGravityInMeters(); + setGravity(_sentAcceleration); + _body->setActivationState(ACTIVE_TAG); } #endif // USE_BULLET_PHYSICS @@ -123,7 +161,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); // if the speeds are very small we zero them out - const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 4.0e-6f; // 2mm/sec + const float MINIMUM_EXTRAPOLATION_SPEED_SQUARED = 1.0e-4f; // 1cm/sec bool zeroSpeed = (glm::length2(_sentVelocity) < MINIMUM_EXTRAPOLATION_SPEED_SQUARED); if (zeroSpeed) { _sentVelocity = glm::vec3(0.0f); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 379470087f..863edebe7d 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -54,8 +54,8 @@ public: #endif // USE_BULLET_PHYSICS // these relay incoming values to the RigidBody - void applyVelocities() const; - void applyGravity() const; + void updateObjectEasy(uint32_t flags, uint32_t frame); + void updateObjectVelocities(); void computeShapeInfo(ShapeInfo& info); diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 46c67c0ec2..6e0b2a784c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -123,9 +123,9 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const { const float FIXED_SUBSTEP = 1.0f / 60.0f; -bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder) { +bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { assert(_body); - float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP + subStepRemainder; + float dt = (float)(simulationFrame - _sentFrame) * FIXED_SUBSTEP; _sentFrame = simulationFrame; bool isActive = _body->isActive(); @@ -183,7 +183,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame, float subStep } const float MIN_ROTATION_DOT = 0.98f; glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); - return (glm::dot(actualRotation, _sentRotation) < MIN_ROTATION_DOT); + return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT); } #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index cb19babc1d..b9d077f4bb 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -56,8 +56,9 @@ public: ObjectMotionState(); ~ObjectMotionState(); - virtual void applyVelocities() const = 0; - virtual void applyGravity() const = 0; + // An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine + virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0; + virtual void updateObjectVelocities() = 0; virtual void computeShapeInfo(ShapeInfo& info) = 0; @@ -84,7 +85,7 @@ public: void clearOutgoingPacketFlags(uint32_t flags) { _outgoingPacketFlags &= ~flags; } bool doesNotNeedToSendUpdate() const; - virtual bool shouldSendUpdate(uint32_t simulationFrame, float subStepRemainder); + virtual bool shouldSendUpdate(uint32_t simulationFrame); virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0; virtual MotionType computeMotionType() const = 0; diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 4129f1c7b0..666fcd2e89 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -41,14 +41,12 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { // this is step (4) QSet::iterator stateItr = _outgoingPackets.begin(); - uint32_t frame = getFrameCount(); - float subStepRemainder = getSubStepRemainder(); while (stateItr != _outgoingPackets.end()) { ObjectMotionState* state = *stateItr; if (state->doesNotNeedToSendUpdate()) { stateItr = _outgoingPackets.erase(stateItr); - } else if (state->shouldSendUpdate(frame, subStepRemainder)) { - state->sendUpdate(_entityPacketSender, frame); + } else if (state->shouldSendUpdate(_frameCount)) { + state->sendUpdate(_entityPacketSender, _frameCount); ++stateItr; } else { ++stateItr; @@ -140,7 +138,8 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { updateObjectHard(body, motionState, flags); } else if (flags) { // an EASY update does NOT require that the body be pulled out of physics engine - updateObjectEasy(body, motionState, flags); + // hence the MotionState has all the knowledge and authority to perform the update. + motionState->updateObjectEasy(flags, _frameCount); } } @@ -269,8 +268,12 @@ bool PhysicsEngine::addObject(ObjectMotionState* motionState) { body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); motionState->_body = body; - motionState->applyVelocities(); - motionState->applyGravity(); + motionState->updateObjectVelocities(); + // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. + // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime + const float LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec + const float ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec + body->setSleepingThresholds(LINEAR_VELOCITY_THRESHOLD, ANGULAR_VELOCITY_THRESHOLD); break; } case MOTION_TYPE_STATIC: @@ -334,7 +337,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio } bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS; if (easyUpdate) { - updateObjectEasy(body, motionState, flags); + motionState->updateObjectEasy(flags, _frameCount); } // update the motion parameters @@ -385,31 +388,4 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio body->activate(); } -// private -void PhysicsEngine::updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { - if (flags & EntityItem::DIRTY_POSITION) { - btTransform transform; - motionState->getWorldTransform(transform); - body->setWorldTransform(transform); - } - if (flags & EntityItem::DIRTY_VELOCITY) { - motionState->applyVelocities(); - motionState->applyGravity(); - } - body->setRestitution(motionState->_restitution); - body->setFriction(motionState->_friction); - body->setDamping(motionState->_linearDamping, motionState->_angularDamping); - - if (flags & EntityItem::DIRTY_MASS) { - float mass = motionState->getMass(); - btVector3 inertia(0.0f, 0.0f, 0.0f); - body->getCollisionShape()->calculateLocalInertia(mass, inertia); - body->setMassProps(mass, inertia); - body->updateInertiaTensor(); - } - body->activate(); - - // TODO: support collision groups -}; - #endif // USE_BULLET_PHYSICS diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index e93495e1d2..c6d6bd4626 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -71,12 +71,6 @@ public: /// \return number of simulation frames the physics engine has taken uint32_t getFrameCount() const { return _frameCount; } - /// \return substep remainder used for Bullet MotionState extrapolation - // Bullet will extrapolate the positions provided to MotionState::setWorldTransform() in an effort to provide - // smoother visible motion when the render frame rate does not match that of the simulation loop. We provide - // access to this fraction for improved filtering of update packets to interested parties. - float getSubStepRemainder() { return _dynamicsWorld->getLocalTimeAccumulation(); } - protected: void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); From 04b4a95ccb4605ed88cad78e0c5316b59d593faf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 13 Jan 2015 14:21:41 -0800 Subject: [PATCH 27/30] fix for bad cleanup (3 places) --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/entities/src/EntityItemProperties.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a18f8fc71d..885d589ed1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -911,8 +911,8 @@ AACube EntityItem::getMinimumAACube() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; - glm::vec3 unrotatedMinRelativeToEntity = - unrotatedMaxRelativeToEntity; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); @@ -936,8 +936,8 @@ AABox EntityItem::getAABox() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; - glm::vec3 unrotatedMinRelativeToEntity = - unrotatedMaxRelativeToEntity; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d50096f752..77d70e8abd 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -860,8 +860,8 @@ AABox EntityItemProperties::getAABoxInMeters() const { // _position represents the position of the registration point. glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; - glm::vec3 unrotatedMinRelativeToEntity = - unrotatedMaxRelativeToEntity; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); From 6eb35bf98cfbefc3b5c4a23caa3eba66c266c646 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 13 Jan 2015 16:13:18 -0800 Subject: [PATCH 28/30] tweaks to descriptions --- .../resources/describe-settings.json | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 3ee62634c8..e2f751a7f0 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -305,23 +305,25 @@ "settings": [ { "name": "persistFilename", - "label": "Persistant Filename", - "help": "the filename for your entities", + "label": "Entities Filename", + "help": "the path to the file entities are stored in. Make sure the path exists.", "placeholder": "resources/models.svo", - "default": "resources/models.svo" + "default": "resources/models.svo", + "advanced": true }, { "name": "persistInterval", - "label": "Persist Interval", - "help": "Interval between persist checks in msecs.", + "label": "Save Check Interval", + "help": "Milliseconds between checks for saving the current state of entities.", "placeholder": "30000", - "default": "30000" + "default": "30000", + "advanced": true }, { "name": "backups", "type": "table", "label": "Backup Rules", - "help": "In this table you can define a set of rules for how frequently to backup copies of your content file.", + "help": "In this table you can define a set of rules for how frequently to backup copies of your entites content file.", "numbered": false, "default": [ {"Name":"Half Hourly Rolling","backupInterval":1800,"format":".backup.halfhourly.%N","maxBackupVersions":5}, @@ -347,7 +349,7 @@ }, { "name": "backupInterval", - "label": "Backup Interval", + "label": "Backup Interval in Seconds", "help": "Interval between backup checks in seconds.", "placeholder": 1800, "default": 1800, @@ -367,27 +369,31 @@ "name": "NoPersist", "type": "checkbox", "help": "Don't persist your entities to a file.", - "default": false + "default": false, + "advanced": true }, { "name": "NoBackup", "type": "checkbox", "help": "Don't regularly backup your persisted entities to a backup file.", - "default": false + "default": false, + "advanced": true }, { "name": "statusHost", "label": "Status Hostname", "help": "host name or IP address of the server for accessing the status page", "placeholder": "", - "default": "" + "default": "", + "advanced": true }, { "name": "statusPort", "label": "Status Port", "help": "port of the server for accessing the status page", "placeholder": "", - "default": "" + "default": "", + "advanced": true }, { "name": "verboseDebug", From e7eb12202ae17cb7c2cd530280680546932191fc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 Jan 2015 09:41:34 -0800 Subject: [PATCH 29/30] Fix rotation handles not showing up --- examples/libraries/entitySelectionTool.js | 25 +++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 2b83d7740d..40db7b057a 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -242,6 +242,9 @@ SelectionDisplay = (function () { var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18; var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.17; + var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.png"; + var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.png"; + var showExtendedStretchHandles = false; var spaceMode = SPACE_LOCAL; @@ -590,7 +593,7 @@ SelectionDisplay = (function () { }); var yawHandle = Overlays.addOverlay("billboard", { - url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png", + url: ROTATE_ARROW_WEST_NORTH_URL, position: { x:0, y: 0, z: 0}, color: rotateHandleColor, alpha: rotateHandleAlpha, @@ -603,7 +606,7 @@ SelectionDisplay = (function () { var pitchHandle = Overlays.addOverlay("billboard", { - url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png", + url: ROTATE_ARROW_WEST_NORTH_URL, position: { x:0, y: 0, z: 0}, color: rotateHandleColor, alpha: rotateHandleAlpha, @@ -616,7 +619,7 @@ SelectionDisplay = (function () { var rollHandle = Overlays.addOverlay("billboard", { - url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png", + url: ROTATE_ARROW_WEST_NORTH_URL, position: { x:0, y: 0, z: 0}, color: rotateHandleColor, alpha: rotateHandleAlpha, @@ -835,8 +838,8 @@ SelectionDisplay = (function () { rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far }; - Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-south.png" }); - Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-south.png" }); + Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL }); + Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_SOUTH_URL }); } else { @@ -867,8 +870,8 @@ SelectionDisplay = (function () { pitchCenter = { x: right, y: boundsCenter.y, z: boundsCenter.z }; rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near}; - Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" }); - Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" }); + Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); } } else { @@ -899,8 +902,8 @@ SelectionDisplay = (function () { pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z }; rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: far}; - Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" }); - Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" }); + Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); } else { @@ -928,8 +931,8 @@ SelectionDisplay = (function () { rollCenter = { x: boundsCenter.x, y: boundsCenter.y, z: near }; pitchCenter = { x: left, y: boundsCenter.y, z: boundsCenter.z}; - Overlays.editOverlay(pitchHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" }); - Overlays.editOverlay(rollHandle, { url: "https://public.highfidelity.io/images/rotate-arrow-west-north.png" }); + Overlays.editOverlay(pitchHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); + Overlays.editOverlay(rollHandle, { url: ROTATE_ARROW_WEST_NORTH_URL }); } } From 6ce71d96559f8ddd20795eef461a19bcd0505748 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Wed, 14 Jan 2015 13:54:34 -0800 Subject: [PATCH 30/30] Fix library and placement reference Fix library reference and switch the gun hand. --- examples/controllers/hydra/gun.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js index 18fe9c542d..b60a70ca36 100644 --- a/examples/controllers/hydra/gun.js +++ b/examples/controllers/hydra/gun.js @@ -14,7 +14,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("libraries/globals.js"); +Script.include("../../libraries/globals.js"); function getRandomFloat(min, max) { return Math.random() * (max - min) + min; @@ -254,8 +254,8 @@ function takeFiringPose() { } } -MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20); -//MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20); +//MyAvatar.attach(gunModel, "RightHand", {x:0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(-0, -160, -79), 0.20); +MyAvatar.attach(gunModel, "LeftHand", {x:-0.02, y: 0.11, z: 0.04}, Quat.fromPitchYawRollDegrees(0, 0, 79), 0.20); // Give a bit of time to load before playing sound Script.setTimeout(playLoadSound, 2000);