diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 7646f0a454..0179814641 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -14,6 +14,7 @@ #include #include #include +#include "ModelScriptingInterface.h" #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -73,7 +74,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; _meshDirty In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain. - decompressVolumeData() is called to decompress _voxelData into _volData. getMesh() is called to invoke the + decompressVolumeData() is called to decompress _voxelData into _volData. recomputeMesh() is called to invoke the polyVox surface extractor to create _mesh (as well as set Simulation _dirtyFlags). Because Simulation::DIRTY_SHAPE is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on the surface style. @@ -81,7 +82,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; When a script changes _volData, compressVolumeDataAndSendEditPacket is called to update _voxelData and to send a packet to the entity-server. - decompressVolumeData, getMesh, computeShapeInfoWorker, and compressVolumeDataAndSendEditPacket are too expensive + decompressVolumeData, recomputeMesh, computeShapeInfoWorker, and compressVolumeDataAndSendEditPacket are too expensive to run on a thread that has other things to do. These use QtConcurrent::run to spawn a thread. As each thread finishes, it adjusts the dirty flags so that the next call to render() will kick off the next step. @@ -570,7 +571,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { if (voxelDataDirty) { decompressVolumeData(); } else if (volDataDirty) { - getMesh(); + recomputeMesh(); } model::MeshPointer mesh; @@ -1096,7 +1097,7 @@ void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() { } } -void RenderablePolyVoxEntityItem::getMesh() { +void RenderablePolyVoxEntityItem::recomputeMesh() { // use _volData to make a renderable mesh PolyVoxSurfaceStyle voxelSurfaceStyle; withReadLock([&] { @@ -1171,7 +1172,7 @@ void RenderablePolyVoxEntityItem::getMesh() { } void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) { - // this catches the payload from getMesh + // this catches the payload from recomputeMesh bool neighborsNeedUpdate; withWriteLock([&] { _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; @@ -1426,7 +1427,6 @@ std::shared_ptr RenderablePolyVoxEntityItem::getZPN return std::dynamic_pointer_cast(_zPNeighbor.lock()); } - void RenderablePolyVoxEntityItem::bonkNeighbors() { // flag neighbors to the negative of this entity as needing to rebake their meshes. cacheNeighbors(); @@ -1446,7 +1446,6 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() { } } - void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { EntityItem::locationChanged(tellPhysics); if (!_pipeline || !render::Item::isValidID(_myItem)) { @@ -1458,3 +1457,17 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { scene->enqueuePendingChanges(pendingChanges); } + +bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { + bool success = false; + MeshProxy* meshProxy = nullptr; + model::MeshPointer mesh = nullptr; + withReadLock([&] { + if (_meshInitialized) { + success = true; + meshProxy = new MeshProxy(_mesh); + } + }); + result = meshToScriptValue(engine, meshProxy); + return success; +} diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ee4c3b318f..e86356deb3 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -130,6 +130,7 @@ public: std::function thunk); void setMesh(model::MeshPointer mesh); + bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const override; void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } @@ -164,7 +165,7 @@ private: ShapeInfo _shapeInfo; PolyVox::SimpleVolume* _volData = nullptr; - bool _volDataDirty = false; // does getMesh need to be called? + bool _volDataDirty = false; // does recomputeMesh need to be called? int _onCount; // how many non-zero voxels are in _volData bool _neighborsNeedUpdate { false }; @@ -175,7 +176,7 @@ private: // these are run off the main thread void decompressVolumeData(); void compressVolumeDataAndSendEditPacket(); - virtual void getMesh() override; // recompute mesh + virtual void recomputeMesh() override; // recompute mesh void computeShapeInfoWorker(); // these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c6a17a56bd..b83816cc19 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -822,8 +822,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra } } -bool EntityScriptingInterface::setVoxels(QUuid entityID, - std::function actor) { +bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function actor) { if (!_entityTree) { return false; } @@ -887,32 +886,38 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function& points) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index c0260bd199..5822d93df2 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -228,7 +228,7 @@ 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 MeshProxy* voxelsToMesh(QUuid entityID); + 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); @@ -321,7 +321,7 @@ signals: private: bool actionWorker(const QUuid& entityID, std::function actor); - bool setVoxels(QUuid entityID, std::function actor); + bool polyVoxWorker(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 2a374c1d17..a827a9903d 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -242,3 +242,7 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const { }); return voxelDataCopy; } + +bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { + return false; +} diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 4f478c8bf7..bc8ace2827 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -129,7 +129,9 @@ class PolyVoxEntityItem : public EntityItem { virtual void rebakeMesh() {}; void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } - virtual void getMesh() {}; // recompute mesh + virtual void recomputeMesh() {}; + + virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const; protected: glm::vec3 _voxelVolumeSize; // this is always 3 bytes diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index fd550749f7..30ef9a713e 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include "ModelScriptingInterface.h" ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { @@ -23,9 +25,10 @@ MeshProxy::~MeshProxy() { QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) { - QScriptValue obj("something"); - return obj; + return engine->newQObject(in, QScriptEngine::QtOwnership, + QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects); } void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) { + out = qobject_cast(value.toQObject()); } diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index 3d3e6b94a2..4cc493b257 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -37,6 +37,8 @@ public: MeshPointer getMeshPointer() const { return _mesh; } + Q_INVOKABLE int getNumVertices() const { return _mesh->getNumVertices(); } + protected: MeshPointer _mesh; };