interim checkin

This commit is contained in:
humbletim 2018-02-15 14:14:07 -05:00
parent a08770c816
commit 145a0df082
21 changed files with 1219 additions and 634 deletions

View file

@ -600,7 +600,9 @@ public:
QString error;
scriptable::ModelProviderPointer provider;
if (auto entityInterface = getEntityModelProvider(static_cast<EntityItemID>(uuid))) {
if (uuid.isNull()) {
provider = nullptr;
} else if (auto entityInterface = getEntityModelProvider(static_cast<EntityItemID>(uuid))) {
provider = entityInterface;
} else if (auto overlayInterface = getOverlayModelProvider(static_cast<OverlayID>(uuid))) {
provider = overlayInterface;

View file

@ -13,7 +13,7 @@
#include <Transform.h>
#include <SpatiallyNestable.h>
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/Forward.h>
#include "Overlay.h"
namespace model { class Mesh; }
@ -37,7 +37,7 @@ public:
virtual bool is3D() const override { return true; }
virtual uint32_t fetchMetaSubItems(render::ItemIDs& subItems) const override { subItems.push_back(getRenderItemID()); return (uint32_t) subItems.size(); }
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override { return scriptable::ModelProvider::modelUnavailableError(ok); }
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override { return scriptable::ModelProvider::modelUnavailableError(ok); }
// TODO: consider implementing registration points in this class
glm::vec3 getCenter() const { return getWorldPosition(); }

View file

@ -630,7 +630,7 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const {
return 0;
}
scriptable::ScriptableModel ModelOverlay::getScriptableModel(bool* ok) {
scriptable::ScriptableModelBase ModelOverlay::getScriptableModel(bool* ok) {
if (!_model || !_model->isLoaded()) {
return Base3DOverlay::getScriptableModel(ok);
}

View file

@ -59,7 +59,7 @@ public:
void setDrawInFront(bool drawInFront) override;
void setDrawHUDLayer(bool drawHUDLayer) override;
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
protected:
Transform evalRenderTransform() override;

View file

@ -180,15 +180,15 @@ Transform Shape3DOverlay::evalRenderTransform() {
return transform;
}
scriptable::ScriptableModel Shape3DOverlay::getScriptableModel(bool* ok) {
scriptable::ScriptableModelBase Shape3DOverlay::getScriptableModel(bool* ok) {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto vertexColor = ColorUtils::toVec3(_color);
scriptable::ScriptableModel result;
scriptable::ScriptableModelBase result;
result.metadata = {
{ "origin", "Shape3DOverlay::"+shapeStrings[_shape] },
{ "overlayID", getID() },
};
result.meshes << geometryCache->meshFromShape(_shape, vertexColor);
result.append(geometryCache->meshFromShape(_shape, vertexColor), {{ "shape", shapeStrings[_shape] }});
if (ok) {
*ok = true;
}

View file

@ -37,7 +37,7 @@ public:
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
protected:
Transform evalRenderTransform() override;

View file

@ -13,7 +13,7 @@ include_hifi_library_headers(fbx)
include_hifi_library_headers(entities)
include_hifi_library_headers(avatars)
include_hifi_library_headers(controllers)
include_hifi_library_headers(graphics-scripting) # for ScriptableModel.h
include_hifi_library_headers(graphics-scripting) # for Forward.h
target_bullet()
target_polyvox()

View file

@ -17,7 +17,7 @@
#include <Sound.h>
#include "AbstractViewStateInterface.h"
#include "EntitiesRendererLogging.h"
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/Forward.h>
class EntityTreeRenderer;
@ -55,7 +55,7 @@ public:
const uint64_t& getUpdateTime() const { return _updateTime; }
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override { return scriptable::ModelProvider::modelUnavailableError(ok); }
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override { return scriptable::ModelProvider::modelUnavailableError(ok); }
protected:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
virtual void onAddToScene(const EntityItemPointer& entity);

View file

@ -950,12 +950,9 @@ QStringList RenderableModelEntityItem::getJointNames() const {
return result;
}
scriptable::ScriptableModel render::entities::ModelEntityRenderer::getScriptableModel(bool* ok) {
scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel(bool* ok) {
ModelPointer model;
withReadLock([&] {
model = _model;
});
withReadLock([&] { model = _model; });
if (!model || !model->isLoaded()) {
return scriptable::ModelProvider::modelUnavailableError(ok);
@ -964,6 +961,18 @@ scriptable::ScriptableModel render::entities::ModelEntityRenderer::getScriptable
return _model->getScriptableModel(ok);
}
bool render::entities::ModelEntityRenderer::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer newModel, int meshIndex, int partIndex) {
qCDebug(entitiesrenderer) << "REPLACING RenderableModelEntityItem" << newModel->objectName();
ModelPointer model;
withReadLock([&] { model = _model; });
if (!model || !model->isLoaded()) {
return false;
}
return _model->replaceScriptableModelMeshPart(newModel, meshIndex, partIndex);
}
void RenderableModelEntityItem::simulateRelayedJoints() {
ModelPointer model = getModel();
if (model && model->isLoaded()) {

View file

@ -140,7 +140,8 @@ class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem
public:
ModelEntityRenderer(const EntityItemPointer& entity);
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
virtual bool replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer model, int meshIndex, int partIndex) override;
protected:
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;

View file

@ -7,23 +7,48 @@
#include <gpu/Format.h>
#include <gpu/Stream.h>
#include <graphics/Geometry.h>
#include <Extents.h>
#include <AABox.h>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/packing.hpp>
#include <glm/detail/type_vec.hpp>
namespace glm {
using hvec2 = glm::tvec2<glm::detail::hdata>;
using hvec4 = glm::tvec4<glm::detail::hdata>;
}
//#define DEBUG_BUFFERVIEW_SCRIPTING
#ifdef DEBUG_BUFFERVIEW_SCRIPTING
//#ifdef DEBUG_BUFFERVIEW_SCRIPTING
#include "DebugNames.h"
QLoggingCategory bufferview_helpers{"hifi.bufferview"};
#endif
//#endif
namespace {
QLoggingCategory bufferhelper_logging{"hifi.bufferview"};
const std::array<const char*, 4> XYZW = {{ "x", "y", "z", "w" }};
const std::array<const char*, 4> ZERO123 = {{ "0", "1", "2", "3" }};
}
gpu::BufferView buffer_helpers::getBufferView(graphics::MeshPointer mesh, gpu::Stream::Slot slot) {
return slot == gpu::Stream::POSITION ? mesh->getVertexBuffer() : mesh->getAttributeBuffer(slot);
}
QMap<QString,int> buffer_helpers::ATTRIBUTES{
{"position", gpu::Stream::POSITION },
{"normal", gpu::Stream::NORMAL },
{"color", gpu::Stream::COLOR },
{"tangent", gpu::Stream::TEXCOORD0 },
{"skin_cluster_index", gpu::Stream::SKIN_CLUSTER_INDEX },
{"skin_cluster_weight", gpu::Stream::SKIN_CLUSTER_WEIGHT },
{"texcoord0", gpu::Stream::TEXCOORD0 },
{"texcoord1", gpu::Stream::TEXCOORD1 },
{"texcoord2", gpu::Stream::TEXCOORD2 },
{"texcoord3", gpu::Stream::TEXCOORD3 },
{"texcoord4", gpu::Stream::TEXCOORD4 },
};
template <typename T>
QVariant getBufferViewElement(const gpu::BufferView& view, quint32 index, bool asArray = false) {
return glmVecToVariant(view.get<T>(index), asArray);
@ -61,14 +86,14 @@ static void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint3
packedTangent = tangentStruct.pack;
}
bool bufferViewElementFromVariant(const gpu::BufferView& view, quint32 index, const QVariant& v) {
bool buffer_helpers::fromVariant(const gpu::BufferView& view, quint32 index, const QVariant& v) {
const auto& element = view._element;
const auto vecN = element.getScalarCount();
const auto dataType = element.getType();
const auto byteLength = element.getSize();
const auto BYTES_PER_ELEMENT = byteLength / vecN;
#ifdef DEBUG_BUFFERVIEW_SCRIPTING
qCDebug(bufferview_helpers) << "bufferViewElementFromVariant" << index << DebugNames::stringFrom(dataType) << BYTES_PER_ELEMENT << vecN;
qCDebug(bufferhelper_logging) << "bufferViewElementFromVariant" << index << DebugNames::stringFrom(dataType) << BYTES_PER_ELEMENT << vecN;
#endif
if (BYTES_PER_ELEMENT == 1) {
switch(vecN) {
@ -122,16 +147,34 @@ bool bufferViewElementFromVariant(const gpu::BufferView& view, quint32 index, co
return false;
}
QVariant bufferViewElementToVariant(const gpu::BufferView& view, quint32 index, bool asArray, const char* hint) {
bool boundsCheck(const gpu::BufferView& view, quint32 index) {
const auto byteLength = view._element.getSize();
return (
index < view.getNumElements() &&
index * byteLength < (view._size - 1) * byteLength
);
}
QVariant buffer_helpers::toVariant(const gpu::BufferView& view, quint32 index, bool asArray, const char* hint) {
const auto& element = view._element;
const auto vecN = element.getScalarCount();
const auto dataType = element.getType();
const auto byteLength = element.getSize();
const auto BYTES_PER_ELEMENT = byteLength / vecN;
Q_ASSERT(index < view.getNumElements());
Q_ASSERT(index * vecN * BYTES_PER_ELEMENT < (view._size - vecN * BYTES_PER_ELEMENT));
if (!boundsCheck(view, index)) {
// sanity checks
auto byteOffset = index * vecN * BYTES_PER_ELEMENT;
auto maxByteOffset = (view._size - 1) * vecN * BYTES_PER_ELEMENT;
if (byteOffset > maxByteOffset) {
qDebug() << "bufferViewElementToVariant -- byteOffset out of range " << byteOffset << " < " << maxByteOffset << DebugNames::stringFrom(dataType);
qDebug() << "bufferViewElementToVariant -- index: " << index << "numElements" << view.getNumElements();
qDebug() << "bufferViewElementToVariant -- vecN: " << vecN << "byteLength" << byteLength << "BYTES_PER_ELEMENT" << BYTES_PER_ELEMENT;
}
Q_ASSERT(byteOffset <= maxByteOffset);
}
#ifdef DEBUG_BUFFERVIEW_SCRIPTING
qCDebug(bufferview_helpers) << "bufferViewElementToVariant" << index << DebugNames::stringFrom(dataType) << BYTES_PER_ELEMENT << vecN;
qCDebug(bufferhelper_logging) << "bufferViewElementToVariant" << index << DebugNames::stringFrom(dataType) << BYTES_PER_ELEMENT << vecN;
#endif
if (BYTES_PER_ELEMENT == 1) {
switch(vecN) {
@ -221,22 +264,137 @@ const T glmVecFromVariant(const QVariant& v) {
}
template <typename T>
gpu::BufferView bufferViewFromVector(QVector<T> elements, gpu::Element elementType) {
gpu::BufferView buffer_helpers::fromVector(const QVector<T>& elements, const gpu::Element& elementType) {
auto vertexBuffer = std::make_shared<gpu::Buffer>(elements.size() * sizeof(T), (gpu::Byte*)elements.data());
return { vertexBuffer, 0, vertexBuffer->getSize(),sizeof(T), elementType };
}
template<> gpu::BufferView buffer_helpers::fromVector<unsigned int>(const QVector<unsigned int>& elements, const gpu::Element& elementType) { return fromVector(elements, elementType); }
template<> gpu::BufferView buffer_helpers::fromVector<glm::vec3>(const QVector<glm::vec3>& elements, const gpu::Element& elementType) { return fromVector(elements, elementType); }
template<> gpu::BufferView bufferViewFromVector<unsigned int>(QVector<unsigned int> elements, gpu::Element elementType) { return bufferViewFromVector(elements, elementType); }
template<> gpu::BufferView bufferViewFromVector<glm::vec3>(QVector<glm::vec3> elements, gpu::Element elementType) { return bufferViewFromVector(elements, elementType); }
template <typename T> struct getVec4;// { static T get(const gpu::BufferView& view, quint32 index, const char *hint); };
template <typename T> struct getScalar;// { static T get(const gpu::BufferView& view, quint32 index, const char *hint); };
gpu::BufferView cloneBufferView(const gpu::BufferView& input) {
struct gotter {
static float error(const QString& name, const gpu::BufferView& view, quint32 index, const char *hint) {
qDebug() << QString("gotter:: unhandled type=%1(element=%2(%3)) size=%4(per=%5) vec%6 hint=%7 #%8")
.arg(name)
.arg(DebugNames::stringFrom(view._element.getType()))
.arg(view._element.getType())
.arg(view._element.getSize())
.arg(view._element.getSize() / view._element.getScalarCount())
.arg(view._element.getScalarCount())
.arg(hint)
.arg(view.getNumElements());
Q_ASSERT(false);
assert(false);
return NAN;
}
};
template <typename T> struct getScalar : gotter {
static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::uint32>(index);
case gpu::UINT16: return view.get<glm::uint16>(index);
case gpu::UINT8: return view.get<glm::uint8>(index);
case gpu::INT32: return view.get<glm::int32>(index);
case gpu::INT16: return view.get<glm::int16>(index);
case gpu::INT8: return view.get<glm::int8>(index);
case gpu::FLOAT: return view.get<glm::float32>(index);
case gpu::HALF: return T(glm::unpackSnorm1x8(view.get<glm::int8>(index)));
default: break;
} return T(error("getScalar", view, index, hint));
}
};
template <typename T> struct getVec2 : gotter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::u32vec2>(index);
case gpu::UINT16: return view.get<glm::u16vec2>(index);
case gpu::UINT8: return view.get<glm::u8vec2>(index);
case gpu::INT32: return view.get<glm::i32vec2>(index);
case gpu::INT16: return view.get<glm::i16vec2>(index);
case gpu::INT8: return view.get<glm::i8vec2>(index);
case gpu::FLOAT: return view.get<glm::fvec2>(index);
case gpu::HALF: return glm::unpackSnorm2x8(view.get<glm::int16>(index));
default: break;
} return T(error("getVec2", view, index, hint)); }};
template <typename T> struct getVec3 : gotter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::u32vec3>(index);
case gpu::UINT16: return view.get<glm::u16vec3>(index);
case gpu::UINT8: return view.get<glm::u8vec3>(index);
case gpu::INT32: return view.get<glm::i32vec3>(index);
case gpu::INT16: return view.get<glm::i16vec3>(index);
case gpu::INT8: return view.get<glm::i8vec3>(index);
case gpu::FLOAT: return view.get<glm::fvec3>(index);
case gpu::HALF:
case gpu::NUINT8:
case gpu::NINT2_10_10_10:
if (view._element.getSize() == sizeof(glm::int32)) {
return getVec4<T>::get(view, index, hint);
}
default: break;
} return T(error("getVec3", view, index, hint)); }};
template <typename T> struct getVec4 : gotter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) {
assert(view._element.getSize() == sizeof(glm::int32));
switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::u32vec4>(index);
case gpu::UINT16: return view.get<glm::u16vec4>(index);
case gpu::UINT8: return view.get<glm::u8vec4>(index);
case gpu::INT32: return view.get<glm::i32vec4>(index);
case gpu::INT16: return view.get<glm::i16vec4>(index);
case gpu::INT8: return view.get<glm::i8vec4>(index);
case gpu::NUINT32: break;
case gpu::NUINT16: break;
case gpu::NUINT8: return glm::unpackUnorm4x8(view.get<glm::uint32>(index));
case gpu::NUINT2: break;
case gpu::NINT32: break;
case gpu::NINT16: break;
case gpu::NINT8: break;
case gpu::COMPRESSED: break;
case gpu::NUM_TYPES: break;
case gpu::FLOAT: return view.get<glm::fvec4>(index);
case gpu::HALF: return glm::unpackSnorm4x8(view.get<glm::int32>(index));
case gpu::NINT2_10_10_10: return glm::unpackSnorm3x10_1x2(view.get<glm::uint32>(index));
} return T(error("getVec4", view, index, hint)); }};
template <typename FUNC, typename T>
struct getVec {
static QVector<T> __to_vector__(const gpu::BufferView& view, const char *hint) {
QVector<T> result;
const quint32 count = (quint32)view.getNumElements();
result.resize(count);
for (quint32 i = 0; i < count; i++) {
result[i] = FUNC::get(view, i, hint);
}
return result;
}
static T __to_scalar__(const gpu::BufferView& view, quint32 index, const char *hint) {
assert(boundsCheck(view, index));
return FUNC::get(view, index, hint);
}
};
template <> QVector<int> buffer_helpers::toVector<int>(const gpu::BufferView& view, const char *hint) { return getVec<getScalar<int>,int>::__to_vector__(view, hint); }
template <> QVector<glm::vec2> buffer_helpers::toVector<glm::vec2>(const gpu::BufferView& view, const char *hint) { return getVec<getVec2<glm::vec2>,glm::vec2>::__to_vector__(view, hint); }
template <> QVector<glm::vec3> buffer_helpers::toVector<glm::vec3>(const gpu::BufferView& view, const char *hint) { return getVec<getVec3<glm::vec3>,glm::vec3>::__to_vector__(view, hint); }
template <> QVector<glm::vec4> buffer_helpers::toVector<glm::vec4>(const gpu::BufferView& view, const char *hint) { return getVec<getVec4<glm::vec4>,glm::vec4>::__to_vector__(view, hint); }
template <> int buffer_helpers::convert<int>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getScalar<int>,int>::__to_scalar__(view, index, hint); }
template <> glm::vec2 buffer_helpers::convert<glm::vec2>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getVec2<glm::vec2>,glm::vec2>::__to_scalar__(view, index, hint); }
template <> glm::vec3 buffer_helpers::convert<glm::vec3>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getVec3<glm::vec3>,glm::vec3>::__to_scalar__(view, index, hint); }
template <> glm::vec4 buffer_helpers::convert<glm::vec4>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getVec4<glm::vec4>,glm::vec4>::__to_scalar__(view, index, hint); }
gpu::BufferView buffer_helpers::clone(const gpu::BufferView& input) {
return gpu::BufferView(
std::make_shared<gpu::Buffer>(input._buffer->getSize(), input._buffer->getData()),
input._offset, input._size, input._stride, input._element
);
}
gpu::BufferView resizedBufferView(const gpu::BufferView& input, quint32 numElements) {
gpu::BufferView buffer_helpers::resize(const gpu::BufferView& input, quint32 numElements) {
auto effectiveSize = input._buffer->getSize() / input.getNumElements();
qDebug() << "resize input" << input.getNumElements() << input._buffer->getSize() << "effectiveSize" << effectiveSize;
auto vsize = input._element.getSize() * numElements;
@ -248,3 +406,235 @@ gpu::BufferView resizedBufferView(const gpu::BufferView& input, quint32 numEleme
qDebug() << "resized output" << output.getNumElements() << output._buffer->getSize();
return output;
}
graphics::MeshPointer buffer_helpers::cloneMesh(graphics::MeshPointer mesh) {
auto clone = std::make_shared<graphics::Mesh>();
//[](graphics::Mesh* blah) {
//qCDebug(bufferhelper_logging) << "--- DELETING MESH POINTER" << blah;
// delete blah;
//});
clone->displayName = (QString::fromStdString(mesh->displayName) + "-clone").toStdString();
//qCInfo(bufferhelper_logging) << "+++ ALLOCATED MESH POINTER ScriptableMesh::cloneMesh" << clone->displayName << clone.get() << !!mesh;
clone->setIndexBuffer(buffer_helpers::clone(mesh->getIndexBuffer()));
clone->setPartBuffer(buffer_helpers::clone(mesh->getPartBuffer()));
auto attributeViews = buffer_helpers::gatherBufferViews(mesh);
for (const auto& a : attributeViews) {
auto& view = a.second;
auto slot = buffer_helpers::ATTRIBUTES[a.first];
auto points = buffer_helpers::clone(view);
if (slot == gpu::Stream::POSITION) {
clone->setVertexBuffer(points);
} else {
clone->addAttribute(slot, points);
}
}
return clone;
}
/// --- buffer view <-> variant helpers
namespace {
// expand the corresponding attribute buffer (creating it if needed) so that it matches POSITIONS size and specified element type
gpu::BufferView _expandedAttributeBuffer(const graphics::MeshPointer mesh, gpu::Stream::Slot slot) {
gpu::BufferView bufferView = buffer_helpers::getBufferView(mesh, slot);
const auto& elementType = bufferView._element;
//auto vecN = element.getScalarCount();
//auto type = element.getType();
//gpu::Element elementType = getVecNElement(type, vecN);
gpu::Size elementSize = elementType.getSize();
auto nPositions = mesh->getNumVertices();
auto vsize = nPositions * elementSize;
auto diffTypes = (elementType.getType() != bufferView._element.getType() ||
elementType.getSize() > bufferView._element.getSize() ||
elementType.getScalarCount() > bufferView._element.getScalarCount() ||
vsize > bufferView._size
);
QString hint = QString("%1").arg(slot);
#ifdef DEBUG_BUFFERVIEW_SCRIPTING
hint = DebugNames::stringFrom(slot);
#endif
#ifdef DEV_BUILD
auto beforeCount = bufferView.getNumElements();
auto beforeTotal = bufferView._size;
#endif
if (bufferView.getNumElements() < nPositions || diffTypes) {
if (!bufferView._buffer || bufferView.getNumElements() == 0) {
qCInfo(bufferhelper_logging).nospace() << "ScriptableMesh -- adding missing mesh attribute '" << hint << "' for BufferView";
gpu::Byte *data = new gpu::Byte[vsize];
memset(data, 0, vsize);
auto buffer = new gpu::Buffer(vsize, (gpu::Byte*)data);
delete[] data;
bufferView = gpu::BufferView(buffer, elementType);
mesh->addAttribute(slot, bufferView);
} else {
qCInfo(bufferhelper_logging) << "ScriptableMesh -- resizing Buffer current:" << hint << bufferView._buffer->getSize() << "wanted:" << vsize;
bufferView._element = elementType;
bufferView._buffer->resize(vsize);
bufferView._size = bufferView._buffer->getSize();
}
}
#ifdef DEV_BUILD
auto afterCount = bufferView.getNumElements();
auto afterTotal = bufferView._size;
if (beforeTotal != afterTotal || beforeCount != afterCount) {
QString typeName = QString("%1").arg(bufferView._element.getType());
#ifdef DEBUG_BUFFERVIEW_SCRIPTING
typeName = DebugNames::stringFrom(bufferView._element.getType());
#endif
qCDebug(bufferhelper_logging, "NOTE:: _expandedAttributeBuffer.%s vec%d %s (before count=%lu bytes=%lu // after count=%lu bytes=%lu)",
hint.toStdString().c_str(), bufferView._element.getScalarCount(),
typeName.toStdString().c_str(), beforeCount, beforeTotal, afterCount, afterTotal);
}
#endif
return bufferView;
}
gpu::BufferView expandAttributeToMatchPositions(graphics::MeshPointer mesh, gpu::Stream::Slot slot) {
if (slot == gpu::Stream::POSITION) {
return buffer_helpers::getBufferView(mesh, slot);
}
return _expandedAttributeBuffer(mesh, slot);
}
}
std::map<QString, gpu::BufferView> buffer_helpers::gatherBufferViews(graphics::MeshPointer mesh, const QStringList& expandToMatchPositions) {
std::map<QString, gpu::BufferView> attributeViews;
if (!mesh) {
return attributeViews;
}
for (const auto& a : buffer_helpers::ATTRIBUTES.toStdMap()) {
auto name = a.first;
auto slot = a.second;
auto view = getBufferView(mesh, slot);
auto beforeCount = view.getNumElements();
auto beforeTotal = view._size;
if (expandToMatchPositions.contains(name)) {
expandAttributeToMatchPositions(mesh, slot);
}
if (beforeCount > 0) {
auto element = view._element;
auto vecN = element.getScalarCount();
//auto type = element.getType();
QString typeName = QString("%1").arg(element.getType());
#ifdef DEBUG_BUFFERVIEW_SCRIPTING
typeName = DebugNames::stringFrom(element.getType());
#endif
attributeViews[name] = getBufferView(mesh, slot);
#if DEV_BUILD
auto afterTotal = attributeViews[name]._size;
auto afterCount = attributeViews[name].getNumElements();
if (beforeTotal != afterTotal || beforeCount != afterCount) {
qCDebug(bufferhelper_logging, "NOTE:: gatherBufferViews.%s vec%d %s (before count=%lu bytes=%lu // after count=%lu bytes=%lu)",
name.toStdString().c_str(), vecN, typeName.toStdString().c_str(), beforeCount, beforeTotal, afterCount, afterTotal);
}
#endif
}
}
return attributeViews;
}
bool buffer_helpers::recalculateNormals(graphics::MeshPointer mesh) {
qCInfo(bufferhelper_logging) << "Recalculating normals" << !!mesh;
if (!mesh) {
return false;
}
buffer_helpers::gatherBufferViews(mesh, { "normal", "color" }); // ensures #normals >= #positions
auto normals = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
auto verts = mesh->getVertexBuffer();
auto indices = mesh->getIndexBuffer();
auto esize = indices._element.getSize();
auto numPoints = indices.getNumElements();
const auto TRIANGLE = 3;
quint32 numFaces = (quint32)numPoints / TRIANGLE;
//QVector<Triangle> faces;
QVector<glm::vec3> faceNormals;
QMap<QString,QVector<quint32>> vertexToFaces;
//faces.resize(numFaces);
faceNormals.resize(numFaces);
auto numNormals = normals.getNumElements();
qCInfo(bufferhelper_logging) << QString("numFaces: %1, numNormals: %2, numPoints: %3").arg(numFaces).arg(numNormals).arg(numPoints);
if (normals.getNumElements() != verts.getNumElements()) {
return false;
}
for (quint32 i = 0; i < numFaces; i++) {
quint32 I = TRIANGLE * i;
quint32 i0 = esize == 4 ? indices.get<quint32>(I+0) : indices.get<quint16>(I+0);
quint32 i1 = esize == 4 ? indices.get<quint32>(I+1) : indices.get<quint16>(I+1);
quint32 i2 = esize == 4 ? indices.get<quint32>(I+2) : indices.get<quint16>(I+2);
Triangle face = {
verts.get<glm::vec3>(i1),
verts.get<glm::vec3>(i2),
verts.get<glm::vec3>(i0)
};
faceNormals[i] = face.getNormal();
if (glm::isnan(faceNormals[i].x)) {
qCInfo(bufferhelper_logging) << i << i0 << i1 << i2 << glmVecToVariant(face.v0) << glmVecToVariant(face.v1) << glmVecToVariant(face.v2);
break;
}
vertexToFaces[glm::to_string(face.v0).c_str()] << i;
vertexToFaces[glm::to_string(face.v1).c_str()] << i;
vertexToFaces[glm::to_string(face.v2).c_str()] << i;
}
for (quint32 j = 0; j < numNormals; j++) {
//auto v = verts.get<glm::vec3>(j);
glm::vec3 normal { 0.0f, 0.0f, 0.0f };
QString key { glm::to_string(verts.get<glm::vec3>(j)).c_str() };
const auto& faces = vertexToFaces.value(key);
if (faces.size()) {
for (const auto i : faces) {
normal += faceNormals[i];
}
normal *= 1.0f / (float)faces.size();
} else {
static int logged = 0;
if (logged++ < 10) {
qCInfo(bufferhelper_logging) << "no faces for key!?" << key;
}
normal = verts.get<glm::vec3>(j);
}
if (glm::isnan(normal.x)) {
static int logged = 0;
if (logged++ < 10) {
qCInfo(bufferhelper_logging) << "isnan(normal.x)" << j << glmVecToVariant(normal);
}
break;
}
normals.edit<glm::vec3>(j) = glm::normalize(normal);
}
return true;
}
QVariant buffer_helpers::toVariant(const glm::mat4& mat4) {
QVector<float> floats;
floats.resize(16);
memcpy(floats.data(), &mat4, sizeof(glm::mat4));
QVariant v;
v.setValue<QVector<float>>(floats);
return v;
};
QVariant buffer_helpers::toVariant(const Extents& box) {
return QVariantMap{
{ "center", glmVecToVariant(box.minimum + (box.size() / 2.0f)) },
{ "minimum", glmVecToVariant(box.minimum) },
{ "maximum", glmVecToVariant(box.maximum) },
{ "dimensions", glmVecToVariant(box.size()) },
};
}
QVariant buffer_helpers::toVariant(const AABox& box) {
return QVariantMap{
{ "brn", glmVecToVariant(box.getCorner()) },
{ "tfl", glmVecToVariant(box.calcTopFarLeft()) },
{ "center", glmVecToVariant(box.calcCenter()) },
{ "minimum", glmVecToVariant(box.getMinimumPoint()) },
{ "maximum", glmVecToVariant(box.getMaximumPoint()) },
{ "dimensions", glmVecToVariant(box.getDimensions()) },
};
}

View file

@ -7,6 +7,8 @@
#pragma once
#include <QtCore>
#include <memory>
#include <glm/glm.hpp>
namespace gpu {
class BufferView;
@ -15,11 +17,34 @@ namespace gpu {
template <typename T> QVariant glmVecToVariant(const T& v, bool asArray = false);
template <typename T> const T glmVecFromVariant(const QVariant& v);
QVariant bufferViewElementToVariant(const gpu::BufferView& view, quint32 index, bool asArray = false, const char* hint = "");
bool bufferViewElementFromVariant(const gpu::BufferView& view, quint32 index, const QVariant& v);
template <typename T> gpu::BufferView bufferViewFromVector(QVector<T> elements, gpu::Element elementType);
namespace graphics {
class Mesh;
using MeshPointer = std::shared_ptr<Mesh>;
}
gpu::BufferView cloneBufferView(const gpu::BufferView& input);
gpu::BufferView resizedBufferView(const gpu::BufferView& input, quint32 numElements);
class Extents;
class AABox;
struct buffer_helpers {
static graphics::MeshPointer cloneMesh(graphics::MeshPointer mesh);
static QMap<QString,int> ATTRIBUTES;
static std::map<QString, gpu::BufferView> gatherBufferViews(graphics::MeshPointer mesh, const QStringList& expandToMatchPositions = QStringList());
static bool recalculateNormals(graphics::MeshPointer meshProxy);
static gpu::BufferView getBufferView(graphics::MeshPointer mesh, quint8 slot);
static QVariant toVariant(const Extents& box);
static QVariant toVariant(const AABox& box);
static QVariant toVariant(const glm::mat4& mat4);
static QVariant toVariant(const gpu::BufferView& view, quint32 index, bool asArray = false, const char* hint = "");
static bool fromVariant(const gpu::BufferView& view, quint32 index, const QVariant& v);
template <typename T> static gpu::BufferView fromVector(const QVector<T>& elements, const gpu::Element& elementType);
template <typename T> static QVector<T> toVector(const gpu::BufferView& view, const char *hint = "");
template <typename T> static T convert(const gpu::BufferView& view, quint32 index, const char* hint = "");
static gpu::BufferView clone(const gpu::BufferView& input);
static gpu::BufferView resize(const gpu::BufferView& input, quint32 numElements);
};

View file

@ -26,7 +26,7 @@ QScriptValue getBufferViewElement(QScriptEngine* js, const gpu::BufferView& view
}
QScriptValue bufferViewElementToScriptValue(QScriptEngine* engine, const gpu::BufferView& view, quint32 index, bool asArray, const char* hint) {
QVariant result = bufferViewElementToVariant(view, index, asArray, hint);
QVariant result = buffer_helpers::toVariant(view, index, asArray, hint);
if (!result.isValid()) {
return QScriptValue::NullValue;
}
@ -39,7 +39,7 @@ void setBufferViewElement(const gpu::BufferView& view, quint32 index, const QScr
}
bool bufferViewElementFromScriptValue(const QScriptValue& v, const gpu::BufferView& view, quint32 index) {
return bufferViewElementFromVariant(view, index, v.toVariant());
return buffer_helpers::fromVariant(view, index, v.toVariant());
}
//

View file

@ -0,0 +1,107 @@
#pragma once
#include <QtCore/QObject>
#include <QtCore/QVector>
#include <QtCore/QVariant>
#include <QtCore/QUuid>
#include <QPointer>
#include <memory>
#include <DependencyManager.h>
namespace graphics {
class Mesh;
}
namespace gpu {
class BufferView;
}
class QScriptEngine;
namespace scriptable {
using Mesh = graphics::Mesh;
using MeshPointer = std::shared_ptr<scriptable::Mesh>;
using WeakMeshPointer = std::weak_ptr<scriptable::Mesh>;
class ScriptableModelBase;
using ScriptableModelBasePointer = QPointer<ScriptableModelBase>;
class ModelProvider;
using ModelProviderPointer = std::shared_ptr<scriptable::ModelProvider>;
using WeakModelProviderPointer = std::weak_ptr<scriptable::ModelProvider>;
class ScriptableMeshBase : public QObject {
Q_OBJECT
public:
WeakModelProviderPointer provider;
ScriptableModelBasePointer model;
WeakMeshPointer mesh;
MeshPointer ownedMesh;
QVariantMap metadata;
ScriptableMeshBase(WeakModelProviderPointer provider, ScriptableModelBasePointer model, WeakMeshPointer mesh, const QVariantMap& metadata);
ScriptableMeshBase(WeakMeshPointer mesh = WeakMeshPointer());
ScriptableMeshBase(MeshPointer mesh, const QVariantMap& metadata);
ScriptableMeshBase(const ScriptableMeshBase& other) { *this = other; }
ScriptableMeshBase& operator=(const ScriptableMeshBase& view);
virtual ~ScriptableMeshBase();
Q_INVOKABLE const scriptable::MeshPointer getMeshPointer() const { return mesh.lock(); }
Q_INVOKABLE const scriptable::ModelProviderPointer getModelProviderPointer() const { return provider.lock(); }
Q_INVOKABLE const scriptable::ScriptableModelBasePointer getModelBasePointer() const { return model; }
};
// abstract container for holding one or more references to mesh pointers
class ScriptableModelBase : public QObject {
Q_OBJECT
public:
WeakModelProviderPointer provider;
QUuid objectID; // spatially nestable ID
QVariantMap metadata;
QVector<scriptable::ScriptableMeshBase> meshes;
ScriptableModelBase(QObject* parent = nullptr) : QObject(parent) {}
ScriptableModelBase(const ScriptableModelBase& other) { *this = other; }
ScriptableModelBase& operator=(const ScriptableModelBase& other) {
provider = other.provider;
objectID = other.objectID;
metadata = other.metadata;
for (auto& mesh : other.meshes) {
append(mesh);
}
return *this;
}
virtual ~ScriptableModelBase();
void mixin(const QVariantMap& other);
void append(const ScriptableModelBase& other, const QVariantMap& modelMetadata = QVariantMap());
void append(scriptable::WeakMeshPointer mesh, const QVariantMap& metadata = QVariantMap());
void append(const ScriptableMeshBase& mesh, const QVariantMap& metadata = QVariantMap());
// TODO: in future containers for these could go here
// QVariantMap shapes;
// QVariantMap materials;
// QVariantMap armature;
};
// mixin class for Avatar/Entity/Overlay Rendering that expose their in-memory graphics::Meshes
class ModelProvider {
public:
QVariantMap metadata{ { "providerType", "unknown" } };
static scriptable::ScriptableModelBase modelUnavailableError(bool* ok) { if (ok) { *ok = false; } return {}; }
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) = 0;
virtual bool replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer model, int meshIndex, int partIndex) { return false; }
};
// mixin class for resolving UUIDs into a corresponding ModelProvider
class ModelProviderFactory : public Dependency {
public:
virtual scriptable::ModelProviderPointer lookupModelProvider(QUuid uuid) = 0;
};
using uint32 = quint32;
class ScriptableModel;
using ScriptableModelPointer = QPointer<ScriptableModel>;
class ScriptableMesh;
using ScriptableMeshPointer = QPointer<ScriptableMesh>;
class ScriptableMeshPart;
using ScriptableMeshPartPointer = QPointer<ScriptableMeshPart>;
bool registerMetaTypes(QScriptEngine* engine);
}

View file

@ -0,0 +1,3 @@
#include "GraphicsScriptingUtil.h"
Q_LOGGING_CATEGORY(graphics_scripting, "hifi.scripting.graphics")

View file

@ -0,0 +1,85 @@
#pragma once
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValue>
#include <QtCore/QPointer>
#include <QtCore/QObject>
#include <QtCore/QLoggingCategory>
#include <QDebug>
#include <memory>
#include <functional>
Q_DECLARE_LOGGING_CATEGORY(graphics_scripting)
namespace scriptable {
// derive current context's C++ QObject (based on current JS "this" value)
template <typename T> T this_qobject_cast(QScriptEngine* engine) {
auto context = engine ? engine->currentContext() : nullptr;
return qscriptvalue_cast<T>(context ? context->thisObject() : QScriptValue::NullValue);
}
// JS => QPointer<QObject>
template <typename T> QPointer<T> qpointer_qobject_cast(const QScriptValue& value) {
auto obj = value.toQObject();
qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString();
if (auto tmp = qobject_cast<T*>(obj)) {
return QPointer<T>(tmp);
}
if (auto tmp = static_cast<T*>(obj)) {
return QPointer<T>(tmp);
}
return nullptr;
}
inline QString toDebugString(QObject* tmp) {
return QString("%0 (0x%1%2)")
.arg(tmp ? tmp->metaObject()->className() : "QObject")
.arg(qulonglong(tmp), 16, 16, QChar('0'))
.arg(tmp && tmp->objectName().size() ? " name=" + tmp->objectName() : "");
}
template <typename T> QString toDebugString(std::shared_ptr<T> tmp) {
return toDebugString(qobject_cast<QObject*>(tmp.get()));
}
// C++ > QtOwned instance
template <typename T, class... Rest> std::shared_ptr<T> make_qtowned(Rest... rest) {
T* tmp = new T(rest...);
qCInfo(graphics_scripting) << "scriptable::make_qtowned" << toDebugString(tmp);
QString debug = toDebugString(tmp);
if (tmp) {
tmp->metadata["__ownership__"] = QScriptEngine::QtOwnership;
QObject::connect(tmp, &QObject::destroyed, [=]() { qCInfo(graphics_scripting) << "-------- ~scriptable::make_qtowned" << debug; });
auto ptr = std::shared_ptr<T>(tmp, [debug](T* tmp) {
//qDebug() << "~std::shared_ptr<T>" << debug;
delete tmp;
});
return ptr;
} else {
return std::shared_ptr<T>(tmp);
}
}
// C++ > ScriptOwned JS instance
template <typename T, class... Rest> QPointer<T> make_scriptowned(Rest... rest) {
T* tmp = new T(rest...);
qCInfo(graphics_scripting) << "scriptable::make_scriptowned" << toDebugString(tmp);
if (tmp) {
tmp->metadata["__ownership__"] = QScriptEngine::ScriptOwnership;
//auto blah = (DeleterFunction)[](void* delme) { };
return add_scriptowned_destructor(tmp);
} else {
return QPointer<T>(tmp);
}
}
// C++ > ScriptOwned JS instance
template <typename T> QPointer<T> add_scriptowned_destructor(T* tmp) {
QString debug = toDebugString(tmp);
if (tmp) {
QObject::connect(tmp, &QObject::destroyed, [=]() {
qCInfo(graphics_scripting) << "-------- ~scriptable::make_scriptowned" << debug;// << !!customDeleter;
//if (customDeleter) {
// customDeleter(tmp);
//}
});
} else {
qCInfo(graphics_scripting) << "add_scriptowned_destructor -- not connecting to null value" << debug;
}
return QPointer<T>(tmp);
}
}

View file

@ -26,12 +26,11 @@
#include "BufferViewScripting.h"
#include "ScriptableMesh.h"
#include "GraphicsScriptingUtil.h"
#include "ModelScriptingInterface.moc"
namespace {
QLoggingCategory model_scripting { "hifi.model.scripting" };
}
#include "RegisteredMetaTypes.h"
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
if (auto scriptEngine = qobject_cast<QScriptEngine*>(parent)) {
@ -39,8 +38,51 @@ ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(pare
}
}
void ModelScriptingInterface::getMeshes(QUuid uuid, QScriptValue scopeOrCallback, QScriptValue methodOrName) {
auto handler = makeScopedHandlerObject(scopeOrCallback, methodOrName);
bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableMeshPointer mesh, int meshIndex, int partIndex) {
auto model = scriptable::make_qtowned<scriptable::ScriptableModel>();
if (mesh) {
model->append(*mesh);
}
return updateMeshes(uuid, model.get());
}
bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model) {
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
qCDebug(graphics_scripting) << "appProvider" << appProvider.data();
scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? provider->metadata.value("providerType").toString() : QString();
if (providerType.isEmpty()) {
providerType = "unknown";
}
bool success = false;
if (provider) {
qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
auto scriptableMeshes = provider->getScriptableModel(&success);
qCDebug(graphics_scripting) << "//fetched meshes from " << providerType << "success:" <<success << "#" << scriptableMeshes.meshes.size();
if (success) {
const scriptable::ScriptableModelBasePointer base = model->operator scriptable::ScriptableModelBasePointer();
qCDebug(graphics_scripting) << "as base" << base;
if (base) {
//auto meshes = model->getConstMeshes();
success = provider->replaceScriptableModelMeshPart(base, -1, -1);
// for (uint32_t m = 0; success && m < meshes.size(); m++) {
// const auto& mesh = meshes.at(m);
// for (int p = 0; success && p < mesh->getNumParts(); p++) {
// qCDebug(graphics_scripting) << "provider->replaceScriptableModelMeshPart" << "meshIndex" << m << "partIndex" << p;
// success = provider->replaceScriptableModelMeshPart(base, m, p);
// //if (!success) {
// qCDebug(graphics_scripting) << "//provider->replaceScriptableModelMeshPart" << "meshIndex" << m << "partIndex" << p << success;
// }
// }
}
}
}
return success;
}
void ModelScriptingInterface::getMeshes(QUuid uuid, QScriptValue callback) {
auto handler = scriptable::jsBindCallback(callback);
Q_ASSERT(handler.engine() == this->engine());
QPointer<BaseScriptEngine> engine = dynamic_cast<BaseScriptEngine*>(handler.engine());
@ -49,18 +91,23 @@ void ModelScriptingInterface::getMeshes(QUuid uuid, QScriptValue scopeOrCallback
QString error;
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
qDebug() << "appProvider" << appProvider.data();
qCDebug(graphics_scripting) << "appProvider" << appProvider.data();
scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? provider->metadata.value("providerType").toString() : QString();
if (providerType.isEmpty()) {
providerType = "unknown";
}
if (provider) {
qCDebug(model_scripting) << "fetching meshes from " << providerType << "...";
qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
auto scriptableMeshes = provider->getScriptableModel(&success);
qCDebug(model_scripting) << "//fetched meshes from " << providerType << "success:" <<success << "#" << scriptableMeshes.meshes.size();
qCDebug(graphics_scripting) << "//fetched meshes from " << providerType << "success:" <<success << "#" << scriptableMeshes.meshes.size();
if (success) {
meshes = new scriptable::ScriptableModel(scriptableMeshes);//SimpleModelProxy::fromScriptableModel(scriptableMeshes);
meshes = scriptable::make_scriptowned<scriptable::ScriptableModel>(scriptableMeshes);
QString debugString = scriptable::toDebugString(meshes);
QObject::connect(meshes, &QObject::destroyed, this, [=]() {
qCDebug(graphics_scripting) << "///fetched meshes" << debugString;
});
if (meshes->objectName().isEmpty()) {
meshes->setObjectName(providerType+"::meshes");
}
@ -75,20 +122,20 @@ void ModelScriptingInterface::getMeshes(QUuid uuid, QScriptValue scopeOrCallback
}
if (!error.isEmpty()) {
qCWarning(model_scripting) << "ModelScriptingInterface::getMeshes ERROR" << error;
qCWarning(graphics_scripting) << "ModelScriptingInterface::getMeshes ERROR" << error;
callScopedHandlerObject(handler, engine->makeError(error), QScriptValue::NullValue);
} else {
callScopedHandlerObject(handler, QScriptValue::NullValue, engine->newQObject(meshes, QScriptEngine::ScriptOwnership));
callScopedHandlerObject(handler, QScriptValue::NullValue, engine->toScriptValue(meshes));
}
}
QString ModelScriptingInterface::meshToOBJ(const scriptable::ScriptableModel& _in) {
const auto& in = _in.getConstMeshes();
qCDebug(model_scripting) << "meshToOBJ" << in.size();
qCDebug(graphics_scripting) << "meshToOBJ" << in.size();
if (in.size()) {
QList<scriptable::MeshPointer> meshes;
foreach (auto meshProxy, in) {
qCDebug(model_scripting) << "meshToOBJ" << meshProxy;
qCDebug(graphics_scripting) << "meshToOBJ" << meshProxy;
if (meshProxy) {
meshes.append(getMeshPointer(meshProxy));
}
@ -207,7 +254,7 @@ QScriptValue ModelScriptingInterface::appendMeshes(scriptable::ScriptableModel _
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
return engine()->toScriptValue(scriptable::ScriptableMeshPointer(new scriptable::ScriptableMesh(nullptr, result)));
return engine()->toScriptValue(scriptable::make_scriptowned<scriptable::ScriptableMesh>(result));
}
QScriptValue ModelScriptingInterface::transformMesh(scriptable::ScriptableMeshPointer meshProxy, glm::mat4 transform) {
@ -220,8 +267,7 @@ QScriptValue ModelScriptingInterface::transformMesh(scriptable::ScriptableMeshPo
[&](glm::vec3 color){ return color; },
[&](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); },
[&](uint32_t index){ return index; });
scriptable::ScriptableMeshPointer resultProxy = scriptable::ScriptableMeshPointer(new scriptable::ScriptableMesh(nullptr, result));
return engine()->toScriptValue(resultProxy);
return engine()->toScriptValue(scriptable::make_scriptowned<scriptable::ScriptableMesh>(result));
}
QScriptValue ModelScriptingInterface::getVertexCount(scriptable::ScriptableMeshPointer meshProxy) {
@ -270,7 +316,7 @@ QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices
sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh->addAttribute(gpu::Stream::NORMAL, normalBufferView);
} else {
qCWarning(model_scripting, "ModelScriptingInterface::newMesh normals must be same length as vertices");
qCWarning(graphics_scripting, "ModelScriptingInterface::newMesh normals must be same length as vertices");
}
// indices (faces)
@ -300,54 +346,10 @@ QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices
scriptable::ScriptableMeshPointer meshProxy = scriptable::ScriptableMeshPointer(new scriptable::ScriptableMesh(nullptr, mesh));
return engine()->toScriptValue(meshProxy);
return engine()->toScriptValue(scriptable::make_scriptowned<scriptable::ScriptableMesh>(mesh));
}
namespace {
QScriptValue meshPointerToScriptValue(QScriptEngine* engine, scriptable::ScriptableMeshPointer const &in) {
if (!in) {
return QScriptValue::NullValue;
}
return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
}
void meshPointerFromScriptValue(const QScriptValue& value, scriptable::ScriptableMeshPointer &out) {
auto obj = value.toQObject();
qDebug() << "meshPointerFromScriptValue" << obj;
if (auto tmp = qobject_cast<scriptable::ScriptableMesh*>(obj)) {
out = tmp;
}
// FIXME: Why does above cast not work on Win32!?
if (!out) {
if (auto smp = static_cast<scriptable::ScriptableMesh*>(obj)) {
qDebug() << "meshPointerFromScriptValue2" << smp;
out = smp;
}
}
}
QScriptValue modelPointerToScriptValue(QScriptEngine* engine, const scriptable::ScriptableModelPointer &in) {
return engine->newQObject(in, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
// QScriptValue result = engine->newArray();
// int i = 0;
// foreach(auto& mesh, in->getMeshes()) {
// result.setProperty(i++, meshPointerToScriptValue(engine, mesh));
// }
// return result;
}
void modelPointerFromScriptValue(const QScriptValue& value, scriptable::ScriptableModelPointer &out) {
const auto length = value.property("length").toInt32();
qCDebug(model_scripting) << "in modelPointerFromScriptValue, length =" << length;
for (int i = 0; i < length; i++) {
if (const auto meshProxy = qobject_cast<scriptable::ScriptableMesh*>(value.property(i).toQObject())) {
out->meshes.append(meshProxy->getMeshPointer());
} else {
qCDebug(model_scripting) << "null meshProxy" << i;
}
}
}
// FIXME: MESHFACES:
// QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const mesh::MeshFace &meshFace) {
@ -365,29 +367,11 @@ namespace {
// qScriptValueToSequence(array, result);
// }
QScriptValue qVectorUInt32ToScriptValue(QScriptEngine* engine, const QVector<quint32>& vector) {
return qScriptValueFromSequence(engine, vector);
}
void qVectorUInt32FromScriptValue(const QScriptValue& array, QVector<quint32>& result) {
qScriptValueToSequence(array, result);
}
}
int meshUint32 = qRegisterMetaType<quint32>();
namespace mesh {
int meshUint32 = qRegisterMetaType<uint32>();
}
int qVectorMeshUint32 = qRegisterMetaType<QVector<quint32>>();
void ModelScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<scriptable::ScriptableMeshPointer>>(engine);
qScriptRegisterSequenceMetaType<QVector<quint32>>(engine);
qScriptRegisterMetaType(engine, qVectorUInt32ToScriptValue, qVectorUInt32FromScriptValue);
qScriptRegisterMetaType(engine, meshPointerToScriptValue, meshPointerFromScriptValue);
qScriptRegisterMetaType(engine, modelPointerToScriptValue, modelPointerFromScriptValue);
scriptable::registerMetaTypes(engine);
// FIXME: MESHFACES: remove if MeshFace is not needed anywhere
// qScriptRegisterSequenceMetaType<mesh::MeshFaces>(engine);
// qScriptRegisterMetaType(engine, meshFaceToScriptValue, meshFaceFromScriptValue);
@ -395,7 +379,7 @@ void ModelScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
}
MeshPointer ModelScriptingInterface::getMeshPointer(const scriptable::ScriptableMesh& meshProxy) {
return meshProxy._mesh;//getMeshPointer(&meshProxy);
return meshProxy.getMeshPointer();
}
MeshPointer ModelScriptingInterface::getMeshPointer(scriptable::ScriptableMesh& meshProxy) {
return getMeshPointer(&meshProxy);
@ -406,7 +390,7 @@ MeshPointer ModelScriptingInterface::getMeshPointer(scriptable::ScriptableMeshPo
if (context()){
context()->throwError("expected meshProxy as first parameter");
} else {
qDebug() << "expected meshProxy as first parameter";
qCDebug(graphics_scripting) << "expected meshProxy as first parameter";
}
return result;
}
@ -415,7 +399,7 @@ MeshPointer ModelScriptingInterface::getMeshPointer(scriptable::ScriptableMeshPo
if (context()) {
context()->throwError("expected valid meshProxy as first parameter");
} else {
qDebug() << "expected valid meshProxy as first parameter";
qCDebug(graphics_scripting) << "expected valid meshProxy as first parameter";
}
return result;
}

View file

@ -15,19 +15,17 @@
#include <QtCore/QObject>
#include <QUrl>
#include <RegisteredMetaTypes.h>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptable>
#include "ScriptableMesh.h"
#include <DependencyManager.h>
class ModelScriptingInterface : public QObject, public QScriptable, public Dependency {
Q_OBJECT
public:
ModelScriptingInterface(QObject* parent = nullptr);
static void registerMetaTypes(QScriptEngine* engine);
public slots:
/**jsdoc
@ -36,7 +34,9 @@ public slots:
* @function ModelScriptingInterface.getMeshes
* @param {EntityID} entityID The ID of the entity whose meshes are to be retrieve
*/
void getMeshes(QUuid uuid, QScriptValue scopeOrCallback, QScriptValue methodOrName = QScriptValue());
void getMeshes(QUuid uuid, QScriptValue callback);
bool updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model);
bool updateMeshes(QUuid uuid, const scriptable::ScriptableMeshPointer mesh, int meshIndex=0, int partIndex=0);
QString meshToOBJ(const scriptable::ScriptableModel& in);
@ -48,6 +48,8 @@ public slots:
QScriptValue getVertexCount(scriptable::ScriptableMeshPointer meshProxy);
QScriptValue getVertex(scriptable::ScriptableMeshPointer meshProxy, quint32 vertexIndex);
static void registerMetaTypes(QScriptEngine* engine);
private:
scriptable::MeshPointer getMeshPointer(scriptable::ScriptableMeshPointer meshProxy);
scriptable::MeshPointer getMeshPointer(scriptable::ScriptableMesh& meshProxy);

View file

@ -11,142 +11,188 @@
#include <DependencyManager.h>
//#include <graphics-scriping/Forward.h>
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/BufferViewHelpers.h>
#include <QtScript/QScriptable>
#include <QtScript/QScriptValue>
namespace graphics {
class Mesh;
}
namespace gpu {
class BufferView;
}
namespace scriptable {
class ScriptableMeshPart;
using ScriptableMeshPartPointer = QPointer<ScriptableMeshPart>;
class ScriptableMesh : public QObject, QScriptable {
QScriptValue jsBindCallback(QScriptValue callback);
class ScriptableMesh : public ScriptableMeshBase, QScriptable {
Q_OBJECT
public:
Q_PROPERTY(quint32 numParts READ getNumParts)
Q_PROPERTY(quint32 numAttributes READ getNumAttributes)
Q_PROPERTY(quint32 numVertices READ getNumVertices)
Q_PROPERTY(quint32 numIndices READ getNumIndices)
Q_PROPERTY(QVariantMap metadata MEMBER _metadata)
Q_PROPERTY(uint32 numParts READ getNumParts)
Q_PROPERTY(uint32 numAttributes READ getNumAttributes)
Q_PROPERTY(uint32 numVertices READ getNumVertices)
Q_PROPERTY(uint32 numIndices READ getNumIndices)
Q_PROPERTY(QVariantMap metadata MEMBER metadata)
Q_PROPERTY(QVector<QString> attributeNames READ getAttributeNames)
Q_PROPERTY(QVector<scriptable::ScriptableMeshPartPointer> parts READ getMeshParts)
Q_PROPERTY(bool valid READ hasValidMesh)
bool hasValidMesh() const { return (bool)getMeshPointer(); }
Q_PROPERTY(bool validOwned READ hasValidOwnedMesh)
bool hasValidOwnedMesh() const { return (bool)getOwnedMeshPointer(); }
static QMap<QString,int> ATTRIBUTES;
static std::map<QString, gpu::BufferView> gatherBufferViews(MeshPointer mesh, const QStringList& expandToMatchPositions = QStringList());
operator const ScriptableMeshBase*() const { return (qobject_cast<const scriptable::ScriptableMeshBase*>(this)); }
ScriptableMesh(scriptable::MeshPointer mesh) : ScriptableMeshBase(mesh) { ownedMesh = mesh; }
ScriptableMesh(WeakModelProviderPointer provider, ScriptableModelBasePointer model, MeshPointer mesh, const QVariantMap& metadata)
: ScriptableMeshBase(provider, model, mesh, metadata) { ownedMesh = mesh; }
//ScriptableMesh& operator=(const ScriptableMesh& other) { model=other.model; mesh=other.mesh; metadata=other.metadata; return *this; };
//ScriptableMesh() : QObject(), model(nullptr) {}
//ScriptableMesh(const ScriptableMesh& other) : QObject(), model(other.model), mesh(other.mesh), metadata(other.metadata) {}
ScriptableMesh(const ScriptableMeshBase& other);
ScriptableMesh(const ScriptableMesh& other) : ScriptableMeshBase(other) {};
virtual ~ScriptableMesh();
ScriptableMesh& operator=(const ScriptableMesh& other) { _model=other._model; _mesh=other._mesh; _metadata=other._metadata; return *this; };
ScriptableMesh() : QObject(), _model(nullptr) {}
ScriptableMesh(ScriptableModelPointer parent, scriptable::MeshPointer mesh) : QObject(), _model(parent), _mesh(mesh) {}
ScriptableMesh(const ScriptableMesh& other) : QObject(), _model(other._model), _mesh(other._mesh), _metadata(other._metadata) {}
~ScriptableMesh() { qDebug() << "~ScriptableMesh" << this; }
scriptable::MeshPointer getMeshPointer() const { return _mesh; }
Q_INVOKABLE const scriptable::ScriptableModelPointer getParentModel() const { return qobject_cast<scriptable::ScriptableModel*>(model); }
Q_INVOKABLE const scriptable::MeshPointer getOwnedMeshPointer() const { return ownedMesh; }
scriptable::ScriptableMeshPointer getSelf() const { return const_cast<scriptable::ScriptableMesh*>(this); }
public slots:
quint32 getNumParts() const;
quint32 getNumVertices() const;
quint32 getNumAttributes() const;
quint32 getNumIndices() const { return 0; }
uint32 getNumParts() const;
uint32 getNumVertices() const;
uint32 getNumAttributes() const;
uint32 getNumIndices() const;
QVector<QString> getAttributeNames() const;
QVector<scriptable::ScriptableMeshPartPointer> getMeshParts() const;
QVariantMap getVertexAttributes(quint32 vertexIndex) const;
QVariantMap getVertexAttributes(quint32 vertexIndex, QVector<QString> attributes) const;
QVariantMap getVertexAttributes(uint32 vertexIndex) const;
QVariantMap getVertexAttributes(uint32 vertexIndex, QVector<QString> attributes) const;
QVector<quint32> getIndices() const;
QVector<quint32> findNearbyIndices(const glm::vec3& origin, float epsilon = 1e-6) const;
QVector<uint32> getIndices() const;
QVector<uint32> findNearbyIndices(const glm::vec3& origin, float epsilon = 1e-6) const;
QVariantMap getMeshExtents() const;
bool setVertexAttributes(quint32 vertexIndex, QVariantMap attributes);
QVariantMap scaleToFit(float unitScale);
bool setVertexAttributes(uint32 vertexIndex, QVariantMap attributes);
QVariantList getAttributeValues(const QString& attributeName) const;
int _getSlotNumber(const QString& attributeName) const;
scriptable::ScriptableMeshPointer cloneMesh(bool recalcNormals = false);
public:
operator bool() const { return !mesh.expired(); }
public slots:
// QScriptEngine-specific wrappers
uint32 mapAttributeValues(QScriptValue callback);
};
// TODO: part-specific wrapper for working with raw geometries
class ScriptableMeshPart : public QObject, QScriptable {
Q_OBJECT
public:
Q_PROPERTY(uint32 partIndex MEMBER partIndex CONSTANT)
Q_PROPERTY(int numElementsPerFace MEMBER _elementsPerFace CONSTANT)
Q_PROPERTY(QString topology MEMBER _topology CONSTANT)
Q_PROPERTY(uint32 numFaces READ getNumFaces)
Q_PROPERTY(uint32 numAttributes READ getNumAttributes)
Q_PROPERTY(uint32 numVertices READ getNumVertices)
Q_PROPERTY(uint32 numIndices READ getNumIndices)
Q_PROPERTY(QVector<QString> attributeNames READ getAttributeNames)
Q_PROPERTY(QVariantMap metadata MEMBER metadata)
//Q_PROPERTY(scriptable::ScriptableMeshPointer parentMesh MEMBER parentMesh CONSTANT HIDE)
ScriptableMeshPart(scriptable::ScriptableMeshPointer parentMesh, int partIndex);
ScriptableMeshPart& operator=(const ScriptableMeshPart& view) { parentMesh=view.parentMesh; return *this; };
ScriptableMeshPart(const ScriptableMeshPart& other) : parentMesh(other.parentMesh), partIndex(other.partIndex) {}
~ScriptableMeshPart() { qDebug() << "~ScriptableMeshPart" << this; }
public slots:
scriptable::ScriptableMeshPointer getParentMesh() const { return parentMesh; }
uint32 getNumAttributes() const { return parentMesh ? parentMesh->getNumAttributes() : 0; }
uint32 getNumVertices() const { return parentMesh ? parentMesh->getNumVertices() : 0; }
uint32 getNumIndices() const { return parentMesh ? parentMesh->getNumIndices() : 0; }
uint32 getNumFaces() const { return parentMesh ? parentMesh->getNumIndices() / _elementsPerFace : 0; }
QVector<QString> getAttributeNames() const { return parentMesh ? parentMesh->getAttributeNames() : QVector<QString>(); }
QVector<uint32> getFace(uint32 faceIndex) const {
auto inds = parentMesh ? parentMesh->getIndices() : QVector<uint32>();
return faceIndex+2 < (uint32)inds.size() ? inds.mid(faceIndex*3, 3) : QVector<uint32>();
}
QVariantMap scaleToFit(float unitScale);
QVariantMap translate(const glm::vec3& translation);
QVariantMap scale(const glm::vec3& scale, const glm::vec3& origin = glm::vec3(NAN));
QVariantMap rotateDegrees(const glm::vec3& eulerAngles, const glm::vec3& origin = glm::vec3(NAN));
QVariantMap rotate(const glm::quat& rotation, const glm::vec3& origin = glm::vec3(NAN));
QVariantMap transform(const glm::mat4& transform);
public:
operator bool() const { return _mesh != nullptr; }
ScriptableModelPointer _model;
scriptable::MeshPointer _mesh;
QVariantMap _metadata;
bool unrollVertices(bool recalcNormals = false);
bool dedupeVertices(float epsilon = 1e-6);
bool recalculateNormals() { return buffer_helpers::recalculateNormals(getMeshPointer()); }
bool replaceMeshData(scriptable::ScriptableMeshPartPointer source, const QVector<QString>& attributeNames = QVector<QString>());
scriptable::ScriptableMeshPartPointer cloneMeshPart(bool recalcNormals = false) {
if (parentMesh) {
if (auto clone = parentMesh->cloneMesh(recalcNormals)) {
return clone->getMeshParts().value(partIndex);
}
}
return nullptr;
}
QString toOBJ();
public slots:
// QScriptEngine-specific wrappers
QScriptValue mapAttributeValues(QScriptValue scopeOrCallback, QScriptValue methodOrName = QScriptValue());
bool dedupeVertices(float epsilon = 1e-6);
bool recalculateNormals();
QScriptValue cloneMesh(bool recalcNormals = true);
QScriptValue unrollVertices(bool recalcNormals = true);
bool replaceMeshData(scriptable::ScriptableMeshPointer source, const QVector<QString>& attributeNames = QVector<QString>());
QString toOBJ();
};
// TODO: part-specific wrapper for working with raw geometries
class ScriptableMeshPart : public QObject {
Q_OBJECT
public:
Q_PROPERTY(QString topology READ getTopology)
Q_PROPERTY(quint32 numFaces READ getNumFaces)
ScriptableMeshPart& operator=(const ScriptableMeshPart& view) { parentMesh=view.parentMesh; return *this; };
ScriptableMeshPart(const ScriptableMeshPart& other) : parentMesh(other.parentMesh) {}
ScriptableMeshPart() {}
~ScriptableMeshPart() { qDebug() << "~ScriptableMeshPart" << this; }
public slots:
QString getTopology() const { return "triangles"; }
quint32 getNumFaces() const { return parentMesh.getIndices().size() / 3; }
QVector<quint32> getFace(quint32 faceIndex) const {
auto inds = parentMesh.getIndices();
return faceIndex+2 < (quint32)inds.size() ? inds.mid(faceIndex*3, 3) : QVector<quint32>();
}
uint32 mapAttributeValues(QScriptValue callback);
public:
scriptable::ScriptableMesh parentMesh;
int partIndex;
scriptable::ScriptableMeshPointer parentMesh;
uint32 partIndex;
QVariantMap metadata;
protected:
int _elementsPerFace{ 3 };
QString _topology{ "triangles" };
scriptable::MeshPointer getMeshPointer() const { return parentMesh ? parentMesh->getMeshPointer() : nullptr; }
};
class GraphicsScriptingInterface : public QObject {
class GraphicsScriptingInterface : public QObject, QScriptable {
Q_OBJECT
public:
GraphicsScriptingInterface(QObject* parent = nullptr) : QObject(parent) {}
GraphicsScriptingInterface(const GraphicsScriptingInterface& other) {}
public slots:
ScriptableMeshPart exportMeshPart(ScriptableMesh mesh, int part) { return {}; }
public slots:
ScriptableMeshPartPointer exportMeshPart(ScriptableMeshPointer mesh, int part=0) {
return ScriptableMeshPartPointer(new ScriptableMeshPart(mesh, part));
}
bool updateMeshPart(ScriptableMeshPointer mesh, ScriptableMeshPartPointer part);
};
// callback helper that lets C++ method signatures remain simple (ie: taking a single callback argument) while
// still supporting extended Qt signal-like (scope, "methodName") and (scope, function(){}) "this" binding conventions
QScriptValue jsBindCallback(QScriptValue callback);
// derive a corresponding C++ class instance from the current script engine's thisObject
template <typename T> T this_qobject_cast(QScriptEngine* engine);
}
Q_DECLARE_METATYPE(scriptable::ScriptableMeshPointer)
Q_DECLARE_METATYPE(QVector<scriptable::ScriptableMeshPointer>)
Q_DECLARE_METATYPE(scriptable::ScriptableMeshPartPointer)
Q_DECLARE_METATYPE(QVector<scriptable::ScriptableMeshPartPointer>)
Q_DECLARE_METATYPE(scriptable::GraphicsScriptingInterface)
// FIXME: MESHFACES: faces were supported in the original Model.* API -- are they still needed/used/useful for anything yet?
#include <memory>
namespace mesh {
using uint32 = quint32;
class MeshFace;
using MeshFaces = QVector<mesh::MeshFace>;
class MeshFace {
public:
MeshFace() {}
MeshFace(QVector<mesh::uint32> vertexIndices) : vertexIndices(vertexIndices) {}
MeshFace(QVector<scriptable::uint32> vertexIndices) : vertexIndices(vertexIndices) {}
~MeshFace() {}
QVector<mesh::uint32> vertexIndices;
QVector<scriptable::uint32> vertexIndices;
// TODO -- material...
};
};
Q_DECLARE_METATYPE(mesh::MeshFace)
Q_DECLARE_METATYPE(QVector<mesh::MeshFace>)
Q_DECLARE_METATYPE(mesh::uint32)
Q_DECLARE_METATYPE(QVector<mesh::uint32>)
Q_DECLARE_METATYPE(scriptable::uint32)
Q_DECLARE_METATYPE(QVector<scriptable::uint32>)

View file

@ -1,56 +1,24 @@
#pragma once
#include <glm/glm.hpp>
#include <QtCore/QObject>
#include <QtCore/QVector>
#include <QtCore/QList>
#include <QtCore/QVariant>
#include <QtCore/QUuid>
#include <QPointer>
#include <memory>
#include "Forward.h"
#include <DependencyManager.h>
namespace graphics {
class Mesh;
}
namespace gpu {
class BufferView;
}
class QScriptValue;
namespace scriptable {
using Mesh = graphics::Mesh;
using MeshPointer = std::shared_ptr<scriptable::Mesh>;
class ScriptableModel;
using ScriptableModelPointer = QPointer<ScriptableModel>;
class ScriptableMesh;
using ScriptableMeshPointer = QPointer<ScriptableMesh>;
// abstract container for holding one or more scriptable meshes
class ScriptableModel : public QObject {
class ScriptableModel : public ScriptableModelBase {
Q_OBJECT
public:
QUuid objectID;
QVariantMap metadata;
QVector<scriptable::MeshPointer> meshes;
Q_PROPERTY(QVector<scriptable::ScriptableMeshPointer> meshes READ getMeshes)
Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT)
Q_PROPERTY(QVariantMap metadata MEMBER metadata CONSTANT)
Q_INVOKABLE QString toString() const;
Q_PROPERTY(uint32 numMeshes READ getNumMeshes)
Q_PROPERTY(QVector<scriptable::ScriptableMeshPointer> meshes READ getMeshes)
ScriptableModel(QObject* parent = nullptr) : QObject(parent) {}
ScriptableModel(const ScriptableModel& other) : objectID(other.objectID), metadata(other.metadata), meshes(other.meshes) {}
ScriptableModel& operator=(const ScriptableModel& view) { objectID = view.objectID; metadata = view.metadata; meshes = view.meshes; return *this; }
~ScriptableModel() { qDebug() << "~ScriptableModel" << this; }
void mixin(const ScriptableModel& other) {
for (const auto& key : other.metadata.keys()) { metadata[key] = other.metadata[key]; }
for (const auto& mesh : other.meshes) { meshes << mesh; }
}
ScriptableModel(QObject* parent = nullptr) : ScriptableModelBase(parent) {}
ScriptableModel(const ScriptableModel& other) : ScriptableModelBase(other) {}
ScriptableModel(const ScriptableModelBase& other) : ScriptableModelBase(other) {}
ScriptableModel& operator=(const ScriptableModelBase& view) { ScriptableModelBase::operator=(view); return *this; }
virtual ~ScriptableModel() { qDebug() << "~ScriptableModel" << this; }
Q_INVOKABLE scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap());
// TODO: in future accessors for these could go here
// QVariantMap shapes;
// QVariantMap materials;
@ -58,28 +26,23 @@ namespace scriptable {
QVector<scriptable::ScriptableMeshPointer> getMeshes();
const QVector<scriptable::ScriptableMeshPointer> getConstMeshes() const;
operator scriptable::ScriptableModelBasePointer() {
QPointer<scriptable::ScriptableModelBase> p;
p = qobject_cast<scriptable::ScriptableModelBase*>(this);
return p;
}
// QScriptEngine-specific wrappers
Q_INVOKABLE QScriptValue mapAttributeValues(QScriptValue scopeOrCallback, QScriptValue methodOrName);
Q_INVOKABLE uint32 mapAttributeValues(QScriptValue callback);
Q_INVOKABLE QString toString() const;
Q_INVOKABLE uint32 getNumMeshes() { return meshes.size(); }
};
// mixin class for Avatar/Entity/Overlay Rendering that expose their in-memory graphics::Meshes
class ModelProvider {
public:
QVariantMap metadata;
static scriptable::ScriptableModel modelUnavailableError(bool* ok) { if (ok) { *ok = false; } return {}; }
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) = 0;
};
using ModelProviderPointer = std::shared_ptr<scriptable::ModelProvider>;
// mixin class for Application to resolve UUIDs into a corresponding ModelProvider
class ModelProviderFactory : public Dependency {
public:
virtual scriptable::ModelProviderPointer lookupModelProvider(QUuid uuid) = 0;
};
}
Q_DECLARE_METATYPE(scriptable::MeshPointer)
Q_DECLARE_METATYPE(scriptable::ScriptableModel)
Q_DECLARE_METATYPE(scriptable::WeakMeshPointer)
Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer)
Q_DECLARE_METATYPE(scriptable::ScriptableModelBase)
Q_DECLARE_METATYPE(scriptable::ScriptableModelBasePointer)