This commit is contained in:
SamGondelman 2018-02-27 10:08:30 -08:00
commit a4b04d9d43
10 changed files with 187 additions and 141 deletions

View file

@ -135,7 +135,4 @@ namespace scriptable {
using ScriptableMeshPointer = QPointer<ScriptableMesh>;
class ScriptableMeshPart;
using ScriptableMeshPartPointer = QPointer<ScriptableMeshPart>;
bool registerMetaTypes(QScriptEngine* engine);
}
Q_DECLARE_METATYPE(NestableType)

View file

@ -26,9 +26,6 @@
#include <SpatiallyNestable.h>
GraphicsScriptingInterface::GraphicsScriptingInterface(QObject* parent) : QObject(parent), QScriptable() {
if (auto scriptEngine = qobject_cast<QScriptEngine*>(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<graphics::Mesh::Part> parts = {{ 0, indices.size(), 0, topology}};
QVector<graphics::Mesh::Part> parts = {{ 0, indices.size(), 0, topology }};
mesh->setPartBuffer(buffer_helpers::newFromVector(parts, gpu::Element::PART_DRAWCALL));
return scriptable::make_scriptowned<scriptable::ScriptableMesh>(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<glm::uint32>& vector) {
return qScriptValueFromSequence(engine, vector);
}
QVector<int> metaTypeIds{
qRegisterMetaType<glm::uint32>("uint32"),
qRegisterMetaType<glm::uint32>("glm::uint32"),
qRegisterMetaType<QVector<glm::uint32>>(),
qRegisterMetaType<QVector<glm::uint32>>("QVector<uint32>"),
qRegisterMetaType<scriptable::ScriptableMeshes>(),
qRegisterMetaType<scriptable::ScriptableMeshes>("ScriptableMeshes"),
qRegisterMetaType<scriptable::ScriptableMeshes>("scriptable::ScriptableMeshes"),
qRegisterMetaType<QVector<scriptable::ScriptableMeshPointer>>("QVector<scriptable::ScriptableMeshPointer>"),
qRegisterMetaType<scriptable::ScriptableMeshPointer>(),
qRegisterMetaType<scriptable::ScriptableModelPointer>(),
qRegisterMetaType<scriptable::ScriptableMeshPartPointer>(),
qRegisterMetaType<scriptable::ScriptableMaterial>(),
qRegisterMetaType<QVector<scriptable::ScriptableMaterial>>(),
qRegisterMetaType<scriptable::MultiMaterialMap>(),
qRegisterMetaType<graphics::Mesh::Topology>(),
};
}
void qVectorUInt32FromScriptValue(const QScriptValue& array, QVector<glm::uint32>& result) {
qScriptValueToSequence(array, result);
namespace scriptable {
template <typename T> int registerQPointerMetaType(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<QPointer<T>>>(engine);
return qScriptRegisterMetaType<QPointer<T>>(
engine,
[](QScriptEngine* engine, const QPointer<T>& object) -> QScriptValue {
if (!object) {
return QScriptValue::NullValue;
}
return engine->newQObject(object, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::AutoCreateDynamicProperties);
},
[](const QScriptValue& value, QPointer<T>& out) {
auto obj = value.toQObject();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString();
#endif
if (auto tmp = qobject_cast<T*>(obj)) {
out = QPointer<T>(tmp);
return;
}
#if 0
if (auto tmp = static_cast<T*>(obj)) {
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast -- via static_cast" << obj << tmp << value.toString();
#endif
out = QPointer<T>(tmp);
return;
}
#endif
out = nullptr;
}
);
}
QScriptValue qVectorScriptableMaterialToScriptValue(QScriptEngine* engine, const QVector<scriptable::ScriptableMaterial>& vector) {
@ -346,102 +389,38 @@ namespace {
// No need to convert from QScriptValue to MultiMaterialMap
}
QVector<int> metaTypeIds{
qRegisterMetaType<glm::uint32>("uint32"),
qRegisterMetaType<glm::uint32>("glm::uint32"),
qRegisterMetaType<QVector<glm::uint32>>(),
qRegisterMetaType<QVector<glm::uint32>>("QVector<uint32>"),
qRegisterMetaType<scriptable::ScriptableMeshes>(),
qRegisterMetaType<scriptable::ScriptableMeshes>("ScriptableMeshes"),
qRegisterMetaType<scriptable::ScriptableMeshes>("scriptable::ScriptableMeshes"),
qRegisterMetaType<QVector<scriptable::ScriptableMeshPointer>>("QVector<scriptable::ScriptableMeshPointer>"),
qRegisterMetaType<scriptable::ScriptableMeshPointer>(),
qRegisterMetaType<scriptable::ScriptableModelPointer>(),
qRegisterMetaType<scriptable::ScriptableMeshPartPointer>(),
qRegisterMetaType<scriptable::ScriptableMaterial>(),
qRegisterMetaType<QVector<scriptable::ScriptableMaterial>>(),
qRegisterMetaType<scriptable::MultiMaterialMap>(),
qRegisterMetaType<graphics::Mesh::Topology>(),
};
}
namespace scriptable {
template <typename T> int registerQPointerThing(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<QPointer<T>>>(engine);
return qScriptRegisterMetaType<QPointer<T>>(
engine,
[](QScriptEngine* engine, const QPointer<T>& object) -> QScriptValue {
if (!object) {
return QScriptValue::NullValue;
}
return engine->newQObject(object, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::AutoCreateDynamicProperties);
},
[](const QScriptValue& value, QPointer<T>& out) {
auto obj = value.toQObject();
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast" << obj << value.toString();
#endif
if (auto tmp = qobject_cast<T*>(obj)) {
out = QPointer<T>(tmp);
return;
}
#if 0
if (auto tmp = static_cast<T*>(obj)) {
#ifdef SCRIPTABLE_MESH_DEBUG
qCInfo(graphics_scripting) << "qpointer_qobject_cast -- via static_cast" << obj << tmp << value.toString();
#endif
out = QPointer<T>(tmp);
return;
}
#endif
out = nullptr;
}
);
}
template <typename T> int registerDebugEnum(QScriptEngine* engine, const DebugEnums<T>& debugEnums) {
static const DebugEnums<T>& poop = debugEnums;
static const DebugEnums<T>& instance = debugEnums;
return qScriptRegisterMetaType<T>(
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<QVector<glm::uint32>>(engine);
qScriptRegisterSequenceMetaType<QVector<scriptable::ScriptableMaterial>>(engine);
void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<glm::uint32>>(engine);
qScriptRegisterSequenceMetaType<QVector<scriptable::ScriptableMaterial>>(engine);
qScriptRegisterMetaType(engine, qVectorUInt32ToScriptValue, qVectorUInt32FromScriptValue);
scriptable::registerQPointerMetaType<scriptable::ScriptableModel>(engine);
scriptable::registerQPointerMetaType<scriptable::ScriptableMesh>(engine);
scriptable::registerQPointerMetaType<scriptable::ScriptableMeshPart>(engine);
registerQPointerThing<scriptable::ScriptableModel>(engine);
registerQPointerThing<scriptable::ScriptableMesh>(engine);
registerQPointerThing<scriptable::ScriptableMeshPart>(engine);
qScriptRegisterMetaType<QVector<scriptable::ScriptableMeshPointer>>(
engine,
[](QScriptEngine* engine, const QVector<scriptable::ScriptableMeshPointer>& vector) -> QScriptValue {
return qScriptValueFromSequence(engine, vector);
},
[](const QScriptValue& array, QVector<scriptable::ScriptableMeshPointer>& result) {
qScriptValueToSequence(array, result);
}
);
qScriptRegisterMetaType(engine, scriptableMaterialToScriptValue, scriptableMaterialFromScriptValue);
qScriptRegisterMetaType(engine, qVectorScriptableMaterialToScriptValue, qVectorScriptableMaterialFromScriptValue);
qScriptRegisterMetaType(engine, multiMaterialMapToScriptValue, multiMaterialMapFromScriptValue);
scriptable::registerDebugEnum<graphics::Mesh::Topology>(engine, graphics::TOPOLOGIES);
scriptable::registerDebugEnum<gpu::Type>(engine, gpu::TYPES);
scriptable::registerDebugEnum<gpu::Semantic>(engine, gpu::SEMANTICS);
scriptable::registerDebugEnum<gpu::Dimension>(engine, gpu::DIMENSIONS);
registerDebugEnum<graphics::Mesh::Topology>(engine, graphics::TOPOLOGIES);
registerDebugEnum<gpu::Type>(engine, gpu::TYPES);
registerDebugEnum<gpu::Semantic>(engine, gpu::SEMANTICS);
registerDebugEnum<gpu::Dimension>(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"

View file

@ -20,6 +20,12 @@
#include "ScriptableMesh.h"
#include <DependencyManager.h>
/**jsdoc
* The experimental Graphics API <em>(experimental)</em> 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<glm::uint32>)
Q_DECLARE_METATYPE(NestableType)
#endif // hifi_GraphicsScriptingInterface_h

View file

@ -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<gpu::Stream::Slot>(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<gpu::Stream::Slot>(slotNum));
return buffer_helpers::getValue<QVariant>(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<gpu::Stream::Slot>(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));

View file

@ -28,6 +28,15 @@
#include <graphics/Geometry.h>
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<scriptable::ScriptableMeshPartPointer> 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<scriptable::ScriptableModel*>(model); }
@ -97,5 +105,3 @@ namespace scriptable {
Q_DECLARE_METATYPE(scriptable::ScriptableMeshPointer)
Q_DECLARE_METATYPE(QVector<scriptable::ScriptableMeshPointer>)
Q_DECLARE_METATYPE(glm::uint32)
Q_DECLARE_METATYPE(QVector<glm::uint32>)

View file

@ -21,6 +21,7 @@
#include <graphics/GpuHelpers.h>
#include <graphics/Geometry.h>
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<gpu::Stream::Slot>(slotNum));
return buffer_helpers::setValue(bufferView, vertexIndex, value);
}
@ -368,9 +369,10 @@ bool scriptable::ScriptableMeshPart::setIndices(const QVector<glm::uint32>& 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<graphics::Mesh::Part>(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<graphics::Mesh::Part>(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<glm::uint32> 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<glm::uint32>();
}
return QVector<glm::uint32>();
}
QVariantMap scriptable::ScriptableMeshPart::getPartExtents() const {

View file

@ -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)

View file

@ -15,6 +15,14 @@ class QScriptValue;
namespace scriptable {
using ScriptableMeshes = QVector<scriptable::ScriptableMeshPointer>;
/**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<scriptable::ScriptableModelPointer>)
Q_DECLARE_METATYPE(scriptable::ScriptableMaterial)
Q_DECLARE_METATYPE(scriptable::MultiMaterialMap)

View file

@ -21,8 +21,7 @@ namespace graphics {
};
}
namespace gpu {
DebugEnums<Type> TYPES{
DebugEnums<Type> TYPES{
{ Type::FLOAT, "float" },
{ Type::INT32, "int32" },
{ Type::UINT32, "uint32" },

View file

@ -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;