hook up a way to get mesh out of polyvox

This commit is contained in:
Seth Alves 2017-01-28 20:42:14 -08:00
parent d6b2216448
commit d158f6afd1
8 changed files with 60 additions and 30 deletions

View file

@ -14,6 +14,7 @@
#include <QByteArray> #include <QByteArray>
#include <QtConcurrent/QtConcurrentRun> #include <QtConcurrent/QtConcurrentRun>
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include "ModelScriptingInterface.h"
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -73,7 +74,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
_meshDirty _meshDirty
In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain. 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 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 is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on
the surface style. 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 When a script changes _volData, compressVolumeDataAndSendEditPacket is called to update _voxelData and to
send a packet to the entity-server. 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 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. 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) { if (voxelDataDirty) {
decompressVolumeData(); decompressVolumeData();
} else if (volDataDirty) { } else if (volDataDirty) {
getMesh(); recomputeMesh();
} }
model::MeshPointer mesh; model::MeshPointer mesh;
@ -1096,7 +1097,7 @@ void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
} }
} }
void RenderablePolyVoxEntityItem::getMesh() { void RenderablePolyVoxEntityItem::recomputeMesh() {
// use _volData to make a renderable mesh // use _volData to make a renderable mesh
PolyVoxSurfaceStyle voxelSurfaceStyle; PolyVoxSurfaceStyle voxelSurfaceStyle;
withReadLock([&] { withReadLock([&] {
@ -1171,7 +1172,7 @@ void RenderablePolyVoxEntityItem::getMesh() {
} }
void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) { void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) {
// this catches the payload from getMesh // this catches the payload from recomputeMesh
bool neighborsNeedUpdate; bool neighborsNeedUpdate;
withWriteLock([&] { withWriteLock([&] {
_dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS;
@ -1426,7 +1427,6 @@ std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getZPN
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_zPNeighbor.lock()); return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_zPNeighbor.lock());
} }
void RenderablePolyVoxEntityItem::bonkNeighbors() { void RenderablePolyVoxEntityItem::bonkNeighbors() {
// flag neighbors to the negative of this entity as needing to rebake their meshes. // flag neighbors to the negative of this entity as needing to rebake their meshes.
cacheNeighbors(); cacheNeighbors();
@ -1446,7 +1446,6 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() {
} }
} }
void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
EntityItem::locationChanged(tellPhysics); EntityItem::locationChanged(tellPhysics);
if (!_pipeline || !render::Item::isValidID(_myItem)) { if (!_pipeline || !render::Item::isValidID(_myItem)) {
@ -1458,3 +1457,17 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
scene->enqueuePendingChanges(pendingChanges); 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;
}

View file

@ -130,6 +130,7 @@ public:
std::function<void(int, int, int, uint8_t)> thunk); std::function<void(int, int, int, uint8_t)> thunk);
void setMesh(model::MeshPointer mesh); void setMesh(model::MeshPointer mesh);
bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const override;
void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); void setCollisionPoints(ShapeInfo::PointCollection points, AABox box);
PolyVox::SimpleVolume<uint8_t>* getVolData() { return _volData; } PolyVox::SimpleVolume<uint8_t>* getVolData() { return _volData; }
@ -164,7 +165,7 @@ private:
ShapeInfo _shapeInfo; ShapeInfo _shapeInfo;
PolyVox::SimpleVolume<uint8_t>* _volData = nullptr; PolyVox::SimpleVolume<uint8_t>* _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 int _onCount; // how many non-zero voxels are in _volData
bool _neighborsNeedUpdate { false }; bool _neighborsNeedUpdate { false };
@ -175,7 +176,7 @@ private:
// these are run off the main thread // these are run off the main thread
void decompressVolumeData(); void decompressVolumeData();
void compressVolumeDataAndSendEditPacket(); void compressVolumeDataAndSendEditPacket();
virtual void getMesh() override; // recompute mesh virtual void recomputeMesh() override; // recompute mesh
void computeShapeInfoWorker(); void computeShapeInfoWorker();
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID // these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID

View file

@ -822,8 +822,7 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
} }
} }
bool EntityScriptingInterface::setVoxels(QUuid entityID, bool EntityScriptingInterface::polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor) {
std::function<bool(PolyVoxEntityItem&)> actor) {
if (!_entityTree) { if (!_entityTree) {
return false; return false;
} }
@ -887,32 +886,38 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function<bool(Line
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) {
return polyVoxEntity.setSphere(center, radius, value); return polyVoxEntity.setSphere(center, radius, value);
}); });
} }
bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) {
return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) {
return polyVoxEntity.setVoxelInVolume(position, value); return polyVoxEntity.setVoxelInVolume(position, value);
}); });
} }
bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [value](PolyVoxEntityItem& polyVoxEntity) {
return polyVoxEntity.setAll(value); return polyVoxEntity.setAll(value);
}); });
} }
bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
const glm::vec3& cuboidSize, int value) { const glm::vec3& cuboidSize, int value) {
return setVoxels(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) { return polyVoxWorker(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) {
return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value); return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value);
}); });
} }
MeshProxy* EntityScriptingInterface::voxelsToMesh(QUuid entityID) { void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) {
return nullptr; polyVoxWorker(entityID, [callback](PolyVoxEntityItem& polyVoxEntity) mutable {
QScriptValue mesh;
polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh);
QScriptValueList args { mesh };
callback.call(QScriptValue(), args);
return true;
});
} }
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) { bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {

View file

@ -228,7 +228,7 @@ public slots:
Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
const glm::vec3& cuboidSize, int value); 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<glm::vec3>& points); Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point); Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
@ -321,7 +321,7 @@ signals:
private: private:
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor); bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor);
bool setVoxels(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor); bool polyVoxWorker(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor);
bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor); bool setPoints(QUuid entityID, std::function<bool(LineEntityItem&)> actor);
void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties);

View file

@ -242,3 +242,7 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const {
}); });
return voxelDataCopy; return voxelDataCopy;
} }
bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const {
return false;
}

View file

@ -129,7 +129,9 @@ class PolyVoxEntityItem : public EntityItem {
virtual void rebakeMesh() {}; virtual void rebakeMesh() {};
void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); }
virtual void getMesh() {}; // recompute mesh virtual void recomputeMesh() {};
virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const;
protected: protected:
glm::vec3 _voxelVolumeSize; // this is always 3 bytes glm::vec3 _voxelVolumeSize; // this is always 3 bytes

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QScriptEngine>
#include <QtScript/QScriptValue>
#include "ModelScriptingInterface.h" #include "ModelScriptingInterface.h"
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
@ -23,9 +25,10 @@ MeshProxy::~MeshProxy() {
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) { QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
QScriptValue obj("something"); return engine->newQObject(in, QScriptEngine::QtOwnership,
return obj; QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
} }
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) { void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) {
out = qobject_cast<MeshProxy*>(value.toQObject());
} }

View file

@ -37,6 +37,8 @@ public:
MeshPointer getMeshPointer() const { return _mesh; } MeshPointer getMeshPointer() const { return _mesh; }
Q_INVOKABLE int getNumVertices() const { return _mesh->getNumVertices(); }
protected: protected:
MeshPointer _mesh; MeshPointer _mesh;
}; };