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<AccountManager>(std::bind(&Application::getUserAgent, qApp));
DependencyManager::set<StatTracker>(); DependencyManager::set<StatTracker>();
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT); DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
DependencyManager::set<ScriptInitializerMixin, NativeScriptInitializers>();
DependencyManager::set<Preferences>(); DependencyManager::set<Preferences>();
DependencyManager::set<recording::Deck>(); DependencyManager::set<recording::Deck>();
DependencyManager::set<recording::Recorder>(); DependencyManager::set<recording::Recorder>();

View file

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

View file

@ -1,3 +1,4 @@
// //
// Avatar.h // Avatar.h
// interface/src/avatar // interface/src/avatar
@ -20,7 +21,7 @@
#include <AvatarData.h> #include <AvatarData.h>
#include <ShapeInfo.h> #include <ShapeInfo.h>
#include <render/Scene.h> #include <render/Scene.h>
#include <graphics-scripting/ScriptableModel.h> #include <graphics-scripting/Forward.h>
#include <GLMHelpers.h> #include <GLMHelpers.h>
@ -274,7 +275,7 @@ public:
virtual void setAvatarEntityDataChanged(bool value) override; virtual void setAvatarEntityDataChanged(bool value) override;
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override; virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
public slots: public slots:
// FIXME - these should be migrated to use Pose data instead // 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) { bool render::entities::ModelEntityRenderer::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer newModel, int meshIndex, int partIndex) {
qCDebug(entitiesrenderer) << "REPLACING RenderableModelEntityItem" << newModel->objectName();
ModelPointer model; ModelPointer model;
withReadLock([&] { model = _model; }); withReadLock([&] { model = _model; });
@ -970,7 +969,7 @@ bool render::entities::ModelEntityRenderer::replaceScriptableModelMeshPart(scrip
return false; return false;
} }
return _model->replaceScriptableModelMeshPart(newModel, meshIndex, partIndex); return model->replaceScriptableModelMeshPart(newModel, meshIndex, partIndex);
} }
void RenderableModelEntityItem::simulateRelayedJoints() { void RenderableModelEntityItem::simulateRelayedJoints() {

View file

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

View file

@ -25,7 +25,7 @@ class PolyLineEntityRenderer : public TypedEntityRenderer<PolyLineEntityItem> {
public: public:
PolyLineEntityRenderer(const EntityItemPointer& entity); PolyLineEntityRenderer(const EntityItemPointer& entity);
virtual scriptable::ScriptableModel getScriptableModel(bool* ok = nullptr) override; virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
protected: protected:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, 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) { if (!updateDependents() || !_mesh) {
return scriptable::ModelProvider::modelUnavailableError(ok); return scriptable::ModelProvider::modelUnavailableError(ok);
} }
bool success = false; bool success = false;
glm::mat4 transform = voxelToLocalMatrix(); glm::mat4 transform = voxelToLocalMatrix();
scriptable::ScriptableModel result; scriptable::ScriptableModelBase result;
withReadLock([&] { withReadLock([&] {
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)_mesh->getNumVertices(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)_mesh->getNumVertices();
if (!_meshReady) { if (!_meshReady) {
@ -1433,11 +1433,12 @@ scriptable::ScriptableModel RenderablePolyVoxEntityItem::getScriptableModel(bool
} else { } else {
success = true; success = true;
// the mesh will be in voxel-space. transform it into object-space // the mesh will be in voxel-space. transform it into object-space
result.meshes << result.append(_mesh->map(
_mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, [=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[=](glm::vec3 color){ return color; }, [=](glm::vec3 color){ return color; },
[=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); }, [=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
[&](uint32_t index){ return index; }); [&](uint32_t index){ return index; }
));
} }
}); });
if (ok) { if (ok) {

View file

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

View file

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

View file

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

View file

@ -1897,7 +1897,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
geometry.meshes.append(extracted.mesh); geometry.meshes.append(extracted.mesh);
int meshIndex = geometry.meshes.size() - 1; int meshIndex = geometry.meshes.size() - 1;
if (extracted.mesh._mesh) { 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); meshIDsToMeshIndices.insert(it.key(), meshIndex);
} }
@ -1983,7 +1984,7 @@ FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
reader._loadLightmaps = loadLightmaps; reader._loadLightmaps = loadLightmaps;
reader._lightmapLevel = lightmapLevel; reader._lightmapLevel = lightmapLevel;
qDebug() << "Reading FBX: " << url; qCDebug(modelformat) << "Reading FBX: " << url;
return reader.extractFBXGeometry(mapping, 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[1]) << " ";
out << formatFloat(v[2]); out << formatFloat(v[2]);
if (colorIndex < numColors) { 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[0]);
out << " " << formatFloat(color[1]); out << " " << formatFloat(color[1]);
out << " " << formatFloat(color[2]); 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); const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(gpu::Stream::InputSlot::NORMAL);
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
for (gpu::BufferView::Index i = 0; i < numNormals; i++) { for (gpu::BufferView::Index i = 0; i < numNormals; i++) {
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); //glm::vec3 normal = normalsBufferView.get<glm::vec3>(i);
out << "vn "; out << "vn ";
out << formatFloat(normal[0]) << " "; out << formatFloat(normal[0]) << " ";
@ -117,7 +118,7 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
const gpu::BufferView& indexBuffer = mesh->getIndexBuffer(); const gpu::BufferView& indexBuffer = mesh->getIndexBuffer();
graphics::Index partCount = (graphics::Index)mesh->getNumParts(); 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]"), "_"); .replace(QRegExp("[^-_a-zA-Z0-9]"), "_");
for (int partIndex = 0; partIndex < partCount; partIndex++) { for (int partIndex = 0; partIndex < partCount; partIndex++) {
const graphics::Mesh::Part& part = partBuffer.get<graphics::Mesh::Part>(partIndex); const graphics::Mesh::Part& part = partBuffer.get<graphics::Mesh::Part>(partIndex);

View file

@ -19,7 +19,9 @@ namespace scriptable {
// JS => QPointer<QObject> // JS => QPointer<QObject>
template <typename T> QPointer<T> qpointer_qobject_cast(const QScriptValue& value) { template <typename T> QPointer<T> qpointer_qobject_cast(const QScriptValue& value) {
auto obj = value.toQObject(); auto obj = value.toQObject();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString(); qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString();
#endif
if (auto tmp = qobject_cast<T*>(obj)) { if (auto tmp = qobject_cast<T*>(obj)) {
return QPointer<T>(tmp); return QPointer<T>(tmp);
} }
@ -41,11 +43,15 @@ namespace scriptable {
// C++ > QtOwned instance // C++ > QtOwned instance
template <typename T, class... Rest> std::shared_ptr<T> make_qtowned(Rest... rest) { template <typename T, class... Rest> std::shared_ptr<T> make_qtowned(Rest... rest) {
T* tmp = new T(rest...); T* tmp = new T(rest...);
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "scriptable::make_qtowned" << toDebugString(tmp); qCInfo(graphics_scripting) << "scriptable::make_qtowned" << toDebugString(tmp);
#endif
QString debug = toDebugString(tmp); QString debug = toDebugString(tmp);
if (tmp) { if (tmp) {
tmp->metadata["__ownership__"] = QScriptEngine::QtOwnership; tmp->metadata["__ownership__"] = QScriptEngine::QtOwnership;
#ifdef SCRIPTABLE_MESH_DEBUG
QObject::connect(tmp, &QObject::destroyed, [=]() { qCInfo(graphics_scripting) << "-------- ~scriptable::make_qtowned" << debug; }); QObject::connect(tmp, &QObject::destroyed, [=]() { qCInfo(graphics_scripting) << "-------- ~scriptable::make_qtowned" << debug; });
#endif
auto ptr = std::shared_ptr<T>(tmp, [debug](T* tmp) { auto ptr = std::shared_ptr<T>(tmp, [debug](T* tmp) {
//qDebug() << "~std::shared_ptr<T>" << debug; //qDebug() << "~std::shared_ptr<T>" << debug;
delete tmp; delete tmp;
@ -58,7 +64,9 @@ namespace scriptable {
// C++ > ScriptOwned JS instance // C++ > ScriptOwned JS instance
template <typename T, class... Rest> QPointer<T> make_scriptowned(Rest... rest) { template <typename T, class... Rest> QPointer<T> make_scriptowned(Rest... rest) {
T* tmp = new T(rest...); T* tmp = new T(rest...);
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "scriptable::make_scriptowned" << toDebugString(tmp); qCInfo(graphics_scripting) << "scriptable::make_scriptowned" << toDebugString(tmp);
#endif
if (tmp) { if (tmp) {
tmp->metadata["__ownership__"] = QScriptEngine::ScriptOwnership; tmp->metadata["__ownership__"] = QScriptEngine::ScriptOwnership;
//auto blah = (DeleterFunction)[](void* delme) { }; //auto blah = (DeleterFunction)[](void* delme) { };
@ -71,12 +79,14 @@ namespace scriptable {
template <typename T> QPointer<T> add_scriptowned_destructor(T* tmp) { template <typename T> QPointer<T> add_scriptowned_destructor(T* tmp) {
QString debug = toDebugString(tmp); QString debug = toDebugString(tmp);
if (tmp) { if (tmp) {
#ifdef SCRIPTABLE_MESH_DEBUG
QObject::connect(tmp, &QObject::destroyed, [=]() { QObject::connect(tmp, &QObject::destroyed, [=]() {
qCInfo(graphics_scripting) << "-------- ~scriptable::make_scriptowned" << debug;// << !!customDeleter; qCInfo(graphics_scripting) << "-------- ~scriptable::make_scriptowned" << debug;// << !!customDeleter;
//if (customDeleter) { //if (customDeleter) {
// customDeleter(tmp); // customDeleter(tmp);
//} //}
}); });
#endif
} else { } else {
qCInfo(graphics_scripting) << "add_scriptowned_destructor -- not connecting to null value" << debug; 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) { bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model) {
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>(); 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; scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? provider->metadata.value("providerType").toString() : QString(); QString providerType = provider ? provider->metadata.value("providerType").toString() : QString();
if (providerType.isEmpty()) { if (providerType.isEmpty()) {
@ -56,12 +56,12 @@ bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::Scripta
} }
bool success = false; bool success = false;
if (provider) { if (provider) {
qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "..."; //qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
auto scriptableMeshes = provider->getScriptableModel(&success); 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) { if (success) {
const scriptable::ScriptableModelBasePointer base = model->operator scriptable::ScriptableModelBasePointer(); const scriptable::ScriptableModelBasePointer base = model->operator scriptable::ScriptableModelBasePointer();
qCDebug(graphics_scripting) << "as base" << base; //qCDebug(graphics_scripting) << "as base" << base;
if (base) { if (base) {
//auto meshes = model->getConstMeshes(); //auto meshes = model->getConstMeshes();
success = provider->replaceScriptableModelMeshPart(base, -1, -1); success = provider->replaceScriptableModelMeshPart(base, -1, -1);

View file

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

View file

@ -100,7 +100,7 @@ namespace scriptable {
ScriptableMeshPart(scriptable::ScriptableMeshPointer parentMesh, int partIndex); ScriptableMeshPart(scriptable::ScriptableMeshPointer parentMesh, int partIndex);
ScriptableMeshPart& operator=(const ScriptableMeshPart& view) { parentMesh=view.parentMesh; return *this; }; ScriptableMeshPart& operator=(const ScriptableMeshPart& view) { parentMesh=view.parentMesh; return *this; };
ScriptableMeshPart(const ScriptableMeshPart& other) : parentMesh(other.parentMesh), partIndex(other.partIndex) {} ScriptableMeshPart(const ScriptableMeshPart& other) : parentMesh(other.parentMesh), partIndex(other.partIndex) {}
~ScriptableMeshPart() { qDebug() << "~ScriptableMeshPart" << this; } // ~ScriptableMeshPart() { qDebug() << "~ScriptableMeshPart" << this; }
public slots: public slots:
scriptable::ScriptableMeshPointer getParentMesh() const { return parentMesh; } 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 ScriptableModel& other) : ScriptableModelBase(other) {}
ScriptableModel(const ScriptableModelBase& other) : ScriptableModelBase(other) {} ScriptableModel(const ScriptableModelBase& other) : ScriptableModelBase(other) {}
ScriptableModel& operator=(const ScriptableModelBase& view) { ScriptableModelBase::operator=(view); return *this; } 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()); Q_INVOKABLE scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap());
// TODO: in future accessors for these could go here // 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); 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: 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); auto partBuffer = new gpu::Buffer(sizeof(graphics::Mesh::Part), (gpu::Byte*)&part);
mesh->setPartBuffer(gpu::BufferView(partBuffer, gpu::Element::PART_DRAWCALL)); 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; return mesh;
} }

View file

@ -9,6 +9,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QtCore/QLoggingCategory>
namespace { QLoggingCategory wtf{ "tim.Model.cpp" }; }
#include "Model.h" #include "Model.h"
#include <QMetaType> #include <QMetaType>
@ -26,7 +30,7 @@
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <TBBHelpers.h> #include <TBBHelpers.h>
#include <graphics-scripting/ScriptableModel.h> #include <graphics-scripting/Forward.h>
#include <DualQuaternion.h> #include <DualQuaternion.h>
#include <glm/gtc/packing.hpp> #include <glm/gtc/packing.hpp>
@ -75,7 +79,7 @@ void initCollisionMaterials() {
graphics::MaterialPointer material; graphics::MaterialPointer material;
material = std::make_shared<graphics::Material>(); material = std::make_shared<graphics::Material>();
int index = j * sectionWidth + i; 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 green = component[(index + greenPhase) % NUM_COLLISION_HULL_COLORS];
float blue = component[(index + bluePhase) % NUM_COLLISION_HULL_COLORS]; float blue = component[(index + bluePhase) % NUM_COLLISION_HULL_COLORS];
material->setAlbedo(glm::vec3(red, green, blue)); material->setAlbedo(glm::vec3(red, green, blue));
@ -573,35 +577,109 @@ bool Model::convexHullContains(glm::vec3 point) {
return false; return false;
} }
scriptable::ScriptableModel Model::getScriptableModel(bool* ok) { // FIXME: temporary workaround that updates the whole FBXGeometry (to keep findRayIntersection in sync)
scriptable::ScriptableModel result; #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(); const Geometry::Pointer& renderGeometry = getGeometry();
if (!isLoaded()) { if (!isLoaded()) {
qDebug() << "Model::getScriptableModel -- !isLoaded"; qCDebug(wtf) << "Model::getScriptableModel -- !isLoaded";
return scriptable::ModelProvider::modelUnavailableError(ok); return scriptable::ModelProvider::modelUnavailableError(ok);
} }
const FBXGeometry& geometry = getFBXGeometry(); const FBXGeometry& geometry = getFBXGeometry();
auto mat4toVariant = [](const glm::mat4& mat4) -> QVariant { Transform offset;
QVector<float> floats; offset.setScale(_scale);
floats.resize(16); offset.postTranslate(_offset);
memcpy(floats.data(), &mat4, sizeof(glm::mat4)); glm::mat4 offsetMat = offset.getMatrix();
QVariant v; glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
v.setValue<QVector<float>>(floats); glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
return v;
};
result.metadata = { result.metadata = {
{ "url", _url.toString() }, { "url", _url.toString() },
{ "textures", renderGeometry->getTextures() }, { "textures", renderGeometry->getTextures() },
{ "offset", vec3toVariant(_offset) }, { "offset", vec3toVariant(_offset) },
{ "scale", vec3toVariant(_scale) }, { "scale", vec3toVariant(getScale()) },
{ "rotation", quatToVariant(_rotation) }, { "rotation", quatToVariant(getRotation()) },
{ "translation", vec3toVariant(_translation) }, { "translation", vec3toVariant(getTranslation()) },
{ "meshToModel", mat4toVariant(glm::scale(_scale) * glm::translate(_offset)) }, { "meshToModel", buffer_helpers::toVariant(meshToModelMatrix) },
{ "meshToWorld", mat4toVariant(createMatFromQuatAndPos(_rotation, _translation) * (glm::scale(_scale) * glm::translate(_offset))) }, { "meshToWorld", buffer_helpers::toVariant(meshToWorldMatrix) },
{ "geometryOffset", mat4toVariant(geometry.offset) }, { "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; QVariantList submeshes;
int numberOfMeshes = geometry.meshes.size(); int numberOfMeshes = geometry.meshes.size();
for (int i = 0; i < numberOfMeshes; i++) { for (int i = 0; i < numberOfMeshes; i++) {
@ -610,53 +688,43 @@ scriptable::ScriptableModel Model::getScriptableModel(bool* ok) {
if (!mesh) { if (!mesh) {
continue; continue;
} }
result.meshes << std::const_pointer_cast<graphics::Mesh>(mesh); auto name = geometry.getModelNameOfMesh(i);
auto extraInfo = geometry.getModelNameOfMesh(i); qCDebug(wtf) << "Model::getScriptableModel #" << i << QString::fromStdString(mesh->displayName) << name;
qDebug() << "Model::getScriptableModel #" << i << QString(mesh->displayName) << extraInfo; const AABox& box = _modelSpaceMeshTriangleSets.value(i).getBounds();
submeshes << QVariantMap{ 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 }, { "index", i },
{ "name", name },
{ "renderIDs", renderIDs },
{ "meshIndex", fbxMesh.meshIndex }, { "meshIndex", fbxMesh.meshIndex },
{ "modelName", extraInfo }, { "displayName", QString::fromStdString(mesh->displayName) },
{ "transform", mat4toVariant(fbxMesh.modelTransform) }, { "modelName", QString::fromStdString(mesh->modelName) },
{ "extents", QVariantMap({ { "modelTransform", buffer_helpers::toVariant(fbxMesh.modelTransform) },
{ "minimum", vec3toVariant(fbxMesh.meshExtents.minimum) }, { "transform", buffer_helpers::toVariant(geometry.offset * fbxMesh.modelTransform) },
{ "maximum", vec3toVariant(fbxMesh.meshExtents.maximum) }, { "extents", buffer_helpers::toVariant(fbxMesh.meshExtents) },
})}, { "bounds", buffer_helpers::toVariant(Extents(box)) },
}; { "hardbounds", buffer_helpers::toVariant(Extents(hardbounds)) },
});
} }
if (ok) { if (ok) {
*ok = true; *ok = true;
} }
qDebug() << "//Model::getScriptableModel -- #" << result.meshes.size(); qCDebug(wtf) << "//Model::getScriptableModel -- #" << result.meshes.size();
result.metadata["submeshes"] = submeshes; result.metadata["submeshes"] = submeshes;
return result; 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() { void Model::calculateTriangleSets() {

View file

@ -27,7 +27,7 @@
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <render/Forward.h> #include <render/Forward.h>
#include <render/Scene.h> #include <render/Scene.h>
#include <graphics-scripting/ScriptableModel.h> #include <graphics-scripting/Forward.h>
#include <Transform.h> #include <Transform.h>
#include <SpatiallyNestable.h> #include <SpatiallyNestable.h>
#include <TriangleSet.h> #include <TriangleSet.h>
@ -314,7 +314,8 @@ public:
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); } int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); } 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(); 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(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))); 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); jsPromiseReady(Parent::saveToCache(url, data, metadata), scope, callback);
} }

View file

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

View file

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