mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 18:10:37 +02:00
Merge pull request #9946 from sethalves/model-scripting-1
Model scripting
This commit is contained in:
commit
ac309df3d1
11 changed files with 310 additions and 20 deletions
|
@ -666,11 +666,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 voxelDataDirty;
|
||||||
bool volDataDirty;
|
bool volDataDirty;
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
|
@ -688,6 +685,17 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
recomputeMesh();
|
recomputeMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return !volDataDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
|
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
|
||||||
|
assert(getType() == EntityTypes::PolyVox);
|
||||||
|
Q_ASSERT(args->_batch);
|
||||||
|
|
||||||
|
updateDependents();
|
||||||
|
|
||||||
model::MeshPointer mesh;
|
model::MeshPointer mesh;
|
||||||
glm::vec3 voxelVolumeSize;
|
glm::vec3 voxelVolumeSize;
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
|
@ -1584,14 +1592,22 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
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;
|
bool success = false;
|
||||||
MeshProxy* meshProxy = nullptr;
|
MeshProxy* meshProxy = nullptr;
|
||||||
model::MeshPointer mesh = nullptr;
|
glm::mat4 transform = voxelToLocalMatrix();
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
if (_meshInitialized) {
|
if (_meshInitialized) {
|
||||||
success = true;
|
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);
|
result = meshToScriptValue(engine, meshProxy);
|
||||||
|
|
|
@ -61,6 +61,8 @@ public:
|
||||||
virtual uint8_t getVoxel(int x, int y, int z) override;
|
virtual uint8_t getVoxel(int x, int y, int z) override;
|
||||||
virtual bool setVoxel(int x, int y, int z, uint8_t toValue) override;
|
virtual bool setVoxel(int x, int y, int z, uint8_t toValue) override;
|
||||||
|
|
||||||
|
int getOnCount() const override { return _onCount; }
|
||||||
|
|
||||||
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,
|
||||||
|
@ -133,7 +135,7 @@ 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) const override;
|
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; }
|
||||||
|
|
||||||
|
@ -193,6 +195,7 @@ private:
|
||||||
void cacheNeighbors();
|
void cacheNeighbors();
|
||||||
void copyUpperEdgesFromNeighbors();
|
void copyUpperEdgesFromNeighbors();
|
||||||
void bonkNeighbors();
|
void bonkNeighbors();
|
||||||
|
bool updateDependents();
|
||||||
};
|
};
|
||||||
|
|
||||||
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
|
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// 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 <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
|
||||||
#include "EntityScriptingInterface.h"
|
#include "EntityScriptingInterface.h"
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
@ -1039,13 +1043,20 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3
|
||||||
void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) {
|
void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) {
|
||||||
PROFILE_RANGE(script_entities, __FUNCTION__);
|
PROFILE_RANGE(script_entities, __FUNCTION__);
|
||||||
|
|
||||||
polyVoxWorker(entityID, [callback](PolyVoxEntityItem& polyVoxEntity) mutable {
|
bool success { false };
|
||||||
QScriptValue mesh;
|
QScriptValue mesh { false };
|
||||||
polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh);
|
|
||||||
QScriptValueList args { mesh };
|
polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable {
|
||||||
callback.call(QScriptValue(), args);
|
if (polyVoxEntity.getOnCount() == 0) {
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh);
|
||||||
|
}
|
||||||
return true;
|
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) {
|
||||||
|
@ -1663,3 +1674,20 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons
|
||||||
AABox aaBox(low, dimensions);
|
AABox aaBox(low, dimensions);
|
||||||
return aaBox.findCapsulePenetration(start, end, radius, penetration);
|
return aaBox.findCapsulePenetration(start, end, radius, penetration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
|
||||||
|
glm::mat4 result;
|
||||||
|
if (_entityTree) {
|
||||||
|
_entityTree->withReadLock([&] {
|
||||||
|
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
|
||||||
|
if (entity) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -331,6 +331,15 @@ public slots:
|
||||||
const glm::vec3& start, const glm::vec3& end, float radius);
|
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:
|
signals:
|
||||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
||||||
|
|
|
@ -243,6 +243,6 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const {
|
||||||
return voxelDataCopy;
|
return voxelDataCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const {
|
bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ class PolyVoxEntityItem : public EntityItem {
|
||||||
virtual void setVoxelData(QByteArray voxelData);
|
virtual void setVoxelData(QByteArray voxelData);
|
||||||
virtual const QByteArray getVoxelData() const;
|
virtual const QByteArray getVoxelData() const;
|
||||||
|
|
||||||
|
virtual int getOnCount() const { return 0; }
|
||||||
|
|
||||||
enum PolyVoxSurfaceStyle {
|
enum PolyVoxSurfaceStyle {
|
||||||
SURFACE_MARCHING_CUBES,
|
SURFACE_MARCHING_CUBES,
|
||||||
SURFACE_CUBIC,
|
SURFACE_CUBIC,
|
||||||
|
@ -133,7 +135,7 @@ 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) const;
|
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
|
||||||
|
|
|
@ -198,7 +198,7 @@ public:
|
||||||
BufferView(const BufferPointer& buffer, Size offset, Size size, const Element& element = DEFAULT_ELEMENT);
|
BufferView(const BufferPointer& buffer, Size offset, Size size, const Element& element = DEFAULT_ELEMENT);
|
||||||
BufferView(const BufferPointer& buffer, Size offset, Size size, uint16 stride, const Element& element = DEFAULT_ELEMENT);
|
BufferView(const BufferPointer& buffer, Size offset, Size size, uint16 stride, const Element& element = DEFAULT_ELEMENT);
|
||||||
|
|
||||||
Size getNumElements() const { return _size / _element.getSize(); }
|
Size getNumElements() const { return (_size - _offset) / _stride; }
|
||||||
|
|
||||||
//Template iterator with random access on the buffer sysmem
|
//Template iterator with random access on the buffer sysmem
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -134,6 +134,115 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const {
|
||||||
return totalBound;
|
return totalBound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||||
|
std::function<glm::vec3(glm::vec3)> normalFunc,
|
||||||
|
std::function<uint32_t(uint32_t)> indexFunc) {
|
||||||
|
// vertex data
|
||||||
|
const gpu::BufferView& vertexBufferView = getVertexBuffer();
|
||||||
|
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices();
|
||||||
|
gpu::Resource::Size vertexSize = numVertices * sizeof(glm::vec3);
|
||||||
|
unsigned char* resultVertexData = new unsigned char[vertexSize];
|
||||||
|
unsigned char* vertexDataCursor = resultVertexData;
|
||||||
|
|
||||||
|
for (gpu::BufferView::Index i = 0; i < numVertices; i ++) {
|
||||||
|
glm::vec3 pos = vertexFunc(vertexBufferView.get<glm::vec3>(i));
|
||||||
|
memcpy(vertexDataCursor, &pos, sizeof(pos));
|
||||||
|
vertexDataCursor += sizeof(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal data
|
||||||
|
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||||
|
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);
|
||||||
|
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
|
||||||
|
gpu::Resource::Size normalSize = numNormals * sizeof(glm::vec3);
|
||||||
|
unsigned char* resultNormalData = new unsigned char[normalSize];
|
||||||
|
unsigned char* normalDataCursor = resultNormalData;
|
||||||
|
|
||||||
|
for (gpu::BufferView::Index i = 0; i < numNormals; i ++) {
|
||||||
|
glm::vec3 normal = normalFunc(normalsBufferView.get<glm::vec3>(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();
|
||||||
|
gpu::Resource::Size indexSize = numIndexes * sizeof(uint32_t);
|
||||||
|
unsigned char* resultIndexData = new unsigned char[indexSize];
|
||||||
|
unsigned char* indexDataCursor = resultIndexData;
|
||||||
|
|
||||||
|
for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) {
|
||||||
|
uint32_t index = indexFunc(indexBufferView.get<uint32_t>(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<model::Mesh::Part> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
|
||||||
|
std::function<void(glm::vec3)> normalFunc,
|
||||||
|
std::function<void(uint32_t)> indexFunc) {
|
||||||
|
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||||
|
|
||||||
|
// vertex data
|
||||||
|
const gpu::BufferView& vertexBufferView = getVertexBuffer();
|
||||||
|
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices();
|
||||||
|
for (gpu::BufferView::Index i = 0; i < numVertices; i ++) {
|
||||||
|
vertexFunc(vertexBufferView.get<glm::vec3>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal data
|
||||||
|
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);
|
||||||
|
gpu::BufferView::Index numNormals = (gpu::BufferView::Index) normalsBufferView.getNumElements();
|
||||||
|
for (gpu::BufferView::Index i = 0; i < numNormals; i ++) {
|
||||||
|
normalFunc(normalsBufferView.get<glm::vec3>(i));
|
||||||
|
}
|
||||||
|
// 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 ++) {
|
||||||
|
indexFunc(indexBufferView.get<uint32_t>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Geometry::Geometry() {
|
Geometry::Geometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,4 +257,3 @@ Geometry::~Geometry() {
|
||||||
void Geometry::setMesh(const MeshPointer& mesh) {
|
void Geometry::setMesh(const MeshPointer& mesh) {
|
||||||
_mesh = mesh;
|
_mesh = mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@ typedef AABox Box;
|
||||||
typedef std::vector< Box > Boxes;
|
typedef std::vector< Box > Boxes;
|
||||||
typedef glm::vec3 Vec3;
|
typedef glm::vec3 Vec3;
|
||||||
|
|
||||||
|
class Mesh;
|
||||||
|
using MeshPointer = std::shared_ptr< Mesh >;
|
||||||
|
|
||||||
|
|
||||||
class Mesh {
|
class Mesh {
|
||||||
public:
|
public:
|
||||||
const static Index PRIMITIVE_RESTART_INDEX = -1;
|
const static Index PRIMITIVE_RESTART_INDEX = -1;
|
||||||
|
@ -114,6 +118,15 @@ public:
|
||||||
|
|
||||||
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
|
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
|
||||||
|
|
||||||
|
// create a copy of this mesh after passing its vertices, normals, and indexes though the provided functions
|
||||||
|
MeshPointer map(std::function<glm::vec3(glm::vec3)> vertexFunc,
|
||||||
|
std::function<glm::vec3(glm::vec3)> normalFunc,
|
||||||
|
std::function<uint32_t(uint32_t)> indexFunc);
|
||||||
|
|
||||||
|
void forEach(std::function<void(glm::vec3)> vertexFunc,
|
||||||
|
std::function<void(glm::vec3)> normalFunc,
|
||||||
|
std::function<void(uint32_t)> indexFunc);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
gpu::Stream::FormatPointer _vertexFormat;
|
gpu::Stream::FormatPointer _vertexFormat;
|
||||||
|
@ -130,7 +143,6 @@ protected:
|
||||||
void evalVertexStream();
|
void evalVertexStream();
|
||||||
|
|
||||||
};
|
};
|
||||||
using MeshPointer = std::shared_ptr< Mesh >;
|
|
||||||
|
|
||||||
|
|
||||||
class Geometry {
|
class Geometry {
|
||||||
|
|
|
@ -12,11 +12,12 @@
|
||||||
#include <QScriptEngine>
|
#include <QScriptEngine>
|
||||||
#include <QScriptValueIterator>
|
#include <QScriptValueIterator>
|
||||||
#include <QtScript/QScriptValue>
|
#include <QtScript/QScriptValue>
|
||||||
|
#include "ScriptEngine.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
|
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
|
||||||
|
@ -51,3 +52,108 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
|
||||||
|
|
||||||
return writeOBJToString(meshes);
|
return writeOBJToString(meshes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
||||||
|
// figure out the size of the resulting mesh
|
||||||
|
size_t totalVertexCount { 0 };
|
||||||
|
size_t totalAttributeCount { 0 };
|
||||||
|
size_t totalIndexCount { 0 };
|
||||||
|
foreach (const MeshProxy* meshProxy, in) {
|
||||||
|
MeshPointer mesh = meshProxy->getMeshPointer();
|
||||||
|
totalVertexCount += mesh->getNumVertices();
|
||||||
|
|
||||||
|
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||||
|
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
|
||||||
|
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
|
||||||
|
totalAttributeCount += numNormals;
|
||||||
|
|
||||||
|
totalIndexCount += mesh->getNumIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
// alloc the resulting mesh
|
||||||
|
gpu::Resource::Size combinedVertexSize = totalVertexCount * sizeof(glm::vec3);
|
||||||
|
unsigned char* combinedVertexData = new unsigned char[combinedVertexSize];
|
||||||
|
unsigned char* combinedVertexDataCursor = combinedVertexData;
|
||||||
|
|
||||||
|
gpu::Resource::Size combinedNormalSize = totalAttributeCount * sizeof(glm::vec3);
|
||||||
|
unsigned char* combinedNormalData = new unsigned char[combinedNormalSize];
|
||||||
|
unsigned char* combinedNormalDataCursor = combinedNormalData;
|
||||||
|
|
||||||
|
gpu::Resource::Size combinedIndexSize = totalIndexCount * sizeof(uint32_t);
|
||||||
|
unsigned char* combinedIndexData = new unsigned char[combinedIndexSize];
|
||||||
|
unsigned char* combinedIndexDataCursor = combinedIndexData;
|
||||||
|
|
||||||
|
uint32_t indexStartOffset { 0 };
|
||||||
|
|
||||||
|
foreach (const MeshProxy* meshProxy, in) {
|
||||||
|
MeshPointer mesh = meshProxy->getMeshPointer();
|
||||||
|
mesh->forEach(
|
||||||
|
[&](glm::vec3 position){
|
||||||
|
memcpy(combinedVertexDataCursor, &position, sizeof(position));
|
||||||
|
combinedVertexDataCursor += sizeof(position);
|
||||||
|
},
|
||||||
|
[&](glm::vec3 normal){
|
||||||
|
memcpy(combinedNormalDataCursor, &normal, sizeof(normal));
|
||||||
|
combinedNormalDataCursor += sizeof(normal);
|
||||||
|
},
|
||||||
|
[&](uint32_t index){
|
||||||
|
index += indexStartOffset;
|
||||||
|
memcpy(combinedIndexDataCursor, &index, sizeof(index));
|
||||||
|
combinedIndexDataCursor += sizeof(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
|
||||||
|
indexStartOffset += numVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
model::MeshPointer result(new model::Mesh());
|
||||||
|
|
||||||
|
gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
|
||||||
|
gpu::Buffer* combinedVertexBuffer = new gpu::Buffer(combinedVertexSize, combinedVertexData);
|
||||||
|
gpu::BufferPointer combinedVertexBufferPointer(combinedVertexBuffer);
|
||||||
|
gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement);
|
||||||
|
result->setVertexBuffer(combinedVertexBufferView);
|
||||||
|
|
||||||
|
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
|
||||||
|
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
|
||||||
|
gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData);
|
||||||
|
gpu::BufferPointer combinedNormalsBufferPointer(combinedNormalsBuffer);
|
||||||
|
gpu::BufferView combinedNormalsBufferView(combinedNormalsBufferPointer, normalElement);
|
||||||
|
result->addAttribute(attributeTypeNormal, combinedNormalsBufferView);
|
||||||
|
|
||||||
|
gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW);
|
||||||
|
gpu::Buffer* combinedIndexesBuffer = new gpu::Buffer(combinedIndexSize, combinedIndexData);
|
||||||
|
gpu::BufferPointer combinedIndexesBufferPointer(combinedIndexesBuffer);
|
||||||
|
gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement);
|
||||||
|
result->setIndexBuffer(combinedIndexesBufferView);
|
||||||
|
|
||||||
|
std::vector<model::Mesh::Part> 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) {
|
||||||
|
if (!meshProxy) {
|
||||||
|
return QScriptValue(false);
|
||||||
|
}
|
||||||
|
MeshPointer mesh = meshProxy->getMeshPointer();
|
||||||
|
if (!mesh) {
|
||||||
|
return QScriptValue(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "MeshProxy.h"
|
#include "MeshProxy.h"
|
||||||
|
|
||||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||||
|
class ScriptEngine;
|
||||||
|
|
||||||
class ModelScriptingInterface : public QObject {
|
class ModelScriptingInterface : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -28,6 +29,11 @@ public:
|
||||||
ModelScriptingInterface(QObject* parent);
|
ModelScriptingInterface(QObject* parent);
|
||||||
|
|
||||||
Q_INVOKABLE QString meshToOBJ(MeshProxyList in);
|
Q_INVOKABLE QString meshToOBJ(MeshProxyList in);
|
||||||
|
Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in);
|
||||||
|
Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ScriptEngine* _modelScriptEngine { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
|
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
|
||||||
|
|
Loading…
Reference in a new issue