diff --git a/libraries/graphics-scripting/src/graphics-scripting/Forward.h b/libraries/graphics-scripting/src/graphics-scripting/Forward.h index b978bb6255..650e4104e7 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/Forward.h +++ b/libraries/graphics-scripting/src/graphics-scripting/Forward.h @@ -135,7 +135,4 @@ namespace scriptable { using ScriptableMeshPointer = QPointer; class ScriptableMeshPart; using ScriptableMeshPartPointer = QPointer; - bool registerMetaTypes(QScriptEngine* engine); } - -Q_DECLARE_METATYPE(NestableType) diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp index 384ac1cbd5..ff0170f07d 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.cpp @@ -26,9 +26,6 @@ #include GraphicsScriptingInterface::GraphicsScriptingInterface(QObject* parent) : QObject(parent), QScriptable() { - if (auto scriptEngine = qobject_cast(parent)) { - this->registerMetaTypes(scriptEngine); - } } void GraphicsScriptingInterface::jsThrowError(const QString& error) { @@ -179,12 +176,17 @@ scriptable::ScriptableMeshPointer GraphicsScriptingInterface::newMesh(const QVar const auto numVertices = vertices.size(); const auto numIndices = indices.size(); - const auto topology = graphics::Mesh::TRIANGLES; + const auto topology = graphics::TOPOLOGIES.key(topologyName); + + // TODO: support additional topologies (POINTS and LINES ought to "just work" -- + // if MeshPartPayload::drawCall is updated to actually check the Mesh::Part::_topology value + // (TRIANGLE_STRIP, TRIANGLE_FAN, QUADS, QUAD_STRIP may need additional conversion code though) + static const QStringList acceptableTopologies{ "triangles" }; // sanity checks QString error; - if (!topologyName.isEmpty() && topologyName != "triangles") { - error = "expected 'triangles' or undefined for .topology"; + if (!topologyName.isEmpty() && !acceptableTopologies.contains(topologyName)) { + error = QString("expected .topology to be %1").arg(acceptableTopologies.join(" | ")); } else if (!numIndices) { error = QString("expected non-empty [uint32,...] array for .indices (got type=%1)").arg(ifsMeshData.value("indices").typeName()); } else if (numIndices % 3 != 0) { @@ -227,8 +229,8 @@ scriptable::ScriptableMeshPointer GraphicsScriptingInterface::newMesh(const QVar mesh->modelName = "graphics::newMesh"; mesh->displayName = meshName.toStdString(); - // TODO: newFromVector does no conversion -- later we could autodetect if fitting into gpu::INDEX_UINT16 - // and also pack other values (like NORMAL / TEXCOORD0 where relevant) + // TODO: newFromVector does inbound type conversion, but not compression or packing + // (later we should autodetect if fitting into gpu::INDEX_UINT16 and reduce / pack normals etc.) mesh->setIndexBuffer(buffer_helpers::newFromVector(indices, gpu::Format::INDEX_INT32)); mesh->setVertexBuffer(buffer_helpers::newFromVector(vertices, gpu::Format::VEC3F_XYZ)); if (normals.size()) { @@ -240,7 +242,7 @@ scriptable::ScriptableMeshPointer GraphicsScriptingInterface::newMesh(const QVar if (texCoords0.size()) { mesh->addAttribute(gpu::Stream::TEXCOORD0, buffer_helpers::newFromVector(texCoords0, gpu::Format::VEC2F_UV)); } - QVector parts = {{ 0, indices.size(), 0, topology}}; + QVector parts = {{ 0, indices.size(), 0, topology }}; mesh->setPartBuffer(buffer_helpers::newFromVector(parts, gpu::Element::PART_DRAWCALL)); return scriptable::make_scriptowned(mesh, nullptr); } @@ -262,10 +264,6 @@ QString GraphicsScriptingInterface::exportModelToOBJ(const scriptable::Scriptabl return QString(); } -void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { - scriptable::registerMetaTypes(engine); -} - MeshPointer GraphicsScriptingInterface::getMeshPointer(const scriptable::ScriptableMesh& meshProxy) { return meshProxy.getMeshPointer(); } @@ -287,12 +285,57 @@ MeshPointer GraphicsScriptingInterface::getMeshPointer(scriptable::ScriptableMes } namespace { - QScriptValue qVectorUInt32ToScriptValue(QScriptEngine* engine, const QVector& vector) { - return qScriptValueFromSequence(engine, vector); - } + QVector metaTypeIds{ + qRegisterMetaType("uint32"), + qRegisterMetaType("glm::uint32"), + qRegisterMetaType>(), + qRegisterMetaType>("QVector"), + qRegisterMetaType(), + qRegisterMetaType("ScriptableMeshes"), + qRegisterMetaType("scriptable::ScriptableMeshes"), + qRegisterMetaType>("QVector"), + qRegisterMetaType(), + qRegisterMetaType(), + qRegisterMetaType(), + qRegisterMetaType(), + qRegisterMetaType>(), + qRegisterMetaType(), + qRegisterMetaType(), + }; +} - void qVectorUInt32FromScriptValue(const QScriptValue& array, QVector& result) { - qScriptValueToSequence(array, result); +namespace scriptable { + template int registerQPointerMetaType(QScriptEngine* engine) { + qScriptRegisterSequenceMetaType>>(engine); + return qScriptRegisterMetaType>( + engine, + [](QScriptEngine* engine, const QPointer& object) -> QScriptValue { + if (!object) { + return QScriptValue::NullValue; + } + return engine->newQObject(object, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::AutoCreateDynamicProperties); + }, + [](const QScriptValue& value, QPointer& out) { + auto obj = value.toQObject(); +#ifdef SCRIPTABLE_MESH_DEBUG + qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString(); +#endif + if (auto tmp = qobject_cast(obj)) { + out = QPointer(tmp); + return; + } +#if 0 + if (auto tmp = static_cast(obj)) { +#ifdef SCRIPTABLE_MESH_DEBUG + qCInfo(graphics_scripting) << "qpointer_qobject_cast -- via static_cast" << obj << tmp << value.toString(); +#endif + out = QPointer(tmp); + return; + } +#endif + out = nullptr; + } + ); } QScriptValue qVectorScriptableMaterialToScriptValue(QScriptEngine* engine, const QVector& vector) { @@ -346,102 +389,38 @@ namespace { // No need to convert from QScriptValue to MultiMaterialMap } - QVector metaTypeIds{ - qRegisterMetaType("uint32"), - qRegisterMetaType("glm::uint32"), - qRegisterMetaType>(), - qRegisterMetaType>("QVector"), - qRegisterMetaType(), - qRegisterMetaType("ScriptableMeshes"), - qRegisterMetaType("scriptable::ScriptableMeshes"), - qRegisterMetaType>("QVector"), - qRegisterMetaType(), - qRegisterMetaType(), - qRegisterMetaType(), - qRegisterMetaType(), - qRegisterMetaType>(), - qRegisterMetaType(), - qRegisterMetaType(), - }; -} - -namespace scriptable { - template int registerQPointerThing(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType>>(engine); - return qScriptRegisterMetaType>( - engine, - [](QScriptEngine* engine, const QPointer& object) -> QScriptValue { - if (!object) { - return QScriptValue::NullValue; - } - return engine->newQObject(object, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::AutoCreateDynamicProperties); - }, - [](const QScriptValue& value, QPointer& out) { - auto obj = value.toQObject(); -#ifdef SCRIPTABLE_MESH_DEBUG - qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString(); -#endif - if (auto tmp = qobject_cast(obj)) { - out = QPointer(tmp); - return; - } -#if 0 - if (auto tmp = static_cast(obj)) { -#ifdef SCRIPTABLE_MESH_DEBUG - qCInfo(graphics_scripting) << "qpointer_qobject_cast -- via static_cast" << obj << tmp << value.toString(); -#endif - out = QPointer(tmp); - return; - } -#endif - out = nullptr; - } - ); - } - template int registerDebugEnum(QScriptEngine* engine, const DebugEnums& debugEnums) { - static const DebugEnums& poop = debugEnums; + static const DebugEnums& instance = debugEnums; return qScriptRegisterMetaType( engine, [](QScriptEngine* engine, const T& topology) -> QScriptValue { - return poop.value(topology); + return instance.value(topology); }, [](const QScriptValue& value, T& topology) { - topology = poop.key(value.toString()); + topology = instance.key(value.toString()); } ); } +} - bool registerMetaTypes(QScriptEngine* engine) { - qScriptRegisterSequenceMetaType>(engine); - qScriptRegisterSequenceMetaType>(engine); +void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) { + qScriptRegisterSequenceMetaType>(engine); + qScriptRegisterSequenceMetaType>(engine); - qScriptRegisterMetaType(engine, qVectorUInt32ToScriptValue, qVectorUInt32FromScriptValue); + scriptable::registerQPointerMetaType(engine); + scriptable::registerQPointerMetaType(engine); + scriptable::registerQPointerMetaType(engine); - registerQPointerThing(engine); - registerQPointerThing(engine); - registerQPointerThing(engine); - qScriptRegisterMetaType>( - engine, - [](QScriptEngine* engine, const QVector& vector) -> QScriptValue { - return qScriptValueFromSequence(engine, vector); - }, - [](const QScriptValue& array, QVector& result) { - qScriptValueToSequence(array, result); - } - ); - qScriptRegisterMetaType(engine, scriptableMaterialToScriptValue, scriptableMaterialFromScriptValue); - qScriptRegisterMetaType(engine, qVectorScriptableMaterialToScriptValue, qVectorScriptableMaterialFromScriptValue); - qScriptRegisterMetaType(engine, multiMaterialMapToScriptValue, multiMaterialMapFromScriptValue); + scriptable::registerDebugEnum(engine, graphics::TOPOLOGIES); + scriptable::registerDebugEnum(engine, gpu::TYPES); + scriptable::registerDebugEnum(engine, gpu::SEMANTICS); + scriptable::registerDebugEnum(engine, gpu::DIMENSIONS); - registerDebugEnum(engine, graphics::TOPOLOGIES); - registerDebugEnum(engine, gpu::TYPES); - registerDebugEnum(engine, gpu::SEMANTICS); - registerDebugEnum(engine, gpu::DIMENSIONS); - - return metaTypeIds.size(); - } + qScriptRegisterMetaType(engine, scriptable::scriptableMaterialToScriptValue, scriptable::scriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialToScriptValue, scriptable::qVectorScriptableMaterialFromScriptValue); + qScriptRegisterMetaType(engine, scriptable::multiMaterialMapToScriptValue, scriptable::multiMaterialMapFromScriptValue); + Q_UNUSED(metaTypeIds); } #include "GraphicsScriptingInterface.moc" diff --git a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h index a66e382bc7..84c6cb6fa8 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h +++ b/libraries/graphics-scripting/src/graphics-scripting/GraphicsScriptingInterface.h @@ -20,6 +20,12 @@ #include "ScriptableMesh.h" #include + +/**jsdoc + * The experimental Graphics API (experimental) lets you query and manage certain graphics-related structures (like underlying meshes and textures) from scripting. + * @namespace Graphics + */ + class GraphicsScriptingInterface : public QObject, public QScriptable, public Dependency { Q_OBJECT @@ -29,15 +35,36 @@ public: public slots: /**jsdoc - * Returns the model/meshes associated with a UUID (entityID, overlayID, or avatarID) + * Returns a model reference object associated with the specified UUID ({@link EntityID}, {@link OverlayID}, or {@link AvatarID}). * - * @function GraphicsScriptingInterface.getModel - * @param {UUID} The objectID of the model whose meshes are to be retrieve + * @function Graphics.getModel + * @param {UUID} The objectID of the model whose meshes are to be retrieved. + * @return {Graphics.Model} the resulting Model object */ scriptable::ScriptableModelPointer getModel(QUuid uuid); + bool updateModel(QUuid uuid, const scriptable::ScriptableModelPointer& model); + bool canUpdateModel(QUuid uuid, int meshIndex = -1, int partNumber = -1); + scriptable::ScriptableModelPointer newModel(const scriptable::ScriptableMeshes& meshes); + + /**jsdoc + * Create a new Mesh / Mesh Part with the specified data buffers. + * + * @function Graphics.newMesh + * @param {Graphics.IFSData} ifsMeshData Index-Faced Set (IFS) arrays used to create the new mesh. + * @return {Graphics.Mesh} the resulting Mesh / Mesh Part object + */ + /**jsdoc + * @typedef {object} Graphics.IFSData + * @property {string} [name] - mesh name (useful for debugging / debug prints). + * @property {number[]} indices - vertex indices to use for the mesh faces. + * @property {Vec3[]} vertices - vertex positions (model space) + * @property {Vec3[]} [normals] - vertex normals (normalized) + * @property {Vec3[]} [colors] - vertex colors (normalized) + * @property {Vec2[]} [texCoords0] - vertex texture coordinates (normalized) + */ scriptable::ScriptableMeshPointer newMesh(const QVariantMap& ifsMeshData); #ifdef SCRIPTABLE_MESH_TODO @@ -58,6 +85,8 @@ private: }; -Q_DECLARE_METATYPE(scriptable::ModelProviderPointer) +Q_DECLARE_METATYPE(glm::uint32) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(NestableType) #endif // hifi_GraphicsScriptingInterface_h diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp index af74366f9a..8e6d4bec9b 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.cpp @@ -118,7 +118,7 @@ bool scriptable::ScriptableMesh::setVertexAttributes(glm::uint32 vertexIndex, co return buffer_helpers::mesh::setVertexAttributes(getMeshPointer(), vertexIndex, attributes); } -int scriptable::ScriptableMesh::_getSlotNumber(const QString& attributeName) const { +int scriptable::ScriptableMesh::getSlotNumber(const QString& attributeName) const { if (auto mesh = getMeshPointer()) { return buffer_helpers::ATTRIBUTES.value(attributeName, -1); } @@ -142,9 +142,9 @@ QVariantMap scriptable::ScriptableMesh::getBufferFormats() const { } bool scriptable::ScriptableMesh::removeAttribute(const QString& attributeName) { - auto slot = isValid() ? _getSlotNumber(attributeName) : -1; + auto slot = isValid() ? getSlotNumber(attributeName) : -1; if (slot < 0) { - return 0; + return false; } if (slot == gpu::Stream::POSITION) { context()->throwError("cannot remove .position attribute"); @@ -158,7 +158,7 @@ bool scriptable::ScriptableMesh::removeAttribute(const QString& attributeName) { } glm::uint32 scriptable::ScriptableMesh::addAttribute(const QString& attributeName, const QVariant& defaultValue) { - auto slot = isValid() ? _getSlotNumber(attributeName) : -1; + auto slot = isValid() ? getSlotNumber(attributeName) : -1; if (slot < 0) { return 0; } @@ -187,7 +187,7 @@ glm::uint32 scriptable::ScriptableMesh::addAttribute(const QString& attributeNam } glm::uint32 scriptable::ScriptableMesh::fillAttribute(const QString& attributeName, const QVariant& value) { - auto slot = isValid() ? _getSlotNumber(attributeName) : -1; + auto slot = isValid() ? getSlotNumber(attributeName) : -1; if (slot < 0) { return 0; } @@ -218,7 +218,7 @@ QVariantList scriptable::ScriptableMesh::queryVertexAttributes(QVariant selector if (!isValidIndex(0, attributeName)) { return result; } - auto slotNum = _getSlotNumber(attributeName); + auto slotNum = getSlotNumber(attributeName); const auto& bufferView = buffer_helpers::mesh::getBufferView(getMeshPointer(), static_cast(slotNum)); glm::uint32 numElements = (glm::uint32)bufferView.getNumElements(); for (glm::uint32 i = 0; i < numElements; i++) { @@ -231,7 +231,7 @@ QVariant scriptable::ScriptableMesh::getVertexProperty(glm::uint32 vertexIndex, if (!isValidIndex(vertexIndex, attributeName)) { return QVariant(); } - auto slotNum = _getSlotNumber(attributeName); + auto slotNum = getSlotNumber(attributeName); const auto& bufferView = buffer_helpers::mesh::getBufferView(getMeshPointer(), static_cast(slotNum)); return buffer_helpers::getValue(bufferView, vertexIndex, qUtf8Printable(attributeName)); } @@ -240,7 +240,7 @@ bool scriptable::ScriptableMesh::setVertexProperty(glm::uint32 vertexIndex, cons if (!isValidIndex(vertexIndex, attributeName)) { return false; } - auto slotNum = _getSlotNumber(attributeName); + auto slotNum = getSlotNumber(attributeName); const auto& bufferView = buffer_helpers::mesh::getBufferView(getMeshPointer(), static_cast(slotNum)); return buffer_helpers::setValue(bufferView, vertexIndex, value); } @@ -331,7 +331,7 @@ bool scriptable::ScriptableMesh::isValidIndex(glm::uint32 vertexIndex, const QSt return false; } if (!attributeName.isEmpty()) { - auto slotNum = _getSlotNumber(attributeName); + auto slotNum = getSlotNumber(attributeName); if (slotNum < 0) { if (context()) { context()->throwError(QString("invalid attributeName=%1").arg(attributeName)); diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h index 16393de8c7..62a67aa5e6 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMesh.h @@ -28,6 +28,15 @@ #include namespace scriptable { + /**jsdoc + * @typedef {object} Graphics.Mesh + * @property {Graphics.MeshPart[]} parts - Array of submesh part references. + * @property {string[]} attributeNames - Vertex attribute names (color, normal, etc.) + * @property {number} numParts - The number of parts contained in the mesh. + * @property {number} numIndices - Total number of vertex indices in the mesh. + * @property {number} numVertices - Total number of vertices in the Mesh. + * @property {number} numAttributes - Number of currently defined vertex attributes. + */ class ScriptableMesh : public ScriptableMeshBase, QScriptable { Q_OBJECT public: @@ -65,9 +74,8 @@ namespace scriptable { QVector getMeshParts() const; QVariantMap getMeshExtents() const; - // TODO: remove Q_INVOKABLE (curently exposed for debugging ) - Q_INVOKABLE int _getSlotNumber(const QString& attributeName) const; operator bool() const { return !weakMesh.expired(); } + int getSlotNumber(const QString& attributeName) const; public slots: const scriptable::ScriptableModelPointer getParentModel() const { return qobject_cast(model); } @@ -97,5 +105,3 @@ namespace scriptable { Q_DECLARE_METATYPE(scriptable::ScriptableMeshPointer) Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(glm::uint32) -Q_DECLARE_METATYPE(QVector) diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp index 9d6359bee3..4414b0ad7e 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.cpp @@ -21,6 +21,7 @@ #include #include + QString scriptable::ScriptableMeshPart::toOBJ() { if (!getMeshPointer()) { if (context()) { @@ -56,7 +57,7 @@ bool scriptable::ScriptableMeshPart::setVertexProperty(glm::uint32 vertexIndex, if (!isValidIndex(vertexIndex, attributeName)) { return false; } - auto slotNum = parentMesh->_getSlotNumber(attributeName); + auto slotNum = parentMesh->getSlotNumber(attributeName); const auto& bufferView = buffer_helpers::mesh::getBufferView(getMeshPointer(), static_cast(slotNum)); return buffer_helpers::setValue(bufferView, vertexIndex, value); } @@ -368,9 +369,10 @@ bool scriptable::ScriptableMeshPart::setIndices(const QVector& indi return false; } glm::uint32 len = indices.size(); - if (len != getNumVertices()) { + if (len != getNumIndices()) { context()->throwError(QString("setIndices: currently new indicies must be assign 1:1 across old indicies (indicies.size()=%1, numIndices=%2)") .arg(len).arg(getNumIndices())); + return false; } auto mesh = getMeshPointer(); auto indexBuffer = mesh->getIndexBuffer(); @@ -397,18 +399,24 @@ const graphics::Mesh::Part& scriptable::ScriptableMeshPart::getMeshPart() const return getMeshPointer()->getPartBuffer().get(partIndex); } +// FIXME: how we handle topology will need to be reworked if wanting to support TRIANGLE_STRIP, QUADS and QUAD_STRIP bool scriptable::ScriptableMeshPart::setTopology(graphics::Mesh::Topology topology) { if (!isValid()) { return false; } auto& part = getMeshPointer()->getPartBuffer().edit(partIndex); - if (topology == graphics::Mesh::Topology::POINTS || - topology == graphics::Mesh::Topology::LINES || - topology == graphics::Mesh::Topology::TRIANGLES) { + switch (topology) { +#ifdef DEV_BUILD + case graphics::Mesh::Topology::POINTS: + case graphics::Mesh::Topology::LINES: +#endif + case graphics::Mesh::Topology::TRIANGLES: part._topology = topology; return true; + default: + context()->throwError("changing topology to " + graphics::toString(topology) + " is not yet supported"); + return false; } - return false; } glm::uint32 scriptable::ScriptableMeshPart::getTopologyLength() const { @@ -416,16 +424,23 @@ glm::uint32 scriptable::ScriptableMeshPart::getTopologyLength() const { case graphics::Mesh::Topology::POINTS: return 1; case graphics::Mesh::Topology::LINES: return 2; case graphics::Mesh::Topology::TRIANGLES: return 3; + case graphics::Mesh::Topology::QUADS: return 4; default: qCDebug(graphics_scripting) << "getTopologyLength -- unrecognized topology" << getTopology(); } return 0; } QVector scriptable::ScriptableMeshPart::getFace(glm::uint32 faceIndex) const { - if (faceIndex < getNumFaces()) { - return getIndices().mid(faceIndex * getTopologyLength(), getTopologyLength()); + switch (getTopology()) { + case graphics::Mesh::Topology::POINTS: + case graphics::Mesh::Topology::LINES: + case graphics::Mesh::Topology::TRIANGLES: + case graphics::Mesh::Topology::QUADS: + if (faceIndex < getNumFaces()) { + return getIndices().mid(faceIndex * getTopologyLength(), getTopologyLength()); + } + default: return QVector(); } - return QVector(); } QVariantMap scriptable::ScriptableMeshPart::getPartExtents() const { diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h index 4ef0465ca3..dd71d9b998 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableMeshPart.h @@ -10,6 +10,18 @@ #include "ScriptableMesh.h" namespace scriptable { + /**jsdoc + * @typedef {object} Graphics.MeshPart + * @property {number} partIndex - The part index (within the containing Mesh). + * @property {Graphics.Topology} topology - element interpretation (currently only 'triangles' is supported). + * @property {string[]} attributeNames - Vertex attribute names (color, normal, etc.) + * @property {number} numIndices - Number of vertex indices that this mesh part refers to. + * @property {number} numVerticesPerFace - Number of vertices per face (eg: 3 when topology is 'triangles'). + * @property {number} numFaces - Number of faces represented by the mesh part (numIndices / numVerticesPerFace). + * @property {number} numVertices - Total number of vertices in the containing Mesh. + * @property {number} numAttributes - Number of currently defined vertex attributes. + */ + class ScriptableMeshPart : public QObject, QScriptable { Q_OBJECT Q_PROPERTY(bool valid READ isValid) @@ -18,7 +30,8 @@ namespace scriptable { Q_PROPERTY(glm::uint32 baseVertexIndex READ getBaseVertexIndex WRITE setBaseVertexIndex) Q_PROPERTY(glm::uint32 lastVertexIndex READ getLastVertexIndex WRITE setLastVertexIndex) Q_PROPERTY(int numVerticesPerFace READ getTopologyLength) - Q_PROPERTY(graphics::Mesh::Topology topology READ getTopology WRITE setTopology) + // NOTE: making read-only for now (see also GraphicsScriptingInterface::newMesh and MeshPartPayload::drawCall) + Q_PROPERTY(graphics::Mesh::Topology topology READ getTopology) Q_PROPERTY(glm::uint32 numFaces READ getNumFaces) Q_PROPERTY(glm::uint32 numAttributes READ getNumAttributes) diff --git a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h index 1cb087af6f..b1fe29447f 100644 --- a/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h +++ b/libraries/graphics-scripting/src/graphics-scripting/ScriptableModel.h @@ -15,6 +15,14 @@ class QScriptValue; namespace scriptable { using ScriptableMeshes = QVector; + + /**jsdoc + * @typedef {object} Graphics.Model + * @property {Uuid} objectID - UUID of corresponding inworld object (if model is associated) + * @property {number} numMeshes - The number of submeshes contained in the model. + * @property {Graphics.Mesh[]} meshes - Array of submesh references. + */ + class ScriptableModel : public ScriptableModelBase { Q_OBJECT Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT) @@ -42,8 +50,6 @@ namespace scriptable { scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap()); QString toString() const; - // QScriptEngine-specific wrappers - //glm::uint32 forEachMeshVertexAttribute(QScriptValue callback); protected: glm::uint32 getNumMeshes() { return meshes.size(); } @@ -51,10 +57,7 @@ namespace scriptable { } -Q_DECLARE_METATYPE(scriptable::MeshPointer) -Q_DECLARE_METATYPE(scriptable::WeakMeshPointer) Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer) -Q_DECLARE_METATYPE(scriptable::ScriptableModelBase) -Q_DECLARE_METATYPE(scriptable::ScriptableModelBasePointer) +Q_DECLARE_METATYPE(QVector) Q_DECLARE_METATYPE(scriptable::ScriptableMaterial) Q_DECLARE_METATYPE(scriptable::MultiMaterialMap) diff --git a/libraries/graphics/src/graphics/GpuHelpers.cpp b/libraries/graphics/src/graphics/GpuHelpers.cpp index 63393df5e1..0c3bd945e1 100644 --- a/libraries/graphics/src/graphics/GpuHelpers.cpp +++ b/libraries/graphics/src/graphics/GpuHelpers.cpp @@ -21,8 +21,7 @@ namespace graphics { }; } namespace gpu { - - DebugEnums TYPES{ + DebugEnums TYPES{ { Type::FLOAT, "float" }, { Type::INT32, "int32" }, { Type::UINT32, "uint32" }, diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b114645788..f443184c07 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -604,15 +604,20 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe render::Transaction transaction; const render::ScenePointer& scene = AbstractViewStateInterface::instance()->getMain3DScene(); - meshIndex = meshIndex >= 0 ? meshIndex : 0; - partIndex = partIndex >= 0 ? partIndex : 0; + meshIndex = max(meshIndex, 0); + partIndex = max(partIndex, 0); - if (meshIndex >= meshes.size()) { + if (meshIndex >= (int)meshes.size()) { qDebug() << meshIndex << "meshIndex >= newModel.meshes.size()" << meshes.size(); return false; } auto mesh = meshes[meshIndex].getMeshPointer(); + + if (partIndex >= (int)mesh->getNumParts()) { + qDebug() << partIndex << "partIndex >= mesh->getNumParts()" << mesh->getNumParts(); + return false; + } { // update visual geometry render::Transaction transaction;