From 5791ca4c5111faa42e0f8f64bd9b0806bdf3606c Mon Sep 17 00:00:00 2001 From: humbletim Date: Tue, 20 Feb 2018 12:22:04 -0500 Subject: [PATCH] interim checkin --- interface/src/Application.cpp | 1 + .../src/avatars-renderer/Avatar.cpp | 22 +-- .../src/avatars-renderer/Avatar.h | 5 +- .../src/RenderableModelEntityItem.cpp | 3 +- .../src/RenderablePolyLineEntityItem.cpp | 2 +- .../src/RenderablePolyLineEntityItem.h | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 15 +- .../src/RenderablePolyVoxEntityItem.h | 4 +- .../src/RenderableShapeEntityItem.cpp | 9 +- .../src/RenderableShapeEntityItem.h | 2 +- libraries/fbx/src/FBXReader.cpp | 5 +- libraries/fbx/src/OBJWriter.cpp | 7 +- .../GraphicsScriptingUtil.h | 10 + .../ModelScriptingInterface.cpp | 8 +- .../src/graphics-scripting/ScriptableMesh.cpp | 31 ++- .../src/graphics-scripting/ScriptableMesh.h | 2 +- .../graphics-scripting/ScriptableModel.cpp | 149 ++++++++++++++ .../src/graphics-scripting/ScriptableModel.h | 2 +- libraries/graphics/src/graphics/Geometry.h | 3 +- libraries/render-utils/src/GeometryCache.cpp | 3 +- libraries/render-utils/src/Model.cpp | 184 ++++++++++++------ libraries/render-utils/src/Model.h | 5 +- .../src/Model_temporary_hack.cpp.h | 121 ++++++++++++ .../src/AssetScriptingInterface.cpp | 2 +- libraries/script-engine/src/ScriptEngines.cpp | 30 ++- libraries/script-engine/src/ScriptEngines.h | 11 +- .../src/shared/ScriptInitializerMixin.h | 38 ++++ 27 files changed, 557 insertions(+), 119 deletions(-) create mode 100644 libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp create mode 100644 libraries/render-utils/src/Model_temporary_hack.cpp.h create mode 100644 libraries/shared/src/shared/ScriptInitializerMixin.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bdef2f456b..5bfb1846a5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -771,6 +771,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(std::bind(&Application::getUserAgent, qApp)); DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 8e22f355e4..066afac8f5 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -35,7 +35,7 @@ #include "ModelEntityItem.h" #include "RenderableModelEntityItem.h" -#include +#include #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) { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 5cfc399b65..50301a2507 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -1,3 +1,4 @@ + // // Avatar.h // interface/src/avatar @@ -20,7 +21,7 @@ #include #include #include -#include +#include #include @@ -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 diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3d6714a400..155580d885 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -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() { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index e18bd2a7fe..a70a1613c3 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -281,7 +281,7 @@ std::vector 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); } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 3bb8901178..d9d770e64f 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -25,7 +25,7 @@ class PolyLineEntityRenderer : public TypedEntityRenderer { 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, diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index fd923c40b0..454fba4f94 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -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) { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 55b9be23d8..733d5b62f5 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -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()->getScriptableModel(ok); } diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 746102681c..5ea1c9edb7 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -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) { diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 6ada7e7317..57f899641a 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -22,7 +22,7 @@ class ShapeEntityRenderer : public TypedEntityRenderer { 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; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 50abe7928f..402afea2cc 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -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); } diff --git a/libraries/fbx/src/OBJWriter.cpp b/libraries/fbx/src/OBJWriter.cpp index 5307f49f36..621852f591 100644 --- a/libraries/fbx/src/OBJWriter.cpp +++ b/libraries/fbx/src/OBJWriter.cpp @@ -71,7 +71,8 @@ bool writeOBJToTextStream(QTextStream& out, QList meshes) { out << formatFloat(v[1]) << " "; out << formatFloat(v[2]); if (colorIndex < numColors) { - glm::vec3 color = colorsBufferView.get(colorIndex); + glm::vec3 color = glmVecFromVariant(buffer_helpers::toVariant(colorsBufferView, colorIndex)); + //glm::vec3 color = colorsBufferView.get(colorIndex); out << " " << formatFloat(color[0]); out << " " << formatFloat(color[1]); out << " " << formatFloat(color[2]); @@ -94,7 +95,7 @@ bool writeOBJToTextStream(QTextStream& out, QList 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(bufferViewElementToVariant(normalsBufferView, i)); + glm::vec3 normal = glmVecFromVariant(buffer_helpers::toVariant(normalsBufferView, i)); //glm::vec3 normal = normalsBufferView.get(i); out << "vn "; out << formatFloat(normal[0]) << " "; @@ -117,7 +118,7 @@ bool writeOBJToTextStream(QTextStream& out, QList 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(partIndex); diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h index a536fc413c..cfa510f87f 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingUtil.h @@ -19,7 +19,9 @@ namespace scriptable { // JS => QPointer template QPointer 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(obj)) { return QPointer(tmp); } @@ -41,11 +43,15 @@ namespace scriptable { // C++ > QtOwned instance template std::shared_ptr 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(tmp, [debug](T* tmp) { //qDebug() << "~std::shared_ptr" << debug; delete tmp; @@ -58,7 +64,9 @@ namespace scriptable { // C++ > ScriptOwned JS instance template QPointer 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 QPointer 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; } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ModelScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/ModelScriptingInterface.cpp index ab9403a8ed..d78f646087 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ModelScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ModelScriptingInterface.cpp @@ -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(); - 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:" <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); diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index b83b901acd..c662371c89 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -28,6 +28,8 @@ #include "OBJWriter.h" +// #define SCRIPTABLE_MESH_DEBUG + namespace scriptable { // QScriptValue jsBindCallback(QScriptValue callback); // template QPointer 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(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() { diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h index c655167c2b..ba0efa007d 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h @@ -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; } diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp new file mode 100644 index 0000000000..c8f1975249 --- /dev/null +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.cpp @@ -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 +//#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(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::ScriptableModel::getConstMeshes() const { + QVector out; + for(const auto& mesh : meshes) { + const scriptable::ScriptableMesh* m = qobject_cast(&mesh); + if (!m) { + m = scriptable::make_scriptowned(mesh); + } else { + qCDebug(graphics_scripting) << "reusing scriptable mesh" << m; + } + const scriptable::ScriptableMeshPointer mp = scriptable::ScriptableMeshPointer(const_cast(m)); + out << mp; + } + return out; +} + +QVector scriptable::ScriptableModel::getMeshes() { + QVector out; + for(auto& mesh : meshes) { + scriptable::ScriptableMesh* m = qobject_cast(&mesh); + if (!m) { + m = scriptable::make_scriptowned(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 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(value); + } +} + +namespace scriptable { + bool registerMetaTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, modelPointerToScriptValue, modelPointerFromScriptValue); + return true; + } +} +*/ diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index 97a73ddd61..d2c50bd768 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -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 diff --git a/libraries/graphics/src/graphics/Geometry.h b/libraries/graphics/src/graphics/Geometry.h index 23ebec2965..a75fb1bf62 100755 --- a/libraries/graphics/src/graphics/Geometry.h +++ b/libraries/graphics/src/graphics/Geometry.h @@ -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: diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 6aa42cf6df..95985a48cb 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -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; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ae5ac5d61c..81ff5433f7 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -9,6 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +namespace { QLoggingCategory wtf{ "tim.Model.cpp" }; } + + #include "Model.h" #include @@ -26,7 +30,7 @@ #include #include -#include +#include #include #include @@ -75,7 +79,7 @@ void initCollisionMaterials() { graphics::MaterialPointer material; material = std::make_shared(); 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(*_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 floats; - floats.resize(16); - memcpy(floats.data(), &mat4, sizeof(glm::mat4)); - QVariant v; - v.setValue>(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(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(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 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() { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4fd00c9f9a..375ee016ca 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -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(); diff --git a/libraries/render-utils/src/Model_temporary_hack.cpp.h b/libraries/render-utils/src/Model_temporary_hack.cpp.h new file mode 100644 index 0000000000..bc31abcb37 --- /dev/null +++ b/libraries/render-utils/src/Model_temporary_hack.cpp.h @@ -0,0 +1,121 @@ +#include +#include +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; + MyGeometryMappingResource(const QUrl& url, Geometry::Pointer originalGeometry, std::shared_ptr newModel) : GeometryResource(url) { + fbxGeometry = std::make_shared(); + FBXGeometry& geometry = *fbxGeometry.get(); + const FBXGeometry* original; + shared_ptr tmpGeometry; + if (originalGeometry) { + original = &originalGeometry->getFBXGeometry(); + } else { + tmpGeometry = std::make_shared(); + 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{ original->jointIndices }; + + geometry.animationFrames = QVector{ original->animationFrames }; + geometry.meshIndicesToModelNames = QHash{ original->meshIndicesToModelNames }; + geometry.blendshapeChannelNames = QList{ 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 materialIDAtlas; + for (const FBXMaterial& material : original->materials) { + materialIDAtlas[material.materialID] = _materials.size(); + _materials.push_back(std::make_shared(material, _textureBaseUrl)); + } + std::shared_ptr meshes = std::make_shared(); + std::shared_ptr parts = std::make_shared(); + 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(mesh._mesh->getVertexBuffer(), "mesh.vertices"); + mesh.normals = buffer_helpers::toVector(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::NORMAL), "mesh.normals"); + mesh.colors = buffer_helpers::toVector(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::COLOR), "mesh.colors"); + mesh.texCoords = buffer_helpers::toVector(buffer_helpers::getBufferView(mesh._mesh, gpu::Stream::TEXCOORD0), "mesh.texCoords"); + mesh.texCoords1 = buffer_helpers::toVector(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(mesh._mesh->getIndexBuffer(), "part.triangleIndices"); + mesh.parts << part; + auto p = std::make_shared(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); + }; +}; + diff --git a/libraries/script-engine/src/AssetScriptingInterface.cpp b/libraries/script-engine/src/AssetScriptingInterface.cpp index 1c811573fb..750e612781 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.cpp +++ b/libraries/script-engine/src/AssetScriptingInterface.cpp @@ -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); } diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 78cb05fa0d..873c205706 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -132,6 +132,20 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) { QObject* scriptsModel(); +bool NativeScriptInitializers::registerNativeScriptInitializer(NativeScriptInitializer initializer) { + return registerScriptInitializer([=](ScriptEnginePointer engine) { + initializer(qobject_cast(engine.data())); + }); +} + +bool NativeScriptInitializers::registerScriptInitializer(ScriptInitializer initializer) { + if (auto scriptEngines = DependencyManager::get().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 diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index 5a4b8f2f47..ea07ebe840 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -19,6 +19,7 @@ #include #include +#include #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; + using ScriptInitializer = ScriptInitializerMixin::ScriptInitializer; ScriptEngines(ScriptEngine::Context context); void registerScriptInitializer(ScriptInitializer initializer); - + int runScriptInitializers(ScriptEnginePointer engine); void loadScripts(); void saveScripts(); diff --git a/libraries/shared/src/shared/ScriptInitializerMixin.h b/libraries/shared/src/shared/ScriptInitializerMixin.h new file mode 100644 index 0000000000..50de553b0b --- /dev/null +++ b/libraries/shared/src/shared/ScriptInitializerMixin.h @@ -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 +#include +#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; + 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; + using ScriptInitializer = std::function; + virtual bool registerScriptInitializer(ScriptInitializer initializer) { return false; }; +};