diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index dd62122633..6f9310a36e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -664,11 +664,8 @@ void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) { } } -void RenderablePolyVoxEntityItem::render(RenderArgs* args) { - PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); - assert(getType() == EntityTypes::PolyVox); - Q_ASSERT(args->_batch); +bool RenderablePolyVoxEntityItem::updateDependents() { bool voxelDataDirty; bool volDataDirty; withWriteLock([&] { @@ -686,6 +683,17 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { recomputeMesh(); } + return !volDataDirty; +} + + +void RenderablePolyVoxEntityItem::render(RenderArgs* args) { + PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); + assert(getType() == EntityTypes::PolyVox); + Q_ASSERT(args->_batch); + + updateDependents(); + model::MeshPointer mesh; glm::vec3 voxelVolumeSize; withReadLock([&] { @@ -1571,13 +1579,22 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { scene->enqueuePendingChanges(pendingChanges); } -bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { +bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) { + if (!updateDependents()) { + return false; + } + bool success = false; MeshProxy* meshProxy = nullptr; + glm::mat4 transform = voxelToLocalMatrix(); withReadLock([&] { if (_meshInitialized) { success = true; - meshProxy = new MeshProxy(_mesh); + // 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; })); } }); result = meshToScriptValue(engine, meshProxy); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 7fe45f8d99..5eaf93e3ae 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -133,7 +133,7 @@ public: QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const; void setMesh(model::MeshPointer mesh); - bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const override; + bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) override; void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } @@ -192,6 +192,7 @@ private: void cacheNeighbors(); void copyUpperEdgesFromNeighbors(); void bonkNeighbors(); + bool updateDependents(); }; bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7eae5b2dc4..37e9e940b1 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -8,6 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +#include +#include + #include "EntityScriptingInterface.h" #include "EntityItemID.h" @@ -926,13 +930,16 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) { PROFILE_RANGE(script_entities, __FUNCTION__); - polyVoxWorker(entityID, [callback](PolyVoxEntityItem& polyVoxEntity) mutable { - QScriptValue mesh; - polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); - QScriptValueList args { mesh }; - callback.call(QScriptValue(), args); + bool success; + QScriptValue mesh; + + 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) { @@ -1557,7 +1564,11 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); if (entity) { - result = entity->getEntityToWorldMatrix(); + glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - + entity->getRegistrationPoint()); + result = translation * rotation * registration; } }); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index be34317cd5..fa727aaa7a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -294,6 +294,14 @@ public slots: Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius); + + /**jsdoc + * Returns object to world transform, excluding scale + * + * @function Entities.getEntityTransform + * @param {EntityID} entityID The ID of the entity whose transform is to be returned + * @return {Mat4} Entity's object to world transform, excluding scale + */ Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID); signals: diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index a827a9903d..90344d6c4b 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -243,6 +243,6 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const { return voxelDataCopy; } -bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { +bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) { return false; } diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index ae722b2add..943d273452 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -133,7 +133,7 @@ class PolyVoxEntityItem : public EntityItem { void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } virtual void recomputeMesh() {}; - virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const; + virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result); protected: glm::vec3 _voxelVolumeSize; // this is always 3 bytes diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 2bb6cfa436..4e5134a7d7 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -117,7 +117,7 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const { auto partItEnd = _partBuffer.cbegin() + partEnd; for (;part != partItEnd; part++) { - + Box partBound; auto index = _indexBuffer.cbegin() + (*part)._startIndex; auto endIndex = index + (*part)._numIndices; @@ -134,6 +134,87 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const { return totalBound; } + +model::MeshPointer Mesh::map(std::function vertexFunc, + std::function normalFunc, + std::function indexFunc) { + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + + gpu::Resource::Size vertexSize = getNumVertices() * sizeof(glm::vec3); + unsigned char* resultVertexData = new unsigned char[vertexSize]; + unsigned char* vertexDataCursor = resultVertexData; + + gpu::Resource::Size normalSize = getNumAttributes() * sizeof(glm::vec3); + unsigned char* resultNormalData = new unsigned char[normalSize]; + unsigned char* normalDataCursor = resultNormalData; + + gpu::Resource::Size indexSize = getNumIndices() * sizeof(uint32_t); + unsigned char* resultIndexData = new unsigned char[indexSize]; + unsigned char* indexDataCursor = resultIndexData; + + // vertex data + const gpu::BufferView& vertexBufferView = getVertexBuffer(); + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices(); + for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + glm::vec3 pos = vertexFunc(vertexBufferView.get(i)); + memcpy(vertexDataCursor, &pos, sizeof(pos)); + vertexDataCursor += sizeof(pos); + } + + // normal data + const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)getNumAttributes(); + for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + glm::vec3 normal = normalFunc(normalsBufferView.get(i)); + memcpy(normalDataCursor, &normal, sizeof(normal)); + normalDataCursor += sizeof(normal); + } + // TODO -- other attributes + + // face data + const gpu::BufferView& indexBufferView = getIndexBuffer(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); + for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + uint32_t index = indexFunc(indexBufferView.get(i)); + memcpy(indexDataCursor, &index, sizeof(index)); + indexDataCursor += sizeof(index); + } + + model::MeshPointer result(new model::Mesh()); + + gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); + gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); + gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); + result->setVertexBuffer(resultVertexBufferView); + + gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); + gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); + gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); + result->addAttribute(attributeTypeNormal, resultNormalsBufferView); + + gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); + gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); + gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); + gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); + result->setIndexBuffer(resultIndexesBufferView); + + + // TODO -- shouldn't assume just one part + + std::vector parts; + parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex + (model::Index)result->getNumIndices(), // numIndices + (model::Index)0, // baseVertex + model::Mesh::TRIANGLES)); // topology + result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + return result; +} + + Geometry::Geometry() { } @@ -148,4 +229,3 @@ Geometry::~Geometry() { void Geometry::setMesh(const MeshPointer& mesh) { _mesh = mesh; } - diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index 4256f0be03..9a20861ea7 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -25,6 +25,10 @@ typedef AABox Box; typedef std::vector< Box > Boxes; typedef glm::vec3 Vec3; +class Mesh; +using MeshPointer = std::shared_ptr< Mesh >; + + class Mesh { public: const static Index PRIMITIVE_RESTART_INDEX = -1; @@ -114,6 +118,11 @@ public: static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast(topo); } + // create a copy of this mesh after passing its vertices, normals, and indexes though the provided functions + MeshPointer map(std::function vertexFunc, + std::function normalFunc, + std::function indexFunc); + protected: gpu::Stream::FormatPointer _vertexFormat; @@ -130,7 +139,6 @@ protected: void evalVertexStream(); }; -using MeshPointer = std::shared_ptr< Mesh >; class Geometry { diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 86a651b6b2..71b82a2d60 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -151,84 +151,105 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { } +// QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { +// int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + +// if (!meshProxy) { +// return QScriptValue(false); +// } + +// MeshPointer mesh = meshProxy->getMeshPointer(); + +// gpu::Resource::Size vertexSize = mesh->getNumVertices() * sizeof(glm::vec3); +// unsigned char* resultVertexData = new unsigned char[vertexSize]; +// unsigned char* vertexDataCursor = resultVertexData; + +// gpu::Resource::Size normalSize = mesh->getNumAttributes() * sizeof(glm::vec3); +// unsigned char* resultNormalData = new unsigned char[normalSize]; +// unsigned char* normalDataCursor = resultNormalData; + +// gpu::Resource::Size indexSize = mesh->getNumIndices() * sizeof(uint32_t); +// unsigned char* resultIndexData = new unsigned char[indexSize]; +// unsigned char* indexDataCursor = resultIndexData; + +// // vertex data +// const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); +// gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); +// for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { +// glm::vec3 pos = vertexBufferView.get(i); +// pos = glm::vec3(transform * glm::vec4(pos, 1.0f)); +// memcpy(vertexDataCursor, &pos, sizeof(pos)); +// vertexDataCursor += sizeof(pos); +// } + +// // normal data +// const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); +// gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); +// for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { +// glm::vec3 normal = normalsBufferView.get(i); +// normal = glm::vec3(transform * glm::vec4(normal, 0.0f)); +// memcpy(normalDataCursor, &normal, sizeof(normal)); +// normalDataCursor += sizeof(normal); +// } +// // TODO -- other attributes + +// // face data +// const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); +// gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); +// for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { +// uint32_t index = indexBufferView.get(i); +// memcpy(indexDataCursor, &index, sizeof(index)); +// indexDataCursor += sizeof(index); +// } + +// model::MeshPointer result(new model::Mesh()); + +// gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); +// gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); +// gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); +// gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); +// result->setVertexBuffer(resultVertexBufferView); + +// gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); +// gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); +// gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); +// gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); +// result->addAttribute(attributeTypeNormal, resultNormalsBufferView); + +// gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); +// gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); +// gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); +// gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); +// result->setIndexBuffer(resultIndexesBufferView); + + +// std::vector parts; +// parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex +// (model::Index)result->getNumIndices(), // numIndices +// (model::Index)0, // baseVertex +// model::Mesh::TRIANGLES)); // topology +// result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), +// (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + + +// MeshProxy* resultProxy = new MeshProxy(result); +// return meshToScriptValue(_modelScriptEngine, resultProxy); +// } + + QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { - int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h - + if (!meshProxy) { + return QScriptValue(false); + } MeshPointer mesh = meshProxy->getMeshPointer(); - - gpu::Resource::Size vertexSize = mesh->getNumVertices() * sizeof(glm::vec3); - unsigned char* resultVertexData = new unsigned char[vertexSize]; - unsigned char* vertexDataCursor = resultVertexData; - - gpu::Resource::Size normalSize = mesh->getNumAttributes() * sizeof(glm::vec3); - unsigned char* resultNormalData = new unsigned char[normalSize]; - unsigned char* normalDataCursor = resultNormalData; - - gpu::Resource::Size indexSize = mesh->getNumIndices() * sizeof(uint32_t); - unsigned char* resultIndexData = new unsigned char[indexSize]; - unsigned char* indexDataCursor = resultIndexData; - - // vertex data - const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); - gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); - for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { - glm::vec3 pos = vertexBufferView.get(i); - pos = glm::vec3(transform * glm::vec4(pos, 0.0f)); - memcpy(vertexDataCursor, &pos, sizeof(pos)); - vertexDataCursor += sizeof(pos); + if (!mesh) { + return QScriptValue(false); } - // normal data - const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); - for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { - glm::vec3 normal = normalsBufferView.get(i); - normal = glm::vec3(transform * glm::vec4(normal, 0.0f)); - memcpy(normalDataCursor, &normal, sizeof(normal)); - normalDataCursor += sizeof(normal); - } - // TODO -- other attributes - - // face data - const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); - gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); - for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { - uint32_t index = indexBufferView.get(i); - memcpy(indexDataCursor, &index, sizeof(index)); - indexDataCursor += sizeof(index); - } - - model::MeshPointer result(new model::Mesh()); - - gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); - gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); - gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); - gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); - result->setVertexBuffer(resultVertexBufferView); - - gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); - gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); - gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); - gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); - result->addAttribute(attributeTypeNormal, resultNormalsBufferView); - - gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); - gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); - gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); - gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); - result->setIndexBuffer(resultIndexesBufferView); - - - std::vector parts; - parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex - (model::Index)result->getNumIndices(), // numIndices - (model::Index)0, // baseVertex - model::Mesh::TRIANGLES)); // topology - result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), - (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); - - - + model::MeshPointer result = 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; }); MeshProxy* resultProxy = new MeshProxy(result); return meshToScriptValue(_modelScriptEngine, resultProxy); }