interim checkin

This commit is contained in:
humbletim 2018-02-20 12:22:04 -05:00
parent 145a0df082
commit 5791ca4c51
27 changed files with 557 additions and 119 deletions

View file

@ -771,6 +771,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<StatTracker>();
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
DependencyManager::set<ScriptInitializerMixin, NativeScriptInitializers>();
DependencyManager::set<Preferences>();
DependencyManager::set<recording::Deck>();
DependencyManager::set<recording::Recorder>();

View file

@ -35,7 +35,7 @@
#include "ModelEntityItem.h"
#include "RenderableModelEntityItem.h"
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/Forward.h>
#include "Logging.h"
@ -1763,24 +1763,24 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
}
}
scriptable::ScriptableModel Avatar::getScriptableModel(bool* ok) {
scriptable::ScriptableModelBase Avatar::getScriptableModel(bool* ok) {
qDebug() << "Avatar::getScriptableModel" ;
if (!_skeletonModel || !_skeletonModel->isLoaded()) {
return scriptable::ModelProvider::modelUnavailableError(ok);
}
scriptable::ScriptableModel result;
result.metadata = {
scriptable::ScriptableModelBase result = _skeletonModel->getScriptableModel(ok);
result.objectID = getSessionUUID();
result.mixin({
{ "avatarID", getSessionUUID().toString() },
{ "url", _skeletonModelURL.toString() },
{ "origin", "Avatar/avatar::" + _displayName },
{ "textures", _skeletonModel->getTextures() },
};
result.mixin(_skeletonModel->getScriptableModel(ok));
// FIXME: for now access to attachment models are merged with the main avatar model
for (auto& attachmentModel : _attachmentModels) {
if (attachmentModel->isLoaded()) {
result.mixin(attachmentModel->getScriptableModel(ok));
});
// FIXME: for now access to attachment models are merged into the main avatar ScriptableModel set
for (int i = 0; i < (int)_attachmentModels.size(); i++) {
auto& model = _attachmentModels.at(i);
if (model->isLoaded()) {
result.append(model->getScriptableModel(ok), _attachmentData.at(i).toVariant().toMap());
}
}
if (ok) {

View file

@ -1,3 +1,4 @@
//
// Avatar.h
// interface/src/avatar
@ -20,7 +21,7 @@
#include <AvatarData.h>
#include <ShapeInfo.h>
#include <render/Scene.h>
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/Forward.h>
#include <GLMHelpers.h>
@ -274,7 +275,7 @@ public:
virtual void setAvatarEntityDataChanged(bool value) override;
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
public slots:
// FIXME - these should be migrated to use Pose data instead

View file

@ -962,7 +962,6 @@ scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScript
}
bool render::entities::ModelEntityRenderer::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer newModel, int meshIndex, int partIndex) {
qCDebug(entitiesrenderer) << "REPLACING RenderableModelEntityItem" << newModel->objectName();
ModelPointer model;
withReadLock([&] { model = _model; });
@ -970,7 +969,7 @@ bool render::entities::ModelEntityRenderer::replaceScriptableModelMeshPart(scrip
return false;
}
return _model->replaceScriptableModelMeshPart(newModel, meshIndex, partIndex);
return model->replaceScriptableModelMeshPart(newModel, meshIndex, partIndex);
}
void RenderableModelEntityItem::simulateRelayedJoints() {

View file

@ -281,7 +281,7 @@ std::vector<PolyLineEntityRenderer::Vertex> PolyLineEntityRenderer::updateVertic
return vertices;
}
scriptable::ScriptableModel PolyLineEntityRenderer::getScriptableModel(bool *ok) {
scriptable::ScriptableModelBase PolyLineEntityRenderer::getScriptableModel(bool *ok) {
// TODO: adapt polyline into a triangles mesh...
return EntityRenderer::getScriptableModel(ok);
}

View file

@ -25,7 +25,7 @@ class PolyLineEntityRenderer : public TypedEntityRenderer<PolyLineEntityItem> {
public:
PolyLineEntityRenderer(const EntityItemPointer& entity);
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
protected:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene,

View file

@ -1414,14 +1414,14 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() {
}
}
scriptable::ScriptableModel RenderablePolyVoxEntityItem::getScriptableModel(bool * ok) {
scriptable::ScriptableModelBase RenderablePolyVoxEntityItem::getScriptableModel(bool * ok) {
if (!updateDependents() || !_mesh) {
return scriptable::ModelProvider::modelUnavailableError(ok);
}
bool success = false;
glm::mat4 transform = voxelToLocalMatrix();
scriptable::ScriptableModel result;
scriptable::ScriptableModelBase result;
withReadLock([&] {
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)_mesh->getNumVertices();
if (!_meshReady) {
@ -1433,11 +1433,12 @@ scriptable::ScriptableModel RenderablePolyVoxEntityItem::getScriptableModel(bool
} else {
success = true;
// the mesh will be in voxel-space. transform it into object-space
result.meshes <<
_mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[=](glm::vec3 color){ return color; },
[=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
[&](uint32_t index){ return index; });
result.append(_mesh->map(
[=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[=](glm::vec3 color){ return color; },
[=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
[&](uint32_t index){ return index; }
));
}
});
if (ok) {

View file

@ -113,7 +113,7 @@ public:
void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); }
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
private:
bool updateOnCount(const ivec3& v, uint8_t toValue);
@ -163,7 +163,7 @@ class PolyVoxEntityRenderer : public TypedEntityRenderer<RenderablePolyVoxEntity
public:
PolyVoxEntityRenderer(const EntityItemPointer& entity);
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override {
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override {
return asTypedEntity<RenderablePolyVoxEntityItem>()->getScriptableModel(ok);
}

View file

@ -157,8 +157,8 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
args->_details._trianglesRendered += (int)triCount;
}
scriptable::ScriptableModel ShapeEntityRenderer::getScriptableModel(bool* ok) {
scriptable::ScriptableModel result;
scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel(bool* ok) {
scriptable::ScriptableModelBase result;
result.metadata = {
{ "entityID", getEntity()->getID().toString() },
{ "shape", entity::stringFromShape(_shape) },
@ -169,7 +169,10 @@ scriptable::ScriptableModel ShapeEntityRenderer::getScriptableModel(bool* ok) {
auto vertexColor = glm::vec3(_color);
auto success = false;
if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) {
result.meshes << mesh;
scriptable::ScriptableMeshBase base{ mesh, {
{ "shape", entity::stringFromShape(_shape) },
}};
result.append(base);
success = true;
}
if (ok) {

View file

@ -22,7 +22,7 @@ class ShapeEntityRenderer : public TypedEntityRenderer<ShapeEntityItem> {
public:
ShapeEntityRenderer(const EntityItemPointer& entity);
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
private:
virtual bool needsRenderUpdate() const override;

View file

@ -1897,7 +1897,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
geometry.meshes.append(extracted.mesh);
int meshIndex = geometry.meshes.size() - 1;
if (extracted.mesh._mesh) {
extracted.mesh._mesh->displayName = QString("%1#/mesh/%2").arg(url).arg(meshIndex);
extracted.mesh._mesh->displayName = QString("%1#/mesh/%2").arg(url).arg(meshIndex).toStdString();
extracted.mesh._mesh->modelName = modelIDsToNames.value(modelID).toStdString();
}
meshIDsToMeshIndices.insert(it.key(), meshIndex);
}
@ -1983,7 +1984,7 @@ FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
reader._loadLightmaps = loadLightmaps;
reader._lightmapLevel = lightmapLevel;
qDebug() << "Reading FBX: " << url;
qCDebug(modelformat) << "Reading FBX: " << url;
return reader.extractFBXGeometry(mapping, url);
}

View file

@ -71,7 +71,8 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
out << formatFloat(v[1]) << " ";
out << formatFloat(v[2]);
if (colorIndex < numColors) {
glm::vec3 color = colorsBufferView.get<glm::vec3>(colorIndex);
glm::vec3 color = glmVecFromVariant<glm::vec3>(buffer_helpers::toVariant(colorsBufferView, colorIndex));
//glm::vec3 color = colorsBufferView.get<glm::vec3>(colorIndex);
out << " " << formatFloat(color[0]);
out << " " << formatFloat(color[1]);
out << " " << formatFloat(color[2]);
@ -94,7 +95,7 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(gpu::Stream::InputSlot::NORMAL);
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
for (gpu::BufferView::Index i = 0; i < numNormals; i++) {
glm::vec3 normal = glmVecFromVariant<glm::vec3>(bufferViewElementToVariant(normalsBufferView, i));
glm::vec3 normal = glmVecFromVariant<glm::vec3>(buffer_helpers::toVariant(normalsBufferView, i));
//glm::vec3 normal = normalsBufferView.get<glm::vec3>(i);
out << "vn ";
out << formatFloat(normal[0]) << " ";
@ -117,7 +118,7 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
const gpu::BufferView& indexBuffer = mesh->getIndexBuffer();
graphics::Index partCount = (graphics::Index)mesh->getNumParts();
QString name = (!mesh->displayName.size() ? QString("mesh-%1-part").arg(nth) : QString(mesh->displayName))
QString name = (!mesh->displayName.size() ? QString("mesh-%1-part").arg(nth) : QString::fromStdString(mesh->displayName))
.replace(QRegExp("[^-_a-zA-Z0-9]"), "_");
for (int partIndex = 0; partIndex < partCount; partIndex++) {
const graphics::Mesh::Part& part = partBuffer.get<graphics::Mesh::Part>(partIndex);

View file

@ -19,7 +19,9 @@ namespace scriptable {
// JS => QPointer<QObject>
template <typename T> QPointer<T> qpointer_qobject_cast(const QScriptValue& value) {
auto obj = value.toQObject();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString();
#endif
if (auto tmp = qobject_cast<T*>(obj)) {
return QPointer<T>(tmp);
}
@ -41,11 +43,15 @@ namespace scriptable {
// C++ > QtOwned instance
template <typename T, class... Rest> std::shared_ptr<T> make_qtowned(Rest... rest) {
T* tmp = new T(rest...);
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "scriptable::make_qtowned" << toDebugString(tmp);
#endif
QString debug = toDebugString(tmp);
if (tmp) {
tmp->metadata["__ownership__"] = QScriptEngine::QtOwnership;
#ifdef SCRIPTABLE_MESH_DEBUG
QObject::connect(tmp, &QObject::destroyed, [=]() { qCInfo(graphics_scripting) << "-------- ~scriptable::make_qtowned" << debug; });
#endif
auto ptr = std::shared_ptr<T>(tmp, [debug](T* tmp) {
//qDebug() << "~std::shared_ptr<T>" << debug;
delete tmp;
@ -58,7 +64,9 @@ namespace scriptable {
// C++ > ScriptOwned JS instance
template <typename T, class... Rest> QPointer<T> make_scriptowned(Rest... rest) {
T* tmp = new T(rest...);
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "scriptable::make_scriptowned" << toDebugString(tmp);
#endif
if (tmp) {
tmp->metadata["__ownership__"] = QScriptEngine::ScriptOwnership;
//auto blah = (DeleterFunction)[](void* delme) { };
@ -71,12 +79,14 @@ namespace scriptable {
template <typename T> QPointer<T> add_scriptowned_destructor(T* tmp) {
QString debug = toDebugString(tmp);
if (tmp) {
#ifdef SCRIPTABLE_MESH_DEBUG
QObject::connect(tmp, &QObject::destroyed, [=]() {
qCInfo(graphics_scripting) << "-------- ~scriptable::make_scriptowned" << debug;// << !!customDeleter;
//if (customDeleter) {
// customDeleter(tmp);
//}
});
#endif
} else {
qCInfo(graphics_scripting) << "add_scriptowned_destructor -- not connecting to null value" << debug;
}

View file

@ -48,7 +48,7 @@ bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::Scripta
bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model) {
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
qCDebug(graphics_scripting) << "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()) {
@ -56,12 +56,12 @@ bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::Scripta
}
bool success = false;
if (provider) {
qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
//qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
auto scriptableMeshes = provider->getScriptableModel(&success);
qCDebug(graphics_scripting) << "//fetched meshes from " << providerType << "success:" <<success << "#" << scriptableMeshes.meshes.size();
//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;
//qCDebug(graphics_scripting) << "as base" << base;
if (base) {
//auto meshes = model->getConstMeshes();
success = provider->replaceScriptableModelMeshPart(base, -1, -1);

View file

@ -28,6 +28,8 @@
#include "OBJWriter.h"
// #define SCRIPTABLE_MESH_DEBUG
namespace scriptable {
// QScriptValue jsBindCallback(QScriptValue callback);
// template <typename T> QPointer<T> qpointer_qobject_cast(const QScriptValue& value);
@ -287,7 +289,9 @@ quint32 scriptable::ScriptableMesh::mapAttributeValues(QScriptValue _callback) {
return 0;
}
auto meshPart = js ? js->toScriptValue(getSelf()) : QScriptValue::NullValue;
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "mapAttributeValues" << mesh.get() << js->currentContext()->thisObject().toQObject();
#endif
auto obj = js->newObject();
auto attributeViews = buffer_helpers::gatherBufferViews(mesh, { "normal", "color" });
metadata["last-modified"] = QDateTime::currentDateTime().toTimeSpec(Qt::OffsetFromUTC).toString(Qt::ISODate);
@ -328,9 +332,10 @@ quint32 scriptable::ScriptableMeshPart::mapAttributeValues(QScriptValue callback
}
bool scriptable::ScriptableMeshPart::unrollVertices(bool recalcNormals) {
auto meshProxy = this;
auto mesh = getMeshPointer();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "ScriptableMeshPart::unrollVertices" << !!mesh<< !!meshProxy;
#endif
if (!mesh) {
return false;
}
@ -527,28 +532,32 @@ scriptable::ScriptableMeshPointer scriptable::ScriptableMesh::cloneMesh(bool rec
qCInfo(graphics_scripting) << "ScriptableMesh::cloneMesh -- !meshPointer";
return nullptr;
}
qCInfo(graphics_scripting) << "ScriptableMesh::cloneMesh...";
// qCInfo(graphics_scripting) << "ScriptableMesh::cloneMesh...";
auto clone = buffer_helpers::cloneMesh(mesh);
qCInfo(graphics_scripting) << "ScriptableMesh::cloneMesh...";
// qCInfo(graphics_scripting) << "ScriptableMesh::cloneMesh...";
if (recalcNormals) {
buffer_helpers::recalculateNormals(clone);
}
qCDebug(graphics_scripting) << clone.get();// << metadata;
//qCDebug(graphics_scripting) << clone.get();// << metadata;
auto meshPointer = scriptable::make_scriptowned<scriptable::ScriptableMesh>(provider, model, clone, metadata);
clone.reset(); // free local reference
qCInfo(graphics_scripting) << "========= ScriptableMesh::cloneMesh..." << meshPointer << meshPointer->ownedMesh.use_count();
// qCInfo(graphics_scripting) << "========= ScriptableMesh::cloneMesh..." << meshPointer << meshPointer->ownedMesh.use_count();
//scriptable::MeshPointer* ppMesh = new scriptable::MeshPointer();
//*ppMesh = clone;
if (meshPointer) {
if (0 && meshPointer) {
scriptable::WeakMeshPointer delme = meshPointer->mesh;
QString debugString = scriptable::toDebugString(meshPointer);
QObject::connect(meshPointer, &QObject::destroyed, meshPointer, [=]() {
qCWarning(graphics_scripting) << "*************** cloneMesh/Destroy";
qCWarning(graphics_scripting) << "*************** " << debugString << delme.lock().get();
// qCWarning(graphics_scripting) << "*************** cloneMesh/Destroy";
// qCWarning(graphics_scripting) << "*************** " << debugString << delme.lock().get();
if (!delme.expired()) {
qCWarning(graphics_scripting) << "cloneMesh -- potential memory leak..." << debugString << delme.lock().get();
QTimer::singleShot(250, this, [=]{
if (!delme.expired()) {
qCWarning(graphics_scripting) << "cloneMesh -- potential memory leak..." << debugString << delme.use_count();
}
});
}
});
}
@ -575,12 +584,16 @@ scriptable::ScriptableMeshBase& scriptable::ScriptableMeshBase::operator=(const
}
scriptable::ScriptableMeshBase::~ScriptableMeshBase() {
ownedMesh.reset();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "//~ScriptableMeshBase" << this << "ownedMesh:" << ownedMesh.use_count() << "mesh:" << mesh.use_count();
#endif
}
scriptable::ScriptableMesh::~ScriptableMesh() {
ownedMesh.reset();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "//~ScriptableMesh" << this << "ownedMesh:" << ownedMesh.use_count() << "mesh:" << mesh.use_count();
#endif
}
QString scriptable::ScriptableMeshPart::toOBJ() {

View file

@ -100,7 +100,7 @@ namespace scriptable {
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; }
// ~ScriptableMeshPart() { qDebug() << "~ScriptableMeshPart" << this; }
public slots:
scriptable::ScriptableMeshPointer getParentMesh() const { return parentMesh; }

View file

@ -0,0 +1,149 @@
//
// ScriptableModel.cpp
// libraries/graphics-scripting
//
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GraphicsScriptingUtil.h"
#include "ScriptableModel.h"
#include "ScriptableMesh.h"
#include <QtScript/QScriptEngine>
//#include "ScriptableModel.moc"
void scriptable::ScriptableModelBase::mixin(const QVariantMap& modelMetaData) {
for (const auto& key : modelMetaData.keys()) {
const auto& value = modelMetaData[key];
if (metadata.contains(key) && metadata[key].type() == (QVariant::Type)QMetaType::QVariantList) {
qCDebug(graphics_scripting) << "CONCATENATING" << key << metadata[key].toList().size() << "+" << value.toList().size();
metadata[key] = metadata[key].toList() + value.toList();
} else {
metadata[key] = modelMetaData[key];
}
}
}
scriptable::ScriptableModelBase::~ScriptableModelBase() {
#ifdef SCRIPTABLE_MESH_DEBUG
qCDebug(graphics_scripting) << "~ScriptableModelBase" << this;
#endif
for (auto& m : meshes) {
m.ownedMesh.reset();
//qCDebug(graphics_scripting) << "~~~~ScriptableModelBase" << &m << m.mesh.use_count();
}
meshes.clear();
//qCDebug(graphics_scripting) << "//~ScriptableModelBase" << this;
}
void scriptable::ScriptableModelBase::append(scriptable::WeakMeshPointer mesh, const QVariantMap& metadata) {
//qCDebug(graphics_scripting) << "+ APPEND WeakMeshPointer" << mesh.lock().get();
meshes << ScriptableMeshBase{ provider, this, mesh, metadata };
}
void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh, const QVariantMap& modelMetaData) {
//qCDebug(graphics_scripting) << "+ APPEND ScriptableMeshBase" << &mesh;
if (mesh.provider.lock().get() != provider.lock().get()) {
qCDebug(graphics_scripting) << "warning: appending mesh from different provider..." << mesh.provider.lock().get() << " != " << provider.lock().get();
}
//if (mesh.model && mesh.model != this) {
// qCDebug(graphics_scripting) << "warning: appending mesh from different model..." << mesh.model << " != " << this;
//}
meshes << mesh;
mixin(modelMetaData);
}
void scriptable::ScriptableModelBase::append(const ScriptableModelBase& other, const QVariantMap& modelMetaData) {
//qCDebug(graphics_scripting) << "+ APPEND ScriptableModelBase" << &other;
for (const auto& mesh : other.meshes) { append(mesh); }
mixin(other.metadata);
mixin(modelMetaData);
}
QString scriptable::ScriptableModel::toString() const {
return QString("[ScriptableModel%1%2]")
.arg(objectID.isNull() ? "" : " objectID="+objectID.toString())
.arg(objectName().isEmpty() ? "" : " name=" +objectName());
}
scriptable::ScriptableModelPointer scriptable::ScriptableModel::cloneModel(const QVariantMap& options) {
scriptable::ScriptableModelPointer clone = scriptable::ScriptableModelPointer(new scriptable::ScriptableModel(*this));
qCDebug(graphics_scripting) << "clone->getNumMeshes" << clone->getNumMeshes();
clone->meshes.clear();
qCDebug(graphics_scripting) << "..clone->getNumMeshes" << clone->getNumMeshes();
for (const auto &mesh : getConstMeshes()) {
auto cloned = mesh->cloneMesh(options.value("recalculateNormals").toBool());
if (auto tmp = qobject_cast<scriptable::ScriptableMeshBase*>(cloned)) {
qCDebug(graphics_scripting) << "++ APPEND" << tmp << tmp->ownedMesh.use_count() << tmp->metadata.value("__ownership__") << tmp->metadata.value("__native__");
clone->meshes << *tmp;
tmp->deleteLater();
qCDebug(graphics_scripting) << "//++ APPEND" << clone->meshes.constLast().ownedMesh.use_count();;
} else {
qCDebug(graphics_scripting) << "error cloning mesh" << cloned;
}
}
qCDebug(graphics_scripting) << "//clone->getNumMeshes" << clone->getNumMeshes();
return clone;
}
const QVector<scriptable::ScriptableMeshPointer> scriptable::ScriptableModel::getConstMeshes() const {
QVector<scriptable::ScriptableMeshPointer> out;
for(const auto& mesh : meshes) {
const scriptable::ScriptableMesh* m = qobject_cast<const scriptable::ScriptableMesh*>(&mesh);
if (!m) {
m = scriptable::make_scriptowned<scriptable::ScriptableMesh>(mesh);
} else {
qCDebug(graphics_scripting) << "reusing scriptable mesh" << m;
}
const scriptable::ScriptableMeshPointer mp = scriptable::ScriptableMeshPointer(const_cast<scriptable::ScriptableMesh*>(m));
out << mp;
}
return out;
}
QVector<scriptable::ScriptableMeshPointer> scriptable::ScriptableModel::getMeshes() {
QVector<scriptable::ScriptableMeshPointer> out;
for(auto& mesh : meshes) {
scriptable::ScriptableMesh* m = qobject_cast<scriptable::ScriptableMesh*>(&mesh);
if (!m) {
m = scriptable::make_scriptowned<scriptable::ScriptableMesh>(mesh);
} else {
qCDebug(graphics_scripting) << "reusing scriptable mesh" << m;
}
scriptable::ScriptableMeshPointer mp = scriptable::ScriptableMeshPointer(m);
out << mp;
}
return out;
}
quint32 scriptable::ScriptableModel::mapAttributeValues(QScriptValue callback) {
quint32 result = 0;
QVector<scriptable::ScriptableMeshPointer> in = getMeshes();
if (in.size()) {
foreach (scriptable::ScriptableMeshPointer meshProxy, in) {
result += meshProxy->mapAttributeValues(callback);
}
}
return result;
}
/*namespace {
QScriptValue modelPointerToScriptValue(QScriptEngine* engine, scriptable::ScriptableModelPointer const &in) {
return qObjectToScriptValue(engine, in);
}
void modelPointerFromScriptValue(const QScriptValue& value, scriptable::ScriptableModelPointer &out) {
out = scriptable::qpointer_qobject_cast<scriptable::ScriptableModel>(value);
}
}
namespace scriptable {
bool registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, modelPointerToScriptValue, modelPointerFromScriptValue);
return true;
}
}
*/

View file

@ -16,7 +16,7 @@ namespace scriptable {
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; }
//virtual ~ScriptableModel() { qDebug() << "~ScriptableModel" << this; }
Q_INVOKABLE scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap());
// TODO: in future accessors for these could go here

View file

@ -136,7 +136,8 @@ public:
static MeshPointer createIndexedTriangles_P3F(uint32_t numVertices, uint32_t numTriangles, const glm::vec3* vertices = nullptr, const uint32_t* indices = nullptr);
QString displayName;
std::string modelName;
std::string displayName;
protected:

View file

@ -2448,7 +2448,8 @@ graphics::MeshPointer GeometryCache::meshFromShape(Shape geometryShape, glm::vec
auto partBuffer = new gpu::Buffer(sizeof(graphics::Mesh::Part), (gpu::Byte*)&part);
mesh->setPartBuffer(gpu::BufferView(partBuffer, gpu::Element::PART_DRAWCALL));
mesh->displayName = QString("GeometryCache/shape::%1").arg(GeometryCache::stringFromShape(geometryShape));
mesh->modelName = GeometryCache::stringFromShape(geometryShape).toStdString();
mesh->displayName = QString("GeometryCache/shape::%1").arg(GeometryCache::stringFromShape(geometryShape)).toStdString();
return mesh;
}

View file

@ -9,6 +9,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtCore/QLoggingCategory>
namespace { QLoggingCategory wtf{ "tim.Model.cpp" }; }
#include "Model.h"
#include <QMetaType>
@ -26,7 +30,7 @@
#include <GLMHelpers.h>
#include <TBBHelpers.h>
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/Forward.h>
#include <DualQuaternion.h>
#include <glm/gtc/packing.hpp>
@ -75,7 +79,7 @@ void initCollisionMaterials() {
graphics::MaterialPointer material;
material = std::make_shared<graphics::Material>();
int index = j * sectionWidth + i;
float red = component[index];
float red = component[index % NUM_COLLISION_HULL_COLORS];
float green = component[(index + greenPhase) % NUM_COLLISION_HULL_COLORS];
float blue = component[(index + bluePhase) % NUM_COLLISION_HULL_COLORS];
material->setAlbedo(glm::vec3(red, green, blue));
@ -573,35 +577,109 @@ bool Model::convexHullContains(glm::vec3 point) {
return false;
}
scriptable::ScriptableModel Model::getScriptableModel(bool* ok) {
scriptable::ScriptableModel result;
// FIXME: temporary workaround that updates the whole FBXGeometry (to keep findRayIntersection in sync)
#include "Model_temporary_hack.cpp.h"
bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer _newModel, int meshIndex, int partIndex) {
QMutexLocker lock(&_mutex);
if (!isLoaded()) {
return false;
}
{
// FIXME: temporary workaround for updating the whole FBXGeometry (to keep findRayIntersection in sync)
auto newRenderGeometry = new MyGeometryMappingResource(
_url, _renderGeometry, _newModel ? scriptable::make_qtowned<scriptable::ScriptableModelBase>(*_newModel) : nullptr
);
_needsUpdateTextures = true;
_visualGeometryRequestFailed = false;
invalidCalculatedMeshBoxes();
deleteGeometry();
_renderGeometry.reset(newRenderGeometry);
onInvalidate();
reset();
_rig.destroyAnimGraph();
assert(_rig.jointStatesEmpty());
updateGeometry();
calculateTriangleSets();
computeMeshPartLocalBounds();
_needsReload = false;
_needsFixupInScene = true;
invalidCalculatedMeshBoxes();
setRenderItemsNeedUpdate();
}
return true;
}
scriptable::ScriptableModelBase Model::getScriptableModel(bool* ok) {
QMutexLocker lock(&_mutex);
scriptable::ScriptableModelBase result;
const Geometry::Pointer& renderGeometry = getGeometry();
if (!isLoaded()) {
qDebug() << "Model::getScriptableModel -- !isLoaded";
qCDebug(wtf) << "Model::getScriptableModel -- !isLoaded";
return scriptable::ModelProvider::modelUnavailableError(ok);
}
const FBXGeometry& geometry = getFBXGeometry();
auto mat4toVariant = [](const glm::mat4& mat4) -> QVariant {
QVector<float> floats;
floats.resize(16);
memcpy(floats.data(), &mat4, sizeof(glm::mat4));
QVariant v;
v.setValue<QVector<float>>(floats);
return v;
};
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
glm::mat4 offsetMat = offset.getMatrix();
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
result.metadata = {
{ "url", _url.toString() },
{ "textures", renderGeometry->getTextures() },
{ "offset", vec3toVariant(_offset) },
{ "scale", vec3toVariant(_scale) },
{ "rotation", quatToVariant(_rotation) },
{ "translation", vec3toVariant(_translation) },
{ "meshToModel", mat4toVariant(glm::scale(_scale) * glm::translate(_offset)) },
{ "meshToWorld", mat4toVariant(createMatFromQuatAndPos(_rotation, _translation) * (glm::scale(_scale) * glm::translate(_offset))) },
{ "geometryOffset", mat4toVariant(geometry.offset) },
{ "scale", vec3toVariant(getScale()) },
{ "rotation", quatToVariant(getRotation()) },
{ "translation", vec3toVariant(getTranslation()) },
{ "meshToModel", buffer_helpers::toVariant(meshToModelMatrix) },
{ "meshToWorld", buffer_helpers::toVariant(meshToWorldMatrix) },
{ "geometryOffset", buffer_helpers::toVariant(geometry.offset) },
{ "naturalDimensions", vec3toVariant(getNaturalDimensions()) },
{ "meshExtents", buffer_helpers::toVariant(getMeshExtents()) },
{ "unscaledMeshExtents", buffer_helpers::toVariant(getUnscaledMeshExtents()) },
{ "meshBound", buffer_helpers::toVariant(Extents(getRenderableMeshBound())) },
{ "bindExtents", buffer_helpers::toVariant(getBindExtents()) },
{ "offsetMat", buffer_helpers::toVariant(offsetMat) },
{ "transform", buffer_helpers::toVariant(getTransform().getMatrix()) },
};
{
Transform transform;
transform.setScale(getScale());
transform.setTranslation(getTranslation());
transform.setRotation(getRotation());
result.metadata["_transform"] = buffer_helpers::toVariant(transform.getMatrix());
}
{
glm::vec3 position = _translation;
glm::mat4 rotation = glm::mat4_cast(_rotation);
glm::mat4 translation = glm::translate(position);
glm::mat4 modelToWorldMatrix = translation * rotation;
//glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
result.metadata["_modelToWorld"] = buffer_helpers::toVariant(modelToWorldMatrix);
}
{
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
//glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
result.metadata["_meshToWorld"] = buffer_helpers::toVariant(meshToWorldMatrix);
}
{
Transform transform;
transform.setTranslation(_translation);
transform.setRotation(_rotation);
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
Transform output;
Transform::mult( output, transform, offset);
result.metadata["_renderTransform"] = buffer_helpers::toVariant(output.getMatrix());
}
QVariantList submeshes;
int numberOfMeshes = geometry.meshes.size();
for (int i = 0; i < numberOfMeshes; i++) {
@ -610,53 +688,43 @@ scriptable::ScriptableModel Model::getScriptableModel(bool* ok) {
if (!mesh) {
continue;
}
result.meshes << std::const_pointer_cast<graphics::Mesh>(mesh);
auto extraInfo = geometry.getModelNameOfMesh(i);
qDebug() << "Model::getScriptableModel #" << i << QString(mesh->displayName) << extraInfo;
submeshes << QVariantMap{
auto name = geometry.getModelNameOfMesh(i);
qCDebug(wtf) << "Model::getScriptableModel #" << i << QString::fromStdString(mesh->displayName) << name;
const AABox& box = _modelSpaceMeshTriangleSets.value(i).getBounds();
AABox hardbounds;
auto meshTransform = geometry.offset * fbxMesh.modelTransform;
for (const auto& v : fbxMesh.vertices) {
hardbounds += glm::vec3(meshTransform * glm::vec4(v,1));
}
QVariantList renderIDs;
for (uint32_t m = 0; m < _modelMeshRenderItemIDs.size(); m++) {
auto meshIndex = _modelMeshRenderItemShapes.size() > m ? _modelMeshRenderItemShapes.at(m).meshIndex : -1;
if (meshIndex == i) {
renderIDs << _modelMeshRenderItemIDs[m];
break;
}
}
result.append(std::const_pointer_cast<graphics::Mesh>(mesh), {
{ "index", i },
{ "name", name },
{ "renderIDs", renderIDs },
{ "meshIndex", fbxMesh.meshIndex },
{ "modelName", extraInfo },
{ "transform", mat4toVariant(fbxMesh.modelTransform) },
{ "extents", QVariantMap({
{ "minimum", vec3toVariant(fbxMesh.meshExtents.minimum) },
{ "maximum", vec3toVariant(fbxMesh.meshExtents.maximum) },
})},
};
{ "displayName", QString::fromStdString(mesh->displayName) },
{ "modelName", QString::fromStdString(mesh->modelName) },
{ "modelTransform", buffer_helpers::toVariant(fbxMesh.modelTransform) },
{ "transform", buffer_helpers::toVariant(geometry.offset * fbxMesh.modelTransform) },
{ "extents", buffer_helpers::toVariant(fbxMesh.meshExtents) },
{ "bounds", buffer_helpers::toVariant(Extents(box)) },
{ "hardbounds", buffer_helpers::toVariant(Extents(hardbounds)) },
});
}
if (ok) {
*ok = true;
}
qDebug() << "//Model::getScriptableModel -- #" << result.meshes.size();
qCDebug(wtf) << "//Model::getScriptableModel -- #" << result.meshes.size();
result.metadata["submeshes"] = submeshes;
return result;
// TODO: remove -- this was an earlier approach using renderGeometry instead of FBXGeometry
#if 0 // renderGeometry approach
const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes();
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
glm::mat4 offsetMat = offset.getMatrix();
for (std::shared_ptr<const graphics::Mesh> mesh : meshes) {
if (!mesh) {
continue;
}
qDebug() << "Model::getScriptableModel #" << i++ << mesh->displayName;
auto newmesh = mesh->map(
[=](glm::vec3 position) {
return glm::vec3(offsetMat * glm::vec4(position, 1.0f));
},
[=](glm::vec3 color) { return color; },
[=](glm::vec3 normal) {
return glm::normalize(glm::vec3(offsetMat * glm::vec4(normal, 0.0f)));
},
[&](uint32_t index) { return index; });
newmesh->displayName = mesh->displayName;
result << newmesh;
}
#endif
}
void Model::calculateTriangleSets() {

View file

@ -27,7 +27,7 @@
#include <gpu/Batch.h>
#include <render/Forward.h>
#include <render/Scene.h>
#include <graphics-scripting/ScriptableModel.h>
#include <graphics-scripting/Forward.h>
#include <Transform.h>
#include <SpatiallyNestable.h>
#include <TriangleSet.h>
@ -314,7 +314,8 @@ public:
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); }
Q_INVOKABLE virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override;
Q_INVOKABLE virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
virtual bool replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer model, int meshIndex, int partIndex) override;
void scaleToFit();

View file

@ -0,0 +1,121 @@
#include <graphics-scripting/BufferViewHelpers.h>
#include <graphics-scripting/GraphicsScriptingUtil.h>
class MyGeometryMappingResource : public GeometryResource {
// Q_OBJECT
public:
virtual void init(bool resetLoaded = true) override {
qCDebug(wtf) << "############################# Snarfing init()...";
}
virtual void deleter() override {
qCDebug(wtf) << "############################# Snarfing deleter()...";
}
shared_ptr<FBXGeometry> fbxGeometry;
MyGeometryMappingResource(const QUrl& url, Geometry::Pointer originalGeometry, std::shared_ptr<scriptable::ScriptableModelBase> newModel) : GeometryResource(url) {
fbxGeometry = std::make_shared<FBXGeometry>();
FBXGeometry& geometry = *fbxGeometry.get();
const FBXGeometry* original;
shared_ptr<FBXGeometry> tmpGeometry;
if (originalGeometry) {
original = &originalGeometry->getFBXGeometry();
} else {
tmpGeometry = std::make_shared<FBXGeometry>();
original = tmpGeometry.get();
}
geometry.originalURL = original->originalURL;
geometry.author = original->author;
geometry.applicationName = original->applicationName;
for (const auto &j : original->joints) {
geometry.joints << j;
}
geometry.jointIndices = QHash<QString,int>{ original->jointIndices };
geometry.animationFrames = QVector<FBXAnimationFrame>{ original->animationFrames };
geometry.meshIndicesToModelNames = QHash<int, QString>{ original->meshIndicesToModelNames };
geometry.blendshapeChannelNames = QList<QString>{ original->blendshapeChannelNames };
geometry.hasSkeletonJoints = original->hasSkeletonJoints;
geometry.offset = original->offset;
geometry.leftEyeJointIndex = original->leftEyeJointIndex;
geometry.rightEyeJointIndex = original->rightEyeJointIndex;
geometry.neckJointIndex = original->neckJointIndex;
geometry.rootJointIndex = original->rootJointIndex;
geometry.leanJointIndex = original->leanJointIndex;
geometry.headJointIndex = original->headJointIndex;
geometry.leftHandJointIndex = original->leftHandJointIndex;
geometry.rightHandJointIndex = original->rightHandJointIndex;
geometry.leftToeJointIndex = original->leftToeJointIndex;
geometry.rightToeJointIndex = original->rightToeJointIndex;
geometry.leftEyeSize = original->leftEyeSize;
geometry.rightEyeSize = original->rightEyeSize;
geometry.humanIKJointIndices = original->humanIKJointIndices;
geometry.palmDirection = original->palmDirection;
geometry.neckPivot = original->neckPivot;
geometry.bindExtents = original->bindExtents;
// Copy materials
QHash<QString, size_t> materialIDAtlas;
for (const FBXMaterial& material : original->materials) {
materialIDAtlas[material.materialID] = _materials.size();
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
}
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
std::shared_ptr<GeometryMeshParts> parts = std::make_shared<GeometryMeshParts>();
int meshID = 0;
if (newModel) {
geometry.meshExtents.reset();
for (const auto& newMesh : newModel->meshes) {
FBXMesh mesh;
if (meshID < original->meshes.size()) {
mesh = original->meshes.at(meshID); // copy
}
mesh._mesh = newMesh.getMeshPointer();
// duplicate the buffers
mesh.vertices = buffer_helpers::toVector<glm::vec3>(mesh._mesh->getVertexBuffer(), "mesh.vertices");
mesh.normals = buffer_helpers::toVector<glm::vec3>(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::NORMAL), "mesh.normals");
mesh.colors = buffer_helpers::toVector<glm::vec3>(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::COLOR), "mesh.colors");
mesh.texCoords = buffer_helpers::toVector<glm::vec2>(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::TEXCOORD0), "mesh.texCoords");
mesh.texCoords1 = buffer_helpers::toVector<glm::vec2>(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::TEXCOORD1), "mesh.texCoords1");
geometry.meshes << mesh;
// Copy mesh pointers
meshes->emplace_back(newMesh.getMeshPointer());//buffer_helpers::cloneMesh(ptr));
int partID = 0;
const auto oldParts = mesh.parts;
mesh.parts.clear();
for (const FBXMeshPart& fbxPart : oldParts) {
FBXMeshPart part; // copy;
part.materialID = fbxPart.materialID;
// Construct local parts
///qCDebug(wtf) << "GeometryMappingResource -- meshes part" << meshID << partID << part.materialID;
part.triangleIndices = buffer_helpers::toVector<int>(mesh._mesh->getIndexBuffer(), "part.triangleIndices");
mesh.parts << part;
auto p = std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]);
parts->push_back(p);
partID++;
}
{
// accumulate local transforms
// compute the mesh extents from the transformed vertices
foreach (const glm::vec3& vertex, mesh.vertices) {
glm::vec3 transformedVertex = glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f));
geometry.meshExtents.minimum = glm::min(geometry.meshExtents.minimum, transformedVertex);
geometry.meshExtents.maximum = glm::max(geometry.meshExtents.maximum, transformedVertex);
mesh.meshExtents.minimum = glm::min(mesh.meshExtents.minimum, transformedVertex);
mesh.meshExtents.maximum = glm::max(mesh.meshExtents.maximum, transformedVertex);
}
}
meshID++;
}
}
_meshes = meshes;
_meshParts = parts;
_animGraphOverrideUrl = originalGeometry ? originalGeometry->getAnimGraphOverrideUrl() : QUrl();
_loaded = true;
_fbxGeometry = fbxGeometry;
finishedLoading(true);
};
};

View file

@ -440,7 +440,7 @@ void AssetScriptingInterface::saveToCache(const QUrl& rawURL, const QByteArray&
JS_VERIFY(url.scheme() == "atp" || url.scheme() == "cache", "only 'atp' and 'cache' URL schemes supported");
JS_VERIFY(hash.isEmpty() || hash == hashDataHex(data), QString("invalid checksum hash for atp:HASH style URL (%1 != %2)").arg(hash, hashDataHex(data)));
qCDebug(scriptengine) << "saveToCache" << url.toDisplayString() << data << hash << metadata;
//qCDebug(scriptengine) << "saveToCache" << url.toDisplayString() << data << hash << metadata;
jsPromiseReady(Parent::saveToCache(url, data, metadata), scope, callback);
}

View file

@ -132,6 +132,20 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) {
QObject* scriptsModel();
bool NativeScriptInitializers::registerNativeScriptInitializer(NativeScriptInitializer initializer) {
return registerScriptInitializer([=](ScriptEnginePointer engine) {
initializer(qobject_cast<QScriptEngine*>(engine.data()));
});
}
bool NativeScriptInitializers::registerScriptInitializer(ScriptInitializer initializer) {
if (auto scriptEngines = DependencyManager::get<ScriptEngines>().data()) {
scriptEngines->registerScriptInitializer(initializer);
return true;
}
return false;
}
void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
_scriptInitializers.push_back(initializer);
}
@ -520,6 +534,17 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
emit scriptCountChanged();
}
int ScriptEngines::runScriptInitializers(ScriptEnginePointer scriptEngine) {
// register our application services and set it off on its own thread
int ii=0;
for (auto initializer : _scriptInitializers) {
ii++;
qDebug() << "initializer" << ii;
initializer(scriptEngine);
}
return ii;
}
void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection);
connect(scriptEngine.data(), &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) {
@ -529,10 +554,7 @@ void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
loadScript(scriptName, userLoaded, false, false, true);
});
// register our application services and set it off on its own thread
for (auto initializer : _scriptInitializers) {
initializer(scriptEngine);
}
runScriptInitializers(scriptEngine);
// FIXME disabling 'shift key' debugging for now. If you start up the application with
// the shift key held down, it triggers a deadlock because of script interfaces running

View file

@ -19,6 +19,7 @@
#include <SettingHandle.h>
#include <DependencyManager.h>
#include <shared/ScriptInitializerMixin.h>
#include "ScriptEngine.h"
#include "ScriptsModel.h"
@ -26,6 +27,12 @@
class ScriptEngine;
class NativeScriptInitializers : public ScriptInitializerMixin {
public:
bool registerNativeScriptInitializer(NativeScriptInitializer initializer) override;
bool registerScriptInitializer(ScriptInitializer initializer) override;
};
class ScriptEngines : public QObject, public Dependency {
Q_OBJECT
@ -34,11 +41,11 @@ class ScriptEngines : public QObject, public Dependency {
Q_PROPERTY(QString debugScriptUrl READ getDebugScriptUrl WRITE setDebugScriptUrl)
public:
using ScriptInitializer = std::function<void(ScriptEnginePointer)>;
using ScriptInitializer = ScriptInitializerMixin::ScriptInitializer;
ScriptEngines(ScriptEngine::Context context);
void registerScriptInitializer(ScriptInitializer initializer);
int runScriptInitializers(ScriptEnginePointer engine);
void loadScripts();
void saveScripts();

View file

@ -0,0 +1,38 @@
//
// ScriptInitializerMixin.h
// libraries/shared/src/shared
//
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
#pragma once
#include <functional>
#include <QSharedPointer>
#include "../DependencyManager.h"
class QScriptEngine;
class ScriptEngine;
class ScriptInitializerMixin : public QObject, public Dependency {
Q_OBJECT
public:
// Lightweight `QScriptEngine*` initializer (only depends on built-in Qt components)
// example registration:
// eg: [&](QScriptEngine* engine) -> bool {
// engine->globalObject().setProperties("API", engine->newQObject(...instance...))
// return true;
// }
using NativeScriptInitializer = std::function<void(QScriptEngine*)>;
virtual bool registerNativeScriptInitializer(NativeScriptInitializer initializer) = 0;
// Heavyweight `ScriptEngine*` initializer (tightly coupled to Interface and script-engine library internals)
// eg: [&](ScriptEnginePointer scriptEngine) -> bool {
// engine->registerGlobalObject("API", ...instance..);
// return true;
// }
using ScriptEnginePointer = QSharedPointer<ScriptEngine>;
using ScriptInitializer = std::function<void(ScriptEnginePointer)>;
virtual bool registerScriptInitializer(ScriptInitializer initializer) { return false; };
};