From 2f9766e05146574b2ae625ee80e712d252382e79 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 22 Oct 2014 08:41:31 -0700 Subject: [PATCH 01/55] first cut at light entity --- examples/libraries/entityPropertyDialogBox.js | 13 ++- examples/newEditEntities.js | 28 +++++- interface/src/entities/EntityTreeRenderer.cpp | 2 + .../entities/RenderableLightEntityItem.cpp | 98 ++++++++++++++++++ .../src/entities/RenderableLightEntityItem.h | 40 ++++++++ .../entities/src/EntityItemProperties.cpp | 8 +- libraries/entities/src/EntityItemProperties.h | 12 ++- libraries/entities/src/EntityTypes.cpp | 2 + libraries/entities/src/EntityTypes.h | 3 +- libraries/entities/src/LightEntityItem.cpp | 99 +++++++++++++++++++ libraries/entities/src/LightEntityItem.h | 67 +++++++++++++ 11 files changed, 366 insertions(+), 6 deletions(-) create mode 100644 interface/src/entities/RenderableLightEntityItem.cpp create mode 100644 interface/src/entities/RenderableLightEntityItem.h create mode 100644 libraries/entities/src/LightEntityItem.cpp create mode 100644 libraries/entities/src/LightEntityItem.h diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index becc8c86b2..f07bb9575f 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -133,7 +133,7 @@ EntityPropertyDialogBox = (function () { array.push({ label: "Visible:", value: properties.visible }); index++; - if (properties.type == "Box" || properties.type == "Sphere") { + if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "Light") { array.push({ label: "Color:", type: "header" }); index++; array.push({ label: "Red:", value: properties.color.red }); @@ -143,6 +143,11 @@ EntityPropertyDialogBox = (function () { array.push({ label: "Blue:", value: properties.color.blue }); index++; } + + if (properties.type == "Light") { + array.push({ label: "Spot Light:", value: properties.isSpotlight }); + index++; + } array.push({ button: "Cancel" }); index++; @@ -237,12 +242,16 @@ EntityPropertyDialogBox = (function () { properties.lifetime = array[index++].value; properties.visible = array[index++].value; - if (properties.type == "Box" || properties.type == "Sphere") { + if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "Light") { index++; // skip header properties.color.red = array[index++].value; properties.color.green = array[index++].value; properties.color.blue = array[index++].value; } + if (properties.type == "Light") { + properties.isSpotlight = array[index++].value; + } + Entities.editEntity(editModelID, properties); selectionDisplay.select(editModelID, false); } diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 9b46cdaf3f..28a118a683 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -73,6 +73,7 @@ var toolBar = (function () { newModelButton, newCubeButton, newSphereButton, + newLightButton, browseModelsButton, loadURLMenuItem, loadFileMenuItem, @@ -157,6 +158,15 @@ var toolBar = (function () { visible: true }); + newLightButton = toolBar.addTool({ + imageURL: toolIconUrl + "add-sphere.svg", + subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: toolWidth, + height: toolHeight, + alpha: 0.9, + visible: true + }); + } function toggleNewModelButton(active) { @@ -319,7 +329,23 @@ var toolBar = (function () { color: { red: 255, green: 0, blue: 0 } }); } else { - print("Can't create box: Box would be out of bounds."); + print("Can't create sphere: Sphere would be out of bounds."); + } + return true; + } + + if (newLightButton === toolBar.clicked(clickedOverlay)) { + var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + Entities.addEntity({ + type: "Light", + position: position, + dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, + color: { red: 255, green: 0, blue: 0 } + }); + } else { + print("Can't create Light: Light would be out of bounds."); } return true; } diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 2c7c970376..7eb28c2d3e 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -24,6 +24,7 @@ #include "EntityTreeRenderer.h" #include "RenderableBoxEntityItem.h" +#include "RenderableLightEntityItem.h" #include "RenderableModelEntityItem.h" #include "RenderableSphereEntityItem.h" @@ -39,6 +40,7 @@ EntityTreeRenderer::EntityTreeRenderer() : REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, RenderableBoxEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, RenderableSphereEntityItem::factory) + REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory) } EntityTreeRenderer::~EntityTreeRenderer() { diff --git a/interface/src/entities/RenderableLightEntityItem.cpp b/interface/src/entities/RenderableLightEntityItem.cpp new file mode 100644 index 0000000000..b25ef1e9cc --- /dev/null +++ b/interface/src/entities/RenderableLightEntityItem.cpp @@ -0,0 +1,98 @@ +// +// RenderableLightEntityItem.cpp +// interface/src +// +// Created by Brad Hefta-Gaub on 8/6/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include + +#include "InterfaceConfig.h" + +#include +#include + + +#include "Application.h" +#include "Menu.h" +#include "EntityTreeRenderer.h" +#include "RenderableLightEntityItem.h" + + +EntityItem* RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + return new RenderableLightEntityItem(entityID, properties); +} + +void RenderableLightEntityItem::render(RenderArgs* args) { + PerformanceTimer perfTimer("RenderableLightEntityItem::render"); + assert(getType() == EntityTypes::Light); + glm::vec3 position = getPositionInMeters(); + glm::vec3 center = getCenterInMeters(); + glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; + glm::quat rotation = getRotation(); + float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); + + const float MAX_COLOR = 255.0f; + float red = getColor()[RED_INDEX] / MAX_COLOR; + float green = getColor()[GREEN_INDEX] / MAX_COLOR; + float blue = getColor()[BLUE_INDEX] / MAX_COLOR; + float alpha = getLocalRenderAlpha(); + + /* + /// Adds a point light to render for the current frame. + void addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f), + const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f), + float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f); + + /// Adds a spot light to render for the current frame. + void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f), + const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f), + float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f, + const glm::vec3& direction = glm::vec3(0.0f, 0.0f, -1.0f), float exponent = 0.0f, float cutoff = PI); + */ + + glm::vec3 ambient = glm::vec3(0.0f, 0.0f, 0.0f); + glm::vec3 diffuse = glm::vec3(red, green, blue); + glm::vec3 specular = glm::vec3(red, green, blue); + glm::vec3 direction = IDENTITY_FRONT * rotation; + float constantAttenuation = 1.0f; + float linearAttenuation = 0.0f; + float quadraticAttenuation = 0.0f; + + if (_isSpotlight) { + Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f, + ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, + direction); + } else { + Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f, + ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); + } + + + bool wantDebug = false; + if (wantDebug) { + glColor4f(red, green, blue, alpha); + + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + + glScalef(dimensions.x, dimensions.y, dimensions.z); + Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15); + glPopMatrix(); + glPopMatrix(); + } + +}; diff --git a/interface/src/entities/RenderableLightEntityItem.h b/interface/src/entities/RenderableLightEntityItem.h new file mode 100644 index 0000000000..cecd9b761e --- /dev/null +++ b/interface/src/entities/RenderableLightEntityItem.h @@ -0,0 +1,40 @@ +// +// RenderableLightEntityItem.h +// interface/src/entities +// +// Created by Brad Hefta-Gaub on 8/6/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RenderableLightEntityItem_h +#define hifi_RenderableLightEntityItem_h + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +class RenderableLightEntityItem : public LightEntityItem { +public: + static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + RenderableLightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : + LightEntityItem(entityItemID, properties) + { } + + virtual void render(RenderArgs* args); +}; + + +#endif // hifi_RenderableLightEntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 90f56e36b9..3c3729e436 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -68,6 +68,7 @@ EntityItemProperties::EntityItemProperties() : _animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS), _glowLevel(0.0f), _localRenderAlpha(1.0f), + _isSpotlight(false), _naturalDimensions(1.0f, 1.0f, 1.0f), _colorChanged(false), @@ -78,7 +79,6 @@ EntityItemProperties::EntityItemProperties() : _animationFPSChanged(false), _glowLevelChanged(false), _localRenderAlphaChanged(false), - _defaultSettings(true) { } @@ -120,6 +120,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); + CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); return changedProperties; } @@ -161,6 +162,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove); + COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight); // Sitting properties support QScriptValue sittingPoints = engine->newObject(); @@ -220,6 +222,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localRenderAlpha, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove); + COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(isSpotlight, setIsSpotlight); _lastEdited = usecTimestampNow(); } @@ -370,6 +373,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove()); + APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, properties.getIsSpotlight()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -568,6 +572,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); return valid; } @@ -622,6 +627,7 @@ void EntityItemProperties::markAllChanged() { _animationFPSChanged = true; _glowLevelChanged = true; _localRenderAlphaChanged = true; + _isSpotlightChanged = true; } AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6e1594fb9b..fa047a6cf9 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -65,7 +65,10 @@ enum EntityPropertyList { PROP_IGNORE_FOR_COLLISIONS, PROP_COLLISIONS_WILL_MOVE, - PROP_LAST_ITEM = PROP_COLLISIONS_WILL_MOVE + // property used by Light entity + PROP_IS_SPOTLIGHT, + + PROP_LAST_ITEM = PROP_IS_SPOTLIGHT }; typedef PropertyFlags EntityPropertyFlags; @@ -83,6 +86,7 @@ class EntityItemProperties { friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods friend class BoxEntityItem; // TODO: consider removing this friend relationship and use public methods friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods + friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods public: EntityItemProperties(); virtual ~EntityItemProperties() { }; @@ -233,6 +237,9 @@ public: bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; _collisionsWillMoveChanged = true; } + bool getIsSpotlight() const { return _isSpotlight; } + void setIsSpotlight(bool value) { _isSpotlight = value; _isSpotlightChanged = true; } + void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } private: @@ -288,8 +295,10 @@ private: float _animationFPS; float _glowLevel; float _localRenderAlpha; + bool _isSpotlight; QVector _sittingPoints; glm::vec3 _naturalDimensions; + bool _colorChanged; bool _modelURLChanged; @@ -299,6 +308,7 @@ private: bool _animationFPSChanged; bool _glowLevelChanged; bool _localRenderAlphaChanged; + bool _isSpotlightChanged; bool _defaultSettings; }; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 7505c3f768..aaa297f4fd 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -19,6 +19,7 @@ #include "EntityTypes.h" #include "BoxEntityItem.h" +#include "LightEntityItem.h" #include "ModelEntityItem.h" #include "SphereEntityItem.h" @@ -33,6 +34,7 @@ const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown"; REGISTER_ENTITY_TYPE(Model) REGISTER_ENTITY_TYPE(Box) REGISTER_ENTITY_TYPE(Sphere) +REGISTER_ENTITY_TYPE(Light) const QString& EntityTypes::getEntityTypeName(EntityType entityType) { diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 8851b04b7e..85bbff99ef 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -33,7 +33,8 @@ public: Model, Box, Sphere, - LAST = Sphere + Light, + LAST = Light } EntityType; static const QString& getEntityTypeName(EntityType entityType); diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp new file mode 100644 index 0000000000..91a5f3aac0 --- /dev/null +++ b/libraries/entities/src/LightEntityItem.cpp @@ -0,0 +1,99 @@ +// +// LightEntityItem.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include + +#include + +#include "EntityTree.h" +#include "EntityTreeElement.h" +#include "LightEntityItem.h" + + +EntityItem* LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + return new LightEntityItem(entityID, properties); +} + +// our non-pure virtual subclass for now... +LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : + EntityItem(entityItemID, properties) +{ + _type = EntityTypes::Light; + setProperties(properties, true); + + // a light is not collide-able so we make it's shape be a tiny sphere at origin + _emptyShape.setTranslation(glm::vec3(0.0f,0.0f,0.0f)); + _emptyShape.setRadius(0.0f); +} + +EntityItemProperties LightEntityItem::getProperties() const { + EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class + + properties.setColor(getXColor()); + properties.setGlowLevel(getGlowLevel()); + properties.setIsSpotlight(getIsSpotlight()); + + return properties; +} + +bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { + bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qDebug() << "LightEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); + READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight); + + return bytesRead; +} + + +// TODO: eventually only include properties changed since the params.lastViewFrustumSent time +EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + requestedProperties += PROP_COLOR; + return requestedProperties; +} + +void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); + APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, getIsSpotlight()); +} diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h new file mode 100644 index 0000000000..a87f30a8ed --- /dev/null +++ b/libraries/entities/src/LightEntityItem.h @@ -0,0 +1,67 @@ +// +// LightEntityItem.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 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_LightEntityItem_h +#define hifi_LightEntityItem_h + +#include +#include "EntityItem.h" + +class LightEntityItem : public EntityItem { +public: + static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + + ALLOW_INSTANTIATION // This class can be instantiated + + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties() const; + virtual bool setProperties(const EntityItemProperties& properties, bool forceCopy = false); + + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + + const rgbColor& getColor() const { return _color; } + xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } + + void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } + void setColor(const xColor& value) { + _color[RED_INDEX] = value.red; + _color[GREEN_INDEX] = value.green; + _color[BLUE_INDEX] = value.blue; + } + + bool getIsSpotlight() const { return _isSpotlight; } + void setIsSpotlight(bool value) { _isSpotlight = value; } + + virtual const Shape& getCollisionShapeInMeters() const { return _emptyShape; } + +protected: + virtual void recalculateCollisionShape() { /* nothing to do */ } + + rgbColor _color; + bool _isSpotlight; + SphereShape _emptyShape; +}; + +#endif // hifi_LightEntityItem_h From bf199c1f308142fcabb5dc2e38594922155661df Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 22 Oct 2014 10:11:01 -0700 Subject: [PATCH 02/55] add PROP_IS_SPOTLIGHT to the requested properties --- libraries/entities/src/LightEntityItem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 91a5f3aac0..10387fa8a7 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -82,6 +82,7 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_COLOR; + requestedProperties += PROP_IS_SPOTLIGHT; return requestedProperties; } From 5e497c2d973d3a66ef6095085ea638b2bfe3deb4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 23 Oct 2014 09:18:11 -0400 Subject: [PATCH 03/55] added new macro for getter access to a color --- libraries/entities/src/EntityItemPropertiesMacros.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 16f883a36a..b5a489f88c 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -147,6 +147,10 @@ QScriptValue P = xColorToScriptValue(engine, _##P); \ properties.setProperty(#P, P); +#define COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(P,G) \ + QScriptValue P = xColorToScriptValue(engine, G); \ + properties.setProperty(#P, P); + #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \ properties.setProperty(#P, G); From d4ec337cae00a44718fc0d80d0c5650a583f0c52 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 13:39:56 -0700 Subject: [PATCH 04/55] Don't send reverb data as often --- assignment-client/src/audio/AudioMixer.cpp | 58 ++++++++++++++++------ libraries/audio/src/InboundAudioStream.cpp | 28 ++++++++--- libraries/audio/src/InboundAudioStream.h | 6 +++ 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8d87638434..faaebb1102 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -731,30 +731,56 @@ void AudioMixer::run() { dataAt += sizeof(quint16); // Pack stream properties - bool inAZone = false; + bool hasReverb = false; + float reverbTime; + float wetLevel; + + // find reverb properties for (int i = 0; i < _zoneReverbSettings.size(); ++i) { AudioMixerClientData* data = static_cast(node->getLinkedData()); - glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); + AvatarAudioStream* stream = data->getAvatarAudioStream(); + glm::vec3 streamPosition = stream->getPosition(); if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { - bool hasReverb = true; - float reverbTime = _zoneReverbSettings[i].reverbTime; - float wetLevel = _zoneReverbSettings[i].wetLevel; - - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); + hasReverb = true; + reverbTime = _zoneReverbSettings[i].reverbTime; + wetLevel = _zoneReverbSettings[i].wetLevel; + break; + } + } + AvatarAudioStream* stream = nodeData->getAvatarAudioStream(); + bool dataChanged = (stream->hasReverb() != hasReverb) || + (stream->hasReverb() && (stream->getRevebTime() != reverbTime || + stream->getWetLevel() != wetLevel)); + // Update stream + if (hasReverb) { + stream->setReverb(reverbTime, wetLevel); + } else { + stream->clearReverb(); + } + + // Send at change or every so often + float CHANCE_OF_SEND = 0.01; + bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND); + + unsigned char bitset = 0; + if (sendData) { + setAtBit(bitset, HAS_DATA_BIT); + if (hasReverb) { + setAtBit(bitset, HAS_REVERB_BIT); + } + + memcpy(dataAt, &bitset, sizeof(unsigned char)); + dataAt += sizeof(unsigned char); + + if (hasReverb) { memcpy(dataAt, &reverbTime, sizeof(float)); dataAt += sizeof(float); memcpy(dataAt, &wetLevel, sizeof(float)); dataAt += sizeof(float); - - inAZone = true; - break; } - } - if (!inAZone) { - bool hasReverb = false; - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); + } else { + memcpy(dataAt, &bitset, sizeof(unsigned char)); + dataAt += sizeof(unsigned char); } // pack mixed audio samples diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 59578951f8..3e4a8639c6 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -13,6 +13,7 @@ #include "InboundAudioStream.h" #include "PacketHeaders.h" +#include const int STARVE_HISTORY_CAPACITY = 50; @@ -83,6 +84,12 @@ void InboundAudioStream::clearBuffer() { _currentJitterBufferFrames = 0; } +void InboundAudioStream::setReverb(float reverbTime, float wetLevel) { + _hasReverb = true; + _reverbTime = reverbTime; + _wetLevel = wetLevel; +} + void InboundAudioStream::perSecondCallbackForUpdatingStats() { _incomingSequenceNumberStats.pushStatsToHistory(); _timeGapStatsForDesiredCalcOnTooManyStarves.currentIntervalComplete(); @@ -165,14 +172,19 @@ int InboundAudioStream::parseData(const QByteArray& packet) { int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { int read = 0; if (type == PacketTypeMixedAudio) { - memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool)); - read += sizeof(bool); + char bitset; + memcpy(&bitset, packetAfterSeqNum.data() + read, sizeof(char)); + read += sizeof(char); - if (_hasReverb) { - memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); + bool hasData = oneAtBit(bitset, HAS_DATA_BIT); + if (hasData) { + _hasReverb = oneAtBit(bitset, HAS_REVERB_BIT); + if (_hasReverb) { + memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + } } } @@ -206,7 +218,7 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) { _framesAvailableStat.reset(); } - + int ret = _ringBuffer.addSilentSamples(silentSamples - numSilentFramesToDrop * samplesPerFrame); return ret; diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 3e69db0afb..737147e2ba 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -45,6 +45,10 @@ const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES = 50; const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION = 10; const bool DEFAULT_REPETITION_WITH_FADE = true; +// Mixed Audio bitset +const int HAS_DATA_BIT = 0; // 1st bit +const int HAS_REVERB_BIT = 1; // 2nd bit + class InboundAudioStream : public NodeData { Q_OBJECT public: @@ -158,6 +162,8 @@ public: bool hasReverb() const { return _hasReverb; } float getRevebTime() const { return _reverbTime; } float getWetLevel() const { return _wetLevel; } + void setReverb(float reverbTime, float wetLevel); + void clearReverb() { _hasReverb = false; } public slots: /// This function should be called every second for all the stats to function properly. If dynamic jitter buffers From d528c47a83bacd44fc88b6a53d7d5a7e22a43d66 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 13:42:17 -0700 Subject: [PATCH 05/55] Bump audio packet version --- libraries/networking/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 8ce379b203..b96d88430a 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeSilentAudioFrame: return 4; case PacketTypeMixedAudio: - return 2; + return 3; case PacketTypeAvatarData: return 3; case PacketTypeAvatarIdentity: From 1ae1d28e7b3259fc42647453ef59c079608549b7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 14:07:42 -0700 Subject: [PATCH 06/55] typo --- interface/external/gverb/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/external/gverb/readme.txt b/interface/external/gverb/readme.txt index aa2fe8a602..1a85659b91 100644 --- a/interface/external/gverb/readme.txt +++ b/interface/external/gverb/readme.txt @@ -1,7 +1,7 @@ Instructions for adding the Gverb library to Interface (This is a required library) -Clément Brisset, Octobre 22nd, 2014 +Clément Brisset, October 22nd, 2014 1. Go to https://github.com/highfidelity/gverb Or download the sources directly via this link: From 5e49c08e273b253081650864071bc460d857b250 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 14:08:36 -0700 Subject: [PATCH 07/55] extra space --- libraries/audio/src/InboundAudioStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 3e4a8639c6..a830d7c9db 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -218,7 +218,7 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) { _framesAvailableStat.reset(); } - + int ret = _ringBuffer.addSilentSamples(silentSamples - numSilentFramesToDrop * samplesPerFrame); return ret; From 529a7e0369108305ef96d105d327b1f981f115be Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 23 Oct 2014 22:55:40 -0700 Subject: [PATCH 08/55] CR --- assignment-client/src/audio/AudioMixer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index faaebb1102..31f50251b9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -759,7 +759,7 @@ void AudioMixer::run() { } // Send at change or every so often - float CHANCE_OF_SEND = 0.01; + float CHANCE_OF_SEND = 0.01f; bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND); unsigned char bitset = 0; From 6072fd4066d02098eee08f08d29674a27202c251 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Oct 2014 10:41:54 -0700 Subject: [PATCH 09/55] Added audio env packet type --- libraries/networking/src/PacketHeaders.cpp | 5 +++++ libraries/networking/src/PacketHeaders.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index b96d88430a..0b6a3bc1f0 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -135,8 +135,13 @@ QString nameForPacketType(PacketType type) { PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse); PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack); PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelEditNack); + PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment); PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack); PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment); + PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeat); + PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse); + PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing); + PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply); default: return QString("Type: ") + QString::number((int)type); } diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 7632f47686..2e9ce697f0 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -68,7 +68,7 @@ enum PacketType { PacketTypeEntityAddResponse, PacketTypeOctreeDataNack, // 45 PacketTypeVoxelEditNack, - UNUSED_6, + PacketTypeAudioEnvironment, PacketTypeEntityEditNack, // 48 PacketTypeSignedTransactionPayment, PacketTypeIceServerHeartbeat, From 847ef64b667f266aaceebcec5a4002f48f23fc80 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Oct 2014 14:27:55 -0700 Subject: [PATCH 10/55] move audio env data over to new packet --- assignment-client/src/audio/AudioMixer.cpp | 68 +++++++++++----------- interface/src/Audio.cpp | 21 +++++++ interface/src/Audio.h | 1 + interface/src/DatagramProcessor.cpp | 14 +++-- libraries/audio/src/InboundAudioStream.cpp | 22 +------ libraries/networking/src/PacketHeaders.cpp | 4 +- 6 files changed, 68 insertions(+), 62 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 31f50251b9..afde574ae2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -638,8 +638,9 @@ void AudioMixer::run() { int nextFrame = 0; QElapsedTimer timer; timer.start(); - + char clientMixBuffer[MAX_PACKET_SIZE]; + char clientEnvBuffer[MAX_PACKET_SIZE]; int usecToSleep = BUFFER_SEND_INTERVAL_USECS; @@ -718,23 +719,25 @@ void AudioMixer::run() { && nodeData->getAvatarAudioStream()) { int streamsMixed = prepareMixForListeningNode(node.data()); - - char* dataAt; + + char* mixDataAt; if (streamsMixed > 0) { - // pack header - int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); - dataAt = clientMixBuffer + numBytesPacketHeader; - + // pack headers + int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); + mixDataAt = clientMixBuffer + numBytesMixPacketHeader; + // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); - memcpy(dataAt, &sequence, sizeof(quint16)); - dataAt += sizeof(quint16); - - // Pack stream properties - bool hasReverb = false; - float reverbTime; - float wetLevel; + memcpy(mixDataAt, &sequence, sizeof(quint16)); + mixDataAt += sizeof(quint16); + // pack mixed audio samples + memcpy(mixDataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); + mixDataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; + + // Send stream properties + bool hasReverb = false; + float reverbTime, wetLevel; // find reverb properties for (int i = 0; i < _zoneReverbSettings.size(); ++i) { AudioMixerClientData* data = static_cast(node->getLinkedData()); @@ -762,48 +765,45 @@ void AudioMixer::run() { float CHANCE_OF_SEND = 0.01f; bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND); - unsigned char bitset = 0; if (sendData) { + int numBytesEnvPacketHeader = populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment); + char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader; + + unsigned char bitset = 0; setAtBit(bitset, HAS_DATA_BIT); if (hasReverb) { setAtBit(bitset, HAS_REVERB_BIT); } - memcpy(dataAt, &bitset, sizeof(unsigned char)); - dataAt += sizeof(unsigned char); + memcpy(envDataAt, &bitset, sizeof(unsigned char)); + envDataAt += sizeof(unsigned char); if (hasReverb) { - memcpy(dataAt, &reverbTime, sizeof(float)); - dataAt += sizeof(float); - memcpy(dataAt, &wetLevel, sizeof(float)); - dataAt += sizeof(float); + memcpy(envDataAt, &reverbTime, sizeof(float)); + envDataAt += sizeof(float); + memcpy(envDataAt, &wetLevel, sizeof(float)); + envDataAt += sizeof(float); } - } else { - memcpy(dataAt, &bitset, sizeof(unsigned char)); - dataAt += sizeof(unsigned char); + nodeList->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node); } - - // pack mixed audio samples - memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); - dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; } else { // pack header int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); - dataAt = clientMixBuffer + numBytesPacketHeader; + mixDataAt = clientMixBuffer + numBytesPacketHeader; // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); - memcpy(dataAt, &sequence, sizeof(quint16)); - dataAt += sizeof(quint16); + memcpy(mixDataAt, &sequence, sizeof(quint16)); + mixDataAt += sizeof(quint16); // pack number of silent audio samples quint16 numSilentSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; - memcpy(dataAt, &numSilentSamples, sizeof(quint16)); - dataAt += sizeof(quint16); + memcpy(mixDataAt, &numSilentSamples, sizeof(quint16)); + mixDataAt += sizeof(quint16); } // send mixed audio packet - nodeList->writeDatagram(clientMixBuffer, dataAt - clientMixBuffer, node); + nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); // send an audio stream stats packet if it's time diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index dd84eb3211..7d039387bb 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1018,6 +1018,27 @@ void Audio::parseAudioStreamStatsPacket(const QByteArray& packet) { } } +void Audio::parseAudioEnvironmentData(const QByteArray &packet) { + int numBytesPacketHeader = numBytesForPacketHeader(packet); + const char* dataAt = packet.constData() + numBytesPacketHeader; + + char bitset; + memcpy(&bitset, dataAt, sizeof(char)); + dataAt += sizeof(char); + + bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT);; + if (hasReverb) { + float reverbTime, wetLevel; + memcpy(&reverbTime, dataAt, sizeof(float)); + dataAt += sizeof(float); + memcpy(&wetLevel, dataAt, sizeof(float)); + dataAt += sizeof(float); + _receivedAudioStream.setReverb(reverbTime, wetLevel); + } else { + _receivedAudioStream.clearReverb(); + } +} + void Audio::sendDownstreamAudioStatsPacket() { // since this function is called every second, we'll sample for some of our stats here diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 900b6ce0d6..fcbfb12761 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -125,6 +125,7 @@ public slots: void stop(); void addReceivedAudioToStream(const QByteArray& audioByteArray); void parseAudioStreamStatsPacket(const QByteArray& packet); + void parseAudioEnvironmentData(const QByteArray& packet); void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples); void handleAudioInput(); void reset(); diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 868654b9da..6f9f4cae68 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -49,14 +49,18 @@ void DatagramProcessor::processDatagrams() { PacketType incomingType = packetTypeForPacket(incomingPacket); // only process this packet if we have a match on the packet version switch (incomingType) { + case PacketTypeAudioEnvironment: + case PacketTypeAudioStreamStats: case PacketTypeMixedAudio: - case PacketTypeSilentAudioFrame: - case PacketTypeAudioStreamStats: { - if (incomingType != PacketTypeAudioStreamStats) { - QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection, + case PacketTypeSilentAudioFrame: { + if (incomingType == PacketTypeAudioStreamStats) { + QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection, + Q_ARG(QByteArray, incomingPacket)); + } else if (incomingType == PacketTypeAudioEnvironment) { + QMetaObject::invokeMethod(&application->_audio, "parseAudioEnvironmentData", Qt::QueuedConnection, Q_ARG(QByteArray, incomingPacket)); } else { - QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection, + QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection, Q_ARG(QByteArray, incomingPacket)); } diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index a830d7c9db..12449a9879 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -170,27 +170,9 @@ int InboundAudioStream::parseData(const QByteArray& packet) { } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { - int read = 0; - if (type == PacketTypeMixedAudio) { - char bitset; - memcpy(&bitset, packetAfterSeqNum.data() + read, sizeof(char)); - read += sizeof(char); - - bool hasData = oneAtBit(bitset, HAS_DATA_BIT); - if (hasData) { - _hasReverb = oneAtBit(bitset, HAS_REVERB_BIT); - if (_hasReverb) { - memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - } - } - } - // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t); - return read; + numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); + return 0; } int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 0b6a3bc1f0..73671295df 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeSilentAudioFrame: return 4; case PacketTypeMixedAudio: - return 3; + return 1; case PacketTypeAvatarData: return 3; case PacketTypeAvatarIdentity: @@ -71,11 +71,9 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeOctreeStats: return 1; - case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: return VERSION_ENTITIES_SUPPORT_DIMENSIONS; - case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: From 12f0237dc7df928dd87dcbb628034056070c4e6d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 24 Oct 2014 14:56:56 -0700 Subject: [PATCH 11/55] Cleanup --- assignment-client/src/audio/AudioMixer.cpp | 24 +++++++++++----------- libraries/audio/src/InboundAudioStream.cpp | 1 - libraries/audio/src/InboundAudioStream.h | 5 ++--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index afde574ae2..bd3e37c0ae 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -638,7 +638,7 @@ void AudioMixer::run() { int nextFrame = 0; QElapsedTimer timer; timer.start(); - + char clientMixBuffer[MAX_PACKET_SIZE]; char clientEnvBuffer[MAX_PACKET_SIZE]; @@ -719,13 +719,13 @@ void AudioMixer::run() { && nodeData->getAvatarAudioStream()) { int streamsMixed = prepareMixForListeningNode(node.data()); - + char* mixDataAt; if (streamsMixed > 0) { - // pack headers + // pack header int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio); mixDataAt = clientMixBuffer + numBytesMixPacketHeader; - + // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); memcpy(mixDataAt, &sequence, sizeof(quint16)); @@ -741,8 +741,7 @@ void AudioMixer::run() { // find reverb properties for (int i = 0; i < _zoneReverbSettings.size(); ++i) { AudioMixerClientData* data = static_cast(node->getLinkedData()); - AvatarAudioStream* stream = data->getAvatarAudioStream(); - glm::vec3 streamPosition = stream->getPosition(); + glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { hasReverb = true; reverbTime = _zoneReverbSettings[i].reverbTime; @@ -754,11 +753,13 @@ void AudioMixer::run() { bool dataChanged = (stream->hasReverb() != hasReverb) || (stream->hasReverb() && (stream->getRevebTime() != reverbTime || stream->getWetLevel() != wetLevel)); - // Update stream - if (hasReverb) { - stream->setReverb(reverbTime, wetLevel); - } else { - stream->clearReverb(); + if (dataChanged) { + // Update stream + if (hasReverb) { + stream->setReverb(reverbTime, wetLevel); + } else { + stream->clearReverb(); + } } // Send at change or every so often @@ -770,7 +771,6 @@ void AudioMixer::run() { char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader; unsigned char bitset = 0; - setAtBit(bitset, HAS_DATA_BIT); if (hasReverb) { setAtBit(bitset, HAS_REVERB_BIT); } diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 12449a9879..366659b633 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -13,7 +13,6 @@ #include "InboundAudioStream.h" #include "PacketHeaders.h" -#include const int STARVE_HISTORY_CAPACITY = 50; diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 737147e2ba..ad2b7266ed 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -45,9 +45,8 @@ const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES = 50; const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION = 10; const bool DEFAULT_REPETITION_WITH_FADE = true; -// Mixed Audio bitset -const int HAS_DATA_BIT = 0; // 1st bit -const int HAS_REVERB_BIT = 1; // 2nd bit +// Audio Env bitset +const int HAS_REVERB_BIT = 0; // 1st bit class InboundAudioStream : public NodeData { Q_OBJECT From 61c80183ad224e24dccc63e1f96a66c60a1c0bc7 Mon Sep 17 00:00:00 2001 From: Stojce Date: Sun, 26 Oct 2014 08:12:07 +0100 Subject: [PATCH 12/55] fix for mirror size on different scale resloutions --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index da7693ed7a..8c2966562c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3104,7 +3104,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { } else { // if not rendering the billboard, the region is in device independent coordinates; must convert to device QSize size = getTextureCache()->getFrameBufferSize(); - float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); + float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio() * _renderResolutionScale; int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; glViewport(x, size.height() - y - height, width, height); glScissor(x, size.height() - y - height, width, height); From 5d7a0c29342c65083e54a77ea2dd374d7f7891b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Oct 2014 14:34:43 -0700 Subject: [PATCH 13/55] added light properties to edit tools --- examples/libraries/entityPropertyDialogBox.js | 36 +++++++++++++++++-- examples/newEditEntities.js | 2 +- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index f07bb9575f..a5d9dd2510 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -133,7 +133,7 @@ EntityPropertyDialogBox = (function () { array.push({ label: "Visible:", value: properties.visible }); index++; - if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "Light") { + if (properties.type == "Box" || properties.type == "Sphere") { array.push({ label: "Color:", type: "header" }); index++; array.push({ label: "Red:", value: properties.color.red }); @@ -145,7 +145,27 @@ EntityPropertyDialogBox = (function () { } if (properties.type == "Light") { - array.push({ label: "Spot Light:", value: properties.isSpotlight }); + array.push({ label: "Light Properties:", type: "header" }); + index++; + array.push({ label: "Is Spot Light:", value: properties.isSpotlight }); + index++; + array.push({ label: "Diffuse Red:", value: properties.diffuseColor.red }); + index++; + array.push({ label: "Diffuse Green:", value: properties.diffuseColor.green }); + index++; + array.push({ label: "Diffuse Blue:", value: properties.diffuseColor.blue }); + index++; + array.push({ label: "Ambient Red:", value: properties.ambientColor.red }); + index++; + array.push({ label: "Ambient Green:", value: properties.ambientColor.green }); + index++; + array.push({ label: "Ambient Blue:", value: properties.ambientColor.blue }); + index++; + array.push({ label: "Specular Red:", value: properties.specularColor.red }); + index++; + array.push({ label: "Specular Green:", value: properties.specularColor.green }); + index++; + array.push({ label: "Specular Blue:", value: properties.specularColor.blue }); index++; } array.push({ button: "Cancel" }); @@ -242,14 +262,24 @@ EntityPropertyDialogBox = (function () { properties.lifetime = array[index++].value; properties.visible = array[index++].value; - if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "Light") { + if (properties.type == "Box" || properties.type == "Sphere") { index++; // skip header properties.color.red = array[index++].value; properties.color.green = array[index++].value; properties.color.blue = array[index++].value; } if (properties.type == "Light") { + index++; // skip header properties.isSpotlight = array[index++].value; + properties.diffuseColor.red = array[index++].value; + properties.diffuseColor.green = array[index++].value; + properties.diffuseColor.blue = array[index++].value; + properties.ambientColor.red = array[index++].value; + properties.ambientColor.green = array[index++].value; + properties.ambientColor.blue = array[index++].value; + properties.specularColor.red = array[index++].value; + properties.specularColor.green = array[index++].value; + properties.specularColor.blue = array[index++].value; } Entities.editEntity(editModelID, properties); diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 28a118a683..cfa14f667a 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -159,7 +159,7 @@ var toolBar = (function () { }); newLightButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-sphere.svg", + imageURL: toolIconUrl + "add-fire.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: toolWidth, height: toolHeight, From c17ffe94331b017d5a9d245a8c4a9685e3ac24a3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Oct 2014 14:40:58 -0700 Subject: [PATCH 14/55] add the new properties to LightEntityItem class --- .../entities/RenderableLightEntityItem.cpp | 53 ++++++--------- libraries/entities/src/LightEntityItem.cpp | 33 +++++++-- libraries/entities/src/LightEntityItem.h | 67 ++++++++++++++++--- 3 files changed, 108 insertions(+), 45 deletions(-) diff --git a/interface/src/entities/RenderableLightEntityItem.cpp b/interface/src/entities/RenderableLightEntityItem.cpp index b25ef1e9cc..bf9939e164 100644 --- a/interface/src/entities/RenderableLightEntityItem.cpp +++ b/interface/src/entities/RenderableLightEntityItem.cpp @@ -39,52 +39,44 @@ void RenderableLightEntityItem::render(RenderArgs* args) { float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); const float MAX_COLOR = 255.0f; - float red = getColor()[RED_INDEX] / MAX_COLOR; - float green = getColor()[GREEN_INDEX] / MAX_COLOR; - float blue = getColor()[BLUE_INDEX] / MAX_COLOR; - float alpha = getLocalRenderAlpha(); - - /* - /// Adds a point light to render for the current frame. - void addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f), - const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f), - float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f); - - /// Adds a spot light to render for the current frame. - void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f), - const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f), - float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f, - const glm::vec3& direction = glm::vec3(0.0f, 0.0f, -1.0f), float exponent = 0.0f, float cutoff = PI); - */ - - glm::vec3 ambient = glm::vec3(0.0f, 0.0f, 0.0f); - glm::vec3 diffuse = glm::vec3(red, green, blue); - glm::vec3 specular = glm::vec3(red, green, blue); + float diffuseR = getDiffuseColor()[RED_INDEX] / MAX_COLOR; + float diffuseG = getDiffuseColor()[GREEN_INDEX] / MAX_COLOR; + float diffuseB = getDiffuseColor()[BLUE_INDEX] / MAX_COLOR; + + float ambientR = getAmbientColor()[RED_INDEX] / MAX_COLOR; + float ambientG = getAmbientColor()[GREEN_INDEX] / MAX_COLOR; + float ambientB = getAmbientColor()[BLUE_INDEX] / MAX_COLOR; + + float specularR = getSpecularColor()[RED_INDEX] / MAX_COLOR; + float specularG = getSpecularColor()[GREEN_INDEX] / MAX_COLOR; + float specularB = getSpecularColor()[BLUE_INDEX] / MAX_COLOR; + + glm::vec3 ambient = glm::vec3(ambientR, ambientG, ambientB); + glm::vec3 diffuse = glm::vec3(diffuseR, diffuseG, diffuseB); + glm::vec3 specular = glm::vec3(specularR, specularG, specularB); glm::vec3 direction = IDENTITY_FRONT * rotation; - float constantAttenuation = 1.0f; - float linearAttenuation = 0.0f; - float quadraticAttenuation = 0.0f; + float constantAttenuation = getConstantAttenuation(); + float linearAttenuation = getLinearAttenuation(); + float quadraticAttenuation = getQuadraticAttenuation(); + float exponent = getExponent(); + float cutoff = glm::radians(getCutoff()); if (_isSpotlight) { Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f, ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, - direction); + direction, exponent, cutoff); } else { Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f, ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); } - bool wantDebug = false; if (wantDebug) { - glColor4f(red, green, blue, alpha); - + glColor4f(diffuseR, diffuseG, diffuseB, 1.0f); glPushMatrix(); glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - glPushMatrix(); glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); @@ -94,5 +86,4 @@ void RenderableLightEntityItem::render(RenderArgs* args) { glPopMatrix(); glPopMatrix(); } - }; diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 10387fa8a7..1ee12ece34 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -26,19 +26,33 @@ EntityItem* LightEntityItem::factory(const EntityItemID& entityID, const EntityI // our non-pure virtual subclass for now... LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : EntityItem(entityItemID, properties) -{ +{ _type = EntityTypes::Light; + + // default property values + const quint8 MAX_COLOR = 255; + _ambientColor[RED_INDEX] = _ambientColor[GREEN_INDEX] = _ambientColor[BLUE_INDEX] = 0; + _diffuseColor[RED_INDEX] = _diffuseColor[GREEN_INDEX] = _diffuseColor[BLUE_INDEX] = MAX_COLOR; + _specularColor[RED_INDEX] = _specularColor[GREEN_INDEX] = _specularColor[BLUE_INDEX] = MAX_COLOR; + _constantAttenuation = 1.0f; + _linearAttenuation = 0.0f; + _quadraticAttenuation = 0.0f; + _exponent = 0.0f; + _cutoff = PI; + setProperties(properties, true); // a light is not collide-able so we make it's shape be a tiny sphere at origin - _emptyShape.setTranslation(glm::vec3(0.0f,0.0f,0.0f)); + _emptyShape.setTranslation(glm::vec3(0.0f, 0.0f, 0.0f)); _emptyShape.setRadius(0.0f); } EntityItemProperties LightEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class - properties.setColor(getXColor()); + properties.setDiffuseColor(getDiffuseXColor()); + properties.setAmbientColor(getAmbientXColor()); + properties.setSpecularColor(getSpecularXColor()); properties.setGlowLevel(getGlowLevel()); properties.setIsSpotlight(getIsSpotlight()); @@ -48,7 +62,10 @@ EntityItemProperties LightEntityItem::getProperties() const { bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setDiffuseColor); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); if (somethingChanged) { @@ -71,8 +88,10 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, _isSpotlight); + READ_ENTITY_PROPERTY_COLOR(PROP_DIFFUSE_COLOR, _diffuseColor); + READ_ENTITY_PROPERTY_COLOR(PROP_AMBIENT_COLOR, _ambientColor); + READ_ENTITY_PROPERTY_COLOR(PROP_SPECULAR_COLOR, _specularColor); return bytesRead; } @@ -95,6 +114,8 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor()); APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, getIsSpotlight()); + APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, getDiffuseColor()); + APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, getAmbientColor()); + APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, getSpecularColor()); } diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index a87f30a8ed..ff5e1e725d 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -41,26 +41,77 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - const rgbColor& getColor() const { return _color; } - xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } + const rgbColor& getAmbientColor() const { return _ambientColor; } + xColor getAmbientXColor() const { + xColor color = { _ambientColor[RED_INDEX], _ambientColor[GREEN_INDEX], _ambientColor[BLUE_INDEX] }; return color; + } - void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } - void setColor(const xColor& value) { - _color[RED_INDEX] = value.red; - _color[GREEN_INDEX] = value.green; - _color[BLUE_INDEX] = value.blue; + void setAmbientColor(const rgbColor& value) { memcpy(_ambientColor, value, sizeof(_ambientColor)); } + void setAmbientColor(const xColor& value) { + _ambientColor[RED_INDEX] = value.red; + _ambientColor[GREEN_INDEX] = value.green; + _ambientColor[BLUE_INDEX] = value.blue; + } + + const rgbColor& getDiffuseColor() const { return _diffuseColor; } + xColor getDiffuseXColor() const { + xColor color = { _diffuseColor[RED_INDEX], _diffuseColor[GREEN_INDEX], _diffuseColor[BLUE_INDEX] }; return color; + } + + void setDiffuseColor(const rgbColor& value) { memcpy(_diffuseColor, value, sizeof(_diffuseColor)); } + void setDiffuseColor(const xColor& value) { + _diffuseColor[RED_INDEX] = value.red; + _diffuseColor[GREEN_INDEX] = value.green; + _diffuseColor[BLUE_INDEX] = value.blue; + } + + const rgbColor& getSpecularColor() const { return _specularColor; } + xColor getSpecularXColor() const { + xColor color = { _specularColor[RED_INDEX], _specularColor[GREEN_INDEX], _specularColor[BLUE_INDEX] }; return color; + } + + void setSpecularColor(const rgbColor& value) { memcpy(_specularColor, value, sizeof(_specularColor)); } + void setSpecularColor(const xColor& value) { + _specularColor[RED_INDEX] = value.red; + _specularColor[GREEN_INDEX] = value.green; + _specularColor[BLUE_INDEX] = value.blue; } bool getIsSpotlight() const { return _isSpotlight; } void setIsSpotlight(bool value) { _isSpotlight = value; } + bool getConstantAttenuation() const { return _constantAttenuation; } + void setConstantAttenuation(float value) { _constantAttenuation = value; } + + bool getLinearAttenuation() const { return _linearAttenuation; } + void setLinearAttenuation(float value) { _linearAttenuation = value; } + + bool getQuadraticAttenuation() const { return _quadraticAttenuation; } + void setQuadraticAttenuation(float value) { _quadraticAttenuation = value; } + + bool getExponent() const { return _exponent; } + void setExponent(bool value) { _exponent = value; } + + bool getCutoff() const { return _cutoff; } + void setCutoff(bool value) { _cutoff = value; } + virtual const Shape& getCollisionShapeInMeters() const { return _emptyShape; } protected: virtual void recalculateCollisionShape() { /* nothing to do */ } - rgbColor _color; + // properties of a light + rgbColor _ambientColor; + rgbColor _diffuseColor; + rgbColor _specularColor; bool _isSpotlight; + float _constantAttenuation; + float _linearAttenuation; + float _quadraticAttenuation; + float _exponent; + float _cutoff; + + // used for collision detection SphereShape _emptyShape; }; From ac9c5e73862fa852b34ca2a74bab3147433e1f2f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Oct 2014 14:54:34 -0700 Subject: [PATCH 15/55] some initial adds to properties --- libraries/entities/src/EntityItemProperties.h | 18 ++++++++++++++++-- libraries/entities/src/LightEntityItem.cpp | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index fa047a6cf9..293b868f0f 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -32,7 +32,6 @@ #include "EntityItemPropertiesMacros.h" #include "EntityTypes.h" -// PropertyFlags support enum EntityPropertyList { PROP_PAGED_PROPERTY, PROP_CUSTOM_PROPERTIES_INCLUDED, @@ -52,6 +51,7 @@ enum EntityPropertyList { // these properties are supported by some derived classes PROP_COLOR, + PROP_DIFFUSE_COLOR = PROP_COLOR, // used by light class PROP_MODEL_URL, PROP_ANIMATION_URL, PROP_ANIMATION_FPS, @@ -67,8 +67,15 @@ enum EntityPropertyList { // property used by Light entity PROP_IS_SPOTLIGHT, + PROP_AMBIENT_COLOR, + PROP_SPECULAR_COLOR, + PROP_CONSTANT_ATTENUATION, + PROP_LINEAR_ATTENUATION, + PROP_QUADRATIC_ATTENUATION, + PROP_EXPONENT, + PROP_CUTOFF, - PROP_LAST_ITEM = PROP_IS_SPOTLIGHT + PROP_LAST_ITEM = PROP_CUTOFF }; typedef PropertyFlags EntityPropertyFlags; @@ -240,6 +247,11 @@ public: bool getIsSpotlight() const { return _isSpotlight; } void setIsSpotlight(bool value) { _isSpotlight = value; _isSpotlightChanged = true; } + void setDiffuseColor(const xColor& value) { } + void setAmbientColor(const xColor& value) { } + void setSpecularColor(const xColor& value) { } + + void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } private: @@ -309,6 +321,8 @@ private: bool _glowLevelChanged; bool _localRenderAlphaChanged; bool _isSpotlightChanged; + bool _ambientColorChanged; + bool _specularColorChanged; bool _defaultSettings; }; diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 1ee12ece34..c8e7b92a0d 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -64,8 +64,8 @@ bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setDiffuseColor); //SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); if (somethingChanged) { From bb1eacce7d39bc99b5d4c30d80a1b675b84fee27 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Oct 2014 15:37:52 -0700 Subject: [PATCH 16/55] more tweaks for new light properties --- libraries/entities/src/EntityItemProperties.h | 8 ++++---- libraries/entities/src/LightEntityItem.cpp | 1 - libraries/entities/src/SphereEntityItem.cpp | 3 --- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 293b868f0f..699aa5a612 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -247,11 +247,11 @@ public: bool getIsSpotlight() const { return _isSpotlight; } void setIsSpotlight(bool value) { _isSpotlight = value; _isSpotlightChanged = true; } - void setDiffuseColor(const xColor& value) { } - void setAmbientColor(const xColor& value) { } - void setSpecularColor(const xColor& value) { } + // total hack for now + void setDiffuseColor(const xColor& value) { setColor(value); } + void setAmbientColor(const xColor& value) { setColor(value); } + void setSpecularColor(const xColor& value) { setColor(value); } - void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } private: diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index c8e7b92a0d..1dc25494d8 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -53,7 +53,6 @@ EntityItemProperties LightEntityItem::getProperties() const { properties.setDiffuseColor(getDiffuseXColor()); properties.setAmbientColor(getAmbientXColor()); properties.setSpecularColor(getSpecularXColor()); - properties.setGlowLevel(getGlowLevel()); properties.setIsSpotlight(getIsSpotlight()); return properties; diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 5da218c11a..f5b8eb27e9 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -33,10 +33,7 @@ SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const Entit EntityItemProperties SphereEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class - properties.setColor(getXColor()); - properties.setGlowLevel(getGlowLevel()); - return properties; } From 1de618ed3eb9cbd13a38324557956b78b91e52bf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 Oct 2014 16:25:26 -0700 Subject: [PATCH 17/55] added new light related properties --- .../entities/src/EntityItemProperties.cpp | 65 +++++++++++++++++++ libraries/entities/src/EntityItemProperties.h | 51 +++++++++++++-- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 3c3729e436..8c07091b53 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -79,6 +79,24 @@ EntityItemProperties::EntityItemProperties() : _animationFPSChanged(false), _glowLevelChanged(false), _localRenderAlphaChanged(false), + _isSpotlightChanged(false), + + _ambientColor(), + _specularColor(), + _constantAttenuation(1.0f), + _linearAttenuation(0.0f), + _quadraticAttenuation(0.0f), + _exponent(0.0f), + _cutoff(PI), + + _ambientColorChanged(false), + _specularColorChanged(false), + _constantAttenuationChanged(false), + _linearAttenuationChanged(false), + _quadraticAttenuationChanged(false), + _exponentChanged(false), + _cutoffChanged(false), + _defaultSettings(true) { } @@ -121,6 +139,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); + CHECK_PROPERTY_CHANGE(PROP_AMBIENT_COLOR, ambientColor); + CHECK_PROPERTY_CHANGE(PROP_SPECULAR_COLOR, specularColor); + CHECK_PROPERTY_CHANGE(PROP_CONSTANT_ATTENUATION, constantAttenuation); + CHECK_PROPERTY_CHANGE(PROP_LINEAR_ATTENUATION, linearAttenuation); + CHECK_PROPERTY_CHANGE(PROP_QUADRATIC_ATTENUATION, quadraticAttenuation); + CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent); + CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff); return changedProperties; } @@ -164,6 +189,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove); COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight); + // NOTE: we do want this, so we will read both aliases diffuseColor and color + COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(diffuseColor, getDiffuseColor()); + COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(ambientColor, getAmbientColor()); + COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(specularColor, getSpecularColor()); + COPY_PROPERTY_TO_QSCRIPTVALUE(constantAttenuation); + COPY_PROPERTY_TO_QSCRIPTVALUE(linearAttenuation); + COPY_PROPERTY_TO_QSCRIPTVALUE(quadraticAttenuation); + COPY_PROPERTY_TO_QSCRIPTVALUE(exponent); + COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff); + // Sitting properties support QScriptValue sittingPoints = engine->newObject(); for (int i = 0; i < _sittingPoints.size(); ++i) { @@ -223,6 +258,14 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(ignoreForCollisions, setIgnoreForCollisions); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(collisionsWillMove, setCollisionsWillMove); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(isSpotlight, setIsSpotlight); + COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(diffuseColor, setDiffuseColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(ambientColor, setAmbientColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(specularColor, setSpecularColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(constantAttenuation, setConstantAttenuation); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(linearAttenuation, setLinearAttenuation); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(quadraticAttenuation, setQuadraticAttenuation); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(exponent, setExponent); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff); _lastEdited = usecTimestampNow(); } @@ -374,6 +417,13 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, properties.getIsSpotlight()); + APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, properties.getAmbientColor()); + APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, properties.getSpecularColor()); + APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, properties.getConstantAttenuation()); + APPEND_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, appendValue, properties.getLinearAttenuation()); + APPEND_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, appendValue, properties.getQuadraticAttenuation()); + APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, properties.getExponent()); + APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, properties.getCutoff()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -573,6 +623,13 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); + READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_AMBIENT_COLOR, setAmbientColor); + READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_SPECULAR_COLOR, setSpecularColor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CONSTANT_ATTENUATION, float, setConstantAttenuation); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINEAR_ATTENUATION, float, setLinearAttenuation); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUADRATIC_ATTENUATION, float, setQuadraticAttenuation); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff); return valid; } @@ -628,6 +685,14 @@ void EntityItemProperties::markAllChanged() { _glowLevelChanged = true; _localRenderAlphaChanged = true; _isSpotlightChanged = true; + + _ambientColorChanged = true; + _specularColorChanged = true; + _constantAttenuationChanged = true; + _linearAttenuationChanged = true; + _quadraticAttenuationChanged = true; + _exponentChanged = true; + _cutoffChanged = true; } AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 699aa5a612..1867c2e900 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -248,9 +248,36 @@ public: void setIsSpotlight(bool value) { _isSpotlight = value; _isSpotlightChanged = true; } // total hack for now - void setDiffuseColor(const xColor& value) { setColor(value); } - void setAmbientColor(const xColor& value) { setColor(value); } - void setSpecularColor(const xColor& value) { setColor(value); } + //void setDiffuseColor(const xColor& value) { setColor(value); } + //void setAmbientColor(const xColor& value) { setColor(value); } + //void setSpecularColor(const xColor& value) { setColor(value); } + + xColor getDiffuseColor() const { return _color; } // diffuseColor is an alias for color + xColor getAmbientColor() const { return _ambientColor; } + xColor getSpecularColor() const { return _specularColor; } + + void setDiffuseColor(const xColor& value) { _color = value; _colorChanged = true; } + void setAmbientColor(const xColor& value) { _ambientColor = value; _ambientColorChanged = true; } + void setSpecularColor(const xColor& value) { _specularColor = value; _specularColorChanged = true; } + + bool diffuseColorChanged() const { return _colorChanged; } + bool ambientColorChanged() const { return _ambientColorChanged; } + bool specularColorChanged() const { return _specularColorChanged; } + + bool getConstantAttenuation() const { return _constantAttenuation; } + void setConstantAttenuation(float value) { _constantAttenuation = value; _constantAttenuationChanged = true; } + + bool getLinearAttenuation() const { return _linearAttenuation; } + void setLinearAttenuation(float value) { _linearAttenuation = value; _linearAttenuationChanged = true; } + + bool getQuadraticAttenuation() const { return _quadraticAttenuation; } + void setQuadraticAttenuation(float value) { _quadraticAttenuation = value; _quadraticAttenuationChanged = true; } + + bool getExponent() const { return _exponent; } + void setExponent(bool value) { _exponent = value; _exponentChanged = true; } + + bool getCutoff() const { return _cutoff; } + void setCutoff(bool value) { _cutoff = value; _cutoffChanged = true; } void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } @@ -308,9 +335,11 @@ private: float _glowLevel; float _localRenderAlpha; bool _isSpotlight; + + // TODO: for some reason if you add anything before _sittingPoints in this class, you'll get crashes + // it's not clear to me why this is, but we should research it and fix whatever the underlying problem is QVector _sittingPoints; glm::vec3 _naturalDimensions; - bool _colorChanged; bool _modelURLChanged; @@ -321,8 +350,22 @@ private: bool _glowLevelChanged; bool _localRenderAlphaChanged; bool _isSpotlightChanged; + + xColor _ambientColor; + xColor _specularColor; + float _constantAttenuation; + float _linearAttenuation; + float _quadraticAttenuation; + float _exponent; + float _cutoff; + bool _ambientColorChanged; bool _specularColorChanged; + bool _constantAttenuationChanged; + bool _linearAttenuationChanged; + bool _quadraticAttenuationChanged; + bool _exponentChanged; + bool _cutoffChanged; bool _defaultSettings; }; From a516d062a61f320aff85100ef89f8021f52708ef Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 09:55:13 -0700 Subject: [PATCH 18/55] fix corruption in sitting points, added additional light properties --- .../entities/src/EntityItemProperties.cpp | 39 ++++++++++++++----- libraries/entities/src/EntityItemProperties.h | 13 +++---- libraries/entities/src/LightEntityItem.cpp | 24 +++++++++--- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8c07091b53..c95ec7cc2d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -70,7 +70,6 @@ EntityItemProperties::EntityItemProperties() : _localRenderAlpha(1.0f), _isSpotlight(false), - _naturalDimensions(1.0f, 1.0f, 1.0f), _colorChanged(false), _modelURLChanged(false), _animationURLChanged(false), @@ -97,10 +96,28 @@ EntityItemProperties::EntityItemProperties() : _exponentChanged(false), _cutoffChanged(false), - _defaultSettings(true) + _defaultSettings(true), + _sittingPoints(NULL), + _naturalDimensions(1.0f, 1.0f, 1.0f) { + if (_sittingPoints) { + delete _sittingPoints; + _sittingPoints = NULL; + } } +void EntityItemProperties::setSittingPoints(const QVector& sittingPoints) { + if (!_sittingPoints) { + _sittingPoints = new QVector; + } + _sittingPoints->clear(); + + foreach (SittingPoint sitPoint, sittingPoints) { + _sittingPoints->append(sitPoint); + } +} + + void EntityItemProperties::debugDump() const { qDebug() << "EntityItemProperties..."; qDebug() << " _type=" << EntityTypes::getEntityTypeName(_type); @@ -201,14 +218,18 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons // Sitting properties support QScriptValue sittingPoints = engine->newObject(); - for (int i = 0; i < _sittingPoints.size(); ++i) { - QScriptValue sittingPoint = engine->newObject(); - sittingPoint.setProperty("name", _sittingPoints[i].name); - sittingPoint.setProperty("position", vec3toScriptValue(engine, _sittingPoints[i].position)); - sittingPoint.setProperty("rotation", quatToScriptValue(engine, _sittingPoints[i].rotation)); - sittingPoints.setProperty(i, sittingPoint); + if (_sittingPoints) { + for (int i = 0; i < _sittingPoints->size(); ++i) { + QScriptValue sittingPoint = engine->newObject(); + sittingPoint.setProperty("name", _sittingPoints->at(i).name); + sittingPoint.setProperty("position", vec3toScriptValue(engine, _sittingPoints->at(i).position)); + sittingPoint.setProperty("rotation", quatToScriptValue(engine, _sittingPoints->at(i).rotation)); + sittingPoints.setProperty(i, sittingPoint); + } + sittingPoints.setProperty("length", _sittingPoints->size()); + } else { + sittingPoints.setProperty("length", 0); } - sittingPoints.setProperty("length", _sittingPoints.size()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable AABox aaBox = getAABoxInMeters(); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 1867c2e900..3b72ee8111 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -220,8 +220,7 @@ public: void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; } void markAllChanged(); - QVector getSittingPoints() const { return _sittingPoints; } - void setSittingPoints(QVector sittingPoints) { _sittingPoints = sittingPoints; } + void setSittingPoints(const QVector& sittingPoints); const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; } void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; } @@ -336,11 +335,6 @@ private: float _localRenderAlpha; bool _isSpotlight; - // TODO: for some reason if you add anything before _sittingPoints in this class, you'll get crashes - // it's not clear to me why this is, but we should research it and fix whatever the underlying problem is - QVector _sittingPoints; - glm::vec3 _naturalDimensions; - bool _colorChanged; bool _modelURLChanged; bool _animationURLChanged; @@ -368,6 +362,11 @@ private: bool _cutoffChanged; bool _defaultSettings; + + // NOTE: The following are pseudo client only properties. They are only used in clients which can access + // properties of model geometry. But these properties are not serialized like other properties. + QVector* _sittingPoints; + glm::vec3 _naturalDimensions; }; Q_DECLARE_METATYPE(EntityItemProperties); QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 1dc25494d8..3b58ec01cd 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -50,10 +50,15 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityI EntityItemProperties LightEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class - properties.setDiffuseColor(getDiffuseXColor()); - properties.setAmbientColor(getAmbientXColor()); - properties.setSpecularColor(getSpecularXColor()); - properties.setIsSpotlight(getIsSpotlight()); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight); + properties.setDiffuseColor(getDiffuseXColor()); // special case + COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientColor, getAmbientXColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(specularColor, getSpecularXColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(constantAttenuation, getConstantAttenuation); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(linearAttenuation, getLinearAttenuation); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(quadraticAttenuation, getQuadraticAttenuation); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(exponent, getExponent); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(cutoff, getCutoff); return properties; } @@ -61,11 +66,18 @@ EntityItemProperties LightEntityItem::getProperties() const { bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class + SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setDiffuseColor); //SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(constantAttenuation, setConstantAttenuation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(linearAttenuation, setLinearAttenuation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(quadraticAttenuation, setQuadraticAttenuation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(exponent, setExponent); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(cutoff, setCutoff); + if (somethingChanged) { bool wantDebug = false; From e7d67ee3bab4d74c2f1085a1cac0539c388beae1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 10:00:34 -0700 Subject: [PATCH 19/55] Move rotation handle update to a separate function --- examples/libraries/entitySelectionTool.js | 212 +++++++++++++++------- 1 file changed, 142 insertions(+), 70 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index c503ab82a4..5bce0f5ec0 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -623,10 +623,10 @@ SelectionDisplay = (function () { } + + that.updateRotationHandles = function() { var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); - innerRadius = diagonal; - outerRadius = diagonal * 1.15; var innerActive = false; var innerAlpha = 0.2; var outerAlpha = 0.2; @@ -637,22 +637,18 @@ SelectionDisplay = (function () { } var rotateHandleOffset = 0.05; - var grabberMoveUpOffset = 0.1; var top, far, left, bottom, near, right, boundsCenter, objectCenter, BLN, BRN, BLF, TLN, TRN, TLF, TRF; - // objectCenter = { x: properties.position.x, y: properties.position.y, z: properties.position.z }; - - var dimensions; + var dimensions, rotation; if (spaceMode == SPACE_LOCAL) { - objectCenter = SelectionManager.localPosition; - dimensions = SelectionManager.localDimensions; + rotation = SelectionManager.localRotation; } else { - objectCenter = SelectionManager.worldPosition; - dimensions = SelectionManager.worldDimensions; + rotation = SelectionManager.worldRotation; } objectCenter = SelectionManager.worldPosition; dimensions = SelectionManager.worldDimensions; + var position = objectCenter; top = objectCenter.y + (dimensions.y / 2); far = objectCenter.z + (dimensions.z / 2); @@ -662,7 +658,6 @@ SelectionDisplay = (function () { near = objectCenter.z - (dimensions.z / 2); right = objectCenter.x - (dimensions.x / 2); - // boundsCenter = { x: properties.boundingBox.center.x, y: properties.boundingBox.center.y, z: properties.boundingBox.center.z }; boundsCenter = objectCenter; var yawCorner; @@ -812,10 +807,12 @@ SelectionDisplay = (function () { } var rotateHandlesVisible = true; + var rotationOverlaysVisible = false; var translateHandlesVisible = true; var stretchHandlesVisible = true; var selectionBoxVisible = true; if (mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL" || mode == "TRANSLATE_X in case they Z") { + rotationOverlaysVisible = true; rotateHandlesVisible = false; translateHandlesVisible = false; stretchHandlesVisible = false; @@ -828,8 +825,6 @@ SelectionDisplay = (function () { rotateHandlesVisible = false; translateHandlesVisible = false; } - - Overlays.editOverlay(highlightBox, { visible: false }); var dimensions, rotation, position; if (spaceMode == SPACE_LOCAL) { @@ -842,63 +837,28 @@ SelectionDisplay = (function () { position = SelectionManager.worldPosition; } - Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: boundsCenter.x, y: top + grabberMoveUpOffset, z: boundsCenter.z } }); - - that.updateHandles(); - - Overlays.editOverlay(baseOfEntityProjectionOverlay, { visible: true, solid:true, lineWidth: 2.0, - position: { x: properties.position.x, + position: { x: position.x, y: 0, - z: properties.position.z }, + z: position.z }, - dimensions: { x: properties.dimensions.x, y: properties.dimensions.z }, - rotation: properties.rotation, + dimensions: { x: dimensions.x, y: 0, z: dimensions.z }, + rotation: rotation, }); - Overlays.editOverlay(rotateOverlayTarget, { visible: false }); - - Overlays.editOverlay(rotateOverlayInner, - { - visible: false, - size: innerRadius, - innerRadius: 0.9, - alpha: innerAlpha - }); - - Overlays.editOverlay(rotateOverlayOuter, - { - visible: false, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha, - }); - - Overlays.editOverlay(rotateOverlayCurrent, - { - visible: false, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9, - }); - - Overlays.editOverlay(rotateZeroOverlay, { visible: false }); - Overlays.editOverlay(rotateCurrentOverlay, { visible: false }); + Overlays.editOverlay(rotateOverlayTarget, { visible: rotationOverlaysVisible }); + Overlays.editOverlay(rotateZeroOverlay, { visible: rotationOverlaysVisible }); + Overlays.editOverlay(rotateCurrentOverlay, { visible: rotationOverlaysVisible }); // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden Overlays.editOverlay(yawHandle, { visible: rotateHandlesVisible, position: yawCorner, rotation: yawHandleRotation}); Overlays.editOverlay(pitchHandle, { visible: rotateHandlesVisible, position: pitchCorner, rotation: pitchHandleRotation}); Overlays.editOverlay(rollHandle, { visible: rotateHandlesVisible, position: rollCorner, rotation: rollHandleRotation}); - - Entities.editEntity(entityID, { localRenderAlpha: 0.1 }); }; that.setSpaceMode = function(newSpaceMode) { @@ -931,6 +891,8 @@ SelectionDisplay = (function () { return; } + that.updateRotationHandles(); + var rotation, dimensions, position; if (spaceMode == SPACE_LOCAL) { @@ -945,12 +907,14 @@ SelectionDisplay = (function () { var halfDimensions = Vec3.multiply(0.5, dimensions); - left = -halfDimensions.x; - right = halfDimensions.x; - top = halfDimensions.y; - bottom = -halfDimensions.y; + var left = -halfDimensions.x; + var right = halfDimensions.x; + var top = halfDimensions.y; + var bottom = -halfDimensions.y; var front = far = halfDimensions.z; - near = -halfDimensions.z; + var near = -halfDimensions.z; + + var worldTop = SelectionManager.worldDimensions.y / 2; var LBN = { x: left, y: bottom, z: near }; var RBN = { x: right, y: bottom, z: near }; @@ -1060,7 +1024,7 @@ SelectionDisplay = (function () { position: position, dimensions: dimensions, rotation: rotation, - visible: true, + visible: !(mode == "ROTATE_YAW" || mode == "ROTATE_PITCH" || mode == "ROTATE_ROLL"), }); Overlays.editOverlay(grabberEdgeTR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeTR }); @@ -1076,6 +1040,8 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberEdgeFR, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFR }); Overlays.editOverlay(grabberEdgeFL, { visible: stretchHandlesVisible, rotation: rotation, position: EdgeFL }); + var grabberMoveUpOffset = 0.1; + Overlays.editOverlay(grabberMoveUp, { visible: activeTool == null || mode == "TRANSLATE_UP_DOWN", position: { x: position.x, y: position.y + worldTop + grabberMoveUpOffset, z: position.z } }); }; that.setOverlaysVisible = function(isVisible) { @@ -1563,8 +1529,46 @@ SelectionDisplay = (function () { onBegin: function(event) { SelectionManager.saveProperties(); initialPosition = SelectionManager.worldPosition; + + // Size the overlays to the current selection size + var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; + var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); + innerRadius = diagonal; + outerRadius = diagonal * 1.15; + var innerAlpha = 0.2; + var outerAlpha = 0.2; + Overlays.editOverlay(rotateOverlayInner, + { + visible: true, + size: innerRadius, + innerRadius: 0.9, + alpha: innerAlpha + }); + + Overlays.editOverlay(rotateOverlayOuter, + { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); + + Overlays.editOverlay(rotateOverlayCurrent, + { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); }, onEnd: function(event, reason) { + Overlays.editOverlay(rotateOverlayInner, { visible: false }); + Overlays.editOverlay(rotateOverlayOuter, { visible: false }); + Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); + if (reason == 'cancel') { for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; @@ -1591,9 +1595,6 @@ SelectionDisplay = (function () { Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); - Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true }); - Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true }); - Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true }); var result = Overlays.findRayIntersection(pickRay); @@ -1611,6 +1612,7 @@ SelectionDisplay = (function () { var distanceFromCenter = Vec3.distance(center, result.intersection); var snapToInner = false; + // var innerRadius = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; if (distanceFromCenter < innerRadius) { angleFromZero = Math.floor(angleFromZero/innerSnapAngle) * innerSnapAngle; snapToInner = true; @@ -1671,8 +1673,46 @@ SelectionDisplay = (function () { onBegin: function(event) { SelectionManager.saveProperties(); initialPosition = SelectionManager.worldPosition; + + // Size the overlays to the current selection size + var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; + var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); + var innerRadius = diagonal; + var outerRadius = diagonal * 1.15; + var innerAlpha = 0.2; + var outerAlpha = 0.2; + Overlays.editOverlay(rotateOverlayInner, + { + visible: true, + size: innerRadius, + innerRadius: 0.9, + alpha: innerAlpha + }); + + Overlays.editOverlay(rotateOverlayOuter, + { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); + + Overlays.editOverlay(rotateOverlayCurrent, + { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); }, onEnd: function(event, reason) { + Overlays.editOverlay(rotateOverlayInner, { visible: false }); + Overlays.editOverlay(rotateOverlayOuter, { visible: false }); + Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); + if (reason == 'cancel') { for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; @@ -1698,9 +1738,6 @@ SelectionDisplay = (function () { Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); - Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true }); - Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true }); - Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true }); var result = Overlays.findRayIntersection(pickRay); if (debug) { @@ -1777,8 +1814,46 @@ SelectionDisplay = (function () { onBegin: function(event) { SelectionManager.saveProperties(); initialPosition = SelectionManager.worldPosition; + + // Size the overlays to the current selection size + var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; + var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); + var innerRadius = diagonal; + var outerRadius = diagonal * 1.15; + var innerAlpha = 0.2; + var outerAlpha = 0.2; + Overlays.editOverlay(rotateOverlayInner, + { + visible: true, + size: innerRadius, + innerRadius: 0.9, + alpha: innerAlpha + }); + + Overlays.editOverlay(rotateOverlayOuter, + { + visible: true, + size: outerRadius, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + alpha: outerAlpha, + }); + + Overlays.editOverlay(rotateOverlayCurrent, + { + visible: true, + size: outerRadius, + startAt: 0, + endAt: 0, + innerRadius: 0.9, + }); }, onEnd: function(event, reason) { + Overlays.editOverlay(rotateOverlayInner, { visible: false }); + Overlays.editOverlay(rotateOverlayOuter, { visible: false }); + Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); + if (reason == 'cancel') { for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; @@ -1804,9 +1879,6 @@ SelectionDisplay = (function () { Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); - Overlays.editOverlay(rotateOverlayInner, { ignoreRayIntersection: true }); - Overlays.editOverlay(rotateOverlayOuter, { ignoreRayIntersection: true }); - Overlays.editOverlay(rotateOverlayCurrent, { ignoreRayIntersection: true }); var result = Overlays.findRayIntersection(pickRay); if (debug) { From 48eaa7ce12029f9ff6b2941ba02dba483686f596 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 10:11:18 -0700 Subject: [PATCH 20/55] Cleanup entity tools --- examples/libraries/entitySelectionTool.js | 35 ++++------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 5bce0f5ec0..35f89d082d 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -600,7 +600,7 @@ SelectionDisplay = (function () { currentSelection = entityID; entitySelected = true; - lastCameraPosition = Camera.getPosition(); + // lastCameraPosition = Camera.getPosition(); lastCameraOrientation = Camera.getOrientation(); if (event !== false) { @@ -623,6 +623,11 @@ SelectionDisplay = (function () { } + Entities.editEntity(entityID, { localRenderAlpha: 0.1 }); + Overlays.editOverlay(highlightBox, { visible: false }); + + that.updateHandles(); + } that.updateRotationHandles = function() { var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; @@ -1137,21 +1142,10 @@ SelectionDisplay = (function () { Overlays.editOverlay(zRailOverlay, { visible: false }); }, onMove: function(event) { - if (!entitySelected || mode !== "TRANSLATE_XZ") { - return; // not allowed - } - pickRay = Camera.computePickRay(event.x, event.y); - // translate mode left/right based on view toward entity - var newIntersection = rayPlaneIntersection(pickRay, - selectedEntityPropertiesOriginalPosition, - Quat.getFront(lastCameraOrientation)); - - var vector = Vec3.subtract(newIntersection, lastPlaneIntersection); var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { x: 0, y: 1, z: 0 }); var vector = Vec3.subtract(pick, initialXZPick); - // initialXZPick = pick; // If shifted, constrain to one axis if (event.isShifted) { @@ -1188,7 +1182,6 @@ SelectionDisplay = (function () { if (wantDebug) { print("translateXZ... "); Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection); - Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); Vec3.print(" newPosition:", properties.position); Vec3.print(" newPosition:", newPosition); @@ -1218,9 +1211,6 @@ SelectionDisplay = (function () { } }, onMove: function(event) { - if (!entitySelected || mode !== "TRANSLATE_UP_DOWN") { - return; // not allowed - } pickRay = Camera.computePickRay(event.x, event.y); // translate mode left/right based on view toward entity @@ -1381,9 +1371,6 @@ SelectionDisplay = (function () { }; var onMove = function(event) { - if (!entitySelected || mode !== stretchMode) { - return; // not allowed - } var proportional = spaceMode == SPACE_WORLD || event.isShifted; var position, dimensions, rotation; @@ -1580,10 +1567,6 @@ SelectionDisplay = (function () { } }, onMove: function(event) { - if (!entitySelected || mode !== "ROTATE_YAW") { - return; // not allowed - } - var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); if (debug) { @@ -1724,9 +1707,6 @@ SelectionDisplay = (function () { } }, onMove: function(event) { - if (!entitySelected || mode !== "ROTATE_PITCH") { - return; // not allowed - } var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); if (debug) { @@ -1865,9 +1845,6 @@ SelectionDisplay = (function () { } }, onMove: function(event) { - if (!entitySelected || mode !== "ROTATE_ROLL") { - return; // not allowed - } var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); if (debug) { From 21b6a93fef7809378545165dc64ec3bf927e07b9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 10:12:17 -0700 Subject: [PATCH 21/55] Add entity tool for movement using arrow keys --- examples/libraries/entitySelectionTool.js | 38 ---------- examples/newEditEntities.js | 85 ++++++++++++++++++++++- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 35f89d082d..6ecf18bb00 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1065,44 +1065,6 @@ SelectionDisplay = (function () { entitySelected = false; }; - function applyEntityProperties(data) { - for (var i = 0; i < data.length; i++) { - var entityID = data[i].entityID; - var properties = data[i].properties; - Entities.editEntity(entityID, properties); - } - selectionManager._update(); - }; - - // For currently selected entities, push a command to the UndoStack that uses the current entity properties for the - // redo command, and the saved properties for the undo command. - function pushCommandForSelections() { - var undoData = []; - var redoData = []; - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - var currentProperties = Entities.getEntityProperties(entityID); - undoData.push({ - entityID: entityID, - properties: { - position: initialProperties.position, - rotation: initialProperties.rotation, - dimensions: initialProperties.dimensions, - }, - }); - redoData.push({ - entityID: entityID, - properties: { - position: currentProperties.position, - rotation: currentProperties.rotation, - dimensions: currentProperties.dimensions, - }, - }); - } - UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); - } - var initialXZPick = null; var isConstrained = false; var startPosition = null; diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index aa38baf9e2..675e33ce90 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -671,8 +671,91 @@ Controller.keyReleaseEvent.connect(function (event) { if (isActive) { cameraManager.enable(); } + } else { + var delta = null; + + if (event.text == 'UP') { + if (event.isControl || event.isAlt) { + delta = { x: 0, y: 1, z: 0 }; + } else { + delta = { x: 0, y: 0, z: -1 }; + } + } else if (event.text == 'DOWN') { + if (event.isControl || event.isAlt) { + delta = { x: 0, y: -1, z: 0 }; + } else { + delta = { x: 0, y: 0, z: 1 }; + } + } else if (event.text == 'LEFT') { + delta = { x: -1, y: 0, z: 0 }; + } else if (event.text == 'RIGHT') { + delta = { x: 1, y: 0, z: 0 }; + } + + if (delta != null) { + // Adjust delta so that movements are relative to the current camera orientation + var lookDirection = Quat.getFront(Camera.getOrientation()); + lookDirection.z *= -1; + + var angle = Math.atan2(lookDirection.z, lookDirection.x); + angle -= (Math.PI / 4); + + var rotation = Math.floor(angle / (Math.PI / 2)) * (Math.PI / 2); + var rotator = Quat.fromPitchYawRollRadians(0, rotation, 0); + + delta = Vec3.multiplyQbyV(rotator, delta); + + SelectionManager.saveProperties(); + + for (var i = 0; i < selectionManager.selections.length; i++) { + var entityID = selectionManager.selections[i]; + var properties = Entities.getEntityProperties(entityID); + Entities.editEntity(entityID, { + position: Vec3.sum(properties.position, delta) + }); + } + + pushCommandForSelections(); + + selectionManager._update(); + } } }); +function applyEntityProperties(data) { + for (var i = 0; i < data.length; i++) { + var entityID = data[i].entityID; + var properties = data[i].properties; + Entities.editEntity(entityID, properties); + } + selectionManager._update(); +}; - +// For currently selected entities, push a command to the UndoStack that uses the current entity properties for the +// redo command, and the saved properties for the undo command. +function pushCommandForSelections() { + var undoData = []; + var redoData = []; + for (var i = 0; i < SelectionManager.selections.length; i++) { + var entityID = SelectionManager.selections[i]; + var initialProperties = SelectionManager.savedProperties[entityID.id]; + var currentProperties = Entities.getEntityProperties(entityID); + undoData.push({ + entityID: entityID, + properties: { + position: initialProperties.position, + rotation: initialProperties.rotation, + dimensions: initialProperties.dimensions, + }, + }); + redoData.push({ + entityID: entityID, + properties: { + position: currentProperties.position, + rotation: currentProperties.rotation, + dimensions: currentProperties.dimensions, + }, + }); + } + UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); +} From f3242d87781673bb57ae9d480c9387d1ecf97671 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 10:46:50 -0700 Subject: [PATCH 22/55] make PROP_DIFFUSE_COLOR a true property and wire up LightEntityProperties correctly --- .../entities/src/EntityItemProperties.cpp | 8 +++++-- libraries/entities/src/EntityItemProperties.h | 13 +++++------ libraries/entities/src/LightEntityItem.cpp | 22 ++++++++++++++++--- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index c95ec7cc2d..c05fe5417d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -80,6 +80,7 @@ EntityItemProperties::EntityItemProperties() : _localRenderAlphaChanged(false), _isSpotlightChanged(false), + _diffuseColor(), _ambientColor(), _specularColor(), _constantAttenuation(1.0f), @@ -88,6 +89,7 @@ EntityItemProperties::EntityItemProperties() : _exponent(0.0f), _cutoff(PI), + _diffuseColorChanged(false), _ambientColorChanged(false), _specularColorChanged(false), _constantAttenuationChanged(false), @@ -156,6 +158,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); + CHECK_PROPERTY_CHANGE(PROP_DIFFUSE_COLOR, diffuseColor); CHECK_PROPERTY_CHANGE(PROP_AMBIENT_COLOR, ambientColor); CHECK_PROPERTY_CHANGE(PROP_SPECULAR_COLOR, specularColor); CHECK_PROPERTY_CHANGE(PROP_CONSTANT_ATTENUATION, constantAttenuation); @@ -205,8 +208,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions); COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove); COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight); - - // NOTE: we do want this, so we will read both aliases diffuseColor and color COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(diffuseColor, getDiffuseColor()); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(ambientColor, getAmbientColor()); COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(specularColor, getSpecularColor()); @@ -438,6 +439,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, properties.getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, properties.getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, appendValue, properties.getIsSpotlight()); + APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, properties.getDiffuseColor()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, properties.getAmbientColor()); APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, properties.getSpecularColor()); APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, properties.getConstantAttenuation()); @@ -644,6 +646,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); + READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_DIFFUSE_COLOR, setDiffuseColor); READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_AMBIENT_COLOR, setAmbientColor); READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_SPECULAR_COLOR, setSpecularColor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CONSTANT_ATTENUATION, float, setConstantAttenuation); @@ -707,6 +710,7 @@ void EntityItemProperties::markAllChanged() { _localRenderAlphaChanged = true; _isSpotlightChanged = true; + _diffuseColorChanged = true; _ambientColorChanged = true; _specularColorChanged = true; _constantAttenuationChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3b72ee8111..5fef2151b2 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -51,7 +51,6 @@ enum EntityPropertyList { // these properties are supported by some derived classes PROP_COLOR, - PROP_DIFFUSE_COLOR = PROP_COLOR, // used by light class PROP_MODEL_URL, PROP_ANIMATION_URL, PROP_ANIMATION_FPS, @@ -67,6 +66,7 @@ enum EntityPropertyList { // property used by Light entity PROP_IS_SPOTLIGHT, + PROP_DIFFUSE_COLOR, PROP_AMBIENT_COLOR, PROP_SPECULAR_COLOR, PROP_CONSTANT_ATTENUATION, @@ -246,16 +246,11 @@ public: bool getIsSpotlight() const { return _isSpotlight; } void setIsSpotlight(bool value) { _isSpotlight = value; _isSpotlightChanged = true; } - // total hack for now - //void setDiffuseColor(const xColor& value) { setColor(value); } - //void setAmbientColor(const xColor& value) { setColor(value); } - //void setSpecularColor(const xColor& value) { setColor(value); } - - xColor getDiffuseColor() const { return _color; } // diffuseColor is an alias for color + xColor getDiffuseColor() const { return _diffuseColor; } xColor getAmbientColor() const { return _ambientColor; } xColor getSpecularColor() const { return _specularColor; } - void setDiffuseColor(const xColor& value) { _color = value; _colorChanged = true; } + void setDiffuseColor(const xColor& value) { _diffuseColor = value; _diffuseColorChanged = true; } void setAmbientColor(const xColor& value) { _ambientColor = value; _ambientColorChanged = true; } void setSpecularColor(const xColor& value) { _specularColor = value; _specularColorChanged = true; } @@ -345,6 +340,7 @@ private: bool _localRenderAlphaChanged; bool _isSpotlightChanged; + xColor _diffuseColor; xColor _ambientColor; xColor _specularColor; float _constantAttenuation; @@ -353,6 +349,7 @@ private: float _exponent; float _cutoff; + bool _diffuseColorChanged; bool _ambientColorChanged; bool _specularColorChanged; bool _constantAttenuationChanged; diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 3b58ec01cd..c4688fd63f 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -67,8 +67,7 @@ bool LightEntityItem::setProperties(const EntityItemProperties& properties, bool bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setDiffuseColor); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(diffuseColor, setDiffuseColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientColor, setAmbientColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(specularColor, setSpecularColor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); @@ -103,6 +102,11 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_COLOR(PROP_DIFFUSE_COLOR, _diffuseColor); READ_ENTITY_PROPERTY_COLOR(PROP_AMBIENT_COLOR, _ambientColor); READ_ENTITY_PROPERTY_COLOR(PROP_SPECULAR_COLOR, _specularColor); + READ_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, float, _constantAttenuation); + READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, float, _linearAttenuation); + READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, float, _quadraticAttenuation); + READ_ENTITY_PROPERTY(PROP_EXPONENT, float, _exponent); + READ_ENTITY_PROPERTY(PROP_CUTOFF, float, _cutoff); return bytesRead; } @@ -111,8 +115,15 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, // TODO: eventually only include properties changed since the params.lastViewFrustumSent time EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; requestedProperties += PROP_IS_SPOTLIGHT; + requestedProperties += PROP_DIFFUSE_COLOR; + requestedProperties += PROP_AMBIENT_COLOR; + requestedProperties += PROP_SPECULAR_COLOR; + requestedProperties += PROP_CONSTANT_ATTENUATION; + requestedProperties += PROP_LINEAR_ATTENUATION; + requestedProperties += PROP_QUADRATIC_ATTENUATION; + requestedProperties += PROP_EXPONENT; + requestedProperties += PROP_CUTOFF; return requestedProperties; } @@ -129,4 +140,9 @@ void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, appendColor, getDiffuseColor()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_COLOR, appendColor, getAmbientColor()); APPEND_ENTITY_PROPERTY(PROP_SPECULAR_COLOR, appendColor, getSpecularColor()); + APPEND_ENTITY_PROPERTY(PROP_CONSTANT_ATTENUATION, appendValue, getConstantAttenuation()); + APPEND_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION, appendValue, getLinearAttenuation()); + APPEND_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION, appendValue, getQuadraticAttenuation()); + APPEND_ENTITY_PROPERTY(PROP_EXPONENT, appendValue, getExponent()); + APPEND_ENTITY_PROPERTY(PROP_CUTOFF, appendValue, getCutoff()); } From e21bf78d04b9b696534175458c81ae0e434e1786 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 11:21:26 -0700 Subject: [PATCH 23/55] Remove cancel tool functionality --- examples/libraries/entitySelectionTool.js | 69 +++-------------------- examples/newEditEntities.js | 2 - 2 files changed, 7 insertions(+), 64 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 6ecf18bb00..25342e7f44 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1091,15 +1091,8 @@ SelectionDisplay = (function () { isConstrained = false; }, onEnd: function(event, reason) { - if (reason == 'cancel') { - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - Entities.editEntity(entityID, initialProperties); - } - } else { - pushCommandForSelections(); - } + pushCommandForSelections(duplicatedEntityIDs); + Overlays.editOverlay(xRailOverlay, { visible: false }); Overlays.editOverlay(zRailOverlay, { visible: false }); }, @@ -1162,15 +1155,7 @@ SelectionDisplay = (function () { SelectionManager.saveProperties(); }, onEnd: function(event, reason) { - if (reason == 'cancel') { - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - Entities.editEntity(entityID, initialProperties); - } - } else { - pushCommandForSelections(); - } + pushCommandForSelections(); }, onMove: function(event) { pickRay = Camera.computePickRay(event.x, event.y); @@ -1321,15 +1306,7 @@ SelectionDisplay = (function () { Overlays.editOverlay(yRailOverlay, { visible: false }); Overlays.editOverlay(zRailOverlay, { visible: false }); - if (reason == 'cancel') { - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - Entities.editEntity(entityID, initialProperties); - } - } else { - pushCommandForSelections(); - } + pushCommandForSelections(); }; var onMove = function(event) { @@ -1425,14 +1402,6 @@ SelectionDisplay = (function () { }; }; - that.cancelTool = function() { - if (activeTool) { - activeTool.onEnd(null, 'cancel'); - activeTool = null; - SelectionManager._update(); - } - }; - function addStretchTool(overlay, mode, pivot, direction) { if (!pivot) { pivot = Vec3.multiply(-1, direction); @@ -1518,15 +1487,7 @@ SelectionDisplay = (function () { Overlays.editOverlay(rotateOverlayOuter, { visible: false }); Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - if (reason == 'cancel') { - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - Entities.editEntity(entityID, initialProperties); - } - } else { - pushCommandForSelections(); - } + pushCommandForSelections(); }, onMove: function(event) { var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); @@ -1658,15 +1619,7 @@ SelectionDisplay = (function () { Overlays.editOverlay(rotateOverlayOuter, { visible: false }); Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - if (reason == 'cancel') { - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - Entities.editEntity(entityID, initialProperties); - } - } else { - pushCommandForSelections(); - } + pushCommandForSelections(); }, onMove: function(event) { var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); @@ -1796,15 +1749,7 @@ SelectionDisplay = (function () { Overlays.editOverlay(rotateOverlayOuter, { visible: false }); Overlays.editOverlay(rotateOverlayCurrent, { visible: false }); - if (reason == 'cancel') { - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - Entities.editEntity(entityID, initialProperties); - } - } else { - pushCommandForSelections(); - } + pushCommandForSelections(); }, onMove: function(event) { var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 675e33ce90..c53e2e9f2e 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -659,8 +659,6 @@ Controller.keyReleaseEvent.connect(function (event) { handeMenuEvent("Delete"); } else if (event.text == "TAB") { selectionDisplay.toggleSpaceMode(); - } else if (event.text == "ESC") { - selectionDisplay.cancelTool(); } else if (event.text == "f") { if (entitySelected) { // Get latest properties From 9c30903eb67e6339da4038c145e2b860838b99cc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 12:05:56 -0700 Subject: [PATCH 24/55] add the VerboseLoggingHelper class for repeated messages --- libraries/shared/src/VerboseLoggingHelper.cpp | 34 ++++++++++++++++++ libraries/shared/src/VerboseLoggingHelper.h | 36 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 libraries/shared/src/VerboseLoggingHelper.cpp create mode 100644 libraries/shared/src/VerboseLoggingHelper.h diff --git a/libraries/shared/src/VerboseLoggingHelper.cpp b/libraries/shared/src/VerboseLoggingHelper.cpp new file mode 100644 index 0000000000..6fa3f8a5a5 --- /dev/null +++ b/libraries/shared/src/VerboseLoggingHelper.cpp @@ -0,0 +1,34 @@ +// +// VerboseLoggingHelper.cpp +// libraries/shared/src +// +// Created by Stephen Birarda on 2014-10-28. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "VerboseLoggingHelper.h" + +VerboseLoggingHelper& VerboseLoggingHelper::getInstance() { + static VerboseLoggingHelper sharedInstance; + return sharedInstance; +} + +VerboseLoggingHelper::VerboseLoggingHelper() { + // setup our timer to flush the verbose logs every 5 seconds + _timer = new QTimer(this); + connect(_timer, &QTimer::timeout, this, &VerboseLoggingHelper::flushMessages); + _timer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); +} + +void VerboseLoggingHelper::flushMessages() { + QHash::iterator message = _messageCountHash.begin(); + while (message != _messageCountHash.end()) { + qDebug() << message.key().arg(message.value()); + message = _messageCountHash.erase(message); + } +} \ No newline at end of file diff --git a/libraries/shared/src/VerboseLoggingHelper.h b/libraries/shared/src/VerboseLoggingHelper.h new file mode 100644 index 0000000000..368dfa51e6 --- /dev/null +++ b/libraries/shared/src/VerboseLoggingHelper.h @@ -0,0 +1,36 @@ +// +// VerboseLoggingHelper.h +// libraries/shared/src +// +// Created by Stephen Birarda on 2014-10-28. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_VerboseLoggingHelper_h +#define hifi_VerboseLoggingHelper_h + +#include +#include +#include + +const int VERBOSE_LOG_INTERVAL_SECONDS = 5; + +class VerboseLoggingHelper : public QObject { + Q_OBJECT +public: + static VerboseLoggingHelper& getInstance(); + + void addMessage(const QString& message) { _messageCountHash[message] += 1; } +private: + VerboseLoggingHelper(); + + void flushMessages(); + + QTimer* _timer; + QHash _messageCountHash; +}; + +#endif // hifi_VerboseLoggingHelper_h \ No newline at end of file From 8a4c716452ae0c1dd95468ffe0eafff1ee4d83a1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 12:15:52 -0700 Subject: [PATCH 25/55] leverage the VerboseLoggingHelper for packets from unknown nodes --- libraries/networking/src/LimitedNodeList.cpp | 8 ++++++-- libraries/shared/src/VerboseLoggingHelper.cpp | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 919dc75c23..93f50b2824 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" @@ -211,8 +213,10 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { - qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" - << uuidFromPacketHeader(packet); + QString unknownPacketString = "%1 packets of type " + QString::number(checkType) + + " received from unknown node with UUID " + + uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); + VerboseLoggingHelper::getInstance().addMessage(unknownPacketString); } } else { return true; diff --git a/libraries/shared/src/VerboseLoggingHelper.cpp b/libraries/shared/src/VerboseLoggingHelper.cpp index 6fa3f8a5a5..ae014f425d 100644 --- a/libraries/shared/src/VerboseLoggingHelper.cpp +++ b/libraries/shared/src/VerboseLoggingHelper.cpp @@ -28,7 +28,8 @@ VerboseLoggingHelper::VerboseLoggingHelper() { void VerboseLoggingHelper::flushMessages() { QHash::iterator message = _messageCountHash.begin(); while (message != _messageCountHash.end()) { - qDebug() << message.key().arg(message.value()); + qDebug() << qPrintable(message.key().arg(message.value())) + << "in last" << VERBOSE_LOG_INTERVAL_SECONDS << "seconds."; message = _messageCountHash.erase(message); } } \ No newline at end of file From 8570088f9d119bd54346113444d8ae933ae2004d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 12:26:45 -0700 Subject: [PATCH 26/55] added light exampple --- examples/spotlightExample.js | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 examples/spotlightExample.js diff --git a/examples/spotlightExample.js b/examples/spotlightExample.js new file mode 100644 index 0000000000..5eb5432f3f --- /dev/null +++ b/examples/spotlightExample.js @@ -0,0 +1,37 @@ +// +// spotlightExample.js +// examples +// +// Created by Brad Hefta-Gaub on 10/28/14. +// Copyright 2014 High Fidelity, Inc. +// +// This is an example script that demonstrates creating and editing a particle +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var lightProperties = { + type: "Light", + position: { x: 0, y: 0, z: 0 }, + dimensions: { x: 1000, y: 1000, z: 1000 }, + angularVelocity: { x: 0, y: 10, z: 0 }, + angularDamping: 0, + + isSpotlight: true, + diffuseColor: { red: 255, green: 255, blue: 255 }, + ambientColor: { red: 255, green: 255, blue: 255 }, + specularColor: { red: 255, green: 255, blue: 255 }, + + constantAttenuation: 1, + linearAttenuation: 0, + quadraticAttenuation: 0, + exponent: 0, + cutoff: 180, // in degrees +}; + +var spotlightID = Entities.addEntity(lightProperties); + +Script.scriptEnding.connect(function() { + Entities.deleteEntity(spotlightID); +}); From c3cd733c2f3fb811146b029b8ffd7ead594dc639 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 12:40:17 -0700 Subject: [PATCH 27/55] tweaks to edits for lights --- examples/libraries/entityPropertyDialogBox.js | 15 +++++++++++++++ examples/newEditEntities.js | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index a5d9dd2510..c23f8b0dcc 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -167,6 +167,16 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Specular Blue:", value: properties.specularColor.blue }); index++; + array.push({ label: "Constant Attenuation:", value: properties.constantAttenuation }); + index++; + array.push({ label: "Linear Attenuation:", value: properties.linearAttenuation }); + index++; + array.push({ label: "Quadratic Attenuation:", value: properties.quadraticAttenuation }); + index++; + array.push({ label: "Exponent:", value: properties.exponent }); + index++; + array.push({ label: "Cutoff (in degrees):", value: properties.cutoff }); + index++; } array.push({ button: "Cancel" }); index++; @@ -280,6 +290,11 @@ EntityPropertyDialogBox = (function () { properties.specularColor.red = array[index++].value; properties.specularColor.green = array[index++].value; properties.specularColor.blue = array[index++].value; + properties.constantAttenuation = array[index++].value; + properties.linearAttenuation = array[index++].value; + properties.quadraticAttenuation = array[index++].value; + properties.exponent = array[index++].value; + properties.cutoff = array[index++].value; } Entities.editEntity(editModelID, properties); diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index edfe8c1b9d..5ecbe2459c 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -159,7 +159,7 @@ var toolBar = (function () { }); newLightButton = toolBar.addTool({ - imageURL: toolIconUrl + "add-fire.svg", + imageURL: toolIconUrl + "light.svg", subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: toolWidth, height: toolHeight, From 8f53e1731b1f8c556a88c84ba85dd73764c4f613 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 12:40:44 -0700 Subject: [PATCH 28/55] Add selectionManager.setSelections and hasSelection --- examples/libraries/entitySelectionTool.js | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 25342e7f44..f1ce6fc659 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -45,8 +45,20 @@ SelectionManager = (function() { that.eventListener = func; }; + that.hasSelection = function() { + return that.selections.length > 0; + }; + + that.setSelections = function(entityIDs) { + that.selections = []; + for (var i = 0; i < entityIDs.length; i++) { + that.selections.push(entityIDs[i]); + } + + that._update(); + }; + that.addEntity = function(entityID) { - print("Adding: " + entityID.id); var idx = that.selections.indexOf(entityID); if (idx == -1) { that.selections.push(entityID); @@ -77,8 +89,6 @@ SelectionManager = (function() { that.worldDimensions = null; that.worldPosition = null; } else if (that.selections.length == 1) { - SelectionDisplay.setSpaceMode(SPACE_LOCAL); - var properties = Entities.getEntityProperties(that.selections[0]); that.localDimensions = properties.dimensions; that.localPosition = properties.position; @@ -86,10 +96,9 @@ SelectionManager = (function() { that.worldDimensions = properties.boundingBox.dimensions; that.worldPosition = properties.boundingBox.center; - } else { - // For 1+ selections we can only modify selections in world space - SelectionDisplay.setSpaceMode(SPACE_WORLD); + SelectionDisplay.setSpaceMode(SPACE_LOCAL); + } else { that.localRotation = null; that.localDimensions = null; that.localPosition = null; @@ -122,6 +131,9 @@ SelectionManager = (function() { y: brn.y + (that.worldDimensions.y / 2), z: brn.z + (that.worldDimensions.z / 2), }; + + // For 1+ selections we can only modify selections in world space + SelectionDisplay.setSpaceMode(SPACE_WORLD); } if (that.eventListener) { From 8debb33c6ad445c8d54ea2b8812956be073d6ab2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 12:44:57 -0700 Subject: [PATCH 29/55] default light properties --- examples/newEditEntities.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 5ecbe2459c..6369f87417 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -342,7 +342,16 @@ var toolBar = (function () { type: "Light", position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, - color: { red: 255, green: 0, blue: 0 } + isSpotlight: false, + diffuseColor: { red: 255, green: 255, blue: 255 }, + ambientColor: { red: 255, green: 255, blue: 255 }, + specularColor: { red: 0, green: 0, blue: 0 }, + + constantAttenuation: 1, + linearAttenuation: 0, + quadraticAttenuation: 0, + exponent: 0, + cutoff: 180, // in degrees }); } else { print("Can't create Light: Light would be out of bounds."); From 6c63c2ecd94fe83e1f78b4c09f39635a852b6c34 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 12:47:46 -0700 Subject: [PATCH 30/55] cleanup --- libraries/entities/src/LightEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index c4688fd63f..20f28cd98c 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -51,7 +51,7 @@ EntityItemProperties LightEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight); - properties.setDiffuseColor(getDiffuseXColor()); // special case + COPY_ENTITY_PROPERTY_TO_PROPERTIES(diffuseColor, getDiffuseXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientColor, getAmbientXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(specularColor, getSpecularXColor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(constantAttenuation, getConstantAttenuation); From f26bf5e07b01d56c57fcf1807d0ce7ff702431c8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 13:19:47 -0700 Subject: [PATCH 31/55] duh --- libraries/entities/src/LightEntityItem.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index ff5e1e725d..2006efb896 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -80,20 +80,20 @@ public: bool getIsSpotlight() const { return _isSpotlight; } void setIsSpotlight(bool value) { _isSpotlight = value; } - bool getConstantAttenuation() const { return _constantAttenuation; } + float getConstantAttenuation() const { return _constantAttenuation; } void setConstantAttenuation(float value) { _constantAttenuation = value; } - bool getLinearAttenuation() const { return _linearAttenuation; } + float getLinearAttenuation() const { return _linearAttenuation; } void setLinearAttenuation(float value) { _linearAttenuation = value; } - bool getQuadraticAttenuation() const { return _quadraticAttenuation; } + float getQuadraticAttenuation() const { return _quadraticAttenuation; } void setQuadraticAttenuation(float value) { _quadraticAttenuation = value; } - bool getExponent() const { return _exponent; } - void setExponent(bool value) { _exponent = value; } + float getExponent() const { return _exponent; } + void setExponent(float value) { _exponent = value; } - bool getCutoff() const { return _cutoff; } - void setCutoff(bool value) { _cutoff = value; } + float getCutoff() const { return _cutoff; } + void setCutoff(float value) { _cutoff = value; } virtual const Shape& getCollisionShapeInMeters() const { return _emptyShape; } From 68f51d2484c8e10435da7c609c06746f6ce32efb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 13:39:41 -0700 Subject: [PATCH 32/55] Add entity tool support for unkown entity ids --- examples/libraries/entitySelectionTool.js | 65 +++++++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index f1ce6fc659..c7cf678bde 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -19,10 +19,15 @@ SPACE_WORLD = "world"; SelectionManager = (function() { var that = {}; + var PENDING_SELECTION_CHECK_INTERVAL = 50; + that.savedProperties = {}; that.eventListener = null; that.selections = []; + // These are selections that don't have a known ID yet + that.pendingSelections = []; + var pendingSelectionTimer = null; that.localRotation = Quat.fromPitchYawRollDegrees(0, 0, 0); that.localPosition = { x: 0, y: 0, z: 0 }; @@ -52,16 +57,57 @@ SelectionManager = (function() { that.setSelections = function(entityIDs) { that.selections = []; for (var i = 0; i < entityIDs.length; i++) { - that.selections.push(entityIDs[i]); + var entityID = entityIDs[i]; + if (entityID.isKnownID) { + print('known!'); + that.selections.push(entityID); + } else { + print('not known!'); + that.pendingSelections.push(entityID); + if (pendingSelectionTimer == null) { + pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL); + } + } } that._update(); }; + that._checkPendingSelections = function() { + print("CHECKING PENDING SELCTIONS"); + for (var i = 0; i < that.pendingSelections.length; i++) { + var entityID = that.pendingSelections[i]; + var newEntityID = Entities.identifyEntity(entityID); + if (newEntityID.isKnownID) { + print("is known!"); + that.pendingSelections.splice(i, 1); + that.addEntity(newEntityID); + i--; + } + } + + if (that.pendingSelections.length == 0) { + Script.clearInterval(pendingSelectionTimer); + pendingSelectionTimer = null; + } + } + that.addEntity = function(entityID) { - var idx = that.selections.indexOf(entityID); - if (idx == -1) { - that.selections.push(entityID); + if (entityID.isKnownID) { + print('known: ' + entityID.id); + var idx = that.selections.indexOf(entityID); + if (idx == -1) { + that.selections.push(entityID); + } + } else { + print('not known!'); + var idx = that.pendingSelections.indexOf(entityID); + if (idx == -1) { + that.pendingSelections.push(entityID); + if (pendingSelectionTimer == null) { + pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL); + } + } } that._update(); @@ -73,11 +119,22 @@ SelectionManager = (function() { that.selections.splice(idx, 1); } + var idx = that.pendingSelections.indexOf(entityID); + if (idx >= 0) { + that.pendingSelections.splice(idx, 1); + } + that._update(); }; that.clearSelections = function() { that.selections = []; + that.pendingSelections = []; + + if (pendingSelectionTimer !== null) { + Script.clearInterval(pendingSelectionTimer); + pendingSelectionTimer = null; + } that._update(); }; From 76c3e9f483aedc329bc493f114e104ff52d35022 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 13:42:02 -0700 Subject: [PATCH 33/55] Add support for undoing duplication and deletion commands --- examples/libraries/entitySelectionTool.js | 27 +++++++- examples/newEditEntities.js | 82 ++++++++++++++++++----- 2 files changed, 92 insertions(+), 17 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index c7cf678bde..e9d65eff1d 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1137,6 +1137,7 @@ SelectionDisplay = (function () { var initialXZPick = null; var isConstrained = false; var startPosition = null; + var duplicatedEntityIDs = null; var translateXZTool = { mode: 'TRANSLATE_XZ', onBegin: function(event) { @@ -1151,10 +1152,17 @@ SelectionDisplay = (function () { // copy of the selected entities and move the _original_ entities, not // the new ones. if (event.isAlt) { + duplicatedEntityIDs = []; for (var otherEntityID in SelectionManager.savedProperties) { var properties = SelectionManager.savedProperties[otherEntityID]; var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties, + }); } + } else { + duplicatedEntityIDs = null; } isConstrained = false; @@ -1222,9 +1230,26 @@ SelectionDisplay = (function () { mode: "TRANSLATE_UP_DOWN", onBegin: function(event) { SelectionManager.saveProperties(); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt) { + duplicatedEntityIDs = []; + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties, + }); + } + } else { + duplicatedEntityIDs = null; + } }, onEnd: function(event, reason) { - pushCommandForSelections(); + pushCommandForSelections(duplicatedEntityIDs); }, onMove: function(event) { pickRay = Camera.computePickRay(event.x, event.y); diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index c53e2e9f2e..d9b2f95b3d 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -606,14 +606,24 @@ function handeMenuEvent(menuItem) { } else if (menuItem == "Allow Select Large Models") { allowLargeModels = Menu.isOptionChecked("Allow Select Large Models"); } else if (menuItem == "Delete") { - if (entitySelected) { + if (SelectionManager.hasSelection()) { print(" Delete Entity.... selectedEntityID="+ selectedEntityID); + SelectionManager.saveProperties(); + var savedProperties = []; for (var i = 0; i < selectionManager.selections.length; i++) { - Entities.deleteEntity(selectionManager.selections[i]); + var entityID = SelectionManager.selections[i]; + var initialProperties = SelectionManager.savedProperties[entityID.id]; + SelectionManager.savedProperties[entityID.id]; + savedProperties.push({ + entityID: entityID, + properties: initialProperties + }); + Entities.deleteEntity(entityID); } + SelectionManager.clearSelections(); + pushCommandForSelections([], savedProperties); selectionDisplay.unselect(selectedEntityID); entitySelected = false; - selectionManager.clearSelections(); } else { print(" Delete Entity.... not holding..."); } @@ -623,15 +633,16 @@ function handeMenuEvent(menuItem) { editModelID = -1; if (selectionManager.selections.length == 1) { print(" Edit Properties.... selectedEntityID="+ selectedEntityID); - editModelID = 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") { @@ -720,25 +731,64 @@ Controller.keyReleaseEvent.connect(function (event) { } }); +// When an entity has been deleted we need a way to "undo" this deletion. Because it's not currently +// possible to create an entity with a specific id, earlier undo commands to the deleted entity +// will fail if there isn't a way to find the new entity id. +DELETED_ENTITY_MAP = { +} + function applyEntityProperties(data) { - for (var i = 0; i < data.length; i++) { - var entityID = data[i].entityID; - var properties = data[i].properties; - Entities.editEntity(entityID, properties); + var properties = data.setProperties; + var selectedEntityIDs = []; + for (var i = 0; i < properties.length; i++) { + var entityID = properties[i].entityID; + if (DELETED_ENTITY_MAP[entityID.id] !== undefined) { + entityID = DELETED_ENTITY_MAP[entityID.id]; + } + Entities.editEntity(entityID, properties[i].properties); + selectedEntityIDs.push(entityID); } - selectionManager._update(); + for (var i = 0; i < data.createEntities.length; i++) { + var entityID = data.createEntities[i].entityID; + var properties = data.createEntities[i].properties; + var newEntityID = Entities.addEntity(properties); + DELETED_ENTITY_MAP[entityID.id] = newEntityID; + print(newEntityID.isKnownID); + if (data.selectCreated) { + selectedEntityIDs.push(newEntityID); + } + } + for (var i = 0; i < data.deleteEntities.length; i++) { + var entityID = data.deleteEntities[i].entityID; + if (DELETED_ENTITY_MAP[entityID.id] !== undefined) { + entityID = DELETED_ENTITY_MAP[entityID.id]; + } + Entities.deleteEntity(entityID); + } + + selectionManager.setSelections(selectedEntityIDs); }; // For currently selected entities, push a command to the UndoStack that uses the current entity properties for the -// redo command, and the saved properties for the undo command. -function pushCommandForSelections() { - var undoData = []; - var redoData = []; +// redo command, and the saved properties for the undo command. Also, include create and delete entity data. +function pushCommandForSelections(createdEntityData, deletedEntityData) { + var undoData = { + setProperties: [], + createEntities: deletedEntityData || [], + deleteEntities: createdEntityData || [], + selectCreated: true, + }; + var redoData = { + setProperties: [], + createEntities: createdEntityData || [], + deleteEntities: deletedEntityData || [], + selectCreated: false, + }; for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; var initialProperties = SelectionManager.savedProperties[entityID.id]; var currentProperties = Entities.getEntityProperties(entityID); - undoData.push({ + undoData.setProperties.push({ entityID: entityID, properties: { position: initialProperties.position, @@ -746,7 +796,7 @@ function pushCommandForSelections() { dimensions: initialProperties.dimensions, }, }); - redoData.push({ + redoData.setProperties.push({ entityID: entityID, properties: { position: currentProperties.position, From af103b22ff9f91d098e610ff5f87dd6c19ed4c31 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 13:42:40 -0700 Subject: [PATCH 34/55] Remove extra print statements and whitespace --- examples/libraries/entitySelectionTool.js | 6 ------ examples/newEditEntities.js | 26 +++++++++++------------ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index e9d65eff1d..1d0001a592 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -59,10 +59,8 @@ SelectionManager = (function() { for (var i = 0; i < entityIDs.length; i++) { var entityID = entityIDs[i]; if (entityID.isKnownID) { - print('known!'); that.selections.push(entityID); } else { - print('not known!'); that.pendingSelections.push(entityID); if (pendingSelectionTimer == null) { pendingSelectionTimer = Script.setInterval(that._checkPendingSelections, PENDING_SELECTION_CHECK_INTERVAL); @@ -74,12 +72,10 @@ SelectionManager = (function() { }; that._checkPendingSelections = function() { - print("CHECKING PENDING SELCTIONS"); for (var i = 0; i < that.pendingSelections.length; i++) { var entityID = that.pendingSelections[i]; var newEntityID = Entities.identifyEntity(entityID); if (newEntityID.isKnownID) { - print("is known!"); that.pendingSelections.splice(i, 1); that.addEntity(newEntityID); i--; @@ -94,13 +90,11 @@ SelectionManager = (function() { that.addEntity = function(entityID) { if (entityID.isKnownID) { - print('known: ' + entityID.id); var idx = that.selections.indexOf(entityID); if (idx == -1) { that.selections.push(entityID); } } else { - print('not known!'); var idx = that.pendingSelections.indexOf(entityID); if (idx == -1) { that.pendingSelections.push(entityID); diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index d9b2f95b3d..68d5965b1a 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -1,4 +1,4 @@ -// + // newEditEntities.js // examples // @@ -272,7 +272,7 @@ var toolBar = (function () { toggleNewModelButton(false); file = Window.browse("Select your model file ...", - Settings.getValue("LastModelUploadLocation").path(), + Settings.getValue("LastModelUploadLocation").path(), "Model files (*.fst *.fbx)"); //"Model files (*.fst *.fbx *.svo)"); if (file !== null) { @@ -295,7 +295,7 @@ var toolBar = (function () { var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ + Entities.addEntity({ type: "Box", position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, @@ -312,7 +312,7 @@ var toolBar = (function () { var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ + Entities.addEntity({ type: "Sphere", position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, @@ -433,7 +433,7 @@ function mousePressEvent(event) { var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) + var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); if (0 < x && sizeOK) { @@ -467,7 +467,7 @@ function mousePressEvent(event) { w: selectedEntityProperties.rotation.w, }; selectedEntityProperties.glowLevel = 0.0; - + print("Clicked on " + selectedEntityID.id + " " + entitySelected); tooltip.updateText(selectedEntityProperties); tooltip.show(true); @@ -481,7 +481,7 @@ function mouseMoveEvent(event) { if (!isActive) { return; } - + // allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) { return; @@ -496,11 +496,11 @@ function mouseMoveEvent(event) { } var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), + + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), entityIntersection.properties.position)) * 180 / 3.14; - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) + var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); if (entityIntersection.entityID.isKnownID && sizeOK) { @@ -510,7 +510,7 @@ function mouseMoveEvent(event) { highlightedEntityID = entityIntersection.entityID; selectionDisplay.highlightSelectable(entityIntersection.entityID); } - + } } @@ -550,9 +550,9 @@ function setupModelMenus() { } Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S", + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S", afterItem: "Allow Select Large Models", isCheckable: true }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); From cce1e23eec54cfc173974cbf24a87571d1141498 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 13:43:22 -0700 Subject: [PATCH 35/55] Update UndoStackScriptingInterface to not call redo automatically --- .../script-engine/src/UndoStackScriptingInterface.cpp | 8 ++++++-- libraries/script-engine/src/UndoStackScriptingInterface.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp index ed0f4d563d..6ee3735c13 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.cpp +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -30,6 +30,7 @@ void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScript ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData) : + _hasRedone(false), _undoFunction(undoFunction), _undoData(undoData), _redoFunction(redoFunction), @@ -41,7 +42,11 @@ void ScriptUndoCommand::undo() { } void ScriptUndoCommand::redo() { - QMetaObject::invokeMethod(this, "doRedo"); + if (_hasRedone) { + qDebug() << "Doing redo!"; + QMetaObject::invokeMethod(this, "doRedo"); + } + _hasRedone = true; } void ScriptUndoCommand::doUndo() { @@ -50,7 +55,6 @@ void ScriptUndoCommand::doUndo() { _undoFunction.call(QScriptValue(), args); } - void ScriptUndoCommand::doRedo() { QScriptValueList args; args << _redoData; diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.h b/libraries/script-engine/src/UndoStackScriptingInterface.h index 835e5dfff4..479648fc92 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.h +++ b/libraries/script-engine/src/UndoStackScriptingInterface.h @@ -43,6 +43,7 @@ public slots: void doRedo(); private: + bool _hasRedone; QScriptValue _undoFunction; QScriptValue _undoData; QScriptValue _redoFunction; From bdfdeecc46ba2cf11ba7f059eb35c09f306de0c8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 13:45:31 -0700 Subject: [PATCH 36/55] Fix bug with entity selection shadow --- examples/libraries/entitySelectionTool.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 1d0001a592..a325491dd3 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -894,16 +894,9 @@ SelectionDisplay = (function () { translateHandlesVisible = false; } - var dimensions, rotation, position; - if (spaceMode == SPACE_LOCAL) { - rotation = SelectionManager.localRotation; - dimensions = SelectionManager.localDimensions; - position = SelectionManager.localPosition; - } else { - rotation = SelectionManager.worldRotation; - dimensions = SelectionManager.worldDimensions; - position = SelectionManager.worldPosition; - } + var rotation = SelectionManager.worldRotation; + var dimensions = SelectionManager.worldDimensions; + var position = SelectionManager.worldPosition; Overlays.editOverlay(baseOfEntityProjectionOverlay, { From c802c74396689e4e6ebd81c4917ec7c4e4d79ef8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 28 Oct 2014 13:48:48 -0700 Subject: [PATCH 37/55] Add comment to new redo functionality --- libraries/script-engine/src/UndoStackScriptingInterface.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp index 6ee3735c13..17bf8b1aa6 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.cpp +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -42,8 +42,12 @@ void ScriptUndoCommand::undo() { } void ScriptUndoCommand::redo() { + // QUndoStack will call `redo()` when adding a command to the stack. This + // makes it difficult to work with commands that span a period of time - for instance, + // the entity duplicate + move command that duplicates an entity and then moves it. + // A better implementation might be to properly implement `mergeWith()` and `id()` + // so that the two actions in the example would be merged. if (_hasRedone) { - qDebug() << "Doing redo!"; QMetaObject::invokeMethod(this, "doRedo"); } _hasRedone = true; From 2711ff2b5f9e895888ce1a65779f82846be29f53 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 13:48:53 -0700 Subject: [PATCH 38/55] move functionality from VerboseLoggingHelper into the Logging class --- interface/src/Application.cpp | 4 -- libraries/networking/src/LimitedNodeList.cpp | 8 +-- libraries/networking/src/Logging.cpp | 69 +++++-------------- libraries/networking/src/Logging.h | 41 +++++------ libraries/shared/src/VerboseLoggingHelper.cpp | 35 ---------- libraries/shared/src/VerboseLoggingHelper.h | 36 ---------- 6 files changed, 38 insertions(+), 155 deletions(-) delete mode 100644 libraries/shared/src/VerboseLoggingHelper.cpp delete mode 100644 libraries/shared/src/VerboseLoggingHelper.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 140e51ee3e..f0bd2fb66c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -581,10 +581,6 @@ void Application::initializeGL() { float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; _justStarted = false; qDebug("Startup time: %4.2f seconds.", startupTime); - const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; - - // ask the Logstash class to record the startup time - Logging::stashValue(STAT_TYPE_TIMER, LOGSTASH_INTERFACE_START_TIME_KEY, startupTime); } // update before the first render diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 93f50b2824..46ab4f4b0b 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -19,8 +19,6 @@ #include #include -#include - #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" @@ -213,10 +211,8 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { - QString unknownPacketString = "%1 packets of type " + QString::number(checkType) - + " received from unknown node with UUID " - + uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); - VerboseLoggingHelper::getInstance().addMessage(unknownPacketString); + qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" + << uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); } } else { return true; diff --git a/libraries/networking/src/Logging.cpp b/libraries/networking/src/Logging.cpp index f42f1bda58..bb704729af 100644 --- a/libraries/networking/src/Logging.cpp +++ b/libraries/networking/src/Logging.cpp @@ -9,12 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include -//#include // not available on windows, apparently not needed on mac - #ifdef _WIN32 #include #define getpid _getpid @@ -22,55 +16,22 @@ #define pid_t int // hack to build #endif -#include - -#include "HifiSockAddr.h" -#include "SharedUtil.h" -#include "NodeList.h" +#include #include "Logging.h" -HifiSockAddr Logging::_logstashSocket = HifiSockAddr(); QString Logging::_targetName = QString(); -const HifiSockAddr& Logging::socket() { - - if (_logstashSocket.getAddress().isNull()) { - // we need to construct the socket object - // use the constant port - _logstashSocket.setPort(htons(LOGSTASH_UDP_PORT)); - - // lookup the IP address for the constant hostname - QHostInfo hostInfo = QHostInfo::fromName(LOGSTASH_HOSTNAME); - if (!hostInfo.addresses().isEmpty()) { - // use the first IP address - _logstashSocket.setAddress(hostInfo.addresses().first()); - } else { - qDebug("Failed to lookup logstash IP - will try again on next log attempt."); - } - } - - return _logstashSocket; +Logging& Logging::getInstance() { + static Logging staticInstance; + return staticInstance; } -bool Logging::shouldSendStats() { - static bool shouldSendStats = isInEnvironment("production"); - return shouldSendStats; -} - -void Logging::stashValue(char statType, const char* key, float value) { - static char logstashPacket[MAX_PACKET_SIZE]; - - // load up the logstash packet with the key and the passed float value - // send it to 4 decimal places - int numPacketBytes = sprintf(logstashPacket, "%c %s %.4f", statType, key, value); - - NodeList *nodeList = NodeList::getInstance(); - - if (nodeList) { - nodeList->getNodeSocket().writeDatagram(logstashPacket, numPacketBytes, - _logstashSocket.getAddress(), _logstashSocket.getPort()); - } +Logging::Logging() { + // setup our timer to flush the verbose logs every 5 seconds + QTimer* logFlushTimer = new QTimer(this); + connect(logFlushTimer, &QTimer::timeout, this, &Logging::flushRepeatedMessages); + logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); } const char* stringForLogType(QtMsgType msgType) { @@ -95,6 +56,7 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co if (message.isEmpty()) { return; } + // log prefix is in the following format // [DEBUG] [TIMESTAMP] [PID:PARENT_PID] [TARGET] logged string @@ -118,9 +80,16 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co prefixString.append("]"); } - if (!_targetName.isEmpty()) { - prefixString.append(QString(" [%1]").arg(_targetName)); + if (!getInstance()._targetName.isEmpty()) { + prefixString.append(QString(" [%1]").arg(getInstance()._targetName)); } fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData()); } + +void Logging::flushRepeatedMessages() { + QHash::iterator message = _repeatMessageCountHash.begin(); + while (message != _repeatMessageCountHash.end()) { + message = _repeatMessageCountHash.erase(message); + } +} diff --git a/libraries/networking/src/Logging.h b/libraries/networking/src/Logging.h index c52812bd33..458cbf90e8 100644 --- a/libraries/networking/src/Logging.h +++ b/libraries/networking/src/Logging.h @@ -12,33 +12,18 @@ #ifndef hifi_Logging_h #define hifi_Logging_h -#include +#include +#include +#include +#include +#include -const int LOGSTASH_UDP_PORT = 9500; -const char LOGSTASH_HOSTNAME[] = "graphite.highfidelity.io"; - -const char STAT_TYPE_TIMER = 't'; -const char STAT_TYPE_COUNTER = 'c'; -const char STAT_TYPE_GAUGE = 'g'; - -class HifiSockAddr; +const int VERBOSE_LOG_INTERVAL_SECONDS = 5; /// Handles custom message handling and sending of stats/logs to Logstash instance -class Logging { +class Logging : public QObject { + Q_OBJECT public: - /// \return the socket used to send stats to logstash - static const HifiSockAddr& socket(); - - /// checks if this target should send stats to logstash, given its current environment - /// \return true if the caller should send stats to logstash - static bool shouldSendStats(); - - /// stashes a float value to Logstash instance - /// \param statType a stat type from the constants in this file - /// \param key the key at which to store the stat - /// \param value the value to store - static void stashValue(char statType, const char* key, float value); - /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs static void setTargetName(const QString& targetName) { _targetName = targetName; } @@ -46,9 +31,17 @@ public: /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); + + static void addRepeatedMessageRegex(const QRegExp& regex) { getInstance()._repeatedMessageRegexes.append(regex); } private: - static HifiSockAddr _logstashSocket; + static Logging& getInstance(); + Logging(); + + void flushRepeatedMessages(); + static QString _targetName; + QList _repeatedMessageRegexes; + QHash _repeatMessageCountHash; }; #endif // hifi_Logging_h diff --git a/libraries/shared/src/VerboseLoggingHelper.cpp b/libraries/shared/src/VerboseLoggingHelper.cpp deleted file mode 100644 index ae014f425d..0000000000 --- a/libraries/shared/src/VerboseLoggingHelper.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// VerboseLoggingHelper.cpp -// libraries/shared/src -// -// Created by Stephen Birarda on 2014-10-28. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "VerboseLoggingHelper.h" - -VerboseLoggingHelper& VerboseLoggingHelper::getInstance() { - static VerboseLoggingHelper sharedInstance; - return sharedInstance; -} - -VerboseLoggingHelper::VerboseLoggingHelper() { - // setup our timer to flush the verbose logs every 5 seconds - _timer = new QTimer(this); - connect(_timer, &QTimer::timeout, this, &VerboseLoggingHelper::flushMessages); - _timer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); -} - -void VerboseLoggingHelper::flushMessages() { - QHash::iterator message = _messageCountHash.begin(); - while (message != _messageCountHash.end()) { - qDebug() << qPrintable(message.key().arg(message.value())) - << "in last" << VERBOSE_LOG_INTERVAL_SECONDS << "seconds."; - message = _messageCountHash.erase(message); - } -} \ No newline at end of file diff --git a/libraries/shared/src/VerboseLoggingHelper.h b/libraries/shared/src/VerboseLoggingHelper.h deleted file mode 100644 index 368dfa51e6..0000000000 --- a/libraries/shared/src/VerboseLoggingHelper.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// VerboseLoggingHelper.h -// libraries/shared/src -// -// Created by Stephen Birarda on 2014-10-28. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_VerboseLoggingHelper_h -#define hifi_VerboseLoggingHelper_h - -#include -#include -#include - -const int VERBOSE_LOG_INTERVAL_SECONDS = 5; - -class VerboseLoggingHelper : public QObject { - Q_OBJECT -public: - static VerboseLoggingHelper& getInstance(); - - void addMessage(const QString& message) { _messageCountHash[message] += 1; } -private: - VerboseLoggingHelper(); - - void flushMessages(); - - QTimer* _timer; - QHash _messageCountHash; -}; - -#endif // hifi_VerboseLoggingHelper_h \ No newline at end of file From d3bbd251db27cc517002d41fbd6fe4c5debfd243 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 13:59:23 -0700 Subject: [PATCH 39/55] move Logging to LogHandler --- assignment-client/src/AssignmentClient.cpp | 6 +-- .../src/AssignmentClientMonitor.cpp | 4 +- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- assignment-client/src/main.cpp | 4 +- assignment-client/src/octree/OctreeServer.cpp | 4 +- domain-server/src/main.cpp | 4 +- ice-server/src/main.cpp | 4 +- interface/src/Application.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 3 +- libraries/networking/src/NodeList.cpp | 3 +- .../networking/src/ThreadedAssignment.cpp | 5 ++- .../Logging.cpp => shared/src/LogHandler.cpp} | 41 ++++++++++--------- .../src/Logging.h => shared/src/LogHandler.h} | 30 +++++++------- 14 files changed, 60 insertions(+), 54 deletions(-) rename libraries/{networking/src/Logging.cpp => shared/src/LogHandler.cpp} (78%) rename libraries/{networking/src/Logging.h => shared/src/LogHandler.h} (63%) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index b30cd355d1..e7ac7577b9 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -51,7 +51,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit())); // set the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); @@ -218,7 +218,7 @@ void AssignmentClient::handleAuthenticationRequest() { void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME - Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); + LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment."); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index af09ff1535..02a4ff04f0 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include "AssignmentClientMonitor.h" @@ -21,7 +21,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int num QCoreApplication(argc, argv) { // start the Logging class with the parent's target name - Logging::setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); + LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); _childArguments = arguments(); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8d87638434..cc834798d7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 93f38e3608..3ec7c5cfbf 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 5e103cf767..3bf6990a74 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include +#include #include #include "Assignment.h" @@ -22,7 +22,7 @@ int main(int argc, char* argv[]) { #endif // use the verbose message handler in Logging - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index d0a17287cb..121cac0273 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include "../AssignmentClient.h" @@ -923,7 +923,7 @@ void OctreeServer::run() { beforeRun(); // after payload has been processed - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); const char* STATUS_PORT = "--statusPort"; const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT); diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 82e4bf7cab..ba80e6fce0 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -17,7 +17,7 @@ #include -#include +#include #include #include "DomainServer.h" @@ -27,7 +27,7 @@ int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); #endif - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); int currentExitCode = 0; diff --git a/ice-server/src/main.cpp b/ice-server/src/main.cpp index 21c8b563b1..2326984668 100644 --- a/ice-server/src/main.cpp +++ b/ice-server/src/main.cpp @@ -11,7 +11,7 @@ #include -#include +#include #include "IceServer.h" @@ -20,7 +20,7 @@ int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); #endif - qInstallMessageHandler(Logging::verboseMessageHandler); + qInstallMessageHandler(LogHandler::verboseMessageHandler); IceServer iceServer(argc, argv); return iceServer.exec(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f0bd2fb66c..e1088136c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 46ab4f4b0b..48a94e5444 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -19,10 +19,11 @@ #include #include +#include + #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" -#include "Logging.h" #include "LimitedNodeList.h" #include "PacketHeaders.h" #include "SharedUtil.h" diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index feeb13500a..ff3b86880d 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -15,10 +15,11 @@ #include #include +#include + #include "AccountManager.h" #include "Assignment.h" #include "HifiSockAddr.h" -#include "Logging.h" #include "NodeList.h" #include "PacketHeaders.h" #include "SharedUtil.h" diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 6d2e366499..52644a9a4e 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -14,7 +14,8 @@ #include #include -#include "Logging.h" +#include + #include "ThreadedAssignment.h" ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : @@ -54,7 +55,7 @@ void ThreadedAssignment::setFinished(bool isFinished) { void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running - Logging::setTargetName(targetName); + LogHandler::getInstance().setTargetName(targetName); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(nodeType); diff --git a/libraries/networking/src/Logging.cpp b/libraries/shared/src/LogHandler.cpp similarity index 78% rename from libraries/networking/src/Logging.cpp rename to libraries/shared/src/LogHandler.cpp index bb704729af..123b418562 100644 --- a/libraries/networking/src/Logging.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -1,9 +1,10 @@ // -// Logging.cpp -// libraries/networking/src +// LogHandler.cpp +// libraries/shared/src // -// Created by Stephen Birarda on 6/11/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Stephen Birarda on 2014-10-28. +// Migrated from Logging.cpp created on 6/11/13 +// Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -18,19 +19,17 @@ #include -#include "Logging.h" +#include "LogHandler.h" -QString Logging::_targetName = QString(); - -Logging& Logging::getInstance() { - static Logging staticInstance; +LogHandler& LogHandler::getInstance() { + static LogHandler staticInstance; return staticInstance; } -Logging::Logging() { +LogHandler::LogHandler() { // setup our timer to flush the verbose logs every 5 seconds QTimer* logFlushTimer = new QTimer(this); - connect(logFlushTimer, &QTimer::timeout, this, &Logging::flushRepeatedMessages); + connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages); logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); } @@ -52,34 +51,34 @@ const char* stringForLogType(QtMsgType msgType) { // the following will produce 2000-10-02 13:55:36 -0700 const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; -void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { +void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (message.isEmpty()) { return; } // log prefix is in the following format // [DEBUG] [TIMESTAMP] [PID:PARENT_PID] [TARGET] logged string - + QString prefixString = QString("[%1]").arg(stringForLogType(type)); - + time_t rawTime; time(&rawTime); struct tm* localTime = localtime(&rawTime); - + char dateString[100]; strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime); - + prefixString.append(QString(" [%1]").arg(dateString)); - + prefixString.append(QString(" [%1").arg(getpid())); - + pid_t parentProcessID = getppid(); if (parentProcessID != 0) { prefixString.append(QString(":%1]").arg(parentProcessID)); } else { prefixString.append("]"); } - + if (!getInstance()._targetName.isEmpty()) { prefixString.append(QString(" [%1]").arg(getInstance()._targetName)); } @@ -87,9 +86,11 @@ void Logging::verboseMessageHandler(QtMsgType type, const QMessageLogContext& co fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData()); } -void Logging::flushRepeatedMessages() { +void LogHandler::flushRepeatedMessages() { QHash::iterator message = _repeatMessageCountHash.begin(); while (message != _repeatMessageCountHash.end()) { message = _repeatMessageCountHash.erase(message); } } + + diff --git a/libraries/networking/src/Logging.h b/libraries/shared/src/LogHandler.h similarity index 63% rename from libraries/networking/src/Logging.h rename to libraries/shared/src/LogHandler.h index 458cbf90e8..e89a739c6a 100644 --- a/libraries/networking/src/Logging.h +++ b/libraries/shared/src/LogHandler.h @@ -1,16 +1,17 @@ // -// Logging.h -// libraries/networking/src +// LogHandler.cpp +// libraries/shared/src // -// Created by Stephen Birarda on 6/11/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Stephen Birarda on 2014-10-28. +// Migrated from Logging.cpp created on 6/11/13 +// Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_Logging_h -#define hifi_Logging_h +#ifndef hifi_LogHandler_h +#define hifi_LogHandler_h #include #include @@ -21,27 +22,28 @@ const int VERBOSE_LOG_INTERVAL_SECONDS = 5; /// Handles custom message handling and sending of stats/logs to Logstash instance -class Logging : public QObject { +class LogHandler : public QObject { Q_OBJECT public: + static LogHandler& getInstance(); + /// sets the target name to output via the verboseMessageHandler, called once before logging begins /// \param targetName the desired target name to output in logs - static void setTargetName(const QString& targetName) { _targetName = targetName; } - + void setTargetName(const QString& targetName) { _targetName = targetName; } + /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); - static void addRepeatedMessageRegex(const QRegExp& regex) { getInstance()._repeatedMessageRegexes.append(regex); } + void addRepeatedMessageRegex(const QRegExp& regex) { _repeatedMessageRegexes.append(regex); } private: - static Logging& getInstance(); - Logging(); + LogHandler(); void flushRepeatedMessages(); - static QString _targetName; + QString _targetName; QList _repeatedMessageRegexes; QHash _repeatMessageCountHash; }; -#endif // hifi_Logging_h +#endif // hifi_LogHandler_h \ No newline at end of file From 01b8fa12e25f3e08f798c84a6f2659bb067cc089 Mon Sep 17 00:00:00 2001 From: Stojce Date: Tue, 28 Oct 2014 22:22:50 +0100 Subject: [PATCH 40/55] Change default field of view from 90 to 45 --- libraries/octree/src/ViewFrustum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 4b2b57fab2..f1894c7cab 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -24,7 +24,7 @@ #include "OctreeProjectedPolygon.h" const float DEFAULT_KEYHOLE_RADIUS = 3.0f; -const float DEFAULT_FIELD_OF_VIEW_DEGREES = 90.0f; +const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f; const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.f; const float DEFAULT_ASPECT_RATIO = 16.f/9.f; const float DEFAULT_NEAR_CLIP = 0.08f; From 8e3102266a587897c5f35f3bafc19d938c2e00a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 14:23:34 -0700 Subject: [PATCH 41/55] use the LogHandler in Interface --- interface/src/Application.cpp | 10 ++- libraries/networking/src/LimitedNodeList.cpp | 3 + libraries/shared/src/LogHandler.cpp | 66 ++++++++++++++------ libraries/shared/src/LogHandler.h | 10 ++- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e1088136c4..16d8062303 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -116,12 +116,10 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js"; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - if (message.size() > 0) { - QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate); - QString formattedMessage = QString("[%1] %2\n").arg(dateString).arg(message); - - fprintf(stdout, "%s", qPrintable(formattedMessage)); - Application::getInstance()->getLogger()->addMessage(qPrintable(formattedMessage)); + QString logMessage = LogHandler::getInstance().printMessage(type, context, message); + + if (!logMessage.isEmpty()) { + Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage)); } } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 48a94e5444..600427a733 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -212,6 +212,9 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { << uuidFromPacketHeader(packet); } } else { + static QString repeatedMessage + = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID"); + qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); } diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 123b418562..078cdf5ab6 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -17,6 +17,7 @@ #define pid_t int // hack to build #endif +#include #include #include "LogHandler.h" @@ -26,7 +27,9 @@ LogHandler& LogHandler::getInstance() { return staticInstance; } -LogHandler::LogHandler() { +LogHandler::LogHandler() : + _shouldOutputPID(false) +{ // setup our timer to flush the verbose logs every 5 seconds QTimer* logFlushTimer = new QTimer(this); connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages); @@ -51,9 +54,33 @@ const char* stringForLogType(QtMsgType msgType) { // the following will produce 2000-10-02 13:55:36 -0700 const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; -void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { +void LogHandler::flushRepeatedMessages() { + QHash::iterator message = _repeatMessageCountHash.begin(); + while (message != _repeatMessageCountHash.end()) { + message = _repeatMessageCountHash.erase(message); + } +} + +QString LogHandler::printMessage(QtMsgType type, const QMessageLogContext& context, const QString& message) { + if (message.isEmpty()) { - return; + return QString(); + } + + if (type == QtDebugMsg) { + // for debug messages, check if this matches any of our regexes for repeated log messages + foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) { + QRegExp repeatRegex(regexString); + if (repeatRegex.indexIn(message) != -1) { + + // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message + _repeatMessageCountHash[regexString] += 1; + _lastRepeatedMessage[regexString] = message; + + // return out, we're not printing this one + return QString(); + } + } } // log prefix is in the following format @@ -70,27 +97,26 @@ void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& prefixString.append(QString(" [%1]").arg(dateString)); - prefixString.append(QString(" [%1").arg(getpid())); - - pid_t parentProcessID = getppid(); - if (parentProcessID != 0) { - prefixString.append(QString(":%1]").arg(parentProcessID)); - } else { - prefixString.append("]"); + if (_shouldOutputPID) { + prefixString.append(QString(" [%1").arg(getpid())); + + pid_t parentProcessID = getppid(); + if (parentProcessID != 0) { + prefixString.append(QString(":%1]").arg(parentProcessID)); + } else { + prefixString.append("]"); + } } - if (!getInstance()._targetName.isEmpty()) { - prefixString.append(QString(" [%1]").arg(getInstance()._targetName)); + if (!_targetName.isEmpty()) { + prefixString.append(QString(" [%1]").arg(_targetName)); } - fprintf(stdout, "%s %s\n", prefixString.toLocal8Bit().constData(), message.toLocal8Bit().constData()); + QString logMessage = QString("%1 %2").arg(prefixString, message); + fprintf(stdout, "%s\n", qPrintable(logMessage)); + return logMessage; } -void LogHandler::flushRepeatedMessages() { - QHash::iterator message = _repeatMessageCountHash.begin(); - while (message != _repeatMessageCountHash.end()) { - message = _repeatMessageCountHash.erase(message); - } +void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { + getInstance().printMessage(type, context, message); } - - diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index e89a739c6a..abc39b7040 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -31,19 +31,25 @@ public: /// \param targetName the desired target name to output in logs void setTargetName(const QString& targetName) { _targetName = targetName; } + void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; } + + QString printMessage(QtMsgType type, const QMessageLogContext& context, const QString &message); + /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message); - void addRepeatedMessageRegex(const QRegExp& regex) { _repeatedMessageRegexes.append(regex); } + const QString& addRepeatedMessageRegex(const QString& regexString) { return *_repeatedMessageRegexes.insert(regexString); } private: LogHandler(); void flushRepeatedMessages(); QString _targetName; - QList _repeatedMessageRegexes; + bool _shouldOutputPID; + QSet _repeatedMessageRegexes; QHash _repeatMessageCountHash; + QHash _lastRepeatedMessage; }; #endif // hifi_LogHandler_h \ No newline at end of file From 424793b90515a759cd9fd9b5223bd194867e1db4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 14:49:14 -0700 Subject: [PATCH 42/55] complete output of suppressed repeated messages to log --- interface/src/Application.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/shared/src/LogHandler.cpp | 17 +++++++++++++---- libraries/shared/src/LogHandler.h | 10 +++++++++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 16d8062303..141ba20416 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -116,7 +116,7 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js"; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - QString logMessage = LogHandler::getInstance().printMessage(type, context, message); + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message); if (!logMessage.isEmpty()) { Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage)); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 600427a733..5c4dc6cea2 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -216,7 +216,7 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID"); qDebug() << "Packet of type" << checkType << "received from unknown node with UUID" - << uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)); + << qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet))); } } else { return true; diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 078cdf5ab6..aa377b5683 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -36,7 +36,7 @@ LogHandler::LogHandler() : logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); } -const char* stringForLogType(QtMsgType msgType) { +const char* stringForLogType(LogMsgType msgType) { switch (msgType) { case QtDebugMsg: return "DEBUG"; @@ -46,6 +46,8 @@ const char* stringForLogType(QtMsgType msgType) { return "FATAL"; case QtWarningMsg: return "WARNING"; + case LogSuppressed: + return "SUPPRESS"; default: return "UNKNOWN"; } @@ -57,17 +59,24 @@ const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; void LogHandler::flushRepeatedMessages() { QHash::iterator message = _repeatMessageCountHash.begin(); while (message != _repeatMessageCountHash.end()) { + QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") + .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); + + QMessageLogContext emptyContext; + printMessage(LogSuppressed, emptyContext, repeatMessage); + + _lastRepeatedMessage.remove(message.key()); message = _repeatMessageCountHash.erase(message); } } -QString LogHandler::printMessage(QtMsgType type, const QMessageLogContext& context, const QString& message) { +QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) { if (message.isEmpty()) { return QString(); } - if (type == QtDebugMsg) { + if (type == LogDebug) { // for debug messages, check if this matches any of our regexes for repeated log messages foreach(const QString& regexString, getInstance()._repeatedMessageRegexes) { QRegExp repeatRegex(regexString); @@ -118,5 +127,5 @@ QString LogHandler::printMessage(QtMsgType type, const QMessageLogContext& conte } void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - getInstance().printMessage(type, context, message); + getInstance().printMessage((LogMsgType) type, context, message); } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index abc39b7040..f8f06b0033 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -21,6 +21,14 @@ const int VERBOSE_LOG_INTERVAL_SECONDS = 5; +enum LogMsgType { + LogDebug, + LogWarning, + LogCritical, + LogFatal, + LogSuppressed +}; + /// Handles custom message handling and sending of stats/logs to Logstash instance class LogHandler : public QObject { Q_OBJECT @@ -33,7 +41,7 @@ public: void setShouldOutputPID(bool shouldOutputPID) { _shouldOutputPID = shouldOutputPID; } - QString printMessage(QtMsgType type, const QMessageLogContext& context, const QString &message); + QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message); /// a qtMessageHandler that can be hooked up to a target that links to Qt /// prints various process, message type, and time information From c4538836c16918ab05d3d558e7d3a30105bc74bb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 14:51:47 -0700 Subject: [PATCH 43/55] always output the first matching repeated log message --- libraries/shared/src/LogHandler.cpp | 31 +++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index aa377b5683..9a081e429d 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -59,11 +59,14 @@ const char DATE_STRING_FORMAT[] = "%Y-%m-%d %H:%M:%S %z"; void LogHandler::flushRepeatedMessages() { QHash::iterator message = _repeatMessageCountHash.begin(); while (message != _repeatMessageCountHash.end()) { - QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") - .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); - QMessageLogContext emptyContext; - printMessage(LogSuppressed, emptyContext, repeatMessage); + if (message.value() > 0) { + QString repeatMessage = QString("%1 repeated log entries matching \"%2\" - Last entry: \"%3\"") + .arg(message.value()).arg(message.key()).arg(_lastRepeatedMessage.value(message.key())); + + QMessageLogContext emptyContext; + printMessage(LogSuppressed, emptyContext, repeatMessage); + } _lastRepeatedMessage.remove(message.key()); message = _repeatMessageCountHash.erase(message); @@ -82,12 +85,20 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont QRegExp repeatRegex(regexString); if (repeatRegex.indexIn(message) != -1) { - // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message - _repeatMessageCountHash[regexString] += 1; - _lastRepeatedMessage[regexString] = message; - - // return out, we're not printing this one - return QString(); + if (!_repeatMessageCountHash.contains(regexString)) { + // we have a match but didn't have this yet - output the first one + _repeatMessageCountHash[regexString] = 0; + + // break the foreach so we output the first match + break; + } else { + // we have a match - add 1 to the count of repeats for this message and set this as the last repeated message + _repeatMessageCountHash[regexString] += 1; + _lastRepeatedMessage[regexString] = message; + + // return out, we're not printing this one + return QString(); + } } } } From 4ec70041ccbf210be2dfd96c92311ee7df39d65f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 15:20:02 -0700 Subject: [PATCH 44/55] fix memory leak --- libraries/entities/src/EntityItemProperties.cpp | 5 ++++- libraries/entities/src/EntityItemProperties.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index c05fe5417d..5accda2062 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -102,11 +102,14 @@ EntityItemProperties::EntityItemProperties() : _sittingPoints(NULL), _naturalDimensions(1.0f, 1.0f, 1.0f) { +} + +EntityItemProperties::~EntityItemProperties() { if (_sittingPoints) { delete _sittingPoints; _sittingPoints = NULL; } -} +}; void EntityItemProperties::setSittingPoints(const QVector& sittingPoints) { if (!_sittingPoints) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 5fef2151b2..f977b346cc 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -96,7 +96,7 @@ class EntityItemProperties { friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods public: EntityItemProperties(); - virtual ~EntityItemProperties() { }; + virtual ~EntityItemProperties(); virtual QScriptValue copyToScriptValue(QScriptEngine* engine) const; virtual void copyFromScriptValue(const QScriptValue& object); From 47ba32e95eb7b68dc5aff49dbb5c9c39e064a992 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 Oct 2014 15:27:56 -0700 Subject: [PATCH 45/55] feedback --- libraries/entities/src/EntityItemProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5accda2062..83d13e369d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -109,7 +109,7 @@ EntityItemProperties::~EntityItemProperties() { delete _sittingPoints; _sittingPoints = NULL; } -}; +} void EntityItemProperties::setSittingPoints(const QVector& sittingPoints) { if (!_sittingPoints) { From 2816e8f11403965344699cf7f834d155387b5d99 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:32:23 -0700 Subject: [PATCH 46/55] fix location DataWebDialog missing InterfaceLocation object --- interface/src/Menu.cpp | 4 ++-- libraries/networking/src/AddressManager.cpp | 4 ++++ libraries/networking/src/AddressManager.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 274afd4bca..0bebe06b1c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1315,7 +1315,7 @@ void Menu::displayNameLocationResponse(const QString& errorString) { void Menu::toggleLocationList() { if (!_userLocationsDialog) { JavascriptObjectMap locationObjectMap; - locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance()); + locationObjectMap.insert("InterfaceLocation", &AddressManager::getInstance()); _userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap); } @@ -1359,7 +1359,7 @@ void Menu::nameLocation() { if (!_newLocationDialog) { JavascriptObjectMap locationObjectMap; - locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance()); + locationObjectMap.insert("InterfaceLocation", &AddressManager::getInstance()); _newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap); } diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 1201a8973f..b4765dc362 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -71,6 +71,10 @@ const QString AddressManager::currentPath(bool withOrientation) const { } } +QString AddressManager::getDomainID() const { + return NodeList::getInstance()->getDomainHandler().getUUID().toString(); +} + const JSONCallbackParameters& AddressManager::apiCallbackParameters() { static bool hasSetupParameters = false; static JSONCallbackParameters callbackParams; diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 8a25464223..d6ecdc9fc6 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -31,6 +31,7 @@ class AddressManager : public QObject { Q_PROPERTY(QString protocol READ getProtocol) Q_PROPERTY(QString hostname READ getCurrentDomain) Q_PROPERTY(QString pathname READ currentPath) + Q_PROPERTY(QString domainID READ getDomainID) public: static AddressManager& getInstance(); @@ -41,6 +42,7 @@ public: const QString currentPath(bool withOrientation = true) const; const QString& getCurrentDomain() const { return _currentDomain; } + QString getDomainID() const; void attemptPlaceNameLookup(const QString& lookupString); From 33c247918e96d0bf6b9f4ef1d9f60e3e394c4325 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:37:42 -0700 Subject: [PATCH 47/55] fix for domainID wrapped in braces --- libraries/networking/src/AddressManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index b4765dc362..6113cadb06 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "NodeList.h" @@ -72,7 +73,8 @@ const QString AddressManager::currentPath(bool withOrientation) const { } QString AddressManager::getDomainID() const { - return NodeList::getInstance()->getDomainHandler().getUUID().toString(); + const QUuid& domainID = NodeList::getInstance()->getDomainHandler().getUUID(); + return domainID.isNull() ? "" : uuidStringWithoutCurlyBraces(domainID); } const JSONCallbackParameters& AddressManager::apiCallbackParameters() { From 6ba0845767d94afabfe67e6057671b1bdd829cec Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:39:25 -0700 Subject: [PATCH 48/55] fix warnings that were bugging Xcode --- interface/src/Menu.cpp | 1 - interface/src/gpu/Batch.cpp | 2 ++ interface/src/renderer/Model.cpp | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0bebe06b1c..4e453bfde2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1266,7 +1266,6 @@ void Menu::changeVSync() { } void Menu::changeRenderTargetFramerate(QAction* action) { bool vsynOn = Application::getInstance()->isVSyncOn(); - unsigned int framerate = Application::getInstance()->getRenderTargetFramerate(); QString text = action->text(); if (text == MenuOption::RenderTargetFramerateUnlimited) { diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index 054bc09846..b7db58ea30 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -111,6 +111,8 @@ void Batch::runCommand(Command com, uint32 offset) { CASE_COMMAND(glColor4f); CASE_COMMAND(glMaterialf); CASE_COMMAND(glMaterialfv); + default: + break; } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index e949e9a811..cdec00aee2 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1737,7 +1737,8 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl mesh.texCoords.size() * sizeof(glm::vec2) + (mesh.blendshapes.isEmpty() ? vertexCount * 2 * sizeof(glm::vec3) : 0); //skinProgram->setAttributeBuffer(skinLocations->clusterIndices, GL_FLOAT, offset, 4); - GLBATCH(glVertexAttribPointer)(skinLocations->clusterIndices, 4, GL_FLOAT, GL_TRUE, 0, (const void*) offset); + GLBATCH(glVertexAttribPointer)(skinLocations->clusterIndices, 4, GL_FLOAT, GL_TRUE, 0, + reinterpret_cast(offset)); //skinProgram->setAttributeBuffer(skinLocations->clusterWeights, GL_FLOAT, // offset + vertexCount * sizeof(glm::vec4), 4); GLBATCH(glVertexAttribPointer)(skinLocations->clusterWeights, 4, GL_FLOAT, GL_TRUE, 0, (const void*) (offset + vertexCount * sizeof(glm::vec4))); From 01de6305e943828588fd6d74b7b135122634b3fa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:42:03 -0700 Subject: [PATCH 49/55] add time header for date in log entry --- libraries/shared/src/LogHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 9a081e429d..7b06b77ae8 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -10,6 +10,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #ifdef _WIN32 #include #define getpid _getpid From 992396ba63da824065072ecc2877d0578aadf186 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:48:06 -0700 Subject: [PATCH 50/55] add ctime for strftime call --- libraries/shared/src/LogHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 7b06b77ae8..88afba8c07 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -11,6 +11,7 @@ // #include +#include #ifdef _WIN32 #include From 9af097967ddd8e4fee8fcb59b21bd455eb1abd9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Oct 2014 15:56:30 -0700 Subject: [PATCH 51/55] remove ctime since windows build did not fail without it --- libraries/shared/src/LogHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 88afba8c07..7b06b77ae8 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -11,7 +11,6 @@ // #include -#include #ifdef _WIN32 #include From da70ec4c893dbd7d9018c838f6cfc079784969ee Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 28 Oct 2014 18:22:06 -0700 Subject: [PATCH 52/55] Fix the rendering bug on yosemite: due to the attribute channel number assigned by the compiler which colllides with the fixed pipeline vertex attrib channels, forced the attribute bind location after 3 --- interface/src/renderer/Model.cpp | 43 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index e949e9a811..a7cbfebdd6 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -122,21 +122,36 @@ void Model::setOffset(const glm::vec3& offset) { void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit) { program.bind(); - locations.tangent = program.attributeLocation("tangent"); - locations.alphaThreshold = program.uniformLocation("alphaThreshold"); - program.setUniformValue("diffuseMap", 0); - program.setUniformValue("normalMap", 1); - program.setUniformValue("specularMap", specularTextureUnit); - program.release(); -} -void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) { - initProgram(program, locations, specularTextureUnit); - - program.bind(); - locations.clusterMatrices = program.uniformLocation("clusterMatrices"); - locations.clusterIndices = program.attributeLocation("clusterIndices"); - locations.clusterWeights = program.attributeLocation("clusterWeights"); +#ifdef Q_OS_MAC + // HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite + glBindAttribLocation(program.programId(), 4, "tangent"); + glLinkProgram(program.programId()); +#endif + + locations.tangent = program.attributeLocation("tangent"); + locations.alphaThreshold = program.uniformLocation("alphaThreshold"); + program.setUniformValue("diffuseMap", 0); + program.setUniformValue("normalMap", 1); + program.setUniformValue("specularMap", specularTextureUnit); + program.release(); +} + +void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) { + initProgram(program, locations, specularTextureUnit); + +#ifdef Q_OS_MAC + // HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite + glBindAttribLocation(program.programId(), 5, "clusterIndices"); + glBindAttribLocation(program.programId(), 6, "clusterWeights"); + glLinkProgram(program.programId()); +#endif + + program.bind(); + locations.clusterMatrices = program.uniformLocation("clusterMatrices"); + + locations.clusterIndices = program.attributeLocation("clusterIndices"); + locations.clusterWeights = program.attributeLocation("clusterWeights"); program.release(); } From c39b239f99275495a26b6d286607f705a3843884 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Oct 2014 09:30:51 -0700 Subject: [PATCH 53/55] fix linux build for missing getpid() --- libraries/shared/src/LogHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 7b06b77ae8..1d8e55f432 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -17,6 +17,8 @@ #define getpid _getpid #define getppid _getpid // hack to build #define pid_t int // hack to build +#else +#include // for getpid() on linux #endif #include From 9ddd05ca72fcdf2038fc60fb0126af03a66c90cb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Oct 2014 12:13:07 -0700 Subject: [PATCH 54/55] smoother avatar motion at low velocities --- interface/src/avatar/MyAvatar.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 178113efc1..623631d5e5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -49,8 +49,9 @@ const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; -const float MIN_KEYBOARD_CONTROL_SPEED = 0.50f; const float MAX_WALKING_SPEED = 4.5f; +const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed +const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this // TODO: normalize avatar speed for standard avatar size, then scale all motion logic // to properly follow avatar size. @@ -1286,19 +1287,21 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe // Compute the target keyboard velocity (which ramps up slowly, and damps very quickly) // the max magnitude of which depends on what we're doing: - float motorLength = glm::length(_keyboardMotorVelocity); + float motorSpeed = glm::length(_keyboardMotorVelocity); float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED; float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f; - motorLength *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) { + motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; + const float maxBoostSpeed = _scale * MAX_BOOST_SPEED; + if (motorSpeed < maxBoostSpeed) { // an active keyboard motor should never be slower than this - motorLength = _scale * MIN_KEYBOARD_CONTROL_SPEED; - motorEfficiency = 1.0f; - } else if (motorLength > finalMaxMotorSpeed) { - motorLength = finalMaxMotorSpeed; + float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; + motorSpeed += MIN_AVATAR_SPEED * boostCoefficient; + motorEfficiency += (1.0f - motorEfficiency) * boostCoefficient; + } else if (motorSpeed > finalMaxMotorSpeed) { + motorSpeed = finalMaxMotorSpeed; } - _keyboardMotorVelocity = motorLength * direction; + _keyboardMotorVelocity = motorSpeed * direction; _isPushing = true; } } else { @@ -1430,7 +1433,6 @@ void MyAvatar::updatePosition(float deltaTime) { } // update position - const float MIN_AVATAR_SPEED = 0.075f; if (speed > MIN_AVATAR_SPEED) { applyPositionDelta(deltaTime * velocity); } From e631ab8d38ec938d63a787412b712cefdc3e6cb4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 29 Oct 2014 13:01:47 -0700 Subject: [PATCH 55/55] use Qt::AutoConnection for Avatar::setFoo() methods This prevents a JS script from blocking when setting C++ values. --- interface/src/avatar/Avatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3fcc05d7c7..59c8c90d1c 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -871,7 +871,7 @@ const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f; void Avatar::setJointModelPositionAndOrientation(int index, glm::vec3 position, const glm::quat& rotation) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(const_cast(this), "setJointModelPositionAndOrientation", - Qt::BlockingQueuedConnection, Q_ARG(const int, index), Q_ARG(const glm::vec3, position), + Qt::AutoConnection, Q_ARG(const int, index), Q_ARG(const glm::vec3, position), Q_ARG(const glm::quat&, rotation)); } else { _skeletonModel.inverseKinematics(index, position, rotation, SCRIPT_PRIORITY); @@ -881,7 +881,7 @@ void Avatar::setJointModelPositionAndOrientation(int index, glm::vec3 position, void Avatar::setJointModelPositionAndOrientation(const QString& name, glm::vec3 position, const glm::quat& rotation) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(const_cast(this), "setJointModelPositionAndOrientation", - Qt::BlockingQueuedConnection, Q_ARG(const QString&, name), Q_ARG(const glm::vec3, position), + Qt::AutoConnection, Q_ARG(const QString&, name), Q_ARG(const glm::vec3, position), Q_ARG(const glm::quat&, rotation)); } else { _skeletonModel.inverseKinematics(getJointIndex(name), position, rotation, SCRIPT_PRIORITY);