mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 01:24:36 +02:00
Merge pull request #10015 from sethalves/model-scripting-2
model/mesh scripting
This commit is contained in:
commit
49b3fc8674
20 changed files with 430 additions and 100 deletions
|
@ -404,6 +404,9 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r
|
||||||
float smallestDimensionSize = voxelSize.x;
|
float smallestDimensionSize = voxelSize.x;
|
||||||
smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y);
|
smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y);
|
||||||
smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z);
|
smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z);
|
||||||
|
if (smallestDimensionSize <= 0.0f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize);
|
glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize);
|
||||||
glm::vec3 centerInVoxelCoords = wtvMatrix * glm::vec4(centerWorldCoords, 1.0f);
|
glm::vec3 centerInVoxelCoords = wtvMatrix * glm::vec4(centerWorldCoords, 1.0f);
|
||||||
|
@ -414,21 +417,33 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r
|
||||||
glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize);
|
glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize);
|
||||||
glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize);
|
glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize);
|
||||||
|
|
||||||
|
glm::vec3 radials(radiusWorldCoords / voxelSize.x,
|
||||||
|
radiusWorldCoords / voxelSize.y,
|
||||||
|
radiusWorldCoords / voxelSize.z);
|
||||||
|
|
||||||
// This three-level for loop iterates over every voxel in the volume that might be in the sphere
|
// This three-level for loop iterates over every voxel in the volume that might be in the sphere
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
for (int z = lowI.z; z < highI.z; z++) {
|
for (int z = lowI.z; z < highI.z; z++) {
|
||||||
for (int y = lowI.y; y < highI.y; y++) {
|
for (int y = lowI.y; y < highI.y; y++) {
|
||||||
for (int x = lowI.x; x < highI.x; x++) {
|
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
|
// set voxels whose bounding-box touches the sphere
|
||||||
// convert to world coordinates
|
AABox voxelBox(glm::vec3(x - 0.5f, y - 0.5f, z - 0.5f), glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
glm::vec3 worldPos = glm::vec3(vtwMatrix * pos);
|
if (voxelBox.touchesAAEllipsoid(centerInVoxelCoords, radials)) {
|
||||||
// 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);
|
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);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,6 +692,8 @@ bool RenderablePolyVoxEntityItem::updateDependents() {
|
||||||
_voxelDataDirty = false;
|
_voxelDataDirty = false;
|
||||||
} else if (_volDataDirty) {
|
} else if (_volDataDirty) {
|
||||||
_volDataDirty = false;
|
_volDataDirty = false;
|
||||||
|
} else {
|
||||||
|
_meshReady = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (voxelDataDirty) {
|
if (voxelDataDirty) {
|
||||||
|
@ -694,7 +711,9 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
assert(getType() == EntityTypes::PolyVox);
|
assert(getType() == EntityTypes::PolyVox);
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
|
|
||||||
updateDependents();
|
if (_voxelDataDirty || _volDataDirty) {
|
||||||
|
updateDependents();
|
||||||
|
}
|
||||||
|
|
||||||
model::MeshPointer mesh;
|
model::MeshPointer mesh;
|
||||||
glm::vec3 voxelVolumeSize;
|
glm::vec3 voxelVolumeSize;
|
||||||
|
@ -756,6 +775,12 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
0,
|
0,
|
||||||
sizeof(PolyVox::PositionMaterialNormal));
|
sizeof(PolyVox::PositionMaterialNormal));
|
||||||
|
|
||||||
|
// TODO -- should we be setting this?
|
||||||
|
// batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer,
|
||||||
|
// 12,
|
||||||
|
// sizeof(PolyVox::PositionMaterialNormal));
|
||||||
|
|
||||||
|
|
||||||
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
||||||
|
|
||||||
if (!_xTextureURL.isEmpty() && !_xTexture) {
|
if (!_xTextureURL.isEmpty() && !_xTexture) {
|
||||||
|
@ -1274,23 +1299,27 @@ void RenderablePolyVoxEntityItem::recomputeMesh() {
|
||||||
auto indexBuffer = std::make_shared<gpu::Buffer>(vecIndices.size() * sizeof(uint32_t),
|
auto indexBuffer = std::make_shared<gpu::Buffer>(vecIndices.size() * sizeof(uint32_t),
|
||||||
(gpu::Byte*)vecIndices.data());
|
(gpu::Byte*)vecIndices.data());
|
||||||
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
|
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);
|
mesh->setIndexBuffer(indexBufferView);
|
||||||
|
|
||||||
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getVertices();
|
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getRawVertexData();
|
||||||
auto vertexBuffer = std::make_shared<gpu::Buffer>(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
|
auto vertexBuffer = std::make_shared<gpu::Buffer>(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
|
||||||
(gpu::Byte*)vecVertices.data());
|
(gpu::Byte*)vecVertices.data());
|
||||||
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
|
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
|
||||||
gpu::BufferView vertexBufferView(vertexBufferPtr, 0,
|
gpu::BufferView vertexBufferView(vertexBufferPtr, 0,
|
||||||
vertexBufferPtr->getSize(),
|
vertexBufferPtr->getSize(),
|
||||||
sizeof(PolyVox::PositionMaterialNormal),
|
sizeof(PolyVox::PositionMaterialNormal),
|
||||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW));
|
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||||
mesh->setVertexBuffer(vertexBufferView);
|
mesh->setVertexBuffer(vertexBufferView);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO -- use 3-byte normals rather than 3-float normals
|
||||||
mesh->addAttribute(gpu::Stream::NORMAL,
|
mesh->addAttribute(gpu::Stream::NORMAL,
|
||||||
gpu::BufferView(vertexBufferPtr, sizeof(float) * 3,
|
gpu::BufferView(vertexBufferPtr,
|
||||||
vertexBufferPtr->getSize() ,
|
sizeof(float) * 3, // polyvox mesh is packed: position, normal, material
|
||||||
|
vertexBufferPtr->getSize(),
|
||||||
sizeof(PolyVox::PositionMaterialNormal),
|
sizeof(PolyVox::PositionMaterialNormal),
|
||||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
|
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)));
|
||||||
|
|
||||||
std::vector<model::Mesh::Part> parts;
|
std::vector<model::Mesh::Part> parts;
|
||||||
parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex
|
parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex
|
||||||
|
@ -1312,7 +1341,7 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) {
|
||||||
}
|
}
|
||||||
_mesh = mesh;
|
_mesh = mesh;
|
||||||
_meshDirty = true;
|
_meshDirty = true;
|
||||||
_meshInitialized = true;
|
_meshReady = true;
|
||||||
neighborsNeedUpdate = _neighborsNeedUpdate;
|
neighborsNeedUpdate = _neighborsNeedUpdate;
|
||||||
_neighborsNeedUpdate = false;
|
_neighborsNeedUpdate = false;
|
||||||
});
|
});
|
||||||
|
@ -1324,7 +1353,7 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) {
|
||||||
void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
void RenderablePolyVoxEntityItem::computeShapeInfoWorker() {
|
||||||
// this creates a collision-shape for the physics engine. The shape comes from
|
// this creates a collision-shape for the physics engine. The shape comes from
|
||||||
// _volData for cubic extractors and from _mesh for marching-cube extractors
|
// _volData for cubic extractors and from _mesh for marching-cube extractors
|
||||||
if (!_meshInitialized) {
|
if (!_meshReady) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1592,7 +1621,7 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) {
|
bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
||||||
if (!updateDependents()) {
|
if (!updateDependents()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1601,15 +1630,22 @@ bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QS
|
||||||
MeshProxy* meshProxy = nullptr;
|
MeshProxy* meshProxy = nullptr;
|
||||||
glm::mat4 transform = voxelToLocalMatrix();
|
glm::mat4 transform = voxelToLocalMatrix();
|
||||||
withReadLock([&] {
|
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;
|
success = true;
|
||||||
// the mesh will be in voxel-space. transform it into object-space
|
// the mesh will be in voxel-space. transform it into object-space
|
||||||
meshProxy = new MeshProxy(
|
meshProxy = new MeshProxy(
|
||||||
_mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
|
_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; }));
|
[&](uint32_t index){ return index; }));
|
||||||
|
result << meshProxy;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
result = meshToScriptValue(engine, meshProxy);
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
void render(RenderArgs* args) override;
|
void render(RenderArgs* args) override;
|
||||||
virtual bool supportsDetailedRayIntersection() const override { return true; }
|
virtual bool supportsDetailedRayIntersection() const override { return true; }
|
||||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
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,
|
BoxFace& face, glm::vec3& surfaceNormal,
|
||||||
void** intersectedObject, bool precisionPicking) const override;
|
void** intersectedObject, bool precisionPicking) const override;
|
||||||
|
|
||||||
|
@ -135,18 +135,19 @@ public:
|
||||||
QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const;
|
QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const;
|
||||||
|
|
||||||
void setMesh(model::MeshPointer mesh);
|
void setMesh(model::MeshPointer mesh);
|
||||||
bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) 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; }
|
||||||
|
|
||||||
uint8_t getVoxelInternal(int x, int y, int z) const;
|
uint8_t getVoxelInternal(int x, int y, int z) const;
|
||||||
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
|
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
|
// Transparent polyvox didn't seem to be working so disable for now
|
||||||
bool isTransparent() override { return false; }
|
bool isTransparent() override { return false; }
|
||||||
|
|
||||||
|
bool getMeshes(MeshProxyList& result) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void locationChanged(bool tellPhysics = true) override;
|
virtual void locationChanged(bool tellPhysics = true) override;
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@ private:
|
||||||
model::MeshPointer _mesh;
|
model::MeshPointer _mesh;
|
||||||
gpu::Stream::FormatPointer _vertexFormat;
|
gpu::Stream::FormatPointer _vertexFormat;
|
||||||
bool _meshDirty { true }; // does collision-shape need to be recomputed?
|
bool _meshDirty { true }; // does collision-shape need to be recomputed?
|
||||||
bool _meshInitialized { false };
|
bool _meshReady { false };
|
||||||
|
|
||||||
NetworkTexturePointer _xTexture;
|
NetworkTexturePointer _xTexture;
|
||||||
NetworkTexturePointer _yTexture;
|
NetworkTexturePointer _yTexture;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
set(TARGET_NAME entities)
|
set(TARGET_NAME entities)
|
||||||
setup_hifi_library(Network Script)
|
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()
|
target_bullet()
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ namespace render {
|
||||||
#define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10))
|
#define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10))
|
||||||
#define debugTreeVector(V) V << "[" << V << " in meters ]"
|
#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
|
/// 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
|
/// 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; }
|
QUuid getLastEditedBy() const { return _lastEditedBy; }
|
||||||
void setLastEditedBy(QUuid value) { _lastEditedBy = value; }
|
void setLastEditedBy(QUuid value) { _lastEditedBy = value; }
|
||||||
|
|
||||||
bool matchesJSONFilters(const QJsonObject& jsonFilters) const;
|
bool matchesJSONFilters(const QJsonObject& jsonFilters) const;
|
||||||
|
|
||||||
|
virtual bool getMeshes(MeshProxyList& result) { return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void setSimulated(bool simulated) { _simulated = simulated; }
|
void setSimulated(bool simulated) { _simulated = simulated; }
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <VariantMapToScriptValue.h>
|
#include <VariantMapToScriptValue.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <SpatialParentFinder.h>
|
#include <SpatialParentFinder.h>
|
||||||
|
#include <model-networking/MeshProxy.h>
|
||||||
|
|
||||||
#include "EntitiesLogging.h"
|
#include "EntitiesLogging.h"
|
||||||
#include "EntityActionFactoryInterface.h"
|
#include "EntityActionFactoryInterface.h"
|
||||||
|
@ -1031,25 +1032,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 {
|
|
||||||
if (polyVoxEntity.getOnCount() == 0) {
|
|
||||||
success = true;
|
|
||||||
} else {
|
|
||||||
success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
QScriptValueList args { mesh, success };
|
|
||||||
callback.call(QScriptValue(), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
|
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
|
||||||
PROFILE_RANGE(script_entities, __FUNCTION__);
|
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||||
|
|
||||||
|
@ -1666,6 +1648,30 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons
|
||||||
return aaBox.findCapsulePenetration(start, end, radius, penetration);
|
return aaBox.findCapsulePenetration(start, end, radius, penetration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityScriptingInterface::getMeshes(QUuid entityID, QScriptValue callback) {
|
||||||
|
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||||
|
|
||||||
|
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
|
||||||
|
if (!entity) {
|
||||||
|
qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID;
|
||||||
|
QScriptValueList args { callback.engine()->undefinedValue(), 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 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
|
||||||
glm::mat4 result;
|
glm::mat4 result;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
|
@ -1682,3 +1688,20 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
|
||||||
}
|
}
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -265,7 +265,6 @@ 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 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);
|
||||||
|
@ -330,6 +329,8 @@ public slots:
|
||||||
const glm::vec3& start, const glm::vec3& end, float radius);
|
const glm::vec3& start, const glm::vec3& end, float radius);
|
||||||
|
|
||||||
|
|
||||||
|
Q_INVOKABLE void getMeshes(QUuid entityID, QScriptValue callback);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Returns object to world transform, excluding scale
|
* Returns object to world transform, excluding scale
|
||||||
*
|
*
|
||||||
|
@ -339,6 +340,16 @@ public slots:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID);
|
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:
|
signals:
|
||||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
||||||
|
|
|
@ -242,7 +242,3 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const {
|
||||||
});
|
});
|
||||||
return voxelDataCopy;
|
return voxelDataCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -135,8 +135,6 @@ class PolyVoxEntityItem : public EntityItem {
|
||||||
void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); }
|
void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); }
|
||||||
virtual void recomputeMesh() {};
|
virtual void recomputeMesh() {};
|
||||||
|
|
||||||
virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,16 @@ static QString formatFloat(double n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> 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,
|
// 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.
|
// so keep track of the start index for each mesh.
|
||||||
QList<int> meshVertexStartOffset;
|
QList<int> meshVertexStartOffset;
|
||||||
|
QList<int> meshNormalStartOffset;
|
||||||
int currentVertexStartOffset = 0;
|
int currentVertexStartOffset = 0;
|
||||||
|
int currentNormalStartOffset = 0;
|
||||||
|
|
||||||
// write out all vertices
|
// write out vertices
|
||||||
foreach (const MeshPointer& mesh, meshes) {
|
foreach (const MeshPointer& mesh, meshes) {
|
||||||
meshVertexStartOffset.append(currentVertexStartOffset);
|
meshVertexStartOffset.append(currentVertexStartOffset);
|
||||||
const gpu::BufferView& vertexBuffer = mesh->getVertexBuffer();
|
const gpu::BufferView& vertexBuffer = mesh->getVertexBuffer();
|
||||||
|
@ -64,10 +68,28 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
||||||
}
|
}
|
||||||
out << "\n";
|
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<glm::vec3>(i);
|
||||||
|
out << "vn ";
|
||||||
|
out << formatFloat(normal[0]) << " ";
|
||||||
|
out << formatFloat(normal[1]) << " ";
|
||||||
|
out << formatFloat(normal[2]) << "\n";
|
||||||
|
}
|
||||||
|
currentNormalStartOffset += numNormals;
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
|
||||||
// write out faces
|
// write out faces
|
||||||
int nth = 0;
|
int nth = 0;
|
||||||
foreach (const MeshPointer& mesh, meshes) {
|
foreach (const MeshPointer& mesh, meshes) {
|
||||||
currentVertexStartOffset = meshVertexStartOffset.takeFirst();
|
currentVertexStartOffset = meshVertexStartOffset.takeFirst();
|
||||||
|
currentNormalStartOffset = meshNormalStartOffset.takeFirst();
|
||||||
|
|
||||||
const gpu::BufferView& partBuffer = mesh->getPartBuffer();
|
const gpu::BufferView& partBuffer = mesh->getPartBuffer();
|
||||||
const gpu::BufferView& indexBuffer = mesh->getIndexBuffer();
|
const gpu::BufferView& indexBuffer = mesh->getIndexBuffer();
|
||||||
|
@ -104,9 +126,15 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
|
||||||
indexCount++;
|
indexCount++;
|
||||||
|
|
||||||
out << "f ";
|
out << "f ";
|
||||||
out << currentVertexStartOffset + index0 + 1 << " ";
|
if (haveNormals) {
|
||||||
out << currentVertexStartOffset + index1 + 1 << " ";
|
out << currentVertexStartOffset + index0 + 1 << "//" << currentVertexStartOffset + index0 + 1 << " ";
|
||||||
out << currentVertexStartOffset + index2 + 1 << "\n";
|
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";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
44
libraries/model-networking/src/model-networking/MeshFace.cpp
Normal file
44
libraries/model-networking/src/model-networking/MeshFace.cpp
Normal file
|
@ -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 <RegisteredMetaTypes.h>
|
||||||
|
|
||||||
|
#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<MeshFace>& 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<MeshFace>& 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;
|
||||||
|
}
|
||||||
|
}
|
43
libraries/model-networking/src/model-networking/MeshFace.h
Normal file
43
libraries/model-networking/src/model-networking/MeshFace.h
Normal file
|
@ -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 <QScriptEngine>
|
||||||
|
#include <QScriptValueIterator>
|
||||||
|
#include <QtScript/QScriptValue>
|
||||||
|
|
||||||
|
#include <model/Geometry.h>
|
||||||
|
|
||||||
|
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||||
|
|
||||||
|
class MeshFace {
|
||||||
|
|
||||||
|
public:
|
||||||
|
MeshFace() {}
|
||||||
|
~MeshFace() {}
|
||||||
|
|
||||||
|
QVector<uint32_t> vertexIndices;
|
||||||
|
// TODO -- material...
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(MeshFace)
|
||||||
|
Q_DECLARE_METATYPE(QVector<MeshFace>)
|
||||||
|
|
||||||
|
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace);
|
||||||
|
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult);
|
||||||
|
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector);
|
||||||
|
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_MeshFace_h
|
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// 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<MeshProxy*>(value.toQObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) {
|
||||||
|
// QScriptValueList result;
|
||||||
|
QScriptValue result = engine->newArray();
|
||||||
|
int i = 0;
|
||||||
|
foreach (MeshProxy* const meshProxy, in) {
|
||||||
|
result.setProperty(i++, meshToScriptValue(engine, meshProxy));
|
||||||
|
}
|
||||||
|
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<MeshProxyList::value_type>(itr.value());
|
||||||
|
if (meshProxy) {
|
||||||
|
out.append(meshProxy);
|
||||||
|
} else {
|
||||||
|
qDebug() << "null meshProxy";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// MeshProxy.h
|
// MeshProxy.h
|
||||||
// libraries/script-engine/src
|
// libraries/model/src/model/
|
||||||
//
|
//
|
||||||
// Created by Seth Alves on 2017-1-27.
|
// Created by Seth Alves on 2017-1-27.
|
||||||
// Copyright 2017 High Fidelity, Inc.
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
@ -12,6 +12,10 @@
|
||||||
#ifndef hifi_MeshProxy_h
|
#ifndef hifi_MeshProxy_h
|
||||||
#define hifi_MeshProxy_h
|
#define hifi_MeshProxy_h
|
||||||
|
|
||||||
|
#include <QScriptEngine>
|
||||||
|
#include <QScriptValueIterator>
|
||||||
|
#include <QtScript/QScriptValue>
|
||||||
|
|
||||||
#include <model/Geometry.h>
|
#include <model/Geometry.h>
|
||||||
|
|
||||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||||
|
@ -38,4 +42,11 @@ Q_DECLARE_METATYPE(MeshProxy*);
|
||||||
class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
|
class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
|
||||||
Q_DECLARE_METATYPE(MeshProxyList);
|
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
|
#endif // hifi_MeshProxy_h
|
|
@ -145,7 +145,7 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||||
unsigned char* resultVertexData = new unsigned char[vertexSize];
|
unsigned char* resultVertexData = new unsigned char[vertexSize];
|
||||||
unsigned char* vertexDataCursor = resultVertexData;
|
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<glm::vec3>(i));
|
glm::vec3 pos = vertexFunc(vertexBufferView.get<glm::vec3>(i));
|
||||||
memcpy(vertexDataCursor, &pos, sizeof(pos));
|
memcpy(vertexDataCursor, &pos, sizeof(pos));
|
||||||
vertexDataCursor += sizeof(pos);
|
vertexDataCursor += sizeof(pos);
|
||||||
|
@ -159,7 +159,7 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||||
unsigned char* resultNormalData = new unsigned char[normalSize];
|
unsigned char* resultNormalData = new unsigned char[normalSize];
|
||||||
unsigned char* normalDataCursor = resultNormalData;
|
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<glm::vec3>(i));
|
glm::vec3 normal = normalFunc(normalsBufferView.get<glm::vec3>(i));
|
||||||
memcpy(normalDataCursor, &normal, sizeof(normal));
|
memcpy(normalDataCursor, &normal, sizeof(normal));
|
||||||
normalDataCursor += sizeof(normal);
|
normalDataCursor += sizeof(normal);
|
||||||
|
@ -173,7 +173,7 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||||
unsigned char* resultIndexData = new unsigned char[indexSize];
|
unsigned char* resultIndexData = new unsigned char[indexSize];
|
||||||
unsigned char* indexDataCursor = resultIndexData;
|
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<uint32_t>(i));
|
uint32_t index = indexFunc(indexBufferView.get<uint32_t>(i));
|
||||||
memcpy(indexDataCursor, &index, sizeof(index));
|
memcpy(indexDataCursor, &index, sizeof(index));
|
||||||
indexDataCursor += sizeof(index);
|
indexDataCursor += sizeof(index);
|
||||||
|
@ -217,19 +217,18 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||||
void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
||||||
std::function<void(glm::vec3)> normalFunc,
|
std::function<void(glm::vec3)> normalFunc,
|
||||||
std::function<void(uint32_t)> indexFunc) {
|
std::function<void(uint32_t)> indexFunc) {
|
||||||
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
|
||||||
|
|
||||||
// vertex data
|
// vertex data
|
||||||
const gpu::BufferView& vertexBufferView = getVertexBuffer();
|
const gpu::BufferView& vertexBufferView = getVertexBuffer();
|
||||||
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices();
|
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<glm::vec3>(i));
|
vertexFunc(vertexBufferView.get<glm::vec3>(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// normal data
|
// normal data
|
||||||
|
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||||
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);
|
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 ++) {
|
for (gpu::BufferView::Index i = 0; i < numNormals; i++) {
|
||||||
normalFunc(normalsBufferView.get<glm::vec3>(i));
|
normalFunc(normalsBufferView.get<glm::vec3>(i));
|
||||||
}
|
}
|
||||||
// TODO -- other attributes
|
// TODO -- other attributes
|
||||||
|
@ -237,7 +236,7 @@ void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
||||||
// face data
|
// face data
|
||||||
const gpu::BufferView& indexBufferView = getIndexBuffer();
|
const gpu::BufferView& indexBufferView = getIndexBuffer();
|
||||||
gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices();
|
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<uint32_t>(i));
|
indexFunc(indexBufferView.get<uint32_t>(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,36 +12,18 @@
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
#include <QScriptValueIterator>
|
#include <QScriptValueIterator>
|
||||||
#include <QtScript/QScriptValue>
|
#include <QtScript/QScriptValue>
|
||||||
|
#include <model-networking/MeshFace.h>
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
|
#include "ScriptEngineLogging.h"
|
||||||
#include "ModelScriptingInterface.h"
|
#include "ModelScriptingInterface.h"
|
||||||
#include "OBJWriter.h"
|
#include "OBJWriter.h"
|
||||||
|
|
||||||
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
|
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
|
||||||
_modelScriptEngine = qobject_cast<ScriptEngine*>(parent);
|
_modelScriptEngine = qobject_cast<ScriptEngine*>(parent);
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
|
qScriptRegisterSequenceMetaType<QList<MeshProxy*>>(_modelScriptEngine);
|
||||||
return engine->newQObject(in, QScriptEngine::QtOwnership,
|
qScriptRegisterMetaType(_modelScriptEngine, meshFaceToScriptValue, meshFaceFromScriptValue);
|
||||||
QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
qScriptRegisterMetaType(_modelScriptEngine, qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue);
|
||||||
}
|
|
||||||
|
|
||||||
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) {
|
|
||||||
out = qobject_cast<MeshProxy*>(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<MeshProxyList::value_type>(itr.value());
|
|
||||||
if (meshProxy) {
|
|
||||||
out.append(meshProxy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
|
QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
|
||||||
|
@ -140,8 +122,6 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
||||||
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) {
|
QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) {
|
||||||
if (!meshProxy) {
|
if (!meshProxy) {
|
||||||
return QScriptValue(false);
|
return QScriptValue(false);
|
||||||
|
@ -157,3 +137,57 @@ QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshPro
|
||||||
MeshProxy* resultProxy = new MeshProxy(result);
|
MeshProxy* resultProxy = new MeshProxy(result);
|
||||||
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices,
|
||||||
|
const QVector<glm::vec3>& normals,
|
||||||
|
const QVector<MeshFace>& faces) {
|
||||||
|
model::MeshPointer mesh(new model::Mesh());
|
||||||
|
|
||||||
|
// vertices
|
||||||
|
auto vertexBuffer = std::make_shared<gpu::Buffer>(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<gpu::Buffer>(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<gpu::Buffer>(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<model::Mesh::Part> 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);
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
#include <QScriptValue>
|
#include <QScriptValue>
|
||||||
#include <OBJWriter.h>
|
#include <OBJWriter.h>
|
||||||
#include <model/Geometry.h>
|
#include <model/Geometry.h>
|
||||||
#include "MeshProxy.h"
|
#include <model-networking/MeshProxy.h>
|
||||||
|
#include <model-networking/MeshFace.h>
|
||||||
|
|
||||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||||
class ScriptEngine;
|
class ScriptEngine;
|
||||||
|
@ -31,15 +32,12 @@ public:
|
||||||
Q_INVOKABLE QString meshToOBJ(MeshProxyList in);
|
Q_INVOKABLE QString meshToOBJ(MeshProxyList in);
|
||||||
Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in);
|
Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in);
|
||||||
Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy);
|
Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy);
|
||||||
|
Q_INVOKABLE QScriptValue newMesh(const QVector<glm::vec3>& vertices,
|
||||||
|
const QVector<glm::vec3>& normals,
|
||||||
|
const QVector<MeshFace>& faces);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ScriptEngine* _modelScriptEngine { nullptr };
|
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
|
#endif // hifi_ModelScriptingInterface_h
|
||||||
|
|
|
@ -436,6 +436,38 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
|
||||||
return getClosestPointOnFace(glm::vec3(origin), face);
|
return getClosestPointOnFace(glm::vec3(origin), face);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 ||
|
||||||
|
_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
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 {
|
glm::vec4 AABox::getPlane(BoxFace face) const {
|
||||||
switch (face) {
|
switch (face) {
|
||||||
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
|
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
|
||||||
|
|
|
@ -70,6 +70,7 @@ public:
|
||||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) const;
|
BoxFace& face, glm::vec3& surfaceNormal) const;
|
||||||
bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives
|
bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives
|
||||||
|
bool touchesAAEllipsoid(const glm::vec3& center, const glm::vec3& radials) const;
|
||||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) 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;
|
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ void registerMetaTypes(QScriptEngine* engine) {
|
||||||
qScriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue);
|
qScriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue);
|
qScriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue);
|
qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue);
|
||||||
|
qScriptRegisterMetaType(engine, qVectorIntToScriptValue, qVectorIntFromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
|
qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
|
qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
|
||||||
qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
|
qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
|
||||||
|
@ -386,6 +387,15 @@ QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector<floa
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QScriptValue qVectorIntToScriptValue(QScriptEngine* engine, const QVector<uint32_t>& 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<float>& vector) {
|
void qVectorFloatFromScriptValue(const QScriptValue& array, QVector<float>& vector) {
|
||||||
int length = array.property("length").toInteger();
|
int length = array.property("length").toInteger();
|
||||||
|
|
||||||
|
@ -393,6 +403,15 @@ void qVectorFloatFromScriptValue(const QScriptValue& array, QVector<float>& vect
|
||||||
vector << array.property(i).toVariant().toFloat();
|
vector << array.property(i).toVariant().toFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qVectorIntFromScriptValue(const QScriptValue& array, QVector<uint32_t>& vector) {
|
||||||
|
int length = array.property("length").toInteger();
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
vector << array.property(i).toVariant().toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){
|
QVector<glm::vec3> qVectorVec3FromScriptValue(const QScriptValue& array){
|
||||||
QVector<glm::vec3> newVector;
|
QVector<glm::vec3> newVector;
|
||||||
|
|
|
@ -113,6 +113,10 @@ QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector<floa
|
||||||
void qVectorFloatFromScriptValue(const QScriptValue& array, QVector<float>& vector);
|
void qVectorFloatFromScriptValue(const QScriptValue& array, QVector<float>& vector);
|
||||||
QVector<float> qVectorFloatFromScriptValue(const QScriptValue& array);
|
QVector<float> qVectorFloatFromScriptValue(const QScriptValue& array);
|
||||||
|
|
||||||
|
// vector<uint32_t>
|
||||||
|
QScriptValue qVectorIntToScriptValue(QScriptEngine* engine, const QVector<uint32_t>& vector);
|
||||||
|
void qVectorIntFromScriptValue(const QScriptValue& array, QVector<uint32_t>& vector);
|
||||||
|
|
||||||
QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array);
|
QVector<QUuid> qVectorQUuidFromScriptValue(const QScriptValue& array);
|
||||||
|
|
||||||
QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube);
|
QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube);
|
||||||
|
|
Loading…
Reference in a new issue