From 92817d930265c8a2225c7f8513c96a43641bd6e2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 28 May 2015 10:59:27 -0700 Subject: [PATCH 01/19] created-time is a property so it can be persisted to and retrieved from json saves --- libraries/entities/src/EntityItem.cpp | 19 +++++++++++++++---- libraries/entities/src/EntityItem.h | 4 ++++ .../entities/src/EntityItemProperties.cpp | 15 ++++++--------- libraries/entities/src/EntityItemProperties.h | 4 +--- .../entities/src/EntityItemPropertiesMacros.h | 11 +++++++++-- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e0297fe7d4..8787b48f2d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -896,6 +896,7 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping); COPY_ENTITY_PROPERTY_TO_PROPERTIES(restitution, getRestitution); COPY_ENTITY_PROPERTY_TO_PROPERTIES(friction, getFriction); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated); COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime); COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionSoundURL, getCollisionSoundURL); @@ -931,6 +932,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, updateDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution); SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL); @@ -972,11 +974,13 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { } void EntityItem::recordCreationTime() { - assert(_created == UNKNOWN_CREATED_TIME); - _created = usecTimestampNow(); + if (_created == UNKNOWN_CREATED_TIME) { + _created = usecTimestampNow(); + } + auto now = usecTimestampNow(); _lastEdited = _created; - _lastUpdated = _created; - _lastSimulated = _created; + _lastUpdated = now; + _lastSimulated = now; } @@ -1284,6 +1288,13 @@ void EntityItem::updateLifetime(float value) { } } +void EntityItem::updateCreated(uint64_t value) { + if (_created != value) { + _created = value; + _dirtyFlags |= EntityItem::DIRTY_LIFETIME; + } +} + void EntityItem::setSimulatorID(const QUuid& value) { _simulatorID = value; _simulatorIDChangedTime = usecTimestampNow(); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 4f2132bef4..024616939b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -228,6 +228,9 @@ public: float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity + quint64 getCreated() const { return _created; } /// get the created-time in useconds for the entity + void setCreated(quint64 value) { _created = value; } /// set the created-time in useconds for the entity + /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return _lifetime == ENTITY_ITEM_IMMORTAL_LIFETIME; } @@ -325,6 +328,7 @@ public: void updateIgnoreForCollisions(bool value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); + void updateCreated(uint64_t value); virtual void updateShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const { return _dirtyFlags; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 856c1a1cb4..d3f5b4d055 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -48,6 +48,7 @@ CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING), CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION), CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION), CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME), +CONSTRUCT_PROPERTY(created, UNKNOWN_CREATED_TIME), CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT), CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL), CONSTRUCT_PROPERTY(color, ), @@ -99,7 +100,6 @@ CONSTRUCT_PROPERTY(sourceUrl, ""), _id(UNKNOWN_ENTITY_ID), _idSet(false), _lastEdited(0), -_created(UNKNOWN_CREATED_TIME), _type(EntityTypes::Unknown), _glowLevel(0.0f), @@ -194,13 +194,6 @@ void EntityItemProperties::debugDump() const { props.debugDumpBits(); } -void EntityItemProperties::setCreated(quint64 usecTime) { - _created = usecTime; - if (_lastEdited < _created) { - _lastEdited = _created; - } -} - void EntityItemProperties::setLastEdited(quint64 usecTime) { _lastEdited = usecTime > _created ? usecTime : _created; } @@ -375,10 +368,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(friction); COPY_PROPERTY_TO_QSCRIPTVALUE(density); COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime); - if (!skipDefaults) { + + if (!skipDefaults || _lifetime != defaultEntityProperties._lifetime) { COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable } + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, getCreated()); + COPY_PROPERTY_TO_QSCRIPTVALUE(script); COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint); COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity); @@ -488,6 +484,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution); COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction); COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime); + COPY_PROPERTY_FROM_QSCRIPTVALUE(created, float, setCreated); COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript); COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint); COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 26c26bd474..a0eab130c4 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -96,6 +96,7 @@ public: DEFINE_PROPERTY(PROP_RESTITUTION, Restitution, restitution, float); DEFINE_PROPERTY(PROP_FRICTION, Friction, friction, float); DEFINE_PROPERTY(PROP_LIFETIME, Lifetime, lifetime, float); + DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64); DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString); DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor); @@ -153,8 +154,6 @@ public: float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } - quint64 getCreated() const { return _created; } - void setCreated(quint64 usecTime); bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); } bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); } @@ -199,7 +198,6 @@ private: QUuid _id; bool _idSet; quint64 _lastEdited; - quint64 _created; EntityTypes::EntityType _type; void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); } diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 33abc59e4d..30d32446e7 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -96,6 +96,11 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { retu inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; } +// QScriptValue doesn't support "long long" ints, so use strings +inline QScriptValue convertScriptValue(QScriptEngine* e, quint64 v) { + return QString::number(v); +} + inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); return QScriptValue(QString(b64)); @@ -138,6 +143,10 @@ inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); } inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } +// QScriptValue doesn't support "long long" ints, so use strings +inline uint64_t uint64_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + return (uint64_t) v.toVariant().toString().trimmed().toLongLong(); +} inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; @@ -145,8 +154,6 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& return QByteArray::fromBase64(b64.toUtf8()); } - - inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted QScriptValue x = v.property("x"); From 0cf9afd8ec5c7893fad373cc87df69a0088ee18d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 28 May 2015 21:21:57 -0700 Subject: [PATCH 02/19] attempt to save _created as an iso date in utc --- interface/src/ui/ApplicationOverlay.cpp | 1 - .../entities/src/EntityItemProperties.cpp | 19 +++++++++++++++-- libraries/entities/src/EntityItemProperties.h | 2 ++ .../entities/src/EntityItemPropertiesMacros.h | 21 +++++++++++++------ 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 8a64630266..d9d2a1d971 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -507,7 +507,6 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { QPoint rv; auto canvasSize = qApp->getCanvasSize(); if (qApp->isHMDMode()) { - float t; glm::vec2 polar = getPolarCoordinates(*palm); glm::vec2 point = sphericalToScreen(-polar); rv.rx() = point.x; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d3f5b4d055..7457de3797 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -176,6 +176,14 @@ QString EntityItemProperties::getAnimationSettings() const { return jsonByteString; } + +void EntityItemProperties::setCreated(QDateTime v) { + QDateTime utcV = v; + // utcV.setTimeSpec(Qt::OffsetFromUTC); + _created = utcV.toMSecsSinceEpoch() * 1000; // usec per msec + qDebug() << "EntityItemProperties::setCreated QDateTime" << v << _created; +} + void EntityItemProperties::debugDump() const { qCDebug(entities) << "EntityItemProperties..."; qCDebug(entities) << " _type=" << EntityTypes::getEntityTypeName(_type); @@ -373,7 +381,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable } - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, getCreated()); + + auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec + created.setTimeSpec(Qt::OffsetFromUTC); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created); COPY_PROPERTY_TO_QSCRIPTVALUE(script); COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint); @@ -484,7 +495,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution); COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction); COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime); - COPY_PROPERTY_FROM_QSCRIPTVALUE(created, float, setCreated); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() { + auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec + // result.setTimeSpec(Qt::OffsetFromUTC); + return result; + }); COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript); COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint); COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a0eab130c4..49fd206f93 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -194,6 +194,8 @@ public: void setVoxelDataDirty() { _voxelDataChanged = true; } + void setCreated(QDateTime v); + private: QUuid _id; bool _idSet; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 30d32446e7..66259ad25f 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #ifndef hifi_EntityItemPropertiesMacros_h #define hifi_EntityItemPropertiesMacros_h @@ -96,11 +98,14 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { retu inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; } -// QScriptValue doesn't support "long long" ints, so use strings -inline QScriptValue convertScriptValue(QScriptEngine* e, quint64 v) { - return QString::number(v); +inline QScriptValue convertScriptValue(QScriptEngine* e, QDateTime v) { + auto utcV = v; + utcV.setTimeSpec(Qt::OffsetFromUTC); + auto result = QScriptValue(utcV.toString(Qt::ISODate)); + return result; } + inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); return QScriptValue(QString(b64)); @@ -143,11 +148,15 @@ inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); } inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } -// QScriptValue doesn't support "long long" ints, so use strings -inline uint64_t uint64_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { - return (uint64_t) v.toVariant().toString().trimmed().toLongLong(); +inline QDateTime QDateTime_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = true; + auto result = QDateTime::fromString(v.toVariant().toString().trimmed(), Qt::ISODate); + // result.setTimeSpec(Qt::OffsetFromUTC); + return result; } + + inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; QString b64 = v.toVariant().toString().trimmed(); From 9f4fff358839a364af9d47891e5cc74f2587d614 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 29 May 2015 09:33:29 -0700 Subject: [PATCH 03/19] don't need convertScriptValue(QScriptEngine* e, QDateTime v) --- libraries/entities/src/EntityItemProperties.cpp | 3 +-- libraries/entities/src/EntityItemPropertiesMacros.h | 10 ---------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7457de3797..2c6e36fdff 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -179,7 +179,6 @@ QString EntityItemProperties::getAnimationSettings() const { void EntityItemProperties::setCreated(QDateTime v) { QDateTime utcV = v; - // utcV.setTimeSpec(Qt::OffsetFromUTC); _created = utcV.toMSecsSinceEpoch() * 1000; // usec per msec qDebug() << "EntityItemProperties::setCreated QDateTime" << v << _created; } @@ -384,7 +383,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool auto created = QDateTime::fromMSecsSinceEpoch(getCreated() / 1000.0f, Qt::UTC); // usec per msec created.setTimeSpec(Qt::OffsetFromUTC); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(created, created.toString(Qt::ISODate)); COPY_PROPERTY_TO_QSCRIPTVALUE(script); COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 66259ad25f..6aeb9a2142 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -98,21 +98,11 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { retu inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; } -inline QScriptValue convertScriptValue(QScriptEngine* e, QDateTime v) { - auto utcV = v; - utcV.setTimeSpec(Qt::OffsetFromUTC); - auto result = QScriptValue(utcV.toString(Qt::ISODate)); - return result; -} - - inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); return QScriptValue(QString(b64)); } - - #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \ if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \ QScriptValue groupProperties = properties.property(#g); \ From a96520ca74466b63ffd87b9470ca1d75ab48296f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 29 May 2015 13:43:18 -0700 Subject: [PATCH 04/19] set up EntityItemPropertiesFromScript to either ignore or honor read-only properties --- .../entities/src/EntityItemProperties.cpp | 26 ++++++++++++------- libraries/entities/src/EntityItemProperties.h | 5 ++-- .../entities/src/EntityScriptingInterface.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- libraries/octree/src/Octree.cpp | 8 ++++++ libraries/script-engine/src/ScriptEngine.cpp | 2 +- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2c6e36fdff..ec41b313a0 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -477,7 +477,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool return properties; } -void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { +void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool honorReadOnly) { QScriptValue typeScriptValue = object.property("type"); if (typeScriptValue.isValid()) { setType(typeScriptValue.toVariant().toString()); @@ -494,11 +494,12 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution); COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction); COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() { - auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec - // result.setTimeSpec(Qt::OffsetFromUTC); - return result; - }); + if (!honorReadOnly) { + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() { + auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec + return result; + }); + } COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript); COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint); COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity); @@ -523,7 +524,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked); COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures); COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData); - //COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); DO NOT accept this info from QScriptValue + if (!honorReadOnly) { + COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); + } COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText); COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight); COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor); @@ -565,10 +568,15 @@ QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, return properties.copyToScriptValue(engine, true); } -void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) { - properties.copyFromScriptValue(object); +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties) { + properties.copyFromScriptValue(object, false); } +void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties) { + properties.copyFromScriptValue(object, true); +} + + // TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the // encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar // to how we handle this in the Octree streaming case. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 49fd206f93..8245cf0b6a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -63,7 +63,7 @@ public: void setType(EntityTypes::EntityType type) { _type = type; } virtual QScriptValue copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const; - virtual void copyFromScriptValue(const QScriptValue& object); + virtual void copyFromScriptValue(const QScriptValue& object, bool honorReadOnly); // editing related features supported by all entities quint64 getLastEdited() const { return _lastEdited; } @@ -218,7 +218,8 @@ private: Q_DECLARE_METATYPE(EntityItemProperties); QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); -void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueIgnoreReadOnly(const QScriptValue &object, EntityItemProperties& properties); +void EntityItemPropertiesFromScriptValueHonorReadOnly(const QScriptValue &object, EntityItemProperties& properties); // define these inline here so the macros work diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 54d2ea705e..579ec2a984 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -360,7 +360,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra quuidFromScriptValue(entityIDValue, value.entityID); QScriptValue entityPropertiesValue = object.property("properties"); if (entityPropertiesValue.isValid()) { - EntityItemPropertiesFromScriptValue(entityPropertiesValue, value.properties); + EntityItemPropertiesFromScriptValueHonorReadOnly(entityPropertiesValue, value.properties); } value.distance = object.property("distance").toVariant().toFloat(); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 5eec93e8f5..937472820e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1055,7 +1055,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { QVariantMap entityMap = entityVariant.toMap(); QScriptValue entityScriptValue = variantMapToScriptValue(entityMap, scriptEngine); EntityItemProperties properties; - EntityItemPropertiesFromScriptValue(entityScriptValue, properties); + EntityItemPropertiesFromScriptValueIgnoreReadOnly(entityScriptValue, properties); EntityItemID entityItemID; if (entityMap.contains("id")) { diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index d53d29e444..adc2040b8a 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -2096,7 +2096,15 @@ void Octree::writeToJSONFile(const char* fileName, OctreeElement* element) { top = _rootElement; } + // include the "bitstream" version + PacketType expectedType = expectedDataPacketType(); + PacketVersion expectedVersion = versionForPacketType(expectedType); + entityDescription["Version"] = (int) expectedVersion; + + // store the entity data bool entityDescriptionSuccess = writeToMap(entityDescription, top, true); + + // convert the QVariantMap to JSON if (entityDescriptionSuccess && persistFile.open(QIODevice::WriteOnly)) { persistFile.write(QJsonDocument::fromVariant(entityDescription).toJson()); } else { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 91a4e3c397..30c3fbe8e4 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -318,7 +318,7 @@ void ScriptEngine::init() { registerAvatarTypes(this); registerAudioMetaTypes(this); - qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValue); + qScriptRegisterMetaType(this, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly); qScriptRegisterMetaType(this, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue); qScriptRegisterMetaType(this, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue); qScriptRegisterSequenceMetaType>(this); From 96a40bd673f41f0dfc114e1cc29e5aa714a70050 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 29 May 2015 18:50:26 -0700 Subject: [PATCH 05/19] basic collisions with cubic polyvoxes --- examples/voxels.js | 4 +- .../src/RenderablePolyVoxEntityItem.cpp | 159 ++++++++++++++++-- .../src/RenderablePolyVoxEntityItem.h | 13 +- .../entities/src/EntityScriptingInterface.cpp | 37 ++++ .../entities/src/EntityScriptingInterface.h | 1 + libraries/entities/src/PolyVoxEntityItem.cpp | 5 + libraries/entities/src/PolyVoxEntityItem.h | 4 +- libraries/shared/src/ShapeInfo.h | 3 +- 8 files changed, 201 insertions(+), 25 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index e274f1c4cc..351e723a5b 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -15,9 +15,9 @@ function mousePressEvent(event) { for (var i = 0; i < ids.length; i++) { var id = ids[i]; if (controlHeld) { - Entities.setVoxelSphere(id, intersection.intersection, 1.2, 0); + Entities.setVoxelSphere(id, intersection.intersection, 0.5, 0); } else { - Entities.setVoxelSphere(id, intersection.intersection, 1.2, 255); + Entities.setVoxelSphere(id, intersection.intersection, 0.5, 255); } } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 977a6511c8..9e6d512dc3 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -38,12 +38,22 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties)); } +RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, + const EntityItemProperties& properties) : + PolyVoxEntityItem(entityItemID, properties) { + setVoxelVolumeSize(_voxelVolumeSize); + + model::Mesh* mesh = new model::Mesh(); + model::MeshPointer meshPtr(mesh); + _modelGeometry.setMesh(meshPtr); +} + + RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() { delete _volData; } void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { - if (_volData && voxelVolumeSize == _voxelVolumeSize) { return; } @@ -83,12 +93,32 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { return translation * rotation * centerToCorner; } + +glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { + glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units + glm::mat4 scaled = glm::scale(glm::mat4(), scale); + glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f); + return centerToCorner; +} + glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix()); return worldToModelMatrix; } +void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { + // XXX a volume that is all "on" has no mesh. make a different call for this nearly-all code: + for (int z = 1; z < _volData->getDepth() - 1; z++) { + for (int y = 1; y < _volData->getHeight() - 1; y++) { + for (int x = 1; x < _volData->getWidth() - 1; x++) { + _volData->setVoxelAt(x, y, z, toValue); + } + } + } + compressVolumeData(); +} + void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { // This three-level for loop iterates over every voxel in the volume for (int z = 0; z < _volData->getDepth(); z++) { @@ -106,7 +136,6 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi } } compressVolumeData(); - _needsModelReload = true; } void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) { @@ -119,11 +148,6 @@ void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r } void RenderablePolyVoxEntityItem::getModel() { - if (!_volData) { - // this will cause the allocation of _volData - setVoxelVolumeSize(_voxelVolumeSize); - } - // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; @@ -143,24 +167,25 @@ void RenderablePolyVoxEntityItem::getModel() { } // convert PolyVox mesh to a Sam mesh - model::Mesh* mesh = new model::Mesh(); - model::MeshPointer meshPtr(mesh); + auto mesh = _modelGeometry.getMesh(); const std::vector& vecIndices = polyVoxMesh.getIndices(); auto indexBuffer = new gpu::Buffer(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data()); auto indexBufferPtr = gpu::BufferPointer(indexBuffer); - mesh->setIndexBuffer(gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW))); + auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)); + mesh->setIndexBuffer(*indexBufferView); const std::vector& vecVertices = polyVoxMesh.getVertices(); auto vertexBuffer = new gpu::Buffer(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal), (gpu::Byte*)vecVertices.data()); auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer); - mesh->setVertexBuffer(gpu::BufferView(vertexBufferPtr, - 0, - vertexBufferPtr->getSize() - sizeof(float) * 3, - sizeof(PolyVox::PositionMaterialNormal), - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW))); + auto vertexBufferView = new gpu::BufferView(vertexBufferPtr, + 0, + vertexBufferPtr->getSize() - sizeof(float) * 3, + sizeof(PolyVox::PositionMaterialNormal), + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)); + mesh->setVertexBuffer(*vertexBufferView); mesh->addAttribute(gpu::Stream::NORMAL, gpu::BufferView(vertexBufferPtr, sizeof(float) * 3, @@ -176,7 +201,6 @@ void RenderablePolyVoxEntityItem::getModel() { qDebug() << "---- vecIndices.size() =" << vecIndices.size(); qDebug() << "---- vecVertices.size() =" << vecVertices.size(); - _modelGeometry.setMesh(meshPtr); _needsModelReload = false; } @@ -310,6 +334,9 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { // revert decompressVolumeData(); } + + _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; + _needsModelReload = true; } @@ -329,8 +356,104 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { } } - _needsModelReload = true; - qDebug() << "--------------- voxel decompress ---------------"; qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size(); + + _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; + _needsModelReload = true; + getModel(); +} + +bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { + qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload); + + if (_needsModelReload) { + return false; + } + + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + if (_volData->getVoxelAt(x, y, z) > 0) { + return true; + } + } + } + } + + return false; +} + +void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { + qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo"; + ShapeType type = getShapeType(); + if (type != SHAPE_TYPE_COMPOUND) { + qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo NOT COMPOUND"; + PolyVoxEntityItem::computeShapeInfo(info); + info.setParams(type, 0.5f * getDimensions()); + } else { + _points.clear(); + unsigned int i = 0; + + glm::mat4 wToM = voxelToLocalMatrix(); + + AABox box; + + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + if (_volData->getVoxelAt(x, y, z) > 0) { + QVector pointsInPart; + + float offL = -0.5f; + float offH = 0.5f; + + // XXX I don't really understand why this make it line up. + // float offL = -1.0f; + // float offH = 0.0f; + + + glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); + glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); + glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); + glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); + glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); + glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); + glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); + glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); + + box += p000; + box += p001; + box += p010; + box += p011; + box += p100; + box += p101; + box += p110; + box += p111; + + pointsInPart << p000; + pointsInPart << p001; + pointsInPart << p010; + pointsInPart << p011; + pointsInPart << p100; + pointsInPart << p101; + pointsInPart << p110; + pointsInPart << p111; + + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; + } + } + } + } + + + glm::vec3 collisionModelDimensions = box.getDimensions(); + QByteArray b64 = _voxelData.toBase64(); + info.setParams(type, collisionModelDimensions, QString(b64)); + info.setConvexHulls(_points); + } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index b04b32996b..9623fab4f9 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -21,8 +21,7 @@ class RenderablePolyVoxEntityItem : public PolyVoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - PolyVoxEntityItem(entityItemID, properties) { } + RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual ~RenderablePolyVoxEntityItem(); @@ -47,14 +46,22 @@ public: virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); glm::mat4 voxelToWorldMatrix() const; + glm::mat4 voxelToLocalMatrix() const; glm::mat4 worldToVoxelMatrix() const; + + virtual bool isReadyToComputeShape(); + virtual void computeShapeInfo(ShapeInfo& info); + + // coords are in voxel-volume space virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue); // coords are in world-space virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue); + virtual void setAll(uint8_t toValue); + private: void compressVolumeData(); void decompressVolumeData(); @@ -62,6 +69,8 @@ private: PolyVox::SimpleVolume* _volData = nullptr; model::Geometry _modelGeometry; bool _needsModelReload = true; + + QVector> _points; // XXX }; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 579ec2a984..fe77e0799c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -420,3 +420,40 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c queueEntityMessage(PacketTypeEntityEdit, entityID, properties); return true; } + + +bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { + if (!_entityTree) { + return false; + } + + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID; + return false; + } + + EntityTypes::EntityType entityType = entity->getType(); + if (entityType != EntityTypes::PolyVox) { + return false; + } + + auto now = usecTimestampNow(); + + PolyVoxEntityItem* polyVoxEntity = static_cast(entity.get()); + _entityTree->lockForWrite(); + polyVoxEntity->setAll(value); + entity->setLastEdited(now); + entity->setLastBroadcast(now); + _entityTree->unlock(); + + _entityTree->lockForRead(); + EntityItemProperties properties = entity->getProperties(); + _entityTree->unlock(); + + properties.setVoxelDataDirty(); + properties.setLastEdited(now); + + queueEntityMessage(PacketTypeEntityEdit, entityID, properties); + return true; +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 6c2dc06579..421875feef 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -118,6 +118,7 @@ public slots: Q_INVOKABLE bool getSendPhysicsUpdates() const; Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); + Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE void dumpTree() const; diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index a46fdb2682..fd552f2a20 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -115,3 +115,8 @@ void PolyVoxEntityItem::debugDump() const { qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } + +// virtual +ShapeType PolyVoxEntityItem::getShapeType() const { + return SHAPE_TYPE_COMPOUND; +} diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 53675e6efa..472e72ead0 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -51,7 +51,7 @@ class PolyVoxEntityItem : public EntityItem { _color[BLUE_INDEX] = value.blue; } - virtual ShapeType getShapeType() const { return SHAPE_TYPE_POLYVOX; } + virtual ShapeType getShapeType() const; // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } @@ -88,6 +88,8 @@ class PolyVoxEntityItem : public EntityItem { // coords are in world-space virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {} + virtual void setAll(uint8_t toValue) {} + protected: rgbColor _color; glm::vec3 _voxelVolumeSize; // this is always 3 bytes diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index e2a77fbba2..a3fbe55f36 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -35,8 +35,7 @@ enum ShapeType { SHAPE_TYPE_CYLINDER_X, SHAPE_TYPE_CYLINDER_Y, SHAPE_TYPE_CYLINDER_Z, - SHAPE_TYPE_LINE, - SHAPE_TYPE_POLYVOX + SHAPE_TYPE_LINE }; class ShapeInfo { From c5a0dd72ec0f0f11ffebc8697659495c44d77b05 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 30 May 2015 18:13:57 -0700 Subject: [PATCH 06/19] keep track of number of non-zero voxels, use this information when deciding on shape-type --- .../src/RenderablePolyVoxEntityItem.cpp | 181 ++++++++++-------- .../src/RenderablePolyVoxEntityItem.h | 5 +- 2 files changed, 103 insertions(+), 83 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 4941acdf36..389a5eac4f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -70,6 +70,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive _voxelVolumeSize[1] - 1, _voxelVolumeSize[2] - 1); + _onCount = 0; _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); compressVolumeData(); @@ -117,12 +118,30 @@ glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { } +void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) { + // keep _onCount up to date + uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z); + if (toValue != 0) { + if (uVoxelValue == 0) { + _onCount++; + } + } else { + // toValue == 0 + if (uVoxelValue != 0) { + _onCount--; + assert(_onCount >= 0); + } + } +} + + void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { // XXX a volume that is all "on" has no mesh. make a different call for this nearly-all code: for (int z = 1; z < _volData->getDepth() - 1; z++) { for (int y = 1; y < _volData->getHeight() - 1; y++) { for (int x = 1; x < _volData->getWidth() - 1; x++) { - _volData->setVoxelAt(x, y, z, toValue); + updateOnCount(x, y, z, toValue); + _volData->setVoxelAt(x, y, z, toValue); } } } @@ -140,6 +159,7 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi float fDistToCenter = glm::distance(pos, center); // If the current voxel is less than 'radius' units from the center then we make it solid. if (fDistToCenter <= radius) { + updateOnCount(x, y, z, toValue); _volData->setVoxelAt(x, y, z, toValue); } } @@ -361,6 +381,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { for (int y = 0; y < _volData->getHeight(); y++) { for (int x = 0; x < _volData->getWidth(); x++) { int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x; + updateOnCount(x, y, z, uncompressedData[uncompressedIndex]); _volData->setVoxelAt(x, y, z, uncompressedData[uncompressedIndex]); } } @@ -374,96 +395,92 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { getModel(); } +// virtual +ShapeType RenderablePolyVoxEntityItem::getShapeType() const { + if (_onCount > 0) { + return SHAPE_TYPE_COMPOUND; + } + return SHAPE_TYPE_NONE; +} + + bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { - qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload); - if (_needsModelReload) { - getModel(); + return false; } - for (int z = 0; z < _volData->getDepth(); z++) { - for (int y = 0; y < _volData->getHeight(); y++) { - for (int x = 0; x < _volData->getWidth(); x++) { - if (_volData->getVoxelAt(x, y, z) > 0) { - return true; - } - } - } - } - - return false; + qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload); + return true; } void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo"; ShapeType type = getShapeType(); if (type != SHAPE_TYPE_COMPOUND) { - qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo NOT COMPOUND"; - PolyVoxEntityItem::computeShapeInfo(info); - info.setParams(type, 0.5f * getDimensions()); - } else { - _points.clear(); - unsigned int i = 0; - - glm::mat4 wToM = voxelToLocalMatrix(); - - AABox box; - - for (int z = 0; z < _volData->getDepth(); z++) { - for (int y = 0; y < _volData->getHeight(); y++) { - for (int x = 0; x < _volData->getWidth(); x++) { - if (_volData->getVoxelAt(x, y, z) > 0) { - QVector pointsInPart; - - float offL = -0.5f; - float offH = 0.5f; - - // XXX I don't really understand why this make it line up. - // float offL = -1.0f; - // float offH = 0.0f; - - - glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); - glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); - glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); - glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); - glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); - glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); - glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); - glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); - - box += p000; - box += p001; - box += p010; - box += p011; - box += p100; - box += p101; - box += p110; - box += p111; - - pointsInPart << p000; - pointsInPart << p001; - pointsInPart << p010; - pointsInPart << p011; - pointsInPart << p100; - pointsInPart << p101; - pointsInPart << p110; - pointsInPart << p111; - - // add next convex hull - QVector newMeshPoints; - _points << newMeshPoints; - // add points to the new convex hull - _points[i++] << pointsInPart; - } - } - } - } - - - glm::vec3 collisionModelDimensions = box.getDimensions(); - QByteArray b64 = _voxelData.toBase64(); - info.setParams(type, collisionModelDimensions, QString(b64)); - info.setConvexHulls(_points); + EntityItem::computeShapeInfo(info); + return; } + + _points.clear(); + unsigned int i = 0; + + glm::mat4 wToM = voxelToLocalMatrix(); + + AABox box; + + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + if (_volData->getVoxelAt(x, y, z) > 0) { + QVector pointsInPart; + + float offL = -0.5f; + float offH = 0.5f; + + glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); + glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); + glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); + glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); + glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); + glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); + glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); + glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); + + box += p000; + box += p001; + box += p010; + box += p011; + box += p100; + box += p101; + box += p110; + box += p111; + + pointsInPart << p000; + pointsInPart << p001; + pointsInPart << p010; + pointsInPart << p011; + pointsInPart << p100; + pointsInPart << p101; + pointsInPart << p110; + pointsInPart << p111; + + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; + } + } + } + } + + if (_points.isEmpty()) { + EntityItem::computeShapeInfo(info); + return; + } + + glm::vec3 collisionModelDimensions = box.getDimensions(); + QByteArray b64 = _voxelData.toBase64(); + info.setParams(type, collisionModelDimensions, QString(b64)); + info.setConvexHulls(_points); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index b569d3d5b6..d659cc0e69 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -33,6 +33,7 @@ public: // _needsModelReload = true; } + void updateOnCount(int x, int y, int z, uint8_t new_value); void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } @@ -51,7 +52,7 @@ public: glm::mat4 voxelToLocalMatrix() const; glm::mat4 worldToVoxelMatrix() const; - + virtual ShapeType getShapeType() const; virtual bool isReadyToComputeShape(); virtual void computeShapeInfo(ShapeInfo& info); @@ -73,6 +74,8 @@ private: bool _needsModelReload = true; QVector> _points; // XXX + + int _onCount = 0; // how many non-zero voxels are in _volData }; From ad71d7b7a245a0904116bf8abc1e31e6a5143c91 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 30 May 2015 18:14:36 -0700 Subject: [PATCH 07/19] allow changing of voxel-volume-size with edit.js --- examples/edit.js | 29 +++++++++++++++++++ examples/html/entityProperties.html | 26 ++++++++++++++++- examples/libraries/entityPropertyDialogBox.js | 24 +++++++++++++++ examples/voxels.js | 13 +++++++-- 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 7983a49575..455b843868 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -139,6 +139,7 @@ var toolBar = (function () { newTextButton, newWebButton, newZoneButton, + newPolyVoxButton, browseMarketplaceButton; function initialize() { @@ -224,6 +225,15 @@ var toolBar = (function () { visible: false }); + newPolyVoxButton = toolBar.addTool({ + imageURL: toolIconUrl + "upload.svg", // XXX need a new icon + subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: toolWidth, + height: toolHeight, + alpha: 0.9, + visible: false + }); + that.setActive(false); } @@ -266,6 +276,7 @@ var toolBar = (function () { toolBar.showTool(newTextButton, doShow); toolBar.showTool(newWebButton, doShow); toolBar.showTool(newZoneButton, doShow); + toolBar.showTool(newPolyVoxButton, doShow); }; var RESIZE_INTERVAL = 50; @@ -468,6 +479,24 @@ var toolBar = (function () { return true; } + if (newPolyVoxButton === toolBar.clicked(clickedOverlay)) { + var position = getPositionToCreateEntity(); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + placingEntityID = Entities.addEntity({ + type: "PolyVox", + position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), + DEFAULT_DIMENSIONS), + dimensions: { x: 10, y: 10, z: 10 }, + voxelVolumeSize: {x:16, y:16, z:16}, + voxelSurfaceStyle: 1 + }); + } else { + print("Can't create PolyVox: would be out of bounds."); + } + return true; + } + return false; }; diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 7c214624c2..6b1fc113d4 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -354,6 +354,11 @@ var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z"); var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars"); + var elPolyVoxSelections = document.querySelectorAll(".poly-vox-section"); + var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x"); + var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y"); + var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { @@ -588,7 +593,11 @@ elParticleEmitStrength.value = properties.emitStrength.toFixed(2); elParticleLocalGravity.value = properties.localGravity.toFixed(2); elParticleRadius.value = properties.particleRadius.toFixed(3); - } + } else if (properties.type == "PolyVox") { + elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); + elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); + elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2); + } if (selected) { activeElement.focus(); @@ -832,6 +841,12 @@ elZoneAtmosphereScatteringWavelengthsZ.addEventListener('change', zoneAtmosphereScatterWavelengthsChangeFunction); elZoneAtmosphereHasStars.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('atmosphere','hasStars')); + var voxelVolumeSizeChangeFunction = createEmitVec3PropertyUpdateFunction( + 'voxelVolumeSize', elVoxelVolumeSizeX, elVoxelVolumeSizeY, elVoxelVolumeSizeZ); + elVoxelVolumeSizeX.addEventListener('change', voxelVolumeSizeChangeFunction); + elVoxelVolumeSizeY.addEventListener('change', voxelVolumeSizeChangeFunction); + elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ @@ -973,6 +988,15 @@ +
+
Voxel Volume Size
+
+
X
+
Y
+
Z
+
+
+
Rotation
diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index f9f8d57a51..567b6e3024 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -98,6 +98,21 @@ EntityPropertyDialogBox = (function () { index++; } + if (properties.type == "PolyVox") { + array.push({ label: "Shape Type:", value: properties.shapeType }); + index++; + + array.push({ label: "Voxel Space Size:", type: "header" }); + index++; + + array.push({ label: "X:", value: properties.voxelVolumeSize.x.toFixed(decimals) }); + index++; + array.push({ label: "Y:", value: properties.voxelVolumeSize.y.toFixed(decimals) }); + index++; + array.push({ label: "Z:", value: properties.voxelVolumeSize.z.toFixed(decimals) }); + index++; + } + array.push({ label: "Position:", type: "header" }); index++; array.push({ label: "X:", value: properties.position.x.toFixed(decimals) }); @@ -333,6 +348,15 @@ EntityPropertyDialogBox = (function () { properties.backgroundColor.blue = array[index++].value; } + if (properties.type == "PolyVox") { + properties.shapeType = array[index++].value; + + index++; // skip header + properties.voxelVolumeSize.x = array[index++].value; + properties.voxelVolumeSize.y = array[index++].value; + properties.voxelVolumeSize.z = array[index++].value; + } + index++; // skip header properties.position.x = array[index++].value; properties.position.y = array[index++].value; diff --git a/examples/voxels.js b/examples/voxels.js index 351e723a5b..fc9f6550f5 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -1,5 +1,6 @@ var controlHeld = false; +var shiftHeld = false; function mousePressEvent(event) { @@ -15,9 +16,11 @@ function mousePressEvent(event) { for (var i = 0; i < ids.length; i++) { var id = ids[i]; if (controlHeld) { - Entities.setVoxelSphere(id, intersection.intersection, 0.5, 0); + Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0); + } else if (shiftHeld) { + Entities.setAllVoxels(id, 255); } else { - Entities.setVoxelSphere(id, intersection.intersection, 0.5, 255); + Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255); } } } @@ -28,6 +31,9 @@ function keyPressEvent(event) { if (event.text == "CONTROL") { controlHeld = true; } + if (event.text == "SHIFT") { + shiftHeld = true; + } } @@ -35,6 +41,9 @@ function keyReleaseEvent(event) { if (event.text == "CONTROL") { controlHeld = false; } + if (event.text == "SHIFT") { + shiftHeld = false; + } } From f955cb45b2af42dd334a5474dc97a41daba6f20e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 30 May 2015 18:14:54 -0700 Subject: [PATCH 08/19] keep track of number of non-zero voxels, use this information when deciding on shape-type --- libraries/entities/src/PolyVoxEntityItem.cpp | 6 ------ libraries/entities/src/PolyVoxEntityItem.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index fd552f2a20..a7f1128771 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -114,9 +114,3 @@ void PolyVoxEntityItem::debugDump() const { qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } - - -// virtual -ShapeType PolyVoxEntityItem::getShapeType() const { - return SHAPE_TYPE_COMPOUND; -} diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 06abf7135d..467d41f3e1 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -41,8 +41,6 @@ class PolyVoxEntityItem : public EntityItem { ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - virtual ShapeType getShapeType() const; - // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, From a3589788df19ed31245605b36b0afd978bc0fd90 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 30 May 2015 18:33:35 -0700 Subject: [PATCH 09/19] allow edit.js to change between cubic and marching-cubes surface extractor on polyvox entity-items. --- examples/html/entityProperties.html | 12 ++++++++++++ examples/libraries/entityPropertyDialogBox.js | 7 ++++--- .../src/RenderablePolyVoxEntityItem.cpp | 1 + libraries/entities/src/PolyVoxEntityItem.h | 3 ++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 6b1fc113d4..21e2e83136 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -358,6 +358,7 @@ var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x"); var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y"); var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z"); + var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style"); if (window.EventBridge !== undefined) { @@ -597,6 +598,7 @@ elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2); + elVoxelSurfaceStyle.value = properties.voxelSurfaceStyle; } if (selected) { @@ -846,6 +848,7 @@ elVoxelVolumeSizeX.addEventListener('change', voxelVolumeSizeChangeFunction); elVoxelVolumeSizeY.addEventListener('change', voxelVolumeSizeChangeFunction); elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction); + elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle')); elMoveSelectionToGrid.addEventListener("click", function() { @@ -994,6 +997,15 @@
X
Y
Z
+
+ +
Surface Extractor
+
+
diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index 567b6e3024..1b1a6a9c12 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -99,9 +99,6 @@ EntityPropertyDialogBox = (function () { } if (properties.type == "PolyVox") { - array.push({ label: "Shape Type:", value: properties.shapeType }); - index++; - array.push({ label: "Voxel Space Size:", type: "header" }); index++; @@ -111,6 +108,9 @@ EntityPropertyDialogBox = (function () { index++; array.push({ label: "Z:", value: properties.voxelVolumeSize.z.toFixed(decimals) }); index++; + + array.push({ label: "Surface Extractor", value: properties.voxelSurfaceStyle }); + index++; } array.push({ label: "Position:", type: "header" }); @@ -355,6 +355,7 @@ EntityPropertyDialogBox = (function () { properties.voxelVolumeSize.x = array[index++].value; properties.voxelVolumeSize.y = array[index++].value; properties.voxelVolumeSize.z = array[index++].value; + properties.voxelSurfaceStyle = array[index++].value; } index++; // skip header diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 389a5eac4f..97484f246f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -188,6 +188,7 @@ void RenderablePolyVoxEntityItem::getModel() { surfaceExtractor.execute(); break; } + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: case PolyVoxEntityItem::SURFACE_CUBIC: { PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor (_volData, _volData->getEnclosingRegion(), &polyVoxMesh); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 467d41f3e1..530f073237 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -57,7 +57,8 @@ class PolyVoxEntityItem : public EntityItem { enum PolyVoxSurfaceStyle { SURFACE_MARCHING_CUBES, - SURFACE_CUBIC + SURFACE_CUBIC, + SURFACE_EDGED_CUBIC }; virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; } From b9202ebfb62d41478167c5c5e676fe36c79099c9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 31 May 2015 09:14:59 -0700 Subject: [PATCH 10/19] added SURFACE_EDGED_CUBIC surface extractor which pads the outsides of the voxel-space with empty cells to change how the edges of the surface look --- examples/voxels.js | 4 +- .../src/RenderablePolyVoxEntityItem.cpp | 316 ++++++++++++------ .../src/RenderablePolyVoxEntityItem.h | 4 + libraries/entities/src/PolyVoxEntityItem.h | 3 + 4 files changed, 217 insertions(+), 110 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index fc9f6550f5..5e4ea8df01 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -16,11 +16,11 @@ function mousePressEvent(event) { for (var i = 0; i < ids.length; i++) { var id = ids[i]; if (controlHeld) { - Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0); + Entities.setVoxelSphere(id, intersection.intersection, 4.0, 0); } else if (shiftHeld) { Entities.setAllVoxels(id, 255); } else { - Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255); + Entities.setVoxelSphere(id, intersection.intersection, 4.0, 255); } } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 97484f246f..91d702e52b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -41,11 +41,12 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : PolyVoxEntityItem(entityItemID, properties) { - setVoxelVolumeSize(_voxelVolumeSize); model::Mesh* mesh = new model::Mesh(); model::MeshPointer meshPtr(mesh); _modelGeometry.setMesh(meshPtr); + + setVoxelVolumeSize(_voxelVolumeSize); } @@ -66,22 +67,43 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) delete _volData; } - PolyVox::Vector3DInt32 lowCorner(0, 0, 0); - PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive - _voxelVolumeSize[1] - 1, - _voxelVolumeSize[2] - 1); _onCount = 0; - _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); - compressVolumeData(); + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + PolyVox::Vector3DInt32 lowCorner(0, 0, 0); + PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] + 1, // -1 + 2 because these corners are inclusive + _voxelVolumeSize[1] + 1, + _voxelVolumeSize[2] + 1); + _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); + } else { + PolyVox::Vector3DInt32 lowCorner(0, 0, 0); + PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive + _voxelVolumeSize[1] - 1, + _voxelVolumeSize[2] - 1); + _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); + } + _volData->setBorderValue(255); + decompressVolumeData(); } void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { if (voxelSurfaceStyle == _voxelSurfaceStyle) { - return; + return; + } + + // if we are switching to or from "edged" we need to force a resize of _volData. + if (voxelSurfaceStyle == SURFACE_EDGED_CUBIC || + _voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + if (_volData) { + delete _volData; + } + _volData = nullptr; + PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); + setVoxelVolumeSize(_voxelVolumeSize); + } else { + PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); } - PolyVoxEntityItem::setVoxelSurfaceStyle(voxelSurfaceStyle); _needsModelReload = true; } @@ -95,53 +117,92 @@ void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) { } -glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { +glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const { glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units - glm::mat4 scaled = glm::scale(glm::mat4(), scale); - glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f); - glm::mat4 rotation = glm::mat4_cast(_rotation); - glm::mat4 translation = glm::translate(getCenter()); - return translation * rotation * centerToCorner; + switch (_voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: + return scale / 2.0f; + // return glm::vec3(0.5f, 0.5f, 0.5f); + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: + return scale / -2.0f; + // return glm::vec3(-0.5f, -0.5f, -0.5f); + case PolyVoxEntityItem::SURFACE_CUBIC: + return scale / 2.0f; + // return glm::vec3(0.5f, 0.5f, 0.5f); + } + return glm::vec3(0, 0, 0); } - glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units glm::mat4 scaled = glm::scale(glm::mat4(), scale); - glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f); + glm::mat4 centerToCorner = glm::translate(scaled, (_voxelVolumeSize / -2.0f) + getSurfacePositionAdjustment()); return centerToCorner; } +glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { + glm::mat4 rotation = glm::mat4_cast(_rotation); + glm::mat4 translation = glm::translate(getCenter()); + return translation * rotation * voxelToLocalMatrix(); +} + + glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix()); return worldToModelMatrix; - } +uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { + assert(_volData); + if (x < 0 || y < 0 || z < 0 || + x >= _voxelVolumeSize[0] || y >= _voxelVolumeSize[1] || z >= _voxelVolumeSize[2]) { + return 0; + } + + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + return _volData->getVoxelAt(x + 1, y + 1, z + 1); + } + return _volData->getVoxelAt(x, y, z); +} + +void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) { + assert(_volData); + if (x < 0 || y < 0 || z < 0 || + x >= _voxelVolumeSize[0] || y >= _voxelVolumeSize[1] || z >= _voxelVolumeSize[2]) { + return; + } + + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + _volData->setVoxelAt(x + 1, y + 1, z + 1, toValue); + } else { + _volData->setVoxelAt(x, y, z, toValue); + } +} + + void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) { // keep _onCount up to date - uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z); + uint8_t uVoxelValue = getVoxel(x, y, z); if (toValue != 0) { - if (uVoxelValue == 0) { - _onCount++; - } + if (uVoxelValue == 0) { + _onCount++; + } } else { - // toValue == 0 - if (uVoxelValue != 0) { - _onCount--; - assert(_onCount >= 0); - } + // toValue == 0 + if (uVoxelValue != 0) { + _onCount--; + assert(_onCount >= 0); + } } } void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { - // XXX a volume that is all "on" has no mesh. make a different call for this nearly-all code: - for (int z = 1; z < _volData->getDepth() - 1; z++) { - for (int y = 1; y < _volData->getHeight() - 1; y++) { - for (int x = 1; x < _volData->getWidth() - 1; x++) { - updateOnCount(x, y, z, toValue); - _volData->setVoxelAt(x, y, z, toValue); + for (int z = 0; z < _voxelVolumeSize[2]; z++) { + for (int y = 0; y < _voxelVolumeSize[1]; y++) { + for (int x = 0; x < _voxelVolumeSize[0]; x++) { + updateOnCount(x, y, z, toValue); + setVoxel(x, y, z, toValue); } } } @@ -150,17 +211,17 @@ void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { // This three-level for loop iterates over every voxel in the volume - for (int z = 0; z < _volData->getDepth(); z++) { - for (int y = 0; y < _volData->getHeight(); y++) { - for (int x = 0; x < _volData->getWidth(); x++) { + for (int z = 0; z < _voxelVolumeSize[2]; z++) { + for (int y = 0; y < _voxelVolumeSize[1]; y++) { + for (int x = 0; x < _voxelVolumeSize[0]; x++) { // Store our current position as a vector... glm::vec3 pos(x, y, z); // And compute how far the current position is from the center of the volume float fDistToCenter = glm::distance(pos, center); // If the current voxel is less than 'radius' units from the center then we make it solid. if (fDistToCenter <= radius) { - updateOnCount(x, y, z, toValue); - _volData->setVoxelAt(x, y, z, toValue); + updateOnCount(x, y, z, toValue); + setVoxel(x, y, z, toValue); } } } @@ -235,6 +296,33 @@ void RenderablePolyVoxEntityItem::getModel() { _needsModelReload = false; } + +QString GLMatrixToString(GLfloat* m) { + QString mString = "\n"; + for (int x = 0; x < 4; x++) { + for (int y = 0; y < 4; y++) { + mString += QString::number((double)m[y*4+x], 'f', 2) + " "; + } + mString += "\n"; + } + return mString; +} + + +void printModelViewMatrix() { + GLfloat glMatrix[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, glMatrix); + qDebug() << GLMatrixToString(glMatrix); +} + +void printProjectionMatrix() { + GLfloat glMatrix[16]; + glGetFloatv(GL_PROJECTION_MATRIX, glMatrix); + qDebug() << GLMatrixToString(glMatrix); +} + + + void RenderablePolyVoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); assert(getType() == EntityTypes::PolyVox); @@ -243,20 +331,23 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { getModel(); } - glm::vec3 position = getPosition(); - glm::vec3 dimensions = getDimensions(); - glm::vec3 scale = dimensions / _voxelVolumeSize; - glm::vec3 center = getCenter(); - glm::quat rotation = getRotation(); + // glm::vec3 position = getPosition(); + // glm::vec3 dimensions = getDimensions(); + // glm::vec3 scale = dimensions / _voxelVolumeSize; + // glm::vec3 center = getCenter(); + // glm::quat rotation = getRotation(); 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); - glm::vec3 positionToCenter = center - position; - // make the rendered voxel volume be centered on the entity's position - positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f); - glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); - glScalef(scale.x, scale.y, scale.z); + // 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); + // glm::vec3 positionToCenter = center - position; + // // make the rendered voxel volume be centered on the entity's position + // positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f) - getSurfacePositionAdjustment(); + // glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + // glScalef(scale.x, scale.y, scale.z); + + glm::mat4 m = voxelToWorldMatrix(); + glMultMatrixf(&m[0][0]); auto mesh = _modelGeometry.getMesh(); gpu::Batch batch; @@ -341,14 +432,17 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // compress the data in _volData and save the results. The compressed form is used during // saves to disk and for transmission over the wire void RenderablePolyVoxEntityItem::compressVolumeData() { - int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth(); + int rawSize = _voxelVolumeSize[0] * _voxelVolumeSize[1] * _voxelVolumeSize[2]; QByteArray uncompressedData = QByteArray(rawSize, '\0'); - for (int z = 0; z < _volData->getDepth(); z++) { - for (int y = 0; y < _volData->getHeight(); y++) { - for (int x = 0; x < _volData->getWidth(); x++) { - uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z); - int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x; + for (int z = 0; z < _voxelVolumeSize[2]; z++) { + for (int y = 0; y < _voxelVolumeSize[1]; y++) { + for (int x = 0; x < _voxelVolumeSize[0]; x++) { + uint8_t uVoxelValue = getVoxel(x, y, z); + int uncompressedIndex = + z * _voxelVolumeSize[1] * _voxelVolumeSize[0] + + y * _voxelVolumeSize[0] + + x; uncompressedData[uncompressedIndex] = uVoxelValue; } } @@ -373,17 +467,20 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { // take compressed data and decompreess it into _volData. void RenderablePolyVoxEntityItem::decompressVolumeData() { - int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth(); + int rawSize = _voxelVolumeSize[0] * _voxelVolumeSize[1] * _voxelVolumeSize[2]; QByteArray uncompressedData = QByteArray(rawSize, '\0'); uncompressedData = qUncompress(_voxelData); - for (int z = 0; z < _volData->getDepth(); z++) { - for (int y = 0; y < _volData->getHeight(); y++) { - for (int x = 0; x < _volData->getWidth(); x++) { - int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x; - updateOnCount(x, y, z, uncompressedData[uncompressedIndex]); - _volData->setVoxelAt(x, y, z, uncompressedData[uncompressedIndex]); + for (int z = 0; z < _voxelVolumeSize[2]; z++) { + for (int y = 0; y < _voxelVolumeSize[1]; y++) { + for (int x = 0; x < _voxelVolumeSize[0]; x++) { + int uncompressedIndex = + z * _voxelVolumeSize[1] * _voxelVolumeSize[0] + + y * _voxelVolumeSize[0] + + x; + updateOnCount(x, y, z, uncompressedData[uncompressedIndex]); + setVoxel(x, y, z, uncompressedData[uncompressedIndex]); } } } @@ -399,7 +496,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { // virtual ShapeType RenderablePolyVoxEntityItem::getShapeType() const { if (_onCount > 0) { - return SHAPE_TYPE_COMPOUND; + return SHAPE_TYPE_COMPOUND; } return SHAPE_TYPE_NONE; } @@ -407,7 +504,7 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const { bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { if (_needsModelReload) { - return false; + return false; } qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload); @@ -419,7 +516,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { ShapeType type = getShapeType(); if (type != SHAPE_TYPE_COMPOUND) { EntityItem::computeShapeInfo(info); - return; + return; } _points.clear(); @@ -429,55 +526,58 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { AABox box; - for (int z = 0; z < _volData->getDepth(); z++) { - for (int y = 0; y < _volData->getHeight(); y++) { - for (int x = 0; x < _volData->getWidth(); x++) { - if (_volData->getVoxelAt(x, y, z) > 0) { - QVector pointsInPart; + for (int z = 0; z < _voxelVolumeSize[2]; z++) { + for (int y = 0; y < _voxelVolumeSize[1]; y++) { + for (int x = 0; x < _voxelVolumeSize[0]; x++) { + if (getVoxel(x, y, z) > 0) { + QVector pointsInPart; - float offL = -0.5f; - float offH = 0.5f; + float offL = -0.5f; + float offH = 0.5f; - glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); - glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); - glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); - glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); - glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); - glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); - glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); - glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); + // float offL = 0.0f; + // float offH = 1.0f; + + glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); + glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); + glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); + glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); + glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); + glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); + glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); + glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); - box += p000; - box += p001; - box += p010; - box += p011; - box += p100; - box += p101; - box += p110; - box += p111; + box += p000; + box += p001; + box += p010; + box += p011; + box += p100; + box += p101; + box += p110; + box += p111; - pointsInPart << p000; - pointsInPart << p001; - pointsInPart << p010; - pointsInPart << p011; - pointsInPart << p100; - pointsInPart << p101; - pointsInPart << p110; - pointsInPart << p111; + pointsInPart << p000; + pointsInPart << p001; + pointsInPart << p010; + pointsInPart << p011; + pointsInPart << p100; + pointsInPart << p101; + pointsInPart << p110; + pointsInPart << p111; - // add next convex hull - QVector newMeshPoints; - _points << newMeshPoints; - // add points to the new convex hull - _points[i++] << pointsInPart; - } - } - } + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; + } + } + } } if (_points.isEmpty()) { - EntityItem::computeShapeInfo(info); - return; + EntityItem::computeShapeInfo(info); + return; } glm::vec3 collisionModelDimensions = box.getDimensions(); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index d659cc0e69..a054a6a88f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -33,6 +33,9 @@ public: // _needsModelReload = true; } + virtual uint8_t getVoxel(int x, int y, int z); + virtual void setVoxel(int x, int y, int z, uint8_t toValue); + void updateOnCount(int x, int y, int z, uint8_t new_value); void render(RenderArgs* args); @@ -48,6 +51,7 @@ public: virtual void setVoxelData(QByteArray voxelData); virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); + glm::vec3 getSurfacePositionAdjustment() const; glm::mat4 voxelToWorldMatrix() const; glm::mat4 voxelToLocalMatrix() const; glm::mat4 worldToVoxelMatrix() const; diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 530f073237..8ef59f9f17 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -79,6 +79,9 @@ class PolyVoxEntityItem : public EntityItem { virtual void setAll(uint8_t toValue) {} + virtual uint8_t getVoxel(int x, int y, int z) { return 0; } + virtual void setVoxel(int x, int y, int z, uint8_t toValue) {} + protected: glm::vec3 _voxelVolumeSize; // this is always 3 bytes QByteArray _voxelData; From cfeab893e776e4c5906c9c5e39d4f1712e704a1c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 31 May 2015 09:28:33 -0700 Subject: [PATCH 11/19] fix voxelToLocalMatrix --- .../src/RenderablePolyVoxEntityItem.cpp | 34 +++++-------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 91d702e52b..dfe4885717 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -49,7 +49,6 @@ RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& ent setVoxelVolumeSize(_voxelVolumeSize); } - RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() { delete _volData; } @@ -86,7 +85,6 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) decompressVolumeData(); } - void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { if (voxelSurfaceStyle == _voxelSurfaceStyle) { return; @@ -107,7 +105,6 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel _needsModelReload = true; } - void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) { if (voxelData == _voxelData) { return; @@ -116,37 +113,36 @@ void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) { decompressVolumeData(); } - glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const { glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units switch (_voxelSurfaceStyle) { case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: return scale / 2.0f; - // return glm::vec3(0.5f, 0.5f, 0.5f); case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: return scale / -2.0f; - // return glm::vec3(-0.5f, -0.5f, -0.5f); case PolyVoxEntityItem::SURFACE_CUBIC: return scale / 2.0f; - // return glm::vec3(0.5f, 0.5f, 0.5f); } return glm::vec3(0, 0, 0); } glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units - glm::mat4 scaled = glm::scale(glm::mat4(), scale); - glm::mat4 centerToCorner = glm::translate(scaled, (_voxelVolumeSize / -2.0f) + getSurfacePositionAdjustment()); - return centerToCorner; + glm::vec3 center = getCenter(); + glm::vec3 position = getPosition(); + glm::vec3 positionToCenter = center - position; + positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f) - getSurfacePositionAdjustment(); + glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter); + glm::mat4 scaled = glm::scale(centerToCorner, scale); + return scaled; } glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { glm::mat4 rotation = glm::mat4_cast(_rotation); - glm::mat4 translation = glm::translate(getCenter()); + glm::mat4 translation = glm::translate(getPosition()); return translation * rotation * voxelToLocalMatrix(); } - glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix()); return worldToModelMatrix; @@ -331,21 +327,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { getModel(); } - // glm::vec3 position = getPosition(); - // glm::vec3 dimensions = getDimensions(); - // glm::vec3 scale = dimensions / _voxelVolumeSize; - // glm::vec3 center = getCenter(); - // glm::quat rotation = getRotation(); 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); - // glm::vec3 positionToCenter = center - position; - // // make the rendered voxel volume be centered on the entity's position - // positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f) - getSurfacePositionAdjustment(); - // glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); - // glScalef(scale.x, scale.y, scale.z); - glm::mat4 m = voxelToWorldMatrix(); glMultMatrixf(&m[0][0]); From 00af0a43761a3af3a24d13509f58e8956513612e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Jun 2015 07:15:37 -0700 Subject: [PATCH 12/19] trying to make thing behave when voxel-space is resized --- examples/voxels.js | 4 +- .../src/RenderablePolyVoxEntityItem.cpp | 124 +++++++++++------- .../src/RenderablePolyVoxEntityItem.h | 1 + libraries/shared/src/SettingInterface.cpp | 12 +- 4 files changed, 89 insertions(+), 52 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index 5e4ea8df01..fc9f6550f5 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -16,11 +16,11 @@ function mousePressEvent(event) { for (var i = 0; i < ids.length; i++) { var id = ids[i]; if (controlHeld) { - Entities.setVoxelSphere(id, intersection.intersection, 4.0, 0); + Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0); } else if (shiftHeld) { Entities.setAllVoxels(id, 255); } else { - Entities.setVoxelSphere(id, intersection.intersection, 4.0, 255); + Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255); } } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index dfe4885717..63c8104c80 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -60,6 +60,8 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) qDebug() << "resetting voxel-space size"; + + glm::vec3 previousVolumeSize = _voxelVolumeSize; PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize); if (_volData) { @@ -82,7 +84,8 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); } _volData->setBorderValue(255); - decompressVolumeData(); + decompressVolumeData(previousVolumeSize); + compressVolumeData(); } void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { @@ -155,6 +158,10 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { return 0; } + // if _voxelSurfaceStyle is SURFACE_EDGED_CUBIC, we maintain an extra layer of + // voxels all around the requested voxel space. Having the empty voxels around + // the edges changes how the surface extractor behaves. + if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { return _volData->getVoxelAt(x + 1, y + 1, z + 1); } @@ -211,7 +218,7 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi for (int y = 0; y < _voxelVolumeSize[1]; y++) { for (int x = 0; x < _voxelVolumeSize[0]; x++) { // Store our current position as a vector... - glm::vec3 pos(x, y, z); + glm::vec3 pos(x + 0.5f, y + 0.5f, z + 0.5f); // consider voxels cenetered on their coordinates // And compute how far the current position is from the center of the volume float fDistToCenter = glm::distance(pos, center); // If the current voxel is less than 'radius' units from the center then we make it solid. @@ -293,29 +300,29 @@ void RenderablePolyVoxEntityItem::getModel() { } -QString GLMatrixToString(GLfloat* m) { - QString mString = "\n"; - for (int x = 0; x < 4; x++) { - for (int y = 0; y < 4; y++) { - mString += QString::number((double)m[y*4+x], 'f', 2) + " "; - } - mString += "\n"; - } - return mString; -} +// QString GLMatrixToString(GLfloat* m) { +// QString mString = "\n"; +// for (int x = 0; x < 4; x++) { +// for (int y = 0; y < 4; y++) { +// mString += QString::number((double)m[y*4+x], 'f', 2) + " "; +// } +// mString += "\n"; +// } +// return mString; +// } -void printModelViewMatrix() { - GLfloat glMatrix[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, glMatrix); - qDebug() << GLMatrixToString(glMatrix); -} +// void printModelViewMatrix() { +// GLfloat glMatrix[16]; +// glGetFloatv(GL_MODELVIEW_MATRIX, glMatrix); +// qDebug() << GLMatrixToString(glMatrix); +// } -void printProjectionMatrix() { - GLfloat glMatrix[16]; - glGetFloatv(GL_PROJECTION_MATRIX, glMatrix); - qDebug() << GLMatrixToString(glMatrix); -} +// void printProjectionMatrix() { +// GLfloat glMatrix[16]; +// glGetFloatv(GL_PROJECTION_MATRIX, glMatrix); +// qDebug() << GLMatrixToString(glMatrix); +// } @@ -349,9 +356,20 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { class RaycastFunctor { public: - RaycastFunctor() : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) { } + RaycastFunctor(PolyVox::SimpleVolume* vol) : + _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)), + _vol(vol) { + } bool operator()(PolyVox::SimpleVolume::Sampler& sampler) { + int x = sampler.getPosition().getX(); + int y = sampler.getPosition().getY(); + int z = sampler.getPosition().getZ(); + if (x < 0 || y < 0 || z < 0 || + x > _vol->getWidth() || y > _vol->getHeight() || z > _vol->getDepth()) { + return true; + } + if (sampler.getVoxel() == 0) { return true; // keep raycasting } @@ -360,6 +378,7 @@ public: return false; } glm::vec4 _result; + const PolyVox::SimpleVolume* _vol = nullptr; }; bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, @@ -375,33 +394,45 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o return true; } + // the PolyVox ray intersection code requires a near and far point. glm::mat4 wtvMatrix = worldToVoxelMatrix(); - glm::vec3 farPoint = origin + direction; + glm::vec3 normDirection = glm::normalize(direction); + + // set ray cast length to long enough to cover all of the voxel space + float distanceToEntity = glm::distance(origin, _position); + float largestDimension = glm::max(_dimensions[0], _dimensions[1], _dimensions[2]) * 2.0f; + + glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); + glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f); - glm::vec4 directionInVoxel = farInVoxel - originInVoxel; - + PolyVox::Vector3DFloat start(originInVoxel[0], originInVoxel[1], originInVoxel[2]); - PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]); - pvDirection.normalise(); - - // the PolyVox ray intersection code requires a near and far point. - glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units - float distanceToEntity = glm::distance(origin, _position); - float largestDimension = glm::max(_dimensions[0], _dimensions[1], _dimensions[2]); - // set ray cast length to long enough to cover all of the voxel space - pvDirection *= (distanceToEntity + largestDimension) / glm::min(scale[0], scale[1], scale[2]); + // PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]); + PolyVox::Vector3DFloat far(farInVoxel[0], farInVoxel[1], farInVoxel[2]); PolyVox::RaycastResult raycastResult; - RaycastFunctor callback; - raycastResult = PolyVox::raycastWithDirection(_volData, start, pvDirection, callback); + RaycastFunctor callback(_volData); + raycastResult = PolyVox::raycastWithEndpoints(_volData, start, far, callback); if (raycastResult == PolyVox::RaycastResults::Completed) { // the ray completed its path -- nothing was hit. return false; } - glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * callback._result; + glm::vec4 result = callback._result; + switch (_voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: + result -= glm::vec4(1, 1, 1, 0); // compensate for the extra voxel border + break; + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: + case PolyVoxEntityItem::SURFACE_CUBIC: + break; + } + + result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f); + + glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * result; distance = glm::distance(glm::vec3(intersectedWorldPosition), origin); @@ -449,17 +480,22 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { // take compressed data and decompreess it into _volData. void RenderablePolyVoxEntityItem::decompressVolumeData() { - int rawSize = _voxelVolumeSize[0] * _voxelVolumeSize[1] * _voxelVolumeSize[2]; + decompressVolumeData(_voxelVolumeSize); +} + + +void RenderablePolyVoxEntityItem::decompressVolumeData(glm::vec3 volumeSize) { + int rawSize = volumeSize[0] * volumeSize[1] * volumeSize[2]; QByteArray uncompressedData = QByteArray(rawSize, '\0'); uncompressedData = qUncompress(_voxelData); - for (int z = 0; z < _voxelVolumeSize[2]; z++) { - for (int y = 0; y < _voxelVolumeSize[1]; y++) { - for (int x = 0; x < _voxelVolumeSize[0]; x++) { + for (int z = 0; z < volumeSize[2]; z++) { + for (int y = 0; y < volumeSize[1]; y++) { + for (int x = 0; x < volumeSize[0]; x++) { int uncompressedIndex = - z * _voxelVolumeSize[1] * _voxelVolumeSize[0] + - y * _voxelVolumeSize[0] + + z * volumeSize[1] * volumeSize[0] + + y * volumeSize[0] + x; updateOnCount(x, y, z, uncompressedData[uncompressedIndex]); setVoxel(x, y, z, uncompressedData[uncompressedIndex]); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index a054a6a88f..c8039e79c1 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -72,6 +72,7 @@ public: private: void compressVolumeData(); void decompressVolumeData(); + void decompressVolumeData(glm::vec3 volumeSize); PolyVox::SimpleVolume* _volData = nullptr; model::Geometry _modelGeometry; diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 26cbe3ca13..ee72a4ab45 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -39,12 +39,12 @@ namespace Setting { void init() { // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings::setDefaultFormat(QSettings::IniFormat); - QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); - // set the associated application properties - applicationInfo.beginGroup("INFO"); - QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); - QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); - QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + // QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); + // // set the associated application properties + // applicationInfo.beginGroup("INFO"); + // QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); + // QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); + // QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); // Let's set up the settings Private instance on it's own thread QThread* thread = new QThread(); From d04b61d6a8cb245897e0297b648ab1ccedab9419 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Jun 2015 07:16:16 -0700 Subject: [PATCH 13/19] oops --- libraries/shared/src/SettingInterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index ee72a4ab45..26cbe3ca13 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -39,12 +39,12 @@ namespace Setting { void init() { // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings::setDefaultFormat(QSettings::IniFormat); - // QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); - // // set the associated application properties - // applicationInfo.beginGroup("INFO"); - // QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); - // QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); - // QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); + // set the associated application properties + applicationInfo.beginGroup("INFO"); + QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); + QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); + QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); // Let's set up the settings Private instance on it's own thread QThread* thread = new QThread(); From 43a1519e2952cc041a11c28fd9e95bed3df59e6a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Jun 2015 12:01:45 -0700 Subject: [PATCH 14/19] better handling of changes to the size of voxel space. limit each dimension to 32 --- .../src/RenderablePolyVoxEntityItem.cpp | 187 ++++++++++++------ .../src/RenderablePolyVoxEntityItem.h | 4 +- libraries/entities/src/PolyVoxEntityItem.cpp | 37 +++- libraries/entities/src/PolyVoxEntityItem.h | 7 +- 4 files changed, 172 insertions(+), 63 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 63c8104c80..c3b5033466 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -53,15 +53,35 @@ RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() { delete _volData; } +bool inBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, + int x, int y, int z) { + switch (surfaceStyle) { + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: + case PolyVoxEntityItem::SURFACE_CUBIC: + if (x < 0 || y < 0 || z < 0 || + x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) { + return false; + } + return true; + + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: + if (x < 1 || y < 1 || z < 1 || + x >= vol->getWidth() - 1 || y >= vol->getHeight() - 1 || z >= vol->getDepth() - 1) { + return false; + } + return true; + } + + return false; +} + void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { if (_volData && voxelVolumeSize == _voxelVolumeSize) { return; } - qDebug() << "resetting voxel-space size"; + qDebug() << "resetting voxel-space size" << voxelVolumeSize.x << voxelVolumeSize.y << voxelVolumeSize.z; - - glm::vec3 previousVolumeSize = _voxelVolumeSize; PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize); if (_volData) { @@ -71,21 +91,43 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) _onCount = 0; if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) { + // with _EDGED_ we maintain an extra box of voxels around those that the user asked for. This + // changes how the surface extractor acts -- mainly it becomes impossible to have holes in the + // generated mesh. The non _EDGED_ modes will leave holes in the mesh at the edges of the + // voxel space. PolyVox::Vector3DInt32 lowCorner(0, 0, 0); - PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] + 1, // -1 + 2 because these corners are inclusive - _voxelVolumeSize[1] + 1, - _voxelVolumeSize[2] + 1); + PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x + 1, // -1 + 2 because these corners are inclusive + _voxelVolumeSize.y + 1, + _voxelVolumeSize.z + 1); _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); } else { PolyVox::Vector3DInt32 lowCorner(0, 0, 0); - PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive - _voxelVolumeSize[1] - 1, - _voxelVolumeSize[2] - 1); + PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x - 1, // -1 because these corners are inclusive + _voxelVolumeSize.y - 1, + _voxelVolumeSize.z - 1); _volData = new PolyVox::SimpleVolume(PolyVox::Region(lowCorner, highCorner)); } + + // having the "outside of voxel-space" value be 255 has helped me notice some problems. _volData->setBorderValue(255); - decompressVolumeData(previousVolumeSize); - compressVolumeData(); + + qDebug() << " new size is" << _volData->getWidth() << _volData->getHeight() << _volData->getDepth(); + + // I'm not sure this is needed... the docs say that each element is initialized with its default + // constructor. I'll leave it here for now. + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + _volData->setVoxelAt(x, y, z, 0); + } + } + } + + // It's okay to decompress the old data here, because the data includes its original dimensions along + // with the voxel data, and writing voxels outside the bounds of the new space is harmless. This allows + // adjusting of the voxel-space size without overly mangling the shape. Shrinking the space and then + // restoring the previous size (without any edits in between) will put the original shape back. + decompressVolumeData(); } void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { @@ -153,8 +195,7 @@ glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { assert(_volData); - if (x < 0 || y < 0 || z < 0 || - x >= _voxelVolumeSize[0] || y >= _voxelVolumeSize[1] || z >= _voxelVolumeSize[2]) { + if (!inBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return 0; } @@ -170,8 +211,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) { assert(_volData); - if (x < 0 || y < 0 || z < 0 || - x >= _voxelVolumeSize[0] || y >= _voxelVolumeSize[1] || z >= _voxelVolumeSize[2]) { + if (!inBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return; } @@ -185,6 +225,10 @@ void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) { // keep _onCount up to date + if (!inBounds(_volData, _voxelSurfaceStyle, x, y, z)) { + return; + } + uint8_t uVoxelValue = getVoxel(x, y, z); if (toValue != 0) { if (uVoxelValue == 0) { @@ -201,9 +245,9 @@ void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { - for (int z = 0; z < _voxelVolumeSize[2]; z++) { - for (int y = 0; y < _voxelVolumeSize[1]; y++) { - for (int x = 0; x < _voxelVolumeSize[0]; x++) { + for (int z = 0; z < _voxelVolumeSize.z; z++) { + for (int y = 0; y < _voxelVolumeSize.y; y++) { + for (int x = 0; x < _voxelVolumeSize.x; x++) { updateOnCount(x, y, z, toValue); setVoxel(x, y, z, toValue); } @@ -214,9 +258,9 @@ void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { // This three-level for loop iterates over every voxel in the volume - for (int z = 0; z < _voxelVolumeSize[2]; z++) { - for (int y = 0; y < _voxelVolumeSize[1]; y++) { - for (int x = 0; x < _voxelVolumeSize[0]; x++) { + for (int z = 0; z < _voxelVolumeSize.z; z++) { + for (int y = 0; y < _voxelVolumeSize.y; y++) { + for (int x = 0; x < _voxelVolumeSize.x; x++) { // Store our current position as a vector... glm::vec3 pos(x + 0.5f, y + 0.5f, z + 0.5f); // consider voxels cenetered on their coordinates // And compute how far the current position is from the center of the volume @@ -236,7 +280,7 @@ void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r // glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords); glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f); glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units - float scaleY = scale[0]; + float scaleY = scale.y; float radiusVoxelCoords = radiusWorldCoords / scaleY; setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue); } @@ -356,17 +400,17 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { class RaycastFunctor { public: - RaycastFunctor(PolyVox::SimpleVolume* vol) : + RaycastFunctor(PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle voxelSurfaceStyle) : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)), - _vol(vol) { + _vol(vol), + _voxelSurfaceStyle(voxelSurfaceStyle) { } bool operator()(PolyVox::SimpleVolume::Sampler& sampler) { int x = sampler.getPosition().getX(); int y = sampler.getPosition().getY(); int z = sampler.getPosition().getZ(); - if (x < 0 || y < 0 || z < 0 || - x > _vol->getWidth() || y > _vol->getHeight() || z > _vol->getDepth()) { + if (!inBounds(_vol, _voxelSurfaceStyle, x, y, z)) { return true; } @@ -379,6 +423,7 @@ public: } glm::vec4 _result; const PolyVox::SimpleVolume* _vol = nullptr; + PolyVoxEntityItem::PolyVoxSurfaceStyle _voxelSurfaceStyle; }; bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, @@ -400,19 +445,19 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // set ray cast length to long enough to cover all of the voxel space float distanceToEntity = glm::distance(origin, _position); - float largestDimension = glm::max(_dimensions[0], _dimensions[1], _dimensions[2]) * 2.0f; + float largestDimension = glm::max(_dimensions.x, _dimensions.y, _dimensions.z) * 2.0f; glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f); - PolyVox::Vector3DFloat start(originInVoxel[0], originInVoxel[1], originInVoxel[2]); - // PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]); - PolyVox::Vector3DFloat far(farInVoxel[0], farInVoxel[1], farInVoxel[2]); + PolyVox::Vector3DFloat start(originInVoxel.x, originInVoxel.y, originInVoxel.z); + // PolyVox::Vector3DFloat pvDirection(directionInVoxel.x, directionInVoxel.y, directionInVoxel.z); + PolyVox::Vector3DFloat far(farInVoxel.x, farInVoxel.y, farInVoxel.z); PolyVox::RaycastResult raycastResult; - RaycastFunctor callback(_volData); + RaycastFunctor callback(_volData, _voxelSurfaceStyle); raycastResult = PolyVox::raycastWithEndpoints(_volData, start, far, callback); if (raycastResult == PolyVox::RaycastResults::Completed) { @@ -445,31 +490,42 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // compress the data in _volData and save the results. The compressed form is used during // saves to disk and for transmission over the wire void RenderablePolyVoxEntityItem::compressVolumeData() { - int rawSize = _voxelVolumeSize[0] * _voxelVolumeSize[1] * _voxelVolumeSize[2]; + quint16 voxelXSize = _voxelVolumeSize.x; + quint16 voxelYSize = _voxelVolumeSize.y; + quint16 voxelZSize = _voxelVolumeSize.z; + int rawSize = voxelXSize * voxelYSize * voxelZSize; + QByteArray uncompressedData = QByteArray(rawSize, '\0'); - for (int z = 0; z < _voxelVolumeSize[2]; z++) { - for (int y = 0; y < _voxelVolumeSize[1]; y++) { - for (int x = 0; x < _voxelVolumeSize[0]; x++) { + for (int z = 0; z < voxelZSize; z++) { + for (int y = 0; y < voxelYSize; y++) { + for (int x = 0; x < voxelXSize; x++) { uint8_t uVoxelValue = getVoxel(x, y, z); int uncompressedIndex = - z * _voxelVolumeSize[1] * _voxelVolumeSize[0] + - y * _voxelVolumeSize[0] + + z * voxelYSize * voxelXSize + + y * voxelXSize + x; uncompressedData[uncompressedIndex] = uVoxelValue; } } } - QByteArray newVoxelData = qCompress(uncompressedData, 9); - // HACK -- until we have a way to allow for properties larger than MTU, don't update. - if (newVoxelData.length() < 1200) { + QByteArray newVoxelData; + QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate); + writer << voxelXSize << voxelYSize << voxelZSize; + + QByteArray compressedData = qCompress(uncompressedData, 9); + writer << compressedData; + + // make sure the compressed data can be sent over the wire-protocol + if (newVoxelData.size() < 1150) { _voxelData = newVoxelData; qDebug() << "-------------- voxel compresss --------------"; qDebug() << "raw-size =" << rawSize << " compressed-size =" << newVoxelData.size(); } else { + // HACK -- until we have a way to allow for properties larger than MTU, don't update. qDebug() << "voxel data too large, reverting change."; - // revert + // revert the active voxel-space to the last version that fit. decompressVolumeData(); } @@ -478,25 +534,38 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { } -// take compressed data and decompreess it into _volData. +// take compressed data and expand it into _volData. void RenderablePolyVoxEntityItem::decompressVolumeData() { - decompressVolumeData(_voxelVolumeSize); -} + QDataStream reader(_voxelData); + quint16 voxelXSize, voxelYSize, voxelZSize; + reader >> voxelXSize; + reader >> voxelYSize; + reader >> voxelZSize; + if (voxelXSize == 0 || voxelXSize > MAX_VOXEL_DIMENSION || + voxelYSize == 0 || voxelYSize > MAX_VOXEL_DIMENSION || + voxelZSize == 0 || voxelZSize > MAX_VOXEL_DIMENSION) { + qDebug() << "vixelSize is not reasonable, skipping decompressions." + << voxelXSize << voxelYSize << voxelZSize; + return; + } + + int rawSize = voxelXSize * voxelYSize * voxelZSize; + + QByteArray compressedData; + reader >> compressedData; + QByteArray uncompressedData = qUncompress(compressedData); -void RenderablePolyVoxEntityItem::decompressVolumeData(glm::vec3 volumeSize) { - int rawSize = volumeSize[0] * volumeSize[1] * volumeSize[2]; - QByteArray uncompressedData = QByteArray(rawSize, '\0'); + if (uncompressedData.size() != rawSize) { + qDebug() << "PolyVox decompress -- size is (" << voxelXSize << voxelYSize << voxelZSize << ")" << + "so expected uncompressed length of" << rawSize << "but length is" << uncompressedData.size(); + return; + } - uncompressedData = qUncompress(_voxelData); - - for (int z = 0; z < volumeSize[2]; z++) { - for (int y = 0; y < volumeSize[1]; y++) { - for (int x = 0; x < volumeSize[0]; x++) { - int uncompressedIndex = - z * volumeSize[1] * volumeSize[0] + - y * volumeSize[0] + - x; + for (int z = 0; z < voxelZSize; z++) { + for (int y = 0; y < voxelYSize; y++) { + for (int x = 0; x < voxelXSize; x++) { + int uncompressedIndex = (z * voxelYSize * voxelXSize) + (y * voxelZSize) + x; updateOnCount(x, y, z, uncompressedData[uncompressedIndex]); setVoxel(x, y, z, uncompressedData[uncompressedIndex]); } @@ -544,9 +613,9 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { AABox box; - for (int z = 0; z < _voxelVolumeSize[2]; z++) { - for (int y = 0; y < _voxelVolumeSize[1]; y++) { - for (int x = 0; x < _voxelVolumeSize[0]; x++) { + for (int z = 0; z < _voxelVolumeSize.z; z++) { + for (int y = 0; y < _voxelVolumeSize.y; y++) { + for (int x = 0; x < _voxelVolumeSize.x; x++) { if (getVoxel(x, y, z) > 0) { QVector pointsInPart; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index c8039e79c1..86018b9fb2 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -70,9 +70,11 @@ public: virtual void setAll(uint8_t toValue); private: + // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions + // may not match _voxelVolumeSize. + void compressVolumeData(); void decompressVolumeData(); - void decompressVolumeData(glm::vec3 volumeSize); PolyVox::SimpleVolume* _volData = nullptr; model::Geometry _modelGeometry; diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index a7f1128771..e0cd397594 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -22,7 +22,8 @@ const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32); -const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9)); +const float PolyVoxEntityItem::MAX_VOXEL_DIMENSION = 32.0f; +const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9)); // XXX const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE = PolyVoxEntityItem::SURFACE_MARCHING_CUBES; @@ -41,6 +42,40 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent setProperties(properties); } +void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { + assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x); + assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y); + assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z); + + _voxelVolumeSize = voxelVolumeSize; + if (_voxelVolumeSize.x < 1) { + qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1"; + _voxelVolumeSize.x = 1; + } + if (_voxelVolumeSize.x > MAX_VOXEL_DIMENSION) { + qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max"; + _voxelVolumeSize.x = MAX_VOXEL_DIMENSION; + } + + if (_voxelVolumeSize.y < 1) { + qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1"; + _voxelVolumeSize.y = 1; + } + if (_voxelVolumeSize.y > MAX_VOXEL_DIMENSION) { + qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max"; + _voxelVolumeSize.y = MAX_VOXEL_DIMENSION; + } + + if (_voxelVolumeSize.z < 1) { + qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1"; + _voxelVolumeSize.z = 1; + } + if (_voxelVolumeSize.z > MAX_VOXEL_DIMENSION) { + qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max"; + _voxelVolumeSize.z = MAX_VOXEL_DIMENSION; + } +} + EntityItemProperties PolyVoxEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 8ef59f9f17..63bd4856d3 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -49,7 +49,7 @@ class PolyVoxEntityItem : public EntityItem { virtual void debugDump() const; - virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { _voxelVolumeSize = voxelVolumeSize; } + virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; } virtual void setVoxelData(QByteArray voxelData) { _voxelData = voxelData; } @@ -68,6 +68,8 @@ class PolyVoxEntityItem : public EntityItem { virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; } static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE; + static const float MAX_VOXEL_DIMENSION; + static const QByteArray DEFAULT_VOXEL_DATA; static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE; @@ -81,7 +83,8 @@ class PolyVoxEntityItem : public EntityItem { virtual uint8_t getVoxel(int x, int y, int z) { return 0; } virtual void setVoxel(int x, int y, int z, uint8_t toValue) {} - + + protected: glm::vec3 _voxelVolumeSize; // this is always 3 bytes QByteArray _voxelData; From d1bb6473d9751f7f3c4b139306f4793e648d6ae7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Jun 2015 13:57:28 -0700 Subject: [PATCH 15/19] more work on edge handling and resizing --- .../src/RenderablePolyVoxEntityItem.cpp | 47 ++++++++++------ .../src/RenderablePolyVoxEntityItem.h | 2 + .../entities/src/EntityScriptingInterface.cpp | 56 +++++++------------ .../entities/src/EntityScriptingInterface.h | 3 + libraries/entities/src/PolyVoxEntityItem.h | 2 + 5 files changed, 58 insertions(+), 52 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index c3b5033466..e190d8f8da 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -53,8 +53,9 @@ RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() { delete _volData; } -bool inBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, +bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, int x, int y, int z) { + // x, y, z are in user voxel-coords, not adjusted-for-edge voxel-coords. switch (surfaceStyle) { case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: case PolyVoxEntityItem::SURFACE_CUBIC: @@ -65,8 +66,8 @@ bool inBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::Poly return true; case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: - if (x < 1 || y < 1 || z < 1 || - x >= vol->getWidth() - 1 || y >= vol->getHeight() - 1 || z >= vol->getDepth() - 1) { + if (x < 0 || y < 0 || z < 0 || + x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) { return false; } return true; @@ -75,6 +76,17 @@ bool inBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::Poly return false; } + +bool inBounds(const PolyVox::SimpleVolume* vol, int x, int y, int z) { + // x, y, z are in polyvox volume coords + if (x < 0 || y < 0 || z < 0 || + x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) { + return false; + } + return true; +} + + void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { if (_volData && voxelVolumeSize == _voxelVolumeSize) { return; @@ -195,7 +207,7 @@ glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { assert(_volData); - if (!inBounds(_volData, _voxelSurfaceStyle, x, y, z)) { + if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return 0; } @@ -211,7 +223,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) { assert(_volData); - if (!inBounds(_volData, _voxelSurfaceStyle, x, y, z)) { + if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return; } @@ -225,7 +237,7 @@ void RenderablePolyVoxEntityItem::setVoxel(int x, int y, int z, uint8_t toValue) void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toValue) { // keep _onCount up to date - if (!inBounds(_volData, _voxelSurfaceStyle, x, y, z)) { + if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return; } @@ -243,7 +255,6 @@ void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV } } - void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { for (int z = 0; z < _voxelVolumeSize.z; z++) { for (int y = 0; y < _voxelVolumeSize.y; y++) { @@ -256,6 +267,11 @@ void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { compressVolumeData(); } +void RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) { + updateOnCount(position.x, position.y, position.z, toValue); + setVoxel(position.x, position.y, position.z, toValue); +} + void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { // This three-level for loop iterates over every voxel in the volume for (int z = 0; z < _voxelVolumeSize.z; z++) { @@ -400,17 +416,17 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { class RaycastFunctor { public: - RaycastFunctor(PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle voxelSurfaceStyle) : + RaycastFunctor(PolyVox::SimpleVolume* vol) : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)), - _vol(vol), - _voxelSurfaceStyle(voxelSurfaceStyle) { + _vol(vol) { } bool operator()(PolyVox::SimpleVolume::Sampler& sampler) { int x = sampler.getPosition().getX(); int y = sampler.getPosition().getY(); int z = sampler.getPosition().getZ(); - if (!inBounds(_vol, _voxelSurfaceStyle, x, y, z)) { + + if (!inBounds(_vol, x, y, z)) { return true; } @@ -423,7 +439,6 @@ public: } glm::vec4 _result; const PolyVox::SimpleVolume* _vol = nullptr; - PolyVoxEntityItem::PolyVoxSurfaceStyle _voxelSurfaceStyle; }; bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, @@ -452,13 +467,13 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f); - PolyVox::Vector3DFloat start(originInVoxel.x, originInVoxel.y, originInVoxel.z); + PolyVox::Vector3DFloat startPoint(originInVoxel.x, originInVoxel.y, originInVoxel.z); // PolyVox::Vector3DFloat pvDirection(directionInVoxel.x, directionInVoxel.y, directionInVoxel.z); - PolyVox::Vector3DFloat far(farInVoxel.x, farInVoxel.y, farInVoxel.z); + PolyVox::Vector3DFloat endPoint(farInVoxel.x, farInVoxel.y, farInVoxel.z); PolyVox::RaycastResult raycastResult; - RaycastFunctor callback(_volData, _voxelSurfaceStyle); - raycastResult = PolyVox::raycastWithEndpoints(_volData, start, far, callback); + RaycastFunctor callback(_volData); + raycastResult = PolyVox::raycastWithEndpoints(_volData, startPoint, endPoint, callback); if (raycastResult == PolyVox::RaycastResults::Completed) { // the ray completed its path -- nothing was hit. diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 86018b9fb2..c8f1b4a49d 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -69,6 +69,8 @@ public: virtual void setAll(uint8_t toValue); + virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue); + private: // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions // may not match _voxelVolumeSize. diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 34c5199a0c..6866505d58 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -17,7 +17,6 @@ #include "ModelEntityItem.h" #include "ZoneEntityItem.h" #include "EntitiesLogging.h" -#include "PolyVoxEntityItem.h" EntityScriptingInterface::EntityScriptingInterface() : @@ -395,7 +394,8 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra } -bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { +bool EntityScriptingInterface::setVoxels(QUuid entityID, + std::function actor) { if (!_entityTree) { return false; } @@ -415,7 +415,7 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c PolyVoxEntityItem* polyVoxEntity = static_cast(entity.get()); _entityTree->lockForWrite(); - polyVoxEntity->setSphere(center, radius, value); + actor(*polyVoxEntity); entity->setLastEdited(now); entity->setLastBroadcast(now); _entityTree->unlock(); @@ -432,38 +432,22 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c } +bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { + return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { + polyVoxEntity.setSphere(center, radius, value); + }); +} + + +bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { + return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) { + polyVoxEntity.setVoxelInVolume(position, value); + }); +} + + bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { - if (!_entityTree) { - return false; - } - - EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID; - return false; - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return false; - } - - auto now = usecTimestampNow(); - - PolyVoxEntityItem* polyVoxEntity = static_cast(entity.get()); - _entityTree->lockForWrite(); - polyVoxEntity->setAll(value); - entity->setLastEdited(now); - entity->setLastBroadcast(now); - _entityTree->unlock(); - - _entityTree->lockForRead(); - EntityItemProperties properties = entity->getProperties(); - _entityTree->unlock(); - - properties.setVoxelDataDirty(); - properties.setLastEdited(now); - - queueEntityMessage(PacketTypeEntityEdit, entityID, properties); - return true; + return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) { + polyVoxEntity.setAll(value); + }); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 421875feef..7761effe2f 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -21,6 +21,7 @@ #include #include #include +#include "PolyVoxEntityItem.h" #include "EntityEditPacketSender.h" @@ -117,7 +118,9 @@ public slots: Q_INVOKABLE void setSendPhysicsUpdates(bool value); Q_INVOKABLE bool getSendPhysicsUpdates() const; + bool setVoxels(QUuid entityID, std::function actor); Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); + Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE void dumpTree() const; diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 63bd4856d3..bf8214675b 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -81,6 +81,8 @@ class PolyVoxEntityItem : public EntityItem { virtual void setAll(uint8_t toValue) {} + virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue) {} + virtual uint8_t getVoxel(int x, int y, int z) { return 0; } virtual void setVoxel(int x, int y, int z, uint8_t toValue) {} From ea3f002a65e3ca2942cd0f965bf9b0ff4fd52245 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 1 Jun 2015 14:38:07 -0700 Subject: [PATCH 16/19] ifdef out debug pritns --- .../src/RenderablePolyVoxEntityItem.cpp | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index e190d8f8da..6f2fe42502 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -33,7 +33,6 @@ #include "EntityTreeRenderer.h" #include "RenderablePolyVoxEntityItem.h" - EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties)); } @@ -92,7 +91,9 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) return; } + #ifdef WANT_DEBUG qDebug() << "resetting voxel-space size" << voxelVolumeSize.x << voxelVolumeSize.y << voxelVolumeSize.z; + #endif PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize); @@ -123,7 +124,9 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) // having the "outside of voxel-space" value be 255 has helped me notice some problems. _volData->setBorderValue(255); + #ifdef WANT_DEBUG qDebug() << " new size is" << _volData->getWidth() << _volData->getHeight() << _volData->getDepth(); + #endif // I'm not sure this is needed... the docs say that each element is initialized with its default // constructor. I'll leave it here for now. @@ -348,44 +351,31 @@ void RenderablePolyVoxEntityItem::getModel() { sizeof(PolyVox::PositionMaterialNormal), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW))); + + // auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL); // for (auto normal = normalAttrib.begin(); normal != normalAttrib.end(); normal++) { // (*normal) = -(*normal); // } + + // mesh->addAttribute(gpu::Stream::TEXCOORD, + // gpu::BufferView(vertexBufferPtr, + // sizeof(float) * 2, + // vertexBufferPtr->getSize() - sizeof(float) * 2, + // sizeof(PolyVox::PositionMaterialNormal), + // gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW))); + + + + #ifdef WANT_DEBUG qDebug() << "---- vecIndices.size() =" << vecIndices.size(); qDebug() << "---- vecVertices.size() =" << vecVertices.size(); + #endif _needsModelReload = false; } - -// QString GLMatrixToString(GLfloat* m) { -// QString mString = "\n"; -// for (int x = 0; x < 4; x++) { -// for (int y = 0; y < 4; y++) { -// mString += QString::number((double)m[y*4+x], 'f', 2) + " "; -// } -// mString += "\n"; -// } -// return mString; -// } - - -// void printModelViewMatrix() { -// GLfloat glMatrix[16]; -// glGetFloatv(GL_MODELVIEW_MATRIX, glMatrix); -// qDebug() << GLMatrixToString(glMatrix); -// } - -// void printProjectionMatrix() { -// GLfloat glMatrix[16]; -// glGetFloatv(GL_PROJECTION_MATRIX, glMatrix); -// qDebug() << GLMatrixToString(glMatrix); -// } - - - void RenderablePolyVoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); assert(getType() == EntityTypes::PolyVox); @@ -535,11 +525,15 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { // make sure the compressed data can be sent over the wire-protocol if (newVoxelData.size() < 1150) { _voxelData = newVoxelData; + #ifdef WANT_DEBUG qDebug() << "-------------- voxel compresss --------------"; qDebug() << "raw-size =" << rawSize << " compressed-size =" << newVoxelData.size(); + #endif } else { // HACK -- until we have a way to allow for properties larger than MTU, don't update. + #ifdef WANT_DEBUG qDebug() << "voxel data too large, reverting change."; + #endif // revert the active voxel-space to the last version that fit. decompressVolumeData(); } @@ -560,7 +554,7 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { if (voxelXSize == 0 || voxelXSize > MAX_VOXEL_DIMENSION || voxelYSize == 0 || voxelYSize > MAX_VOXEL_DIMENSION || voxelZSize == 0 || voxelZSize > MAX_VOXEL_DIMENSION) { - qDebug() << "vixelSize is not reasonable, skipping decompressions." + qDebug() << "voxelSize is not reasonable, skipping decompressions." << voxelXSize << voxelYSize << voxelZSize; return; } @@ -587,8 +581,10 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { } } + #ifdef WANT_DEBUG qDebug() << "--------------- voxel decompress ---------------"; qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size(); + #endif _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; _needsModelReload = true; @@ -609,12 +605,16 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { return false; } + #ifdef WANT_DEBUG qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload); + #endif return true; } void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { + #ifdef WANT_DEBUG qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo"; + #endif ShapeType type = getShapeType(); if (type != SHAPE_TYPE_COMPOUND) { EntityItem::computeShapeInfo(info); From 20d3814c1b1e3fda623dbe9dc13011f3c7d41b7e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Jun 2015 10:00:07 -0700 Subject: [PATCH 17/19] code review --- examples/edit.js | 17 +++--- examples/html/entityProperties.html | 58 +++++++++---------- examples/voxels.js | 5 +- .../src/RenderablePolyVoxEntityItem.cpp | 10 +--- .../entities/src/EntityItemProperties.cpp | 24 ++++---- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/shared/src/SettingInterface.cpp | 12 ++-- 7 files changed, 60 insertions(+), 68 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 455b843868..8a8dcb9779 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1,4 +1,3 @@ - // newEditEntities.js // examples // @@ -139,7 +138,7 @@ var toolBar = (function () { newTextButton, newWebButton, newZoneButton, - newPolyVoxButton, + newPolyVoxButton, browseMarketplaceButton; function initialize() { @@ -225,7 +224,7 @@ var toolBar = (function () { visible: false }); - newPolyVoxButton = toolBar.addTool({ + newPolyVoxButton = toolBar.addTool({ imageURL: toolIconUrl + "upload.svg", // XXX need a new icon subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, width: toolWidth, @@ -276,7 +275,7 @@ var toolBar = (function () { toolBar.showTool(newTextButton, doShow); toolBar.showTool(newWebButton, doShow); toolBar.showTool(newZoneButton, doShow); - toolBar.showTool(newPolyVoxButton, doShow); + toolBar.showTool(newPolyVoxButton, doShow); }; var RESIZE_INTERVAL = 50; @@ -486,10 +485,10 @@ var toolBar = (function () { placingEntityID = Entities.addEntity({ type: "PolyVox", position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), - DEFAULT_DIMENSIONS), + DEFAULT_DIMENSIONS), dimensions: { x: 10, y: 10, z: 10 }, - voxelVolumeSize: {x:16, y:16, z:16}, - voxelSurfaceStyle: 1 + voxelVolumeSize: {x:16, y:16, z:16}, + voxelSurfaceStyle: 1 }); } else { print("Can't create PolyVox: would be out of bounds."); @@ -949,7 +948,7 @@ function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) { var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition, Vec3.multiply(selectionManager.worldDimensions, 0.5)); var entities = Entities.findEntitiesInBox(boundingBoxCorner, selectionManager.worldDimensions); - + if (!keepIfTouching) { var isValid; if (selectionManager.localPosition === null) { @@ -1021,7 +1020,7 @@ function handeMenuEvent(menuItem) { } } } else if (menuItem == "Import Entities" || menuItem == "Import Entities from URL") { - + var importURL; if (menuItem == "Import Entities") { importURL = Window.browse("Select models to import", "", "*.json"); diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 21e2e83136..d9cad0feff 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -21,11 +21,11 @@ els[i].setAttribute('disabled', 'disabled'); } } - + function showElements(els, show) { for (var i = 0; i < els.length; i++) { els[i].style.display = (show) ? 'block' : 'none'; - } + } } function createEmitCheckedPropertyUpdateFunction(propertyName) { @@ -344,7 +344,7 @@ var elZoneAtmosphereCenterY = document.getElementById("property-zone-atmosphere-center-y"); var elZoneAtmosphereCenterZ = document.getElementById("property-zone-atmosphere-center-z"); var elCenterAtmosphereToZone = document.getElementById("center-atmosphere-in-zone"); - + var elZoneAtmosphereInnerRadius = document.getElementById("property-zone-atmosphere-inner-radius"); var elZoneAtmosphereOuterRadius = document.getElementById("property-zone-atmosphere-outer-radius"); var elZoneAtmosphereMieScattering = document.getElementById("property-zone-atmosphere-mie-scattering"); @@ -354,12 +354,12 @@ var elZoneAtmosphereScatteringWavelengthsZ = document.getElementById("property-zone-atmosphere-scattering-wavelengths-z"); var elZoneAtmosphereHasStars = document.getElementById("property-zone-atmosphere-has-stars"); - var elPolyVoxSelections = document.querySelectorAll(".poly-vox-section"); - var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x"); + var elPolyVoxSelections = document.querySelectorAll(".poly-vox-section"); + var elVoxelVolumeSizeX = document.getElementById("property-voxel-volume-size-x"); var elVoxelVolumeSizeY = document.getElementById("property-voxel-volume-size-y"); var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z"); - var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style"); - + var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style"); + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { @@ -577,7 +577,7 @@ elZoneAtmosphereScatteringWavelengthsY.value = properties.atmosphere.scatteringWavelengths.y; elZoneAtmosphereScatteringWavelengthsZ.value = properties.atmosphere.scatteringWavelengths.z; elZoneAtmosphereHasStars.checked = properties.atmosphere.hasStars; - + showElements(document.getElementsByClassName('skybox-section'), elZoneBackgroundMode.value == 'skybox'); showElements(document.getElementsByClassName('atmosphere-section'), elZoneBackgroundMode.value == 'atmosphere'); } else if (properties.type == "ParticleEffect") { @@ -595,11 +595,11 @@ elParticleLocalGravity.value = properties.localGravity.toFixed(2); elParticleRadius.value = properties.particleRadius.toFixed(3); } else if (properties.type == "PolyVox") { - elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); - elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); - elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2); - elVoxelSurfaceStyle.value = properties.voxelSurfaceStyle; - } + elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); + elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); + elVoxelVolumeSizeZ.value = properties.voxelVolumeSize.z.toFixed(2); + elVoxelSurfaceStyle.value = properties.voxelSurfaceStyle; + } if (selected) { activeElement.focus(); @@ -715,7 +715,7 @@ elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff')); elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl')); - + elParticleMaxParticles.addEventListener('change', createEmitNumberPropertyUpdateFunction('maxParticles')); elParticleLifeSpan.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifespan')); elParticleEmitRate.addEventListener('change', createEmitNumberPropertyUpdateFunction('emitRate')); @@ -821,7 +821,7 @@ emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox'); } }); - + elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url')); var zoneAtmosphereCenterChangeFunction = createEmitGroupVec3PropertyUpdateFunction( @@ -829,8 +829,8 @@ elZoneAtmosphereCenterX.addEventListener('change', zoneAtmosphereCenterChangeFunction); elZoneAtmosphereCenterY.addEventListener('change', zoneAtmosphereCenterChangeFunction); elZoneAtmosphereCenterZ.addEventListener('change', zoneAtmosphereCenterChangeFunction); - - + + elZoneAtmosphereInnerRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','innerRadius')); elZoneAtmosphereOuterRadius.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','outerRadius')); elZoneAtmosphereMieScattering.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('atmosphere','mieScattering')); @@ -848,8 +848,8 @@ elVoxelVolumeSizeX.addEventListener('change', voxelVolumeSizeChangeFunction); elVoxelVolumeSizeY.addEventListener('change', voxelVolumeSizeChangeFunction); elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction); - elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle')); - + elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle')); + elMoveSelectionToGrid.addEventListener("click", function() { EventBridge.emitWebEvent(JSON.stringify({ @@ -997,14 +997,14 @@
X
Y
Z
- +
Surface Extractor
-
+
@@ -1143,19 +1143,19 @@ - +
Max Particles
-
+
Particle Life Span
-
+
Particle Emission Rate
@@ -1188,7 +1188,7 @@
- +
Model URL
@@ -1203,7 +1203,7 @@ - +
@@ -1382,7 +1382,7 @@
- +
Stage Day
diff --git a/examples/voxels.js b/examples/voxels.js index fc9f6550f5..799af04bef 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -1,4 +1,3 @@ - var controlHeld = false; var shiftHeld = false; @@ -17,8 +16,8 @@ function mousePressEvent(event) { var id = ids[i]; if (controlHeld) { Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0); - } else if (shiftHeld) { - Entities.setAllVoxels(id, 255); + } else if (shiftHeld) { + Entities.setAllVoxels(id, 255); } else { Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 6f2fe42502..83612f3fce 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -78,11 +78,7 @@ bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem:: bool inBounds(const PolyVox::SimpleVolume* vol, int x, int y, int z) { // x, y, z are in polyvox volume coords - if (x < 0 || y < 0 || z < 0 || - x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) { - return false; - } - return true; + return !(x < 0 || y < 0 || z < 0 || x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()); } @@ -183,7 +179,7 @@ glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const { case PolyVoxEntityItem::SURFACE_CUBIC: return scale / 2.0f; } - return glm::vec3(0, 0, 0); + return glm::vec3(0.0f, 0.0f, 0.0f); } glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { @@ -191,7 +187,7 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { glm::vec3 center = getCenter(); glm::vec3 position = getPosition(); glm::vec3 positionToCenter = center - position; - positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f) - getSurfacePositionAdjustment(); + positionToCenter -= _dimensions * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment(); glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter); glm::mat4 scaled = glm::scale(centerToCorner, scale); return scaled; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index eeb3bb3474..698530ef86 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -176,10 +176,8 @@ QString EntityItemProperties::getAnimationSettings() const { return jsonByteString; } - -void EntityItemProperties::setCreated(QDateTime v) { - QDateTime utcV = v; - _created = utcV.toMSecsSinceEpoch() * 1000; // usec per msec +void EntityItemProperties::setCreated(QDateTime &v) { + _created = v.toMSecsSinceEpoch() * 1000; // usec per msec qDebug() << "EntityItemProperties::setCreated QDateTime" << v << _created; } @@ -494,12 +492,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution); COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction); COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime); - if (!honorReadOnly) { - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() { - auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec - return result; - }); - } COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript); COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint); COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity); @@ -524,9 +516,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked); COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures); COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData); - if (!honorReadOnly) { - COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); - } COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText); COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight); COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor); @@ -554,6 +543,15 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle); + if (!honorReadOnly) { + // this is used by the json reader to set things that we don't want javascript to able to affect. + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(created, QDateTime, setCreated, [this]() { + auto result = QDateTime::fromMSecsSinceEpoch(_created / 1000, Qt::UTC); // usec per msec + return result; + }); + COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); + } + _stage.copyFromScriptValue(object, _defaultSettings); _atmosphere.copyFromScriptValue(object, _defaultSettings); _skybox.copyFromScriptValue(object, _defaultSettings); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c6a0b21313..07879b5a6c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -194,7 +194,7 @@ public: void setVoxelDataDirty() { _voxelDataChanged = true; } - void setCreated(QDateTime v); + void setCreated(QDateTime& v); bool hasTerseUpdateChanges() const; diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 26cbe3ca13..ee72a4ab45 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -39,12 +39,12 @@ namespace Setting { void init() { // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings::setDefaultFormat(QSettings::IniFormat); - QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); - // set the associated application properties - applicationInfo.beginGroup("INFO"); - QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); - QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); - QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + // QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); + // // set the associated application properties + // applicationInfo.beginGroup("INFO"); + // QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); + // QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); + // QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); // Let's set up the settings Private instance on it's own thread QThread* thread = new QThread(); From d201f7791e29f032a28d40a24d875355bba309da Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Jun 2015 10:01:43 -0700 Subject: [PATCH 18/19] oops --- libraries/shared/src/SettingInterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index ee72a4ab45..26cbe3ca13 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -39,12 +39,12 @@ namespace Setting { void init() { // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings::setDefaultFormat(QSettings::IniFormat); - // QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); - // // set the associated application properties - // applicationInfo.beginGroup("INFO"); - // QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); - // QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); - // QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); + // set the associated application properties + applicationInfo.beginGroup("INFO"); + QCoreApplication::setApplicationName(applicationInfo.value("name").toString()); + QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); + QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); // Let's set up the settings Private instance on it's own thread QThread* thread = new QThread(); From 11eb073bcfd3aebf404a454ad50596d882572aa4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 2 Jun 2015 10:04:39 -0700 Subject: [PATCH 19/19] fix comment --- libraries/shared/src/SettingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 26cbe3ca13..c14fd33565 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -46,7 +46,7 @@ namespace Setting { QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); - // Let's set up the settings Private instance on it's own thread + // Let's set up the settings Private instance on its own thread QThread* thread = new QThread(); Q_CHECK_PTR(thread); thread->setObjectName("Settings Thread");