From 98cae8d1521ad76afd35389eea79c2152aadaa86 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 20 Mar 2017 09:37:46 -0700 Subject: [PATCH 01/14] added EntityScriptingInterface::getEntityLocalTransform. try harder to make sure polyvox mesh is ready before giving it to javascript --- .../src/RenderablePolyVoxEntityItem.cpp | 17 ++++++++++---- .../src/RenderablePolyVoxEntityItem.h | 4 ++-- .../entities/src/EntityScriptingInterface.cpp | 23 +++++++++++++++---- .../entities/src/EntityScriptingInterface.h | 10 ++++++++ libraries/model/src/model/Geometry.cpp | 2 +- 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 1d58527427..efe284651a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1312,7 +1312,7 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) { } _mesh = mesh; _meshDirty = true; - _meshInitialized = true; + _meshReady = true; neighborsNeedUpdate = _neighborsNeedUpdate; _neighborsNeedUpdate = false; }); @@ -1324,7 +1324,7 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) { void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { // this creates a collision-shape for the physics engine. The shape comes from // _volData for cubic extractors and from _mesh for marching-cube extractors - if (!_meshInitialized) { + if (!_meshReady) { return; } @@ -1601,15 +1601,22 @@ bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QS MeshProxy* meshProxy = nullptr; glm::mat4 transform = voxelToLocalMatrix(); withReadLock([&] { - if (_meshInitialized) { + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)_mesh->getNumVertices(); + if (!_meshReady) { + // we aren't ready to return a mesh. the caller will have to try again later. + success = false; + } else if (numVertices == 0) { + // we are ready, but there are no triangles in the mesh. + success = true; + } else { success = true; // the mesh will be in voxel-space. transform it into object-space meshProxy = new MeshProxy( _mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, [=](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); }, - [](uint32_t index){ return index; })); + [&](uint32_t index){ return index; })); + result = meshToScriptValue(engine, meshProxy); } }); - result = meshToScriptValue(engine, meshProxy); return success; } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index cf4672f068..e6467be987 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -142,7 +142,7 @@ public: uint8_t getVoxelInternal(int x, int y, int z) const; bool setVoxelInternal(int x, int y, int z, uint8_t toValue); - void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; }); } + void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); } // Transparent polyvox didn't seem to be working so disable for now bool isTransparent() override { return false; } @@ -157,7 +157,7 @@ private: model::MeshPointer _mesh; gpu::Stream::FormatPointer _vertexFormat; bool _meshDirty { true }; // does collision-shape need to be recomputed? - bool _meshInitialized { false }; + bool _meshReady { false }; NetworkTexturePointer _xTexture; NetworkTexturePointer _yTexture; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7ab0c3f7d9..88cc527164 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -934,11 +934,7 @@ void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callbac QScriptValue mesh { false }; polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable { - if (polyVoxEntity.getOnCount() == 0) { - success = true; - } else { - success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); - } + success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); return true; }); @@ -1578,3 +1574,20 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { } return result; } + +glm::mat4 EntityScriptingInterface::getEntityLocalTransform(const QUuid& entityID) { + glm::mat4 result; + if (_entityTree) { + _entityTree->withReadLock([&] { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); + if (entity) { + glm::mat4 translation = glm::translate(entity->getLocalPosition()); + glm::mat4 rotation = glm::mat4_cast(entity->getLocalOrientation()); + glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - + entity->getRegistrationPoint()); + result = translation * rotation * registration; + } + }); + } + return result; +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index fa727aaa7a..71758ba53f 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -304,6 +304,16 @@ public slots: */ Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID); + + /**jsdoc + * Returns object to world transform, excluding scale + * + * @function Entities.getEntityLocalTransform + * @param {EntityID} entityID The ID of the entity whose local transform is to be returned + * @return {Mat4} Entity's object to parent transform, excluding scale + */ + Q_INVOKABLE glm::mat4 getEntityLocalTransform(const QUuid& entityID); + signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 04b0db92d3..341015816e 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -228,7 +228,7 @@ void Mesh::forEach(std::function vertexFunc, // normal data const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index) normalsBufferView.getNumElements(); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { normalFunc(normalsBufferView.get(i)); } From df875ab5042725f0f60cfb5cd0baa48d7e4bedfd Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Mar 2017 16:21:45 -0700 Subject: [PATCH 02/14] make RenderablePolyVoxEntityItem::setSphere affect any voxel the sphere touches rather than just the ones whose center the sphere touches --- .../src/RenderablePolyVoxEntityItem.cpp | 39 +++++++++++++++---- libraries/shared/src/AABox.cpp | 26 +++++++++++++ libraries/shared/src/AABox.h | 1 + 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index efe284651a..cd62d72c70 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -414,19 +414,41 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize); glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize); + // This three-level for loop iterates over every voxel in the volume that might be in the sphere + // withWriteLock([&] { + // for (int z = lowI.z; z < highI.z; z++) { + // for (int y = lowI.y; y < highI.y; y++) { + // for (int x = lowI.x; x < highI.x; x++) { + // // Store our current position as a vector... + // glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates + // // convert to world coordinates + // glm::vec3 worldPos = glm::vec3(vtwMatrix * pos); + // // compute how far the current position is from the center of the volume + // float fDistToCenter = glm::distance(worldPos, centerWorldCoords); + // // If the current voxel is less than 'radius' units from the center then we set its value + // if (fDistToCenter <= radiusWorldCoords) { + // result |= setVoxelInternal(x, y, z, toValue); + // } + // } + // } + // } + // }); + + + glm::vec3 radials(radiusWorldCoords / voxelSize.x, + radiusWorldCoords / voxelSize.y, + radiusWorldCoords / voxelSize.z); + float minRadial = glm::min(radials.x, radials.y); + minRadial = glm::min(minRadial, radials.z); + // This three-level for loop iterates over every voxel in the volume that might be in the sphere withWriteLock([&] { for (int z = lowI.z; z < highI.z; z++) { for (int y = lowI.y; y < highI.y; y++) { for (int x = lowI.x; x < highI.x; x++) { - // Store our current position as a vector... - glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates - // convert to world coordinates - glm::vec3 worldPos = glm::vec3(vtwMatrix * pos); - // compute how far the current position is from the center of the volume - float fDistToCenter = glm::distance(worldPos, centerWorldCoords); - // If the current voxel is less than 'radius' units from the center then we set its value - if (fDistToCenter <= radiusWorldCoords) { + AABox voxelBox(glm::vec3(x - 0.5f, y - 0.5f, z - 0.5f), glm::vec3(1.0f, 1.0f, 1.0f)); + // if (voxelBox.touchesSphere(centerInVoxelCoords, minRadial)) { + if (voxelBox.touchesAAEllipsoid(centerInVoxelCoords, radials)) { result |= setVoxelInternal(x, y, z, toValue); } } @@ -434,6 +456,7 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r } }); + if (result) { compressVolumeDataAndSendEditPacket(); } diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index 89d5ce709d..fa993856dd 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -436,6 +436,32 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& return getClosestPointOnFace(glm::vec3(origin), face); } +bool AABox::touchesAAEllipsoid(const glm::vec3& center, glm::vec3 radials) const { + if (_corner.x - radials.x > center.x || + _corner.y - radials.y > center.y || + _corner.z - radials.z > center.z || + _corner.x + _scale.x + radials.x < center.x || + _corner.y + _scale.y + radials.y < center.y || + _corner.z + _scale.z + radials.z < center.z) { + return false; + } + + for (int i = 0; i < FACE_COUNT; i++) { + glm::vec3 closest = getClosestPointOnFace(center, (BoxFace)i) - center; + float x = closest.x; + float y = closest.y; + float z = closest.z; + float a = radials.x; + float b = radials.y; + float c = radials.z; + if (x*x/(a*a) + y*y/(b*b) + z*z/(c*c) < 1.0f) { + return true; + } + } + return false; +} + + glm::vec4 AABox::getPlane(BoxFace face) const { switch (face) { case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x); diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index ccc7b6e302..022f1a6ff1 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -70,6 +70,7 @@ public: bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) const; bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives + bool touchesAAEllipsoid(const glm::vec3& center, glm::vec3 radials) const; bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; From ce9bb439b3106bf53b7100a2346d9c95cde28899 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Mar 2017 09:55:30 -0700 Subject: [PATCH 03/14] change Model api in anticipation of more than just PolyVox being able to give meshes to javascript --- .../src/RenderablePolyVoxEntityItem.cpp | 6 +-- .../src/RenderablePolyVoxEntityItem.h | 3 +- libraries/entities/src/EntityItem.h | 6 ++- .../entities/src/EntityScriptingInterface.cpp | 40 ++++++++++++------- .../entities/src/EntityScriptingInterface.h | 3 +- libraries/entities/src/PolyVoxEntityItem.cpp | 4 -- libraries/entities/src/PolyVoxEntityItem.h | 2 - .../src => model/src/model}/MeshProxy.h | 15 ++++++- .../src/ModelScriptingInterface.cpp | 24 +---------- .../src/ModelScriptingInterface.h | 8 +--- 10 files changed, 52 insertions(+), 59 deletions(-) rename libraries/{script-engine/src => model/src/model}/MeshProxy.h (68%) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index efe284651a..f39d84caaf 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1592,7 +1592,7 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { scene->enqueuePendingChanges(pendingChanges); } -bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) { +bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) { if (!updateDependents()) { return false; } @@ -1615,8 +1615,8 @@ bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QS _mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, [=](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); }, [&](uint32_t index){ return index; })); - result = meshToScriptValue(engine, meshProxy); + result << meshProxy; } }); - return success; + return meshProxy; } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index e6467be987..a0d5c38a14 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -135,7 +135,6 @@ public: QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const; void setMesh(model::MeshPointer mesh); - bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) override; void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } @@ -147,6 +146,8 @@ public: // Transparent polyvox didn't seem to be working so disable for now bool isTransparent() override { return false; } + bool getMeshes(MeshProxyList& result) override; + protected: virtual void locationChanged(bool tellPhysics = true) override; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 163b4d9e45..b973d916e6 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -63,6 +63,8 @@ namespace render { #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" +class MeshProxyList; + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate @@ -470,9 +472,11 @@ public: QUuid getLastEditedBy() const { return _lastEditedBy; } void setLastEditedBy(QUuid value) { _lastEditedBy = value; } - + bool matchesJSONFilters(const QJsonObject& jsonFilters) const; + virtual bool getMeshes(MeshProxyList& result) { return true; } + protected: void setSimulated(bool simulated) { _simulated = simulated; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 88d7acf7bf..0888dd4fb9 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "EntitiesLogging.h" #include "EntityActionFactoryInterface.h" @@ -1040,21 +1041,6 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 }); } -void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) { - PROFILE_RANGE(script_entities, __FUNCTION__); - - bool success { false }; - QScriptValue mesh { false }; - - polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable { - success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); - return true; - }); - - QScriptValueList args { mesh, success }; - callback.call(QScriptValue(), args); -} - bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector& points) { PROFILE_RANGE(script_entities, __FUNCTION__); @@ -1671,6 +1657,30 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons return aaBox.findCapsulePenetration(start, end, radius, penetration); } +void EntityScriptingInterface::getMeshes(QUuid entityID, QScriptValue callback) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID; + QScriptValueList args { false, false }; + callback.call(QScriptValue(), args); + return; + } + + MeshProxyList result; + bool success = entity->getMeshes(result); + + if (success) { + QScriptValue resultAsScriptValue = meshesToScriptValue(callback.engine(), result); + QScriptValueList args { resultAsScriptValue, true }; + callback.call(QScriptValue(), args); + } else { + QScriptValueList args { callback.engine()->undefinedValue(), false }; + callback.call(QScriptValue(), args); + } +} + glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { glm::mat4 result; if (_entityTree) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 944c2bb8d5..7b4c2ff800 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -266,7 +266,6 @@ public slots: Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value); - Q_INVOKABLE void voxelsToMesh(QUuid entityID, QScriptValue callback); Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector& points); Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point); @@ -331,6 +330,8 @@ public slots: const glm::vec3& start, const glm::vec3& end, float radius); + Q_INVOKABLE void getMeshes(QUuid entityID, QScriptValue callback); + /**jsdoc * Returns object to world transform, excluding scale * diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 90344d6c4b..2a374c1d17 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -242,7 +242,3 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const { }); return voxelDataCopy; } - -bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) { - return false; -} diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 311a002a4a..cf7531fc9e 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -135,8 +135,6 @@ class PolyVoxEntityItem : public EntityItem { void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } virtual void recomputeMesh() {}; - virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result); - protected: glm::vec3 _voxelVolumeSize; // this is always 3 bytes diff --git a/libraries/script-engine/src/MeshProxy.h b/libraries/model/src/model/MeshProxy.h similarity index 68% rename from libraries/script-engine/src/MeshProxy.h rename to libraries/model/src/model/MeshProxy.h index 82f5038348..fcd36e6e9c 100644 --- a/libraries/script-engine/src/MeshProxy.h +++ b/libraries/model/src/model/MeshProxy.h @@ -1,6 +1,6 @@ // // MeshProxy.h -// libraries/script-engine/src +// libraries/model/src/model/ // // Created by Seth Alves on 2017-1-27. // Copyright 2017 High Fidelity, Inc. @@ -12,7 +12,11 @@ #ifndef hifi_MeshProxy_h #define hifi_MeshProxy_h -#include +#include +#include +#include + +#include "Geometry.h" using MeshPointer = std::shared_ptr; @@ -38,4 +42,11 @@ Q_DECLARE_METATYPE(MeshProxy*); class MeshProxyList : public QList {}; // typedef and using fight with the Qt macros/templates, do this instead Q_DECLARE_METATYPE(MeshProxyList); + +QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in); +void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out); + +QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in); +void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out); + #endif // hifi_MeshProxy_h diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 833ac5b64d..22b7eb89ed 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -18,30 +18,8 @@ ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { _modelScriptEngine = qobject_cast(parent); -} -QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) { - return engine->newQObject(in, QScriptEngine::QtOwnership, - QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); -} - -void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) { - out = qobject_cast(value.toQObject()); -} - -QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) { - return engine->toScriptValue(in); -} - -void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) { - QScriptValueIterator itr(value); - while(itr.hasNext()) { - itr.next(); - MeshProxy* meshProxy = qscriptvalue_cast(itr.value()); - if (meshProxy) { - out.append(meshProxy); - } - } + qScriptRegisterSequenceMetaType>(_modelScriptEngine); } QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index 14789943e3..105d6d548e 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -17,7 +17,7 @@ #include #include #include -#include "MeshProxy.h" +#include using MeshPointer = std::shared_ptr; class ScriptEngine; @@ -36,10 +36,4 @@ private: ScriptEngine* _modelScriptEngine { nullptr }; }; -QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in); -void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out); - -QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in); -void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out); - #endif // hifi_ModelScriptingInterface_h From ba0c9e405a70ec0d44c1751db3d82553c44dc33e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Mar 2017 10:38:57 -0700 Subject: [PATCH 04/14] cleanup --- .../src/RenderablePolyVoxEntityItem.cpp | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index f37b46d0bb..b7ca5b8e26 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -414,43 +414,33 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize); glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize); - // This three-level for loop iterates over every voxel in the volume that might be in the sphere - // withWriteLock([&] { - // for (int z = lowI.z; z < highI.z; z++) { - // for (int y = lowI.y; y < highI.y; y++) { - // for (int x = lowI.x; x < highI.x; x++) { - // // Store our current position as a vector... - // glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates - // // convert to world coordinates - // glm::vec3 worldPos = glm::vec3(vtwMatrix * pos); - // // compute how far the current position is from the center of the volume - // float fDistToCenter = glm::distance(worldPos, centerWorldCoords); - // // If the current voxel is less than 'radius' units from the center then we set its value - // if (fDistToCenter <= radiusWorldCoords) { - // result |= setVoxelInternal(x, y, z, toValue); - // } - // } - // } - // } - // }); - - glm::vec3 radials(radiusWorldCoords / voxelSize.x, radiusWorldCoords / voxelSize.y, radiusWorldCoords / voxelSize.z); - float minRadial = glm::min(radials.x, radials.y); - minRadial = glm::min(minRadial, radials.z); // This three-level for loop iterates over every voxel in the volume that might be in the sphere withWriteLock([&] { for (int z = lowI.z; z < highI.z; z++) { for (int y = lowI.y; y < highI.y; y++) { for (int x = lowI.x; x < highI.x; x++) { + + // set voxels whose bounding-box touches the sphere AABox voxelBox(glm::vec3(x - 0.5f, y - 0.5f, z - 0.5f), glm::vec3(1.0f, 1.0f, 1.0f)); - // if (voxelBox.touchesSphere(centerInVoxelCoords, minRadial)) { if (voxelBox.touchesAAEllipsoid(centerInVoxelCoords, radials)) { result |= setVoxelInternal(x, y, z, toValue); } + + // TODO -- this version only sets voxels which have centers inside the sphere. which is best? + // // Store our current position as a vector... + // glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates + // // convert to world coordinates + // glm::vec3 worldPos = glm::vec3(vtwMatrix * pos); + // // compute how far the current position is from the center of the volume + // float fDistToCenter = glm::distance(worldPos, centerWorldCoords); + // // If the current voxel is less than 'radius' units from the center then we set its value + // if (fDistToCenter <= radiusWorldCoords) { + // result |= setVoxelInternal(x, y, z, toValue); + // } } } } From bb1c556c911a169f3b384b2cd4515aea481bd7f9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Mar 2017 11:04:50 -0700 Subject: [PATCH 05/14] forgot a file --- libraries/model/src/model/MeshProxy.cpp | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 libraries/model/src/model/MeshProxy.cpp diff --git a/libraries/model/src/model/MeshProxy.cpp b/libraries/model/src/model/MeshProxy.cpp new file mode 100644 index 0000000000..01bafa086c --- /dev/null +++ b/libraries/model/src/model/MeshProxy.cpp @@ -0,0 +1,54 @@ +// +// MeshProxy.cpp +// libraries/model/src/model/ +// +// Created by Seth Alves on 2017-3-22. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MeshProxy.h" + + +QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) { + return engine->newQObject(in, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); +} + +void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) { + out = qobject_cast(value.toQObject()); +} + +QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) { + // QScriptValueList result; + QScriptValue result = engine->newArray(); + int i = 0; + foreach (MeshProxy* const meshProxy, in) { + qDebug() << "meshesToScriptValue adding mesh: " << (void*)meshProxy; + // result.setProperty(i++, QScriptValue(engine, meshProxy)); + result.setProperty(i++, meshToScriptValue(engine, meshProxy)); + // result.setProperty(QString::number(i++), QScriptValue(meshProxy)); + // result[i] = QScriptValue(meshProxy); + // result << QScriptValue(meshProxy); + } + // result.setProperty("length", i); + return result; +} + +void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) { + QScriptValueIterator itr(value); + + qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32(); + + while(itr.hasNext()) { + itr.next(); + MeshProxy* meshProxy = qscriptvalue_cast(itr.value()); + if (meshProxy) { + out.append(meshProxy); + } else { + qDebug() << "null meshProxy"; + } + } +} From 642cf57976fb1ff1ce7062bf2ebd5b7ae0f1929a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Mar 2017 12:49:58 -0700 Subject: [PATCH 06/14] obj-writer now outputs normals --- libraries/fbx/src/OBJWriter.cpp | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/libraries/fbx/src/OBJWriter.cpp b/libraries/fbx/src/OBJWriter.cpp index 5ee04c5718..e236ecb0fa 100644 --- a/libraries/fbx/src/OBJWriter.cpp +++ b/libraries/fbx/src/OBJWriter.cpp @@ -40,12 +40,16 @@ static QString formatFloat(double n) { } bool writeOBJToTextStream(QTextStream& out, QList meshes) { + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + // each mesh's vertices are numbered from zero. We're combining all their vertices into one list here, // so keep track of the start index for each mesh. QList meshVertexStartOffset; + QList meshNormalStartOffset; int currentVertexStartOffset = 0; + int currentNormalStartOffset = 0; - // write out all vertices + // write out vertices foreach (const MeshPointer& mesh, meshes) { meshVertexStartOffset.append(currentVertexStartOffset); const gpu::BufferView& vertexBuffer = mesh->getVertexBuffer(); @@ -64,10 +68,28 @@ bool writeOBJToTextStream(QTextStream& out, QList meshes) { } out << "\n"; + // write out normals + bool haveNormals = true; + foreach (const MeshPointer& mesh, meshes) { + meshNormalStartOffset.append(currentNormalStartOffset); + const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); + for (gpu::BufferView::Index i = 0; i < numNormals; i++) { + glm::vec3 normal = normalsBufferView.get(i); + out << "vn "; + out << formatFloat(normal[0]) << " "; + out << formatFloat(normal[1]) << " "; + out << formatFloat(normal[2]) << "\n"; + } + currentNormalStartOffset += numNormals; + } + out << "\n"; + // write out faces int nth = 0; foreach (const MeshPointer& mesh, meshes) { currentVertexStartOffset = meshVertexStartOffset.takeFirst(); + currentNormalStartOffset = meshNormalStartOffset.takeFirst(); const gpu::BufferView& partBuffer = mesh->getPartBuffer(); const gpu::BufferView& indexBuffer = mesh->getIndexBuffer(); @@ -104,9 +126,15 @@ bool writeOBJToTextStream(QTextStream& out, QList meshes) { indexCount++; out << "f "; - out << currentVertexStartOffset + index0 + 1 << " "; - out << currentVertexStartOffset + index1 + 1 << " "; - out << currentVertexStartOffset + index2 + 1 << "\n"; + if (haveNormals) { + out << currentVertexStartOffset + index0 + 1 << "//" << currentVertexStartOffset + index0 + 1 << " "; + out << currentVertexStartOffset + index1 + 1 << "//" << currentVertexStartOffset + index1 + 1 << " "; + out << currentVertexStartOffset + index2 + 1 << "//" << currentVertexStartOffset + index2 + 1 << "\n"; + } else { + out << currentVertexStartOffset + index0 + 1 << " "; + out << currentVertexStartOffset + index1 + 1 << " "; + out << currentVertexStartOffset + index2 + 1 << "\n"; + } } out << "\n"; } From 8f7f5efadebfb44c114a126d46348159517ad1d8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Mar 2017 12:51:00 -0700 Subject: [PATCH 07/14] new javascript call: Model.newMesh() --- .../src/RenderablePolyVoxEntityItem.h | 2 +- libraries/model/src/model/MeshFace.cpp | 44 ++++++++++++++ libraries/model/src/model/MeshFace.h | 43 +++++++++++++ .../src/ModelScriptingInterface.cpp | 60 ++++++++++++++++++- .../src/ModelScriptingInterface.h | 4 ++ libraries/shared/src/RegisteredMetaTypes.cpp | 19 ++++++ libraries/shared/src/RegisteredMetaTypes.h | 4 ++ 7 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 libraries/model/src/model/MeshFace.cpp create mode 100644 libraries/model/src/model/MeshFace.h diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index a0d5c38a14..cdfe2e38fe 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -66,7 +66,7 @@ public: void render(RenderArgs* args) override; virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; diff --git a/libraries/model/src/model/MeshFace.cpp b/libraries/model/src/model/MeshFace.cpp new file mode 100644 index 0000000000..8092d36aa3 --- /dev/null +++ b/libraries/model/src/model/MeshFace.cpp @@ -0,0 +1,44 @@ +// +// MeshFace.cpp +// libraries/model/src/model/ +// +// Created by Seth Alves on 2017-3-23 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "MeshFace.h" + + +QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace) { + QScriptValue obj = engine->newObject(); + obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices)); + return obj; +} + +void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult) { + qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices); +} + +QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array.setProperty(i, meshFaceToScriptValue(engine, vector.at(i))); + } + return array; +} + +void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector& result) { + int length = array.property("length").toInteger(); + result.clear(); + + for (int i = 0; i < length; i++) { + MeshFace meshFace = MeshFace(); + meshFaceFromScriptValue(array.property(i), meshFace); + result << meshFace; + } +} diff --git a/libraries/model/src/model/MeshFace.h b/libraries/model/src/model/MeshFace.h new file mode 100644 index 0000000000..ef1e3a0b6b --- /dev/null +++ b/libraries/model/src/model/MeshFace.h @@ -0,0 +1,43 @@ +// +// MeshFace.h +// libraries/model/src/model/ +// +// Created by Seth Alves on 2017-3-23 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MeshFace_h +#define hifi_MeshFace_h + +#include +#include +#include + +#include "Geometry.h" + +using MeshPointer = std::shared_ptr; + +class MeshFace { + +public: + MeshFace() {} + ~MeshFace() {} + + QVector vertexIndices; + // TODO -- material... +}; + +Q_DECLARE_METATYPE(MeshFace) +Q_DECLARE_METATYPE(QVector) + +QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace); +void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult); +QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector& vector); +void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector& result); + + + +#endif // hifi_MeshFace_h diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 22b7eb89ed..c02eb642a1 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -12,7 +12,9 @@ #include #include #include +#include #include "ScriptEngine.h" +#include "ScriptEngineLogging.h" #include "ModelScriptingInterface.h" #include "OBJWriter.h" @@ -20,6 +22,8 @@ ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(pare _modelScriptEngine = qobject_cast(parent); qScriptRegisterSequenceMetaType>(_modelScriptEngine); + qScriptRegisterMetaType(_modelScriptEngine, meshFaceToScriptValue, meshFaceFromScriptValue); + qScriptRegisterMetaType(_modelScriptEngine, qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue); } QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { @@ -118,8 +122,6 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { return meshToScriptValue(_modelScriptEngine, resultProxy); } - - QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { if (!meshProxy) { return QScriptValue(false); @@ -135,3 +137,57 @@ QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshPro MeshProxy* resultProxy = new MeshProxy(result); return meshToScriptValue(_modelScriptEngine, resultProxy); } + +QScriptValue ModelScriptingInterface::newMesh(const QVector& vertices, + const QVector& normals, + const QVector& faces) { + model::MeshPointer mesh(new model::Mesh()); + + // vertices + auto vertexBuffer = std::make_shared(vertices.size() * sizeof(glm::vec3), (gpu::Byte*)vertices.data()); + auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer); + gpu::BufferView vertexBufferView(vertexBufferPtr, 0, vertexBufferPtr->getSize(), + sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + mesh->setVertexBuffer(vertexBufferView); + + if (vertices.size() == normals.size()) { + // normals + auto normalBuffer = std::make_shared(normals.size() * sizeof(glm::vec3), (gpu::Byte*)normals.data()); + auto normalBufferPtr = gpu::BufferPointer(normalBuffer); + gpu::BufferView normalBufferView(normalBufferPtr, 0, normalBufferPtr->getSize(), + sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + mesh->addAttribute(gpu::Stream::NORMAL, normalBufferView); + } else { + qCDebug(scriptengine) << "ModelScriptingInterface::newMesh normals must be same length as vertices"; + } + + // indices (faces) + int VERTICES_PER_TRIANGLE = 3; + int indexBufferSize = faces.size() * sizeof(uint32_t) * VERTICES_PER_TRIANGLE; + unsigned char* indexData = new unsigned char[indexBufferSize]; + unsigned char* indexDataCursor = indexData; + foreach(const MeshFace& meshFace, faces) { + for (int i = 0; i < VERTICES_PER_TRIANGLE; i++) { + memcpy(indexDataCursor, &meshFace.vertexIndices[i], sizeof(uint32_t)); + indexDataCursor += sizeof(uint32_t); + } + } + auto indexBuffer = std::make_shared(indexBufferSize, (gpu::Byte*)indexData); + auto indexBufferPtr = gpu::BufferPointer(indexBuffer); + gpu::BufferView indexBufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)); + mesh->setIndexBuffer(indexBufferView); + + // parts + std::vector parts; + parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex + (model::Index)faces.size() * 3, // numIndices + (model::Index)0, // baseVertex + model::Mesh::TRIANGLES)); // topology + mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + + + MeshProxy* meshProxy = new MeshProxy(mesh); + return meshToScriptValue(_modelScriptEngine, meshProxy); +} diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index 105d6d548e..e3d5b18b29 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -18,6 +18,7 @@ #include #include #include +#include using MeshPointer = std::shared_ptr; class ScriptEngine; @@ -31,6 +32,9 @@ public: Q_INVOKABLE QString meshToOBJ(MeshProxyList in); Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in); Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy); + Q_INVOKABLE QScriptValue newMesh(const QVector& vertices, + const QVector& normals, + const QVector& faces); private: ScriptEngine* _modelScriptEngine { nullptr }; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 7f12d6cc00..70067b93f3 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -43,6 +43,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue); qScriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue); qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue); + qScriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue); qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); @@ -386,6 +387,15 @@ QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + int num = vector.at(i); + array.setProperty(i, QScriptValue(num)); + } + return array; +} + void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector) { int length = array.property("length").toInteger(); @@ -393,6 +403,15 @@ void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vect vector << array.property(i).toVariant().toFloat(); } } + +void qVectorIntFromScriptValue(const QScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); + + for (int i = 0; i < length; i++) { + vector << array.property(i).toVariant().toInt(); + } +} + // QVector qVectorVec3FromScriptValue(const QScriptValue& array){ QVector newVector; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 498a8b3b3a..8a15f62eed 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -113,6 +113,10 @@ QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector); QVector qVectorFloatFromScriptValue(const QScriptValue& array); +// vector +QScriptValue qVectorIntToScriptValue(QScriptEngine* engine, const QVector& vector); +void qVectorIntFromScriptValue(const QScriptValue& array, QVector& vector); + QVector qVectorQUuidFromScriptValue(const QScriptValue& array); QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube); From 6e40f03c8e08e31536d472bf8093a6f14212f3e3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Mar 2017 15:08:13 -0700 Subject: [PATCH 08/14] cleanups --- libraries/model/src/model/Geometry.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 341015816e..16608ab63e 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -145,7 +145,7 @@ model::MeshPointer Mesh::map(std::function vertexFunc, unsigned char* resultVertexData = new unsigned char[vertexSize]; unsigned char* vertexDataCursor = resultVertexData; - for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + for (gpu::BufferView::Index i = 0; i < numVertices; i++) { glm::vec3 pos = vertexFunc(vertexBufferView.get(i)); memcpy(vertexDataCursor, &pos, sizeof(pos)); vertexDataCursor += sizeof(pos); @@ -159,7 +159,7 @@ model::MeshPointer Mesh::map(std::function vertexFunc, unsigned char* resultNormalData = new unsigned char[normalSize]; unsigned char* normalDataCursor = resultNormalData; - for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + for (gpu::BufferView::Index i = 0; i < numNormals; i++) { glm::vec3 normal = normalFunc(normalsBufferView.get(i)); memcpy(normalDataCursor, &normal, sizeof(normal)); normalDataCursor += sizeof(normal); @@ -173,7 +173,7 @@ model::MeshPointer Mesh::map(std::function vertexFunc, unsigned char* resultIndexData = new unsigned char[indexSize]; unsigned char* indexDataCursor = resultIndexData; - for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + for (gpu::BufferView::Index i = 0; i < numIndexes; i++) { uint32_t index = indexFunc(indexBufferView.get(i)); memcpy(indexDataCursor, &index, sizeof(index)); indexDataCursor += sizeof(index); @@ -217,19 +217,18 @@ model::MeshPointer Mesh::map(std::function vertexFunc, void Mesh::forEach(std::function vertexFunc, std::function normalFunc, std::function indexFunc) { - int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h - // vertex data const gpu::BufferView& vertexBufferView = getVertexBuffer(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices(); - for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + for (gpu::BufferView::Index i = 0; i < numVertices; i++) { vertexFunc(vertexBufferView.get(i)); } // normal data + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); - for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + for (gpu::BufferView::Index i = 0; i < numNormals; i++) { normalFunc(normalsBufferView.get(i)); } // TODO -- other attributes @@ -237,7 +236,7 @@ void Mesh::forEach(std::function vertexFunc, // face data const gpu::BufferView& indexBufferView = getIndexBuffer(); gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); - for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + for (gpu::BufferView::Index i = 0; i < numIndexes; i++) { indexFunc(indexBufferView.get(i)); } } From 2682586c38eb554b804ff4e1de2e7c40f3af8056 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Mar 2017 06:50:06 -0700 Subject: [PATCH 09/14] some clean-ups and a bug fix in PolyVox to mesh code --- .../src/RenderablePolyVoxEntityItem.cpp | 30 +++++++++++++------ libraries/fbx/src/OBJWriter.cpp | 2 +- libraries/model/src/model/MeshProxy.cpp | 6 ---- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index b7ca5b8e26..7b0146f5b7 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -690,6 +690,8 @@ bool RenderablePolyVoxEntityItem::updateDependents() { _voxelDataDirty = false; } else if (_volDataDirty) { _volDataDirty = false; + } else { + _meshReady = true; } }); if (voxelDataDirty) { @@ -707,7 +709,9 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { assert(getType() == EntityTypes::PolyVox); Q_ASSERT(args->_batch); - updateDependents(); + if (_voxelDataDirty || _volDataDirty) { + updateDependents(); + } model::MeshPointer mesh; glm::vec3 voxelVolumeSize; @@ -769,6 +773,11 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { 0, sizeof(PolyVox::PositionMaterialNormal)); + // batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer, + // 12, + // sizeof(PolyVox::PositionMaterialNormal)); + + batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0); if (!_xTextureURL.isEmpty() && !_xTexture) { @@ -1287,23 +1296,26 @@ void RenderablePolyVoxEntityItem::recomputeMesh() { auto indexBuffer = std::make_shared(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data()); auto indexBufferPtr = gpu::BufferPointer(indexBuffer); - gpu::BufferView indexBufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)); + gpu::BufferView indexBufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::INDEX)); mesh->setIndexBuffer(indexBufferView); - const std::vector& vecVertices = polyVoxMesh.getVertices(); + const std::vector& vecVertices = polyVoxMesh.getRawVertexData(); auto vertexBuffer = std::make_shared(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal), (gpu::Byte*)vecVertices.data()); auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer); gpu::BufferView vertexBufferView(vertexBufferPtr, 0, vertexBufferPtr->getSize(), sizeof(PolyVox::PositionMaterialNormal), - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)); + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); mesh->setVertexBuffer(vertexBufferView); + + mesh->addAttribute(gpu::Stream::NORMAL, - gpu::BufferView(vertexBufferPtr, sizeof(float) * 3, - vertexBufferPtr->getSize() , + gpu::BufferView(vertexBufferPtr, + sizeof(float) * 3, // polyvox mesh is packed: position, normal, material + vertexBufferPtr->getSize(), sizeof(PolyVox::PositionMaterialNormal), - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW))); + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ))); std::vector parts; parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex @@ -1626,10 +1638,10 @@ bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) { // the mesh will be in voxel-space. transform it into object-space meshProxy = new MeshProxy( _mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, - [=](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); }, + [=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); }, [&](uint32_t index){ return index; })); result << meshProxy; } }); - return meshProxy; + return success; } diff --git a/libraries/fbx/src/OBJWriter.cpp b/libraries/fbx/src/OBJWriter.cpp index e236ecb0fa..034263eb53 100644 --- a/libraries/fbx/src/OBJWriter.cpp +++ b/libraries/fbx/src/OBJWriter.cpp @@ -73,7 +73,7 @@ bool writeOBJToTextStream(QTextStream& out, QList meshes) { foreach (const MeshPointer& mesh, meshes) { meshNormalStartOffset.append(currentNormalStartOffset); const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); for (gpu::BufferView::Index i = 0; i < numNormals; i++) { glm::vec3 normal = normalsBufferView.get(i); out << "vn "; diff --git a/libraries/model/src/model/MeshProxy.cpp b/libraries/model/src/model/MeshProxy.cpp index 01bafa086c..1b6fa43c82 100644 --- a/libraries/model/src/model/MeshProxy.cpp +++ b/libraries/model/src/model/MeshProxy.cpp @@ -26,14 +26,8 @@ QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) QScriptValue result = engine->newArray(); int i = 0; foreach (MeshProxy* const meshProxy, in) { - qDebug() << "meshesToScriptValue adding mesh: " << (void*)meshProxy; - // result.setProperty(i++, QScriptValue(engine, meshProxy)); result.setProperty(i++, meshToScriptValue(engine, meshProxy)); - // result.setProperty(QString::number(i++), QScriptValue(meshProxy)); - // result[i] = QScriptValue(meshProxy); - // result << QScriptValue(meshProxy); } - // result.setProperty("length", i); return result; } From 5ed0ff729b5f85de90d6bcdae84de54a2eca6f6c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Mar 2017 07:25:40 -0700 Subject: [PATCH 10/14] cleanups --- libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 7b0146f5b7..5127739357 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -446,7 +446,6 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r } }); - if (result) { compressVolumeDataAndSendEditPacket(); } @@ -773,6 +772,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { 0, sizeof(PolyVox::PositionMaterialNormal)); + // TODO -- should we be setting this? // batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer, // 12, // sizeof(PolyVox::PositionMaterialNormal)); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 0888dd4fb9..4cf4bf8c67 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1663,7 +1663,7 @@ void EntityScriptingInterface::getMeshes(QUuid entityID, QScriptValue callback) EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID; - QScriptValueList args { false, false }; + QScriptValueList args { callback.engine()->undefinedValue(), false }; callback.call(QScriptValue(), args); return; } From 651d87dc2a2f138301c5a21286ad121b779a5aba Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Mar 2017 07:53:25 -0700 Subject: [PATCH 11/14] move Qt-related stuff out of model and into model-networking --- libraries/entities/CMakeLists.txt | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 2 +- .../src/model-networking}/MeshFace.cpp | 0 .../src/model-networking}/MeshFace.h | 2 +- .../src/model-networking}/MeshProxy.cpp | 0 .../src/model-networking}/MeshProxy.h | 2 +- libraries/script-engine/src/ModelScriptingInterface.cpp | 2 +- libraries/script-engine/src/ModelScriptingInterface.h | 4 ++-- 8 files changed, 7 insertions(+), 7 deletions(-) rename libraries/{model/src/model => model-networking/src/model-networking}/MeshFace.cpp (100%) rename libraries/{model/src/model => model-networking/src/model-networking}/MeshFace.h (97%) rename libraries/{model/src/model => model-networking/src/model-networking}/MeshProxy.cpp (100%) rename libraries/{model/src/model => model-networking/src/model-networking}/MeshProxy.h (98%) diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index 1230fe8146..b2ae0f0ab7 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) -link_hifi_libraries(avatars shared audio octree model fbx networking animation) +link_hifi_libraries(avatars shared audio octree model model-networking fbx networking animation) target_bullet() diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f66cf1e8f1..2c332e8d05 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "EntitiesLogging.h" #include "EntityActionFactoryInterface.h" diff --git a/libraries/model/src/model/MeshFace.cpp b/libraries/model-networking/src/model-networking/MeshFace.cpp similarity index 100% rename from libraries/model/src/model/MeshFace.cpp rename to libraries/model-networking/src/model-networking/MeshFace.cpp diff --git a/libraries/model/src/model/MeshFace.h b/libraries/model-networking/src/model-networking/MeshFace.h similarity index 97% rename from libraries/model/src/model/MeshFace.h rename to libraries/model-networking/src/model-networking/MeshFace.h index ef1e3a0b6b..3b81b372c3 100644 --- a/libraries/model/src/model/MeshFace.h +++ b/libraries/model-networking/src/model-networking/MeshFace.h @@ -16,7 +16,7 @@ #include #include -#include "Geometry.h" +#include using MeshPointer = std::shared_ptr; diff --git a/libraries/model/src/model/MeshProxy.cpp b/libraries/model-networking/src/model-networking/MeshProxy.cpp similarity index 100% rename from libraries/model/src/model/MeshProxy.cpp rename to libraries/model-networking/src/model-networking/MeshProxy.cpp diff --git a/libraries/model/src/model/MeshProxy.h b/libraries/model-networking/src/model-networking/MeshProxy.h similarity index 98% rename from libraries/model/src/model/MeshProxy.h rename to libraries/model-networking/src/model-networking/MeshProxy.h index fcd36e6e9c..c5b25b7895 100644 --- a/libraries/model/src/model/MeshProxy.h +++ b/libraries/model-networking/src/model-networking/MeshProxy.h @@ -16,7 +16,7 @@ #include #include -#include "Geometry.h" +#include using MeshPointer = std::shared_ptr; diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index c02eb642a1..f56312568e 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "ScriptEngine.h" #include "ScriptEngineLogging.h" #include "ModelScriptingInterface.h" diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index e3d5b18b29..d899f532d8 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -17,8 +17,8 @@ #include #include #include -#include -#include +#include +#include using MeshPointer = std::shared_ptr; class ScriptEngine; From 6f6343420c2d12ead6828af4b68643a0acf9bae7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Mar 2017 10:56:33 -0700 Subject: [PATCH 12/14] don't crash if entity dimensions somehow include a zero --- .../entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5127739357..419f32f897 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -404,6 +404,9 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r float smallestDimensionSize = voxelSize.x; smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z); + if (smallestDimensionSize <= 0.0f) { + return false; + } glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize); glm::vec3 centerInVoxelCoords = wtvMatrix * glm::vec4(centerWorldCoords, 1.0f); @@ -1310,6 +1313,7 @@ void RenderablePolyVoxEntityItem::recomputeMesh() { mesh->setVertexBuffer(vertexBufferView); + // TODO -- use 3-byte normals rather than 3-float normals mesh->addAttribute(gpu::Stream::NORMAL, gpu::BufferView(vertexBufferPtr, sizeof(float) * 3, // polyvox mesh is packed: position, normal, material From 9789476a73e81e632a8f0a8a756dd02144cf7429 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Mar 2017 10:57:03 -0700 Subject: [PATCH 13/14] handle case where AAEllipsoid is entirely inside the AABox --- libraries/shared/src/AABox.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index fa993856dd..b52deaa4ff 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -437,6 +437,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& } bool AABox::touchesAAEllipsoid(const glm::vec3& center, glm::vec3 radials) const { + // handle case where ellipsoid's alix-aligned box doesn't touch this AABox if (_corner.x - radials.x > center.x || _corner.y - radials.y > center.y || _corner.z - radials.z > center.z || @@ -446,6 +447,11 @@ bool AABox::touchesAAEllipsoid(const glm::vec3& center, glm::vec3 radials) const return false; } + // handle case where ellipsoid is entirely inside this AABox + if (contains(center)) { + return true; + } + for (int i = 0; i < FACE_COUNT; i++) { glm::vec3 closest = getClosestPointOnFace(center, (BoxFace)i) - center; float x = closest.x; From 1cf6945bf222dcbefd31f415521e602ea817eda1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 28 Mar 2017 11:12:00 -0700 Subject: [PATCH 14/14] pass radials argument to AABox::touchesAAEllipsoid as const reference --- libraries/shared/src/AABox.cpp | 2 +- libraries/shared/src/AABox.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index b52deaa4ff..3f3146cc04 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -436,7 +436,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& return getClosestPointOnFace(glm::vec3(origin), face); } -bool AABox::touchesAAEllipsoid(const glm::vec3& center, glm::vec3 radials) const { +bool AABox::touchesAAEllipsoid(const glm::vec3& center, const glm::vec3& radials) const { // handle case where ellipsoid's alix-aligned box doesn't touch this AABox if (_corner.x - radials.x > center.x || _corner.y - radials.y > center.y || diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 022f1a6ff1..a53cc26163 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -70,7 +70,7 @@ public: bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) const; bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives - bool touchesAAEllipsoid(const glm::vec3& center, glm::vec3 radials) const; + bool touchesAAEllipsoid(const glm::vec3& center, const glm::vec3& radials) const; bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;