CR fedback and cleanup

This commit is contained in:
humbletim 2018-02-22 05:15:01 -05:00
parent 5791ca4c51
commit be8d79f53f
36 changed files with 890 additions and 645 deletions

View file

@ -166,7 +166,7 @@
#include "scripting/AccountServicesScriptingInterface.h"
#include "scripting/HMDScriptingInterface.h"
#include "scripting/MenuScriptingInterface.h"
#include "graphics-scripting/ModelScriptingInterface.h"
#include "graphics-scripting/GraphicsScriptingInterface.h"
#include "scripting/SettingsScriptingInterface.h"
#include "scripting/WindowScriptingInterface.h"
#include "scripting/ControllerScriptingInterface.h"
@ -199,6 +199,7 @@
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
#include <src/scripting/GooglePolyScriptingInterface.h>
#include <EntityScriptClient.h>
#include <ModelScriptingInterface.h>
#include <PickManager.h>
#include <PointerManager.h>
@ -800,7 +801,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<ResourceCacheSharedItems>();
DependencyManager::set<DesktopScriptingInterface>();
DependencyManager::set<EntityScriptingInterface>(true);
DependencyManager::set<ModelScriptingInterface>();
DependencyManager::registerInheritance<scriptable::ModelProviderFactory, ApplicationMeshProvider>();
DependencyManager::set<ApplicationMeshProvider>();
DependencyManager::set<RecordingScriptingInterface>();
@ -5981,8 +5981,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
scriptEngine->registerGlobalObject("Render", _renderEngine->getConfiguration().get());
ModelScriptingInterface::registerMetaTypes(scriptEngine.data());
scriptEngine->registerGlobalObject("Model", DependencyManager::get<ModelScriptingInterface>().data());
GraphicsScriptingInterface::registerMetaTypes(scriptEngine.data());
scriptEngine->registerGlobalObject("Graphics", DependencyManager::get<GraphicsScriptingInterface>().data());
scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface());

View file

@ -72,6 +72,7 @@
#include <procedural/ProceduralSkybox.h>
#include <graphics/Skybox.h>
#include <ModelScriptingInterface.h>
#include "FrameTimingsScriptingInterface.h"
#include "Sound.h"

View file

@ -16,7 +16,6 @@
#include <graphics-scripting/Forward.h>
#include "Overlay.h"
namespace model { class Mesh; }
class Base3DOverlay : public Overlay, public SpatiallyNestable, public scriptable::ModelProvider {
Q_OBJECT
using Parent = Overlay;

View file

@ -75,6 +75,7 @@ void ModelOverlay::update(float deltatime) {
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
if (_model->needsFixupInScene()) {
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getID(), NestableType::Overlay, _model);
_model->removeFromScene(scene, transaction);
_model->addToScene(scene, transaction);
@ -83,6 +84,7 @@ void ModelOverlay::update(float deltatime) {
auto modelOverlay = static_cast<ModelOverlay*>(&data);
modelOverlay->setSubRenderItemIDs(newRenderItemIDs);
});
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(getID(), NestableType::Overlay, _model);
}
if (_visibleDirty) {
_visibleDirty = false;
@ -107,12 +109,14 @@ void ModelOverlay::update(float deltatime) {
bool ModelOverlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
Volume3DOverlay::addToScene(overlay, scene, transaction);
_model->addToScene(scene, transaction);
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(getID(), NestableType::Overlay, _model);
return true;
}
void ModelOverlay::removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
Volume3DOverlay::removeFromScene(overlay, scene, transaction);
_model->removeFromScene(scene, transaction);
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getID(), NestableType::Overlay, _model);
transaction.updateItem<Overlay>(getRenderItemID(), [](Overlay& data) {
auto modelOverlay = static_cast<ModelOverlay*>(&data);
modelOverlay->clearSubRenderItemIDs();

View file

@ -221,7 +221,7 @@ void Avatar::updateAvatarEntities() {
return;
}
if (getID() == QUuid()) {
if (getID() == QUuid() || getID() == AVATAR_SELF_ID) {
return; // wait until MyAvatar gets an ID before doing this.
}
@ -577,6 +577,7 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
}
_mustFadeIn = true;
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(getSessionUUID(), NestableType::Avatar, _skeletonModel);
}
void Avatar::fadeIn(render::ScenePointer scene) {
@ -626,6 +627,7 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->removeFromScene(scene, transaction);
}
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getSessionUUID(), NestableType::Avatar, _skeletonModel);
}
void Avatar::updateRenderItem(render::Transaction& transaction) {
@ -1764,12 +1766,11 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
}
scriptable::ScriptableModelBase Avatar::getScriptableModel(bool* ok) {
qDebug() << "Avatar::getScriptableModel" ;
if (!_skeletonModel || !_skeletonModel->isLoaded()) {
return scriptable::ModelProvider::modelUnavailableError(ok);
}
scriptable::ScriptableModelBase result = _skeletonModel->getScriptableModel(ok);
result.objectID = getSessionUUID();
result.objectID = getSessionUUID();
result.mixin({
{ "avatarID", getSessionUUID().toString() },
{ "url", _skeletonModelURL.toString() },
@ -1787,4 +1788,4 @@ scriptable::ScriptableModelBase Avatar::getScriptableModel(bool* ok) {
*ok = true;
}
return result;
}
}

View file

@ -1,4 +1,3 @@
//
// Avatar.h
// interface/src/avatar
@ -276,6 +275,7 @@ public:
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
public slots:
// FIXME - these should be migrated to use Pose data instead

View file

@ -56,6 +56,7 @@ public:
const uint64_t& getUpdateTime() const { return _updateTime; }
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override { return scriptable::ModelProvider::modelUnavailableError(ok); }
protected:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
virtual void onAddToScene(const EntityItemPointer& entity);

View file

@ -950,6 +950,16 @@ QStringList RenderableModelEntityItem::getJointNames() const {
return result;
}
// FIXME: deprecated; remove >= RC67
bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) {
auto model = getModel();
if (!model || !model->isLoaded()) {
return false;
}
BLOCKING_INVOKE_METHOD(model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result));
return !result.isEmpty();
}
scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel(bool* ok) {
ModelPointer model;
withReadLock([&] { model = _model; });
@ -998,6 +1008,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
return;
}
bool changed { false };
// relay any inbound joint changes from scripts/animation/network to the model/rig
_jointDataLock.withWriteLock([&] {
for (int index = 0; index < _localJointData.size(); ++index) {
@ -1005,13 +1016,21 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
if (jointData.rotationDirty) {
model->setJointRotation(index, true, jointData.joint.rotation, 1.0f);
jointData.rotationDirty = false;
changed = true;
}
if (jointData.translationDirty) {
model->setJointTranslation(index, true, jointData.joint.translation, 1.0f);
jointData.translationDirty = false;
changed = true;
}
}
});
if (changed) {
forEachChild([&](SpatiallyNestablePointer object) {
object->locationChanged(false);
});
}
}
using namespace render;
@ -1054,6 +1073,11 @@ void ModelEntityRenderer::removeFromScene(const ScenePointer& scene, Transaction
void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity) {
entity->setModel({});
//emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(entity->getID(), NestableType::Entity, _model);
}
void ModelEntityRenderer::onAddToSceneTyped(const TypedEntityPointer& entity) {
//emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(entity->getID(), NestableType::Entity, _model);
}
@ -1280,6 +1304,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
auto entityRenderer = static_cast<EntityRenderer*>(&data);
entityRenderer->clearSubRenderItemIDs();
});
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, _model);
}
return;
}
@ -1290,6 +1315,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
connect(model.get(), &Model::setURLFinished, this, [&](bool didVisualGeometryRequestSucceed) {
setKey(didVisualGeometryRequestSucceed);
emit requestRenderUpdate();
auto factory = DependencyManager::get<scriptable::ModelProviderFactory>().data();
qDebug() << "leopoly didVisualGeometryRequestSucceed" << didVisualGeometryRequestSucceed << QThread::currentThread() << _model.get();
if(didVisualGeometryRequestSucceed) {
emit factory->modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model);
}
});
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);

View file

@ -111,6 +111,7 @@ public:
virtual int getJointIndex(const QString& name) const override;
virtual QStringList getJointNames() const override;
bool getMeshes(MeshProxyList& result) override; // deprecated
const void* getCollisionMeshKey() const { return _collisionMeshKey; }
signals:
@ -137,6 +138,7 @@ namespace render { namespace entities {
class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem> {
using Parent = TypedEntityRenderer<RenderableModelEntityItem>;
friend class EntityRenderer;
Q_OBJECT
public:
ModelEntityRenderer(const EntityItemPointer& entity);

View file

@ -20,6 +20,8 @@
#include <QByteArray>
#include <QtConcurrent/QtConcurrentRun>
#include <model-networking/SimpleMeshProxy.h>
#include <ModelScriptingInterface.h>
#include <EntityEditPacketSender.h>
#include <PhysicalEntitySimulation.h>
#include <StencilMaskPass.h>
@ -97,7 +99,7 @@ const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
In RenderablePolyVoxEntityItem::render, these flags are checked and changes are propagated along the chain.
decompressVolumeData() is called to decompress _voxelData into _volData. recomputeMesh() is called to invoke the
polyVox surface extractor to create _mesh (as well as set Simulation _dirtyFlags). Because Simulation::DIRTY_SHAPE
polyVox surface extractor to create _mesh (as well as set Simulation _flags). Because Simulation::DIRTY_SHAPE
is set, isReadyToComputeShape() gets called and _shape is created either from _volData or _shape, depending on
the surface style.
@ -1414,6 +1416,39 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() {
}
}
// deprecated
bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
if (!updateDependents()) {
return false;
}
bool success = false;
if (_mesh) {
MeshProxy* meshProxy = nullptr;
glm::mat4 transform = voxelToLocalMatrix();
withReadLock([&] {
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)_mesh->getNumVertices();
if (!_meshReady) {
// we aren't ready to return a mesh. the caller will have to try again later.
success = false;
} else if (numVertices == 0) {
// we are ready, but there are no triangles in the mesh.
success = true;
} else {
success = true;
// the mesh will be in voxel-space. transform it into object-space
meshProxy = new SimpleMeshProxy(
_mesh->map([=](glm::vec3 position) { return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[=](glm::vec3 color) { return color; },
[=](glm::vec3 normal) { return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
[&](uint32_t index) { return index; }));
result << meshProxy;
}
});
}
return success;
}
scriptable::ScriptableModelBase RenderablePolyVoxEntityItem::getScriptableModel(bool * ok) {
if (!updateDependents() || !_mesh) {
return scriptable::ModelProvider::modelUnavailableError(ok);

View file

@ -113,6 +113,7 @@ public:
void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; _meshReady = false; }); }
bool getMeshes(MeshProxyList& result) override; // deprecated
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
private:

View file

@ -16,8 +16,8 @@
#include <GeometryCache.h>
#include <PerfStat.h>
#include <render-utils/simple_vert.h>
#include <render-utils/simple_frag.h>
#include "render-utils/simple_vert.h"
#include "render-utils/simple_frag.h"
//#define SHAPE_ENTITY_USE_FADE_EFFECT
#ifdef SHAPE_ENTITY_USE_FADE_EFFECT
@ -112,8 +112,6 @@ bool ShapeEntityRenderer::isTransparent() const {
return Parent::isTransparent();
}
void ShapeEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
Q_ASSERT(args->_batch);

View file

@ -57,6 +57,8 @@ using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElemen
#define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10))
#define debugTreeVector(V) V << "[" << V << " in meters ]"
class MeshProxyList;
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
/// one directly, instead you must only construct one of it's derived classes with additional features.
@ -454,6 +456,8 @@ public:
bool matchesJSONFilters(const QJsonObject& jsonFilters) const;
virtual bool getMeshes(MeshProxyList& result) { return true; }
virtual void locationChanged(bool tellPhysics = true) override;
virtual bool getScalesWithParent() const override;

View file

@ -585,7 +585,10 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
if (entity->getLocked()) {
shouldDelete = false;
} else {
_entityTree->deleteEntity(entityID);
// only delete local entities, server entities will round trip through the server filters
if (entity->getClientOnly()) {
_entityTree->deleteEntity(entityID);
}
}
}
});
@ -1805,6 +1808,30 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons
return aaBox.findCapsulePenetration(start, end, radius, penetration);
}
void EntityScriptingInterface::getMeshes(QUuid entityID, QScriptValue callback) {
PROFILE_RANGE(script_entities, __FUNCTION__);
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
if (!entity) {
qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID;
QScriptValueList args { callback.engine()->undefinedValue(), false };
callback.call(QScriptValue(), args);
return;
}
MeshProxyList result;
bool success = entity->getMeshes(result);
if (success) {
QScriptValue resultAsScriptValue = meshesToScriptValue(callback.engine(), result);
QScriptValueList args { resultAsScriptValue, true };
callback.call(QScriptValue(), args);
} else {
QScriptValueList args { callback.engine()->undefinedValue(), false };
callback.call(QScriptValue(), args);
}
}
glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
glm::mat4 result;
if (_entityTree) {

View file

@ -37,6 +37,7 @@
#include "BaseScriptEngine.h"
class EntityTree;
class MeshProxy;
// helper factory to compose standardized, async metadata queries for "magic" Entity properties
// like .script and .serverScripts. This is used for automated testing of core scripting features
@ -138,7 +139,7 @@ public slots:
Q_INVOKABLE bool canRezTmpCertified();
/**jsdoc
* @function Entities.canWriteAsseets
* @function Entities.canWriteAssets
* @return {bool} `true` if the DomainServer will allow this Node/Avatar to write to the asset server
*/
Q_INVOKABLE bool canWriteAssets();
@ -400,6 +401,9 @@ public slots:
Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions,
const glm::vec3& start, const glm::vec3& end, float radius);
// FIXME move to a renderable entity interface
Q_INVOKABLE void getMeshes(QUuid entityID, QScriptValue callback);
/**jsdoc
* Returns object to world transform, excluding scale
*

View file

@ -408,7 +408,16 @@ static void createTangents(const FBXMesh& mesh, bool generateFromTexCoords,
}
}
static void createMeshTangents(FBXMesh& mesh, bool generateFromTexCoords) {
static void _createBlendShapeTangents(FBXMesh& mesh, bool generateFromTexCoords, FBXBlendshape& blendShape);
void FBXMesh::createBlendShapeTangents(bool generateTangents) {
for (auto& blendShape : blendshapes) {
_createBlendShapeTangents(*this, generateTangents, blendShape);
}
}
void FBXMesh::createMeshTangents(bool generateFromTexCoords) {
FBXMesh& mesh = *this;
// This is the only workaround I've found to trick the compiler into understanding that mesh.tangents isn't
// const in the lambda function.
auto& tangents = mesh.tangents;
@ -421,7 +430,7 @@ static void createMeshTangents(FBXMesh& mesh, bool generateFromTexCoords) {
});
}
static void createBlendShapeTangents(FBXMesh& mesh, bool generateFromTexCoords, FBXBlendshape& blendShape) {
static void _createBlendShapeTangents(FBXMesh& mesh, bool generateFromTexCoords, FBXBlendshape& blendShape) {
// Create lookup to get index in blend shape from vertex index in mesh
std::vector<int> reverseIndices;
reverseIndices.resize(mesh.vertices.size());
@ -1455,18 +1464,22 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
QSet<QString> remainingModels;
for (QHash<QString, FBXModel>::const_iterator model = models.constBegin(); model != models.constEnd(); model++) {
// models with clusters must be parented to the cluster top
foreach (const QString& deformerID, _connectionChildMap.values(model.key())) {
foreach (const QString& clusterID, _connectionChildMap.values(deformerID)) {
if (!clusters.contains(clusterID)) {
continue;
// Unless the model is a root node.
bool isARootNode = !modelIDs.contains(_connectionParentMap.value(model.key()));
if (!isARootNode) {
foreach(const QString& deformerID, _connectionChildMap.values(model.key())) {
foreach(const QString& clusterID, _connectionChildMap.values(deformerID)) {
if (!clusters.contains(clusterID)) {
continue;
}
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
_connectionParentMap.insert(model.key(), topID);
goto outerBreak;
}
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
_connectionParentMap.insert(model.key(), topID);
goto outerBreak;
}
outerBreak: ;
}
outerBreak:
// make sure the parent is in the child map
QString parent = _connectionParentMap.value(model.key());
@ -1714,10 +1727,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
}
}
createMeshTangents(extracted.mesh, generateTangents);
for (auto& blendShape : extracted.mesh.blendshapes) {
createBlendShapeTangents(extracted.mesh, generateTangents, blendShape);
}
extracted.mesh.createMeshTangents(generateTangents);
extracted.mesh.createBlendShapeTangents(generateTangents);
// find the clusters with which the mesh is associated
QVector<QString> clusterIDs;

View file

@ -22,7 +22,7 @@ namespace glm {
//#define DEBUG_BUFFERVIEW_SCRIPTING
//#ifdef DEBUG_BUFFERVIEW_SCRIPTING
#include "DebugNames.h"
#include "DebugNames.h"
//#endif
namespace {
@ -59,8 +59,8 @@ void setBufferViewElement(const gpu::BufferView& view, quint32 index, const QVar
view.edit<T>(index) = glmVecFromVariant<T>(v);
}
//FIXME copied from Model.cpp
static void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) {
void buffer_helpers::packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) {
auto absNormal = glm::abs(normal);
auto absTangent = glm::abs(tangent);
normal /= glm::max(1e-6f, glm::max(glm::max(absNormal.x, absNormal.y), absNormal.z));
@ -152,9 +152,9 @@ bool boundsCheck(const gpu::BufferView& view, quint32 index) {
return (
index < view.getNumElements() &&
index * byteLength < (view._size - 1) * byteLength
);
);
}
QVariant buffer_helpers::toVariant(const gpu::BufferView& view, quint32 index, bool asArray, const char* hint) {
const auto& element = view._element;
const auto vecN = element.getScalarCount();
@ -189,7 +189,7 @@ QVariant buffer_helpers::toVariant(const gpu::BufferView& view, quint32 index, b
return glmVecToVariant(glm::vec3(glm::unpackSnorm3x10_1x2(packedNormal)));
}
return getBufferViewElement<glm::u8vec4>(view, index, asArray);
return getBufferViewElement<glm::u8vec4>(view, index, asArray);
}
}
} else if (BYTES_PER_ELEMENT == 2) {
@ -271,12 +271,12 @@ gpu::BufferView buffer_helpers::fromVector(const QVector<T>& elements, const gpu
template<> gpu::BufferView buffer_helpers::fromVector<unsigned int>(const QVector<unsigned int>& elements, const gpu::Element& elementType) { return fromVector(elements, elementType); }
template<> gpu::BufferView buffer_helpers::fromVector<glm::vec3>(const QVector<glm::vec3>& elements, const gpu::Element& elementType) { return fromVector(elements, elementType); }
template <typename T> struct getVec4;// { static T get(const gpu::BufferView& view, quint32 index, const char *hint); };
template <typename T> struct GpuVec4ToGlm;// { static T get(const gpu::BufferView& view, quint32 index, const char *hint); };
template <typename T> struct getScalar;// { static T get(const gpu::BufferView& view, quint32 index, const char *hint); };
struct gotter {
struct GpuToGlmAdapter {
static float error(const QString& name, const gpu::BufferView& view, quint32 index, const char *hint) {
qDebug() << QString("gotter:: unhandled type=%1(element=%2(%3)) size=%4(per=%5) vec%6 hint=%7 #%8")
qDebug() << QString("GpuToGlmAdapter:: unhandled type=%1(element=%2(%3)) size=%4(per=%5) vec%6 hint=%7 #%8")
.arg(name)
.arg(DebugNames::stringFrom(view._element.getType()))
.arg(view._element.getType())
@ -288,9 +288,9 @@ struct gotter {
Q_ASSERT(false);
assert(false);
return NAN;
}
}
};
template <typename T> struct getScalar : gotter {
template <typename T> struct getScalar : GpuToGlmAdapter {
static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::uint32>(index);
case gpu::UINT16: return view.get<glm::uint16>(index);
@ -305,7 +305,7 @@ template <typename T> struct getScalar : gotter {
}
};
template <typename T> struct getVec2 : gotter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
template <typename T> struct GpuVec2ToGlm : GpuToGlmAdapter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::u32vec2>(index);
case gpu::UINT16: return view.get<glm::u16vec2>(index);
case gpu::UINT8: return view.get<glm::u8vec2>(index);
@ -315,10 +315,10 @@ template <typename T> struct getVec2 : gotter { static T get(const gpu::BufferVi
case gpu::FLOAT: return view.get<glm::fvec2>(index);
case gpu::HALF: return glm::unpackSnorm2x8(view.get<glm::int16>(index));
default: break;
} return T(error("getVec2", view, index, hint)); }};
} return T(error("GpuVec2ToGlm", view, index, hint)); }};
template <typename T> struct getVec3 : gotter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
template <typename T> struct GpuVec3ToGlm : GpuToGlmAdapter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) { switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::u32vec3>(index);
case gpu::UINT16: return view.get<glm::u16vec3>(index);
case gpu::UINT8: return view.get<glm::u8vec3>(index);
@ -330,12 +330,12 @@ template <typename T> struct getVec3 : gotter { static T get(const gpu::Buffer
case gpu::NUINT8:
case gpu::NINT2_10_10_10:
if (view._element.getSize() == sizeof(glm::int32)) {
return getVec4<T>::get(view, index, hint);
return GpuVec4ToGlm<T>::get(view, index, hint);
}
default: break;
} return T(error("getVec3", view, index, hint)); }};
} return T(error("GpuVec3ToGlm", view, index, hint)); }};
template <typename T> struct getVec4 : gotter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) {
template <typename T> struct GpuVec4ToGlm : GpuToGlmAdapter { static T get(const gpu::BufferView& view, quint32 index, const char *hint) {
assert(view._element.getSize() == sizeof(glm::int32));
switch(view._element.getType()) {
case gpu::UINT32: return view.get<glm::u32vec4>(index);
@ -346,7 +346,7 @@ template <typename T> struct getVec4 : gotter { static T get(const gpu::BufferVi
case gpu::INT8: return view.get<glm::i8vec4>(index);
case gpu::NUINT32: break;
case gpu::NUINT16: break;
case gpu::NUINT8: return glm::unpackUnorm4x8(view.get<glm::uint32>(index));
case gpu::NUINT8: return glm::unpackUnorm4x8(view.get<glm::uint32>(index));
case gpu::NUINT2: break;
case gpu::NINT32: break;
case gpu::NINT16: break;
@ -356,7 +356,7 @@ template <typename T> struct getVec4 : gotter { static T get(const gpu::BufferVi
case gpu::FLOAT: return view.get<glm::fvec4>(index);
case gpu::HALF: return glm::unpackSnorm4x8(view.get<glm::int32>(index));
case gpu::NINT2_10_10_10: return glm::unpackSnorm3x10_1x2(view.get<glm::uint32>(index));
} return T(error("getVec4", view, index, hint)); }};
} return T(error("GpuVec4ToGlm", view, index, hint)); }};
template <typename FUNC, typename T>
@ -376,16 +376,32 @@ struct getVec {
}
};
template <> QVector<int> buffer_helpers::toVector<int>(const gpu::BufferView& view, const char *hint) { return getVec<getScalar<int>,int>::__to_vector__(view, hint); }
template <> QVector<glm::vec2> buffer_helpers::toVector<glm::vec2>(const gpu::BufferView& view, const char *hint) { return getVec<getVec2<glm::vec2>,glm::vec2>::__to_vector__(view, hint); }
template <> QVector<glm::vec3> buffer_helpers::toVector<glm::vec3>(const gpu::BufferView& view, const char *hint) { return getVec<getVec3<glm::vec3>,glm::vec3>::__to_vector__(view, hint); }
template <> QVector<glm::vec4> buffer_helpers::toVector<glm::vec4>(const gpu::BufferView& view, const char *hint) { return getVec<getVec4<glm::vec4>,glm::vec4>::__to_vector__(view, hint); }
template <> QVector<int> buffer_helpers::toVector<int>(const gpu::BufferView& view, const char *hint) {
return getVec<getScalar<int>,int>::__to_vector__(view, hint);
}
template <> QVector<glm::vec2> buffer_helpers::toVector<glm::vec2>(const gpu::BufferView& view, const char *hint) {
return getVec<GpuVec2ToGlm<glm::vec2>,glm::vec2>::__to_vector__(view, hint);
}
template <> QVector<glm::vec3> buffer_helpers::toVector<glm::vec3>(const gpu::BufferView& view, const char *hint) {
return getVec<GpuVec3ToGlm<glm::vec3>,glm::vec3>::__to_vector__(view, hint);
}
template <> QVector<glm::vec4> buffer_helpers::toVector<glm::vec4>(const gpu::BufferView& view, const char *hint) {
return getVec<GpuVec4ToGlm<glm::vec4>,glm::vec4>::__to_vector__(view, hint);
}
template <> int buffer_helpers::convert<int>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getScalar<int>,int>::__to_scalar__(view, index, hint); }
template <> glm::vec2 buffer_helpers::convert<glm::vec2>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getVec2<glm::vec2>,glm::vec2>::__to_scalar__(view, index, hint); }
template <> glm::vec3 buffer_helpers::convert<glm::vec3>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getVec3<glm::vec3>,glm::vec3>::__to_scalar__(view, index, hint); }
template <> glm::vec4 buffer_helpers::convert<glm::vec4>(const gpu::BufferView& view, quint32 index, const char *hint) { return getVec<getVec4<glm::vec4>,glm::vec4>::__to_scalar__(view, index, hint); }
template <> int buffer_helpers::convert<int>(const gpu::BufferView& view, quint32 index, const char *hint) {
return getVec<getScalar<int>,int>::__to_scalar__(view, index, hint);
}
template <> glm::vec2 buffer_helpers::convert<glm::vec2>(const gpu::BufferView& view, quint32 index, const char *hint) {
return getVec<GpuVec2ToGlm<glm::vec2>,glm::vec2>::__to_scalar__(view, index, hint);
}
template <> glm::vec3 buffer_helpers::convert<glm::vec3>(const gpu::BufferView& view, quint32 index, const char *hint) {
return getVec<GpuVec3ToGlm<glm::vec3>,glm::vec3>::__to_scalar__(view, index, hint);
}
template <> glm::vec4 buffer_helpers::convert<glm::vec4>(const gpu::BufferView& view, quint32 index, const char *hint) {
return getVec<GpuVec4ToGlm<glm::vec4>,glm::vec4>::__to_scalar__(view, index, hint);
}
gpu::BufferView buffer_helpers::clone(const gpu::BufferView& input) {
return gpu::BufferView(
@ -410,7 +426,7 @@ gpu::BufferView buffer_helpers::resize(const gpu::BufferView& input, quint32 num
graphics::MeshPointer buffer_helpers::cloneMesh(graphics::MeshPointer mesh) {
auto clone = std::make_shared<graphics::Mesh>();
//[](graphics::Mesh* blah) {
//qCDebug(bufferhelper_logging) << "--- DELETING MESH POINTER" << blah;
//qCDebug(bufferhelper_logging) << "--- DELETING MESH POINTER" << blah;
// delete blah;
//});
clone->displayName = (QString::fromStdString(mesh->displayName) + "-clone").toStdString();
@ -437,12 +453,12 @@ graphics::MeshPointer buffer_helpers::cloneMesh(graphics::MeshPointer mesh) {
namespace {
// expand the corresponding attribute buffer (creating it if needed) so that it matches POSITIONS size and specified element type
gpu::BufferView _expandedAttributeBuffer(const graphics::MeshPointer mesh, gpu::Stream::Slot slot) {
gpu::BufferView bufferView = buffer_helpers::getBufferView(mesh, slot);
gpu::BufferView bufferView = buffer_helpers::getBufferView(mesh, slot);
const auto& elementType = bufferView._element;
//auto vecN = element.getScalarCount();
//auto type = element.getType();
//gpu::Element elementType = getVecNElement(type, vecN);
gpu::Size elementSize = elementType.getSize();
auto nPositions = mesh->getNumVertices();
auto vsize = nPositions * elementSize;
@ -484,8 +500,8 @@ namespace {
typeName = DebugNames::stringFrom(bufferView._element.getType());
#endif
qCDebug(bufferhelper_logging, "NOTE:: _expandedAttributeBuffer.%s vec%d %s (before count=%lu bytes=%lu // after count=%lu bytes=%lu)",
hint.toStdString().c_str(), bufferView._element.getScalarCount(),
typeName.toStdString().c_str(), beforeCount, beforeTotal, afterCount, afterTotal);
hint.toStdString().c_str(), bufferView._element.getScalarCount(),
typeName.toStdString().c_str(), beforeCount, beforeTotal, afterCount, afterTotal);
}
#endif
return bufferView;
@ -529,7 +545,7 @@ std::map<QString, gpu::BufferView> buffer_helpers::gatherBufferViews(graphics::M
auto afterCount = attributeViews[name].getNumElements();
if (beforeTotal != afterTotal || beforeCount != afterCount) {
qCDebug(bufferhelper_logging, "NOTE:: gatherBufferViews.%s vec%d %s (before count=%lu bytes=%lu // after count=%lu bytes=%lu)",
name.toStdString().c_str(), vecN, typeName.toStdString().c_str(), beforeCount, beforeTotal, afterCount, afterTotal);
name.toStdString().c_str(), vecN, typeName.toStdString().c_str(), beforeCount, beforeTotal, afterCount, afterTotal);
}
#endif
}
@ -538,7 +554,7 @@ std::map<QString, gpu::BufferView> buffer_helpers::gatherBufferViews(graphics::M
}
bool buffer_helpers::recalculateNormals(graphics::MeshPointer mesh) {
bool buffer_helpers::recalculateNormals(graphics::MeshPointer mesh) {
qCInfo(bufferhelper_logging) << "Recalculating normals" << !!mesh;
if (!mesh) {
return false;
@ -605,7 +621,7 @@ bool buffer_helpers::recalculateNormals(graphics::MeshPointer mesh) {
}
break;
}
normals.edit<glm::vec3>(j) = glm::normalize(normal);
buffer_helpers::fromVariant(normals, j, glmVecToVariant(glm::normalize(normal)));
}
return true;
}

View file

@ -42,9 +42,11 @@ struct buffer_helpers {
template <typename T> static gpu::BufferView fromVector(const QVector<T>& elements, const gpu::Element& elementType);
template <typename T> static QVector<T> toVector(const gpu::BufferView& view, const char *hint = "");
template <typename T> static QVector<T> toVector(const gpu::BufferView& view, const char *hint = "");
template <typename T> static T convert(const gpu::BufferView& view, quint32 index, const char* hint = "");
static gpu::BufferView clone(const gpu::BufferView& input);
static gpu::BufferView resize(const gpu::BufferView& input, quint32 numElements);
static gpu::BufferView resize(const gpu::BufferView& input, quint32 numElements);
static void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent);
};

View file

@ -42,8 +42,6 @@ bool bufferViewElementFromScriptValue(const QScriptValue& v, const gpu::BufferVi
return buffer_helpers::fromVariant(view, index, v.toVariant());
}
//
template <typename T>
QScriptValue glmVecToScriptValue(QScriptEngine *js, const T& v, bool asArray) {
static const auto len = T().length();

View file

@ -8,10 +8,12 @@
#include <memory>
#include <DependencyManager.h>
#include <SpatiallyNestable.h>
namespace graphics {
class Mesh;
}
class Model;
using ModelPointer = std::shared_ptr<Model>;
namespace gpu {
class BufferView;
}
@ -83,7 +85,7 @@ namespace scriptable {
// mixin class for Avatar/Entity/Overlay Rendering that expose their in-memory graphics::Meshes
class ModelProvider {
public:
QVariantMap metadata{ { "providerType", "unknown" } };
NestableType modelProviderType;
static scriptable::ScriptableModelBase modelUnavailableError(bool* ok) { if (ok) { *ok = false; } return {}; }
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) = 0;
@ -91,9 +93,13 @@ namespace scriptable {
};
// mixin class for resolving UUIDs into a corresponding ModelProvider
class ModelProviderFactory : public Dependency {
class ModelProviderFactory : public QObject, public Dependency {
Q_OBJECT
public:
virtual scriptable::ModelProviderPointer lookupModelProvider(QUuid uuid) = 0;
virtual scriptable::ModelProviderPointer lookupModelProvider(const QUuid& uuid) = 0;
signals:
void modelAddedToScene(const QUuid& objectID, NestableType nestableType, const ModelPointer& sender);
void modelRemovedFromScene(const QUuid& objectID, NestableType nestableType, const ModelPointer& sender);
};
using uint32 = quint32;
@ -105,3 +111,5 @@ namespace scriptable {
using ScriptableMeshPartPointer = QPointer<ScriptableMeshPart>;
bool registerMetaTypes(QScriptEngine* engine);
}
Q_DECLARE_METATYPE(NestableType)

View file

@ -0,0 +1,160 @@
//
// GraphicsScriptingInterface.cpp
// libraries/script-engine/src
//
// Created by Seth Alves on 2017-1-27.
// Copyright 2017 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 "GraphicsScriptingInterface.h"
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValueIterator>
#include <QtScript/QScriptValue>
#include <QUuid>
#include "BaseScriptEngine.h"
#include "ScriptEngineLogging.h"
#include "OBJWriter.h"
#include <GeometryUtil.h>
#include <shared/QtHelpers.h>
#include <graphics-scripting/DebugNames.h>
#include <graphics-scripting/BufferViewHelpers.h>
#include "BufferViewScripting.h"
#include "ScriptableMesh.h"
#include "GraphicsScriptingUtil.h"
#include "GraphicsScriptingInterface.moc"
#include "RegisteredMetaTypes.h"
GraphicsScriptingInterface::GraphicsScriptingInterface(QObject* parent) : QObject(parent) {
if (auto scriptEngine = qobject_cast<QScriptEngine*>(parent)) {
this->registerMetaTypes(scriptEngine);
}
}
bool GraphicsScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableMeshPointer mesh, int meshIndex, int partIndex) {
auto model = scriptable::make_qtowned<scriptable::ScriptableModel>();
if (mesh) {
model->append(*mesh);
}
return updateMeshes(uuid, model.get());
}
bool GraphicsScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model) {
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? SpatiallyNestable::nestableTypeToString(provider->modelProviderType) : QString();
if (providerType.isEmpty()) {
providerType = "unknown";
}
bool success = false;
if (provider) {
auto scriptableMeshes = provider->getScriptableModel(&success);
if (success) {
const scriptable::ScriptableModelBasePointer base = model->operator scriptable::ScriptableModelBasePointer();
if (base) {
success = provider->replaceScriptableModelMeshPart(base, -1, -1);
}
}
}
return success;
}
QScriptValue GraphicsScriptingInterface::getMeshes(QUuid uuid) {
scriptable::ScriptableModel* meshes{ nullptr };
bool success = false;
QString error;
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
qCDebug(graphics_scripting) << "appProvider" << appProvider.data();
scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? SpatiallyNestable::nestableTypeToString(provider->modelProviderType) : QString();
if (providerType.isEmpty()) {
providerType = "unknown";
}
if (provider) {
auto scriptableMeshes = provider->getScriptableModel(&success);
if (success) {
meshes = scriptable::make_scriptowned<scriptable::ScriptableModel>(scriptableMeshes);
if (meshes->objectName().isEmpty()) {
meshes->setObjectName(providerType+"::meshes");
}
if (meshes->objectID.isNull()) {
meshes->objectID = uuid.toString();
}
meshes->metadata["provider"] = SpatiallyNestable::nestableTypeToString(provider->modelProviderType);
}
}
if (!success) {
error = QString("failed to get meshes from %1 provider for uuid %2").arg(providerType).arg(uuid.toString());
}
QPointer<BaseScriptEngine> scriptEngine = dynamic_cast<BaseScriptEngine*>(engine());
QScriptValue result = error.isEmpty() ? scriptEngine->toScriptValue(meshes) : scriptEngine->makeError(error);
if (result.isError()) {
qCWarning(graphics_scripting) << "GraphicsScriptingInterface::getMeshes ERROR" << result.toString();
if (context()) {
context()->throwValue(error);
} else {
qCWarning(graphics_scripting) << "GraphicsScriptingInterface::getMeshes ERROR" << result.toString();
}
return QScriptValue::NullValue;
}
return scriptEngine->toScriptValue(meshes);
}
QString GraphicsScriptingInterface::meshToOBJ(const scriptable::ScriptableModel& _in) {
const auto& in = _in.getConstMeshes();
if (in.size()) {
QList<scriptable::MeshPointer> meshes;
foreach (auto meshProxy, in) {
if (meshProxy) {
meshes.append(getMeshPointer(meshProxy));
}
}
if (meshes.size()) {
return writeOBJToString(meshes);
}
}
if (context()) {
context()->throwError(QString("null mesh"));
}
return QString();
}
void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
scriptable::registerMetaTypes(engine);
}
MeshPointer GraphicsScriptingInterface::getMeshPointer(const scriptable::ScriptableMesh& meshProxy) {
return meshProxy.getMeshPointer();
}
MeshPointer GraphicsScriptingInterface::getMeshPointer(scriptable::ScriptableMesh& meshProxy) {
return getMeshPointer(&meshProxy);
}
MeshPointer GraphicsScriptingInterface::getMeshPointer(scriptable::ScriptableMeshPointer meshProxy) {
MeshPointer result;
if (!meshProxy) {
if (context()){
context()->throwError("expected meshProxy as first parameter");
} else {
qCDebug(graphics_scripting) << "expected meshProxy as first parameter";
}
return result;
}
auto mesh = meshProxy->getMeshPointer();
if (!mesh) {
if (context()) {
context()->throwError("expected valid meshProxy as first parameter");
} else {
qCDebug(graphics_scripting) << "expected valid meshProxy as first parameter";
}
return result;
}
return mesh;
}

View file

@ -1,16 +1,15 @@
//
// ModelScriptingInterface.h
// libraries/script-engine/src
// GraphicsScriptingInterface.h
// libraries/graphics-scripting/src
//
// Created by Seth Alves on 2017-1-27.
// Copyright 2017 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
//
#ifndef hifi_ModelScriptingInterface_h
#define hifi_ModelScriptingInterface_h
#ifndef hifi_GraphicsScriptingInterface_h
#define hifi_GraphicsScriptingInterface_h
#include <QtCore/QObject>
#include <QUrl>
@ -21,35 +20,27 @@
#include "ScriptableMesh.h"
#include <DependencyManager.h>
class ModelScriptingInterface : public QObject, public QScriptable, public Dependency {
class GraphicsScriptingInterface : public QObject, public QScriptable, public Dependency {
Q_OBJECT
public:
ModelScriptingInterface(QObject* parent = nullptr);
GraphicsScriptingInterface(QObject* parent = nullptr);
public slots:
/**jsdoc
* Returns the meshes associated with a UUID (entityID, overlayID, or avatarID)
*
* @function ModelScriptingInterface.getMeshes
* @function GraphicsScriptingInterface.getMeshes
* @param {EntityID} entityID The ID of the entity whose meshes are to be retrieve
*/
void getMeshes(QUuid uuid, QScriptValue callback);
QScriptValue getMeshes(QUuid uuid);
bool updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model);
bool updateMeshes(QUuid uuid, const scriptable::ScriptableMeshPointer mesh, int meshIndex=0, int partIndex=0);
QString meshToOBJ(const scriptable::ScriptableModel& in);
QScriptValue appendMeshes(scriptable::ScriptableModel in);
QScriptValue transformMesh(scriptable::ScriptableMeshPointer meshProxy, glm::mat4 transform);
QScriptValue newMesh(const QVector<glm::vec3>& vertices,
const QVector<glm::vec3>& normals,
const QVector<mesh::MeshFace>& faces);
QScriptValue getVertexCount(scriptable::ScriptableMeshPointer meshProxy);
QScriptValue getVertex(scriptable::ScriptableMeshPointer meshProxy, quint32 vertexIndex);
static void registerMetaTypes(QScriptEngine* engine);
private:
scriptable::MeshPointer getMeshPointer(scriptable::ScriptableMeshPointer meshProxy);
scriptable::MeshPointer getMeshPointer(scriptable::ScriptableMesh& meshProxy);
@ -57,4 +48,4 @@ private:
};
#endif // hifi_ModelScriptingInterface_h
#endif // hifi_GraphicsScriptingInterface_h

View file

@ -1,407 +0,0 @@
//
// ModelScriptingInterface.cpp
// libraries/script-engine/src
//
// Created by Seth Alves on 2017-1-27.
// Copyright 2017 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 "ModelScriptingInterface.h"
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValueIterator>
#include <QtScript/QScriptValue>
#include <QUuid>
#include "BaseScriptEngine.h"
#include "ScriptEngineLogging.h"
#include "OBJWriter.h"
#include <GeometryUtil.h>
#include <shared/QtHelpers.h>
#include <graphics-scripting/DebugNames.h>
#include <graphics-scripting/BufferViewHelpers.h>
#include "BufferViewScripting.h"
#include "ScriptableMesh.h"
#include "GraphicsScriptingUtil.h"
#include "ModelScriptingInterface.moc"
#include "RegisteredMetaTypes.h"
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
if (auto scriptEngine = qobject_cast<QScriptEngine*>(parent)) {
this->registerMetaTypes(scriptEngine);
}
}
bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableMeshPointer mesh, int meshIndex, int partIndex) {
auto model = scriptable::make_qtowned<scriptable::ScriptableModel>();
if (mesh) {
model->append(*mesh);
}
return updateMeshes(uuid, model.get());
}
bool ModelScriptingInterface::updateMeshes(QUuid uuid, const scriptable::ScriptableModelPointer model) {
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
//qCDebug(graphics_scripting) << "appProvider" << appProvider.data();
scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? provider->metadata.value("providerType").toString() : QString();
if (providerType.isEmpty()) {
providerType = "unknown";
}
bool success = false;
if (provider) {
//qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
auto scriptableMeshes = provider->getScriptableModel(&success);
//qCDebug(graphics_scripting) << "//fetched meshes from " << providerType << "success:" <<success << "#" << scriptableMeshes.meshes.size();
if (success) {
const scriptable::ScriptableModelBasePointer base = model->operator scriptable::ScriptableModelBasePointer();
//qCDebug(graphics_scripting) << "as base" << base;
if (base) {
//auto meshes = model->getConstMeshes();
success = provider->replaceScriptableModelMeshPart(base, -1, -1);
// for (uint32_t m = 0; success && m < meshes.size(); m++) {
// const auto& mesh = meshes.at(m);
// for (int p = 0; success && p < mesh->getNumParts(); p++) {
// qCDebug(graphics_scripting) << "provider->replaceScriptableModelMeshPart" << "meshIndex" << m << "partIndex" << p;
// success = provider->replaceScriptableModelMeshPart(base, m, p);
// //if (!success) {
// qCDebug(graphics_scripting) << "//provider->replaceScriptableModelMeshPart" << "meshIndex" << m << "partIndex" << p << success;
// }
// }
}
}
}
return success;
}
void ModelScriptingInterface::getMeshes(QUuid uuid, QScriptValue callback) {
auto handler = scriptable::jsBindCallback(callback);
Q_ASSERT(handler.engine() == this->engine());
QPointer<BaseScriptEngine> engine = dynamic_cast<BaseScriptEngine*>(handler.engine());
scriptable::ScriptableModel* meshes{ nullptr };
bool success = false;
QString error;
auto appProvider = DependencyManager::get<scriptable::ModelProviderFactory>();
qCDebug(graphics_scripting) << "appProvider" << appProvider.data();
scriptable::ModelProviderPointer provider = appProvider ? appProvider->lookupModelProvider(uuid) : nullptr;
QString providerType = provider ? provider->metadata.value("providerType").toString() : QString();
if (providerType.isEmpty()) {
providerType = "unknown";
}
if (provider) {
qCDebug(graphics_scripting) << "fetching meshes from " << providerType << "...";
auto scriptableMeshes = provider->getScriptableModel(&success);
qCDebug(graphics_scripting) << "//fetched meshes from " << providerType << "success:" <<success << "#" << scriptableMeshes.meshes.size();
if (success) {
meshes = scriptable::make_scriptowned<scriptable::ScriptableModel>(scriptableMeshes);
QString debugString = scriptable::toDebugString(meshes);
QObject::connect(meshes, &QObject::destroyed, this, [=]() {
qCDebug(graphics_scripting) << "///fetched meshes" << debugString;
});
if (meshes->objectName().isEmpty()) {
meshes->setObjectName(providerType+"::meshes");
}
if (meshes->objectID.isNull()) {
meshes->objectID = uuid.toString();
}
meshes->metadata["provider"] = provider->metadata;
}
}
if (!success) {
error = QString("failed to get meshes from %1 provider for uuid %2").arg(providerType).arg(uuid.toString());
}
if (!error.isEmpty()) {
qCWarning(graphics_scripting) << "ModelScriptingInterface::getMeshes ERROR" << error;
callScopedHandlerObject(handler, engine->makeError(error), QScriptValue::NullValue);
} else {
callScopedHandlerObject(handler, QScriptValue::NullValue, engine->toScriptValue(meshes));
}
}
QString ModelScriptingInterface::meshToOBJ(const scriptable::ScriptableModel& _in) {
const auto& in = _in.getConstMeshes();
qCDebug(graphics_scripting) << "meshToOBJ" << in.size();
if (in.size()) {
QList<scriptable::MeshPointer> meshes;
foreach (auto meshProxy, in) {
qCDebug(graphics_scripting) << "meshToOBJ" << meshProxy;
if (meshProxy) {
meshes.append(getMeshPointer(meshProxy));
}
}
if (meshes.size()) {
return writeOBJToString(meshes);
}
}
context()->throwError(QString("null mesh"));
return QString();
}
QScriptValue ModelScriptingInterface::appendMeshes(scriptable::ScriptableModel _in) {
const auto& in = _in.getMeshes();
// figure out the size of the resulting mesh
size_t totalVertexCount { 0 };
size_t totalColorCount { 0 };
size_t totalNormalCount { 0 };
size_t totalIndexCount { 0 };
foreach (auto& meshProxy, in) {
scriptable::MeshPointer mesh = getMeshPointer(meshProxy);
totalVertexCount += mesh->getNumVertices();
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(attributeTypeColor);
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
totalColorCount += numColors;
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
totalNormalCount += numNormals;
totalIndexCount += mesh->getNumIndices();
}
// alloc the resulting mesh
gpu::Resource::Size combinedVertexSize = totalVertexCount * sizeof(glm::vec3);
unsigned char* combinedVertexData = new unsigned char[combinedVertexSize];
unsigned char* combinedVertexDataCursor = combinedVertexData;
gpu::Resource::Size combinedColorSize = totalColorCount * sizeof(glm::vec3);
unsigned char* combinedColorData = new unsigned char[combinedColorSize];
unsigned char* combinedColorDataCursor = combinedColorData;
gpu::Resource::Size combinedNormalSize = totalNormalCount * sizeof(glm::vec3);
unsigned char* combinedNormalData = new unsigned char[combinedNormalSize];
unsigned char* combinedNormalDataCursor = combinedNormalData;
gpu::Resource::Size combinedIndexSize = totalIndexCount * sizeof(uint32_t);
unsigned char* combinedIndexData = new unsigned char[combinedIndexSize];
unsigned char* combinedIndexDataCursor = combinedIndexData;
uint32_t indexStartOffset { 0 };
foreach (const auto& meshProxy, in) {
scriptable::MeshPointer mesh = getMeshPointer(meshProxy);
mesh->forEach(
[&](glm::vec3 position){
memcpy(combinedVertexDataCursor, &position, sizeof(position));
combinedVertexDataCursor += sizeof(position);
},
[&](glm::vec3 color){
memcpy(combinedColorDataCursor, &color, sizeof(color));
combinedColorDataCursor += sizeof(color);
},
[&](glm::vec3 normal){
memcpy(combinedNormalDataCursor, &normal, sizeof(normal));
combinedNormalDataCursor += sizeof(normal);
},
[&](uint32_t index){
index += indexStartOffset;
memcpy(combinedIndexDataCursor, &index, sizeof(index));
combinedIndexDataCursor += sizeof(index);
});
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
indexStartOffset += numVertices;
}
graphics::MeshPointer result(new graphics::Mesh());
gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedVertexBuffer = new gpu::Buffer(combinedVertexSize, combinedVertexData);
gpu::BufferPointer combinedVertexBufferPointer(combinedVertexBuffer);
gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement);
result->setVertexBuffer(combinedVertexBufferView);
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedColorsBuffer = new gpu::Buffer(combinedColorSize, combinedColorData);
gpu::BufferPointer combinedColorsBufferPointer(combinedColorsBuffer);
gpu::BufferView combinedColorsBufferView(combinedColorsBufferPointer, colorElement);
result->addAttribute(attributeTypeColor, combinedColorsBufferView);
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData);
gpu::BufferPointer combinedNormalsBufferPointer(combinedNormalsBuffer);
gpu::BufferView combinedNormalsBufferView(combinedNormalsBufferPointer, normalElement);
result->addAttribute(attributeTypeNormal, combinedNormalsBufferView);
gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW);
gpu::Buffer* combinedIndexesBuffer = new gpu::Buffer(combinedIndexSize, combinedIndexData);
gpu::BufferPointer combinedIndexesBufferPointer(combinedIndexesBuffer);
gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement);
result->setIndexBuffer(combinedIndexesBufferView);
std::vector<graphics::Mesh::Part> parts;
parts.emplace_back(graphics::Mesh::Part((graphics::Index)0, // startIndex
(graphics::Index)result->getNumIndices(), // numIndices
(graphics::Index)0, // baseVertex
graphics::Mesh::TRIANGLES)); // topology
result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part),
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
return engine()->toScriptValue(scriptable::make_scriptowned<scriptable::ScriptableMesh>(result));
}
QScriptValue ModelScriptingInterface::transformMesh(scriptable::ScriptableMeshPointer meshProxy, glm::mat4 transform) {
auto mesh = getMeshPointer(meshProxy);
if (!mesh) {
return false;
}
graphics::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[&](glm::vec3 color){ return color; },
[&](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); },
[&](uint32_t index){ return index; });
return engine()->toScriptValue(scriptable::make_scriptowned<scriptable::ScriptableMesh>(result));
}
QScriptValue ModelScriptingInterface::getVertexCount(scriptable::ScriptableMeshPointer meshProxy) {
auto mesh = getMeshPointer(meshProxy);
if (!mesh) {
return -1;
}
return (uint32_t)mesh->getNumVertices();
}
QScriptValue ModelScriptingInterface::getVertex(scriptable::ScriptableMeshPointer meshProxy, quint32 vertexIndex) {
auto mesh = getMeshPointer(meshProxy);
if (!mesh) {
return QScriptValue();
}
const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer();
auto numVertices = mesh->getNumVertices();
if (vertexIndex >= numVertices) {
context()->throwError(QString("invalid index: %1 [0,%2)").arg(vertexIndex).arg(numVertices));
return QScriptValue::NullValue;
}
glm::vec3 pos = vertexBufferView.get<glm::vec3>(vertexIndex);
return engine()->toScriptValue(pos);
}
QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices,
const QVector<glm::vec3>& normals,
const QVector<mesh::MeshFace>& faces) {
graphics::MeshPointer mesh(new graphics::Mesh());
// vertices
auto vertexBuffer = std::make_shared<gpu::Buffer>(vertices.size() * sizeof(glm::vec3), (gpu::Byte*)vertices.data());
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
gpu::BufferView vertexBufferView(vertexBufferPtr, 0, vertexBufferPtr->getSize(),
sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh->setVertexBuffer(vertexBufferView);
if (vertices.size() == normals.size()) {
// normals
auto normalBuffer = std::make_shared<gpu::Buffer>(normals.size() * sizeof(glm::vec3), (gpu::Byte*)normals.data());
auto normalBufferPtr = gpu::BufferPointer(normalBuffer);
gpu::BufferView normalBufferView(normalBufferPtr, 0, normalBufferPtr->getSize(),
sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh->addAttribute(gpu::Stream::NORMAL, normalBufferView);
} else {
qCWarning(graphics_scripting, "ModelScriptingInterface::newMesh normals must be same length as vertices");
}
// indices (faces)
int VERTICES_PER_TRIANGLE = 3;
int indexBufferSize = faces.size() * sizeof(uint32_t) * VERTICES_PER_TRIANGLE;
unsigned char* indexData = new unsigned char[indexBufferSize];
unsigned char* indexDataCursor = indexData;
foreach(const mesh::MeshFace& meshFace, faces) {
for (int i = 0; i < VERTICES_PER_TRIANGLE; i++) {
memcpy(indexDataCursor, &meshFace.vertexIndices[i], sizeof(uint32_t));
indexDataCursor += sizeof(uint32_t);
}
}
auto indexBuffer = std::make_shared<gpu::Buffer>(indexBufferSize, (gpu::Byte*)indexData);
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
gpu::BufferView indexBufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW));
mesh->setIndexBuffer(indexBufferView);
// parts
std::vector<graphics::Mesh::Part> parts;
parts.emplace_back(graphics::Mesh::Part((graphics::Index)0, // startIndex
(graphics::Index)faces.size() * 3, // numIndices
(graphics::Index)0, // baseVertex
graphics::Mesh::TRIANGLES)); // topology
mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part),
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
return engine()->toScriptValue(scriptable::make_scriptowned<scriptable::ScriptableMesh>(mesh));
}
namespace {
// FIXME: MESHFACES:
// QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const mesh::MeshFace &meshFace) {
// QScriptValue obj = engine->newObject();
// obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices));
// return obj;
// }
// void meshFaceFromScriptValue(const QScriptValue &object, mesh::MeshFace& meshFaceResult) {
// qScriptValueToSequence(object.property("vertices"), meshFaceResult.vertexIndices);
// }
// QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<mesh::MeshFace>& vector) {
// return qScriptValueFromSequence(engine, vector);
// }
// void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<mesh::MeshFace>& result) {
// qScriptValueToSequence(array, result);
// }
}
void ModelScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
scriptable::registerMetaTypes(engine);
// FIXME: MESHFACES: remove if MeshFace is not needed anywhere
// qScriptRegisterSequenceMetaType<mesh::MeshFaces>(engine);
// qScriptRegisterMetaType(engine, meshFaceToScriptValue, meshFaceFromScriptValue);
// qScriptRegisterMetaType(engine, qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue);
}
MeshPointer ModelScriptingInterface::getMeshPointer(const scriptable::ScriptableMesh& meshProxy) {
return meshProxy.getMeshPointer();
}
MeshPointer ModelScriptingInterface::getMeshPointer(scriptable::ScriptableMesh& meshProxy) {
return getMeshPointer(&meshProxy);
}
MeshPointer ModelScriptingInterface::getMeshPointer(scriptable::ScriptableMeshPointer meshProxy) {
MeshPointer result;
if (!meshProxy) {
if (context()){
context()->throwError("expected meshProxy as first parameter");
} else {
qCDebug(graphics_scripting) << "expected meshProxy as first parameter";
}
return result;
}
auto mesh = meshProxy->getMeshPointer();
if (!mesh) {
if (context()) {
context()->throwError("expected valid meshProxy as first parameter");
} else {
qCDebug(graphics_scripting) << "expected valid meshProxy as first parameter";
}
return result;
}
return mesh;
}

View file

@ -38,6 +38,7 @@ scriptable::ScriptableModelBase::~ScriptableModelBase() {
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 };

View file

@ -16,7 +16,6 @@ namespace scriptable {
ScriptableModel(const ScriptableModel& other) : ScriptableModelBase(other) {}
ScriptableModel(const ScriptableModelBase& other) : ScriptableModelBase(other) {}
ScriptableModel& operator=(const ScriptableModelBase& view) { ScriptableModelBase::operator=(view); return *this; }
//virtual ~ScriptableModel() { qDebug() << "~ScriptableModel" << this; }
Q_INVOKABLE scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap());
// TODO: in future accessors for these could go here

View file

@ -0,0 +1,27 @@
//
// SimpleMeshProxy.cpp
// libraries/model-networking/src/model-networking/
//
// Created by Seth Alves on 2017-3-22.
// Copyright 2017 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 "SimpleMeshProxy.h"
#include <graphics/Geometry.h>
MeshPointer SimpleMeshProxy::getMeshPointer() const {
return _mesh;
}
int SimpleMeshProxy::getNumVertices() const {
return (int)_mesh->getNumVertices();
}
glm::vec3 SimpleMeshProxy::getPos3(int index) const {
return _mesh->getPos3(index);
}

View file

@ -0,0 +1,36 @@
//
// SimpleMeshProxy.h
// libraries/model-networking/src/model-networking/
//
// Created by Seth Alves on 2017-1-27.
// Copyright 2017 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
//
#ifndef hifi_SimpleMeshProxy_h
#define hifi_SimpleMeshProxy_h
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QtScript/QScriptValue>
#include <RegisteredMetaTypes.h>
class SimpleMeshProxy : public MeshProxy {
public:
SimpleMeshProxy(const MeshPointer& mesh) : _mesh(mesh) { }
MeshPointer getMeshPointer() const override;
int getNumVertices() const override;
glm::vec3 getPos3(int index) const override;
protected:
const MeshPointer _mesh;
};
#endif // hifi_SimpleMeshProxy_h

View file

@ -1318,7 +1318,6 @@ void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, in
renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id);
}
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
const glm::vec4& color, int id) {

View file

@ -31,6 +31,7 @@ namespace { QLoggingCategory wtf{ "tim.Model.cpp" }; }
#include <TBBHelpers.h>
#include <graphics-scripting/Forward.h>
#include <graphics-scripting/BufferViewHelpers.h>
#include <DualQuaternion.h>
#include <glm/gtc/packing.hpp>
@ -333,34 +334,6 @@ void Model::reset() {
}
}
#if FBX_PACK_NORMALS
static void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) {
auto absNormal = glm::abs(normal);
auto absTangent = glm::abs(tangent);
normal /= glm::max(1e-6f, glm::max(glm::max(absNormal.x, absNormal.y), absNormal.z));
tangent /= glm::max(1e-6f, glm::max(glm::max(absTangent.x, absTangent.y), absTangent.z));
normal = glm::clamp(normal, -1.0f, 1.0f);
tangent = glm::clamp(tangent, -1.0f, 1.0f);
normal *= 511.0f;
tangent *= 511.0f;
normal = glm::round(normal);
tangent = glm::round(tangent);
glm::detail::i10i10i10i2 normalStruct;
glm::detail::i10i10i10i2 tangentStruct;
normalStruct.data.x = int(normal.x);
normalStruct.data.y = int(normal.y);
normalStruct.data.z = int(normal.z);
normalStruct.data.w = 0;
tangentStruct.data.x = int(tangent.x);
tangentStruct.data.y = int(tangent.y);
tangentStruct.data.z = int(tangent.z);
tangentStruct.data.w = 0;
packedNormal = normalStruct.pack;
packedTangent = tangentStruct.pack;
}
#endif
bool Model::updateGeometry() {
bool needFullUpdate = false;
@ -591,23 +564,26 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe
// 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;
);
//_needsUpdateTextures = true;
_visualGeometryRequestFailed = false;
invalidCalculatedMeshBoxes();
//invalidCalculatedMeshBoxes();
deleteGeometry();
_renderGeometry.reset(newRenderGeometry);
onInvalidate();
reset();
//onInvalidate();
//reset();
_rig.destroyAnimGraph();
assert(_rig.jointStatesEmpty());
//assert(_rig.jointStatesEmpty());
updateGeometry();
calculateTriangleSets();
computeMeshPartLocalBounds();
_needsReload = false;
//computeMeshPartLocalBounds();
//_needsReload = false;
_needsFixupInScene = true;
invalidCalculatedMeshBoxes();
//invalidCalculatedMeshBoxes();
setRenderItemsNeedUpdate();
//_hasCalculatedTextureInfo = false;
//calculateTextureInfo();
//updateRenderItems();
}
return true;
}
@ -615,7 +591,6 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe
scriptable::ScriptableModelBase Model::getScriptableModel(bool* ok) {
QMutexLocker lock(&_mutex);
scriptable::ScriptableModelBase result;
const Geometry::Pointer& renderGeometry = getGeometry();
if (!isLoaded()) {
qCDebug(wtf) << "Model::getScriptableModel -- !isLoaded";
@ -623,107 +598,26 @@ scriptable::ScriptableModelBase Model::getScriptableModel(bool* ok) {
}
const FBXGeometry& geometry = getFBXGeometry();
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
glm::mat4 offsetMat = offset.getMatrix();
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
result.metadata = {
{ "url", _url.toString() },
{ "textures", renderGeometry->getTextures() },
{ "offset", vec3toVariant(_offset) },
{ "scale", vec3toVariant(getScale()) },
{ "rotation", quatToVariant(getRotation()) },
{ "translation", vec3toVariant(getTranslation()) },
{ "meshToModel", buffer_helpers::toVariant(meshToModelMatrix) },
{ "meshToWorld", buffer_helpers::toVariant(meshToWorldMatrix) },
{ "geometryOffset", buffer_helpers::toVariant(geometry.offset) },
{ "naturalDimensions", vec3toVariant(getNaturalDimensions()) },
{ "meshExtents", buffer_helpers::toVariant(getMeshExtents()) },
{ "unscaledMeshExtents", buffer_helpers::toVariant(getUnscaledMeshExtents()) },
{ "meshBound", buffer_helpers::toVariant(Extents(getRenderableMeshBound())) },
{ "bindExtents", buffer_helpers::toVariant(getBindExtents()) },
{ "offsetMat", buffer_helpers::toVariant(offsetMat) },
{ "transform", buffer_helpers::toVariant(getTransform().getMatrix()) },
};
{
Transform transform;
transform.setScale(getScale());
transform.setTranslation(getTranslation());
transform.setRotation(getRotation());
result.metadata["_transform"] = buffer_helpers::toVariant(transform.getMatrix());
}
{
glm::vec3 position = _translation;
glm::mat4 rotation = glm::mat4_cast(_rotation);
glm::mat4 translation = glm::translate(position);
glm::mat4 modelToWorldMatrix = translation * rotation;
//glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
result.metadata["_modelToWorld"] = buffer_helpers::toVariant(modelToWorldMatrix);
}
{
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
//glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
result.metadata["_meshToWorld"] = buffer_helpers::toVariant(meshToWorldMatrix);
}
{
Transform transform;
transform.setTranslation(_translation);
transform.setRotation(_rotation);
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
Transform output;
Transform::mult( output, transform, offset);
result.metadata["_renderTransform"] = buffer_helpers::toVariant(output.getMatrix());
}
QVariantList submeshes;
int numberOfMeshes = geometry.meshes.size();
for (int i = 0; i < numberOfMeshes; i++) {
const FBXMesh& fbxMesh = geometry.meshes.at(i);
auto mesh = fbxMesh._mesh;
if (!mesh) {
continue;
if (auto mesh = fbxMesh._mesh) {
auto name = geometry.getModelNameOfMesh(i);
result.append(std::const_pointer_cast<graphics::Mesh>(mesh), {
{ "index", i },
{ "name", name },
{ "meshIndex", fbxMesh.meshIndex },
{ "displayName", QString::fromStdString(mesh->displayName) },
{ "modelName", QString::fromStdString(mesh->modelName) },
{ "modelTransform", buffer_helpers::toVariant(fbxMesh.modelTransform) },
{ "transform", buffer_helpers::toVariant(geometry.offset * fbxMesh.modelTransform) },
{ "extents", buffer_helpers::toVariant(fbxMesh.meshExtents) },
});
}
auto name = geometry.getModelNameOfMesh(i);
qCDebug(wtf) << "Model::getScriptableModel #" << i << QString::fromStdString(mesh->displayName) << name;
const AABox& box = _modelSpaceMeshTriangleSets.value(i).getBounds();
AABox hardbounds;
auto meshTransform = geometry.offset * fbxMesh.modelTransform;
for (const auto& v : fbxMesh.vertices) {
hardbounds += glm::vec3(meshTransform * glm::vec4(v,1));
}
QVariantList renderIDs;
for (uint32_t m = 0; m < _modelMeshRenderItemIDs.size(); m++) {
auto meshIndex = _modelMeshRenderItemShapes.size() > m ? _modelMeshRenderItemShapes.at(m).meshIndex : -1;
if (meshIndex == i) {
renderIDs << _modelMeshRenderItemIDs[m];
break;
}
}
result.append(std::const_pointer_cast<graphics::Mesh>(mesh), {
{ "index", i },
{ "name", name },
{ "renderIDs", renderIDs },
{ "meshIndex", fbxMesh.meshIndex },
{ "displayName", QString::fromStdString(mesh->displayName) },
{ "modelName", QString::fromStdString(mesh->modelName) },
{ "modelTransform", buffer_helpers::toVariant(fbxMesh.modelTransform) },
{ "transform", buffer_helpers::toVariant(geometry.offset * fbxMesh.modelTransform) },
{ "extents", buffer_helpers::toVariant(fbxMesh.meshExtents) },
{ "bounds", buffer_helpers::toVariant(Extents(box)) },
{ "hardbounds", buffer_helpers::toVariant(Extents(hardbounds)) },
});
}
if (ok) {
*ok = true;
}
qCDebug(wtf) << "//Model::getScriptableModel -- #" << result.meshes.size();
result.metadata["submeshes"] = submeshes;
return result;
}
@ -1458,7 +1352,7 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo
#if FBX_PACK_NORMALS
glm::uint32 finalNormal;
glm::uint32 finalTangent;
packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
#else
const auto finalNormal = *normalIt;
const auto finalTangent = *tangentIt;
@ -1481,7 +1375,7 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo
#if FBX_PACK_NORMALS
glm::uint32 finalNormal;
glm::uint32 finalTangent;
packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
#else
const auto finalNormal = *normalIt;
const auto finalTangent = *tangentIt;
@ -1555,7 +1449,7 @@ void Model::createVisibleRenderItemSet() {
// all of our mesh vectors must match in size
if (meshes.size() != _meshStates.size()) {
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! " << meshes.size() << _meshStates.size() << " We will not segregate mesh groups yet.";
return;
}

View file

@ -140,7 +140,7 @@ public:
/// Returns a reference to the shared collision geometry.
const Geometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
const QVariantMap getTextures() const { assert(isLoaded()); return getGeometry()->getTextures(); }
Q_INVOKABLE virtual void setTextures(const QVariantMap& textures);
/// Provided as a convenience, will crash if !isLoaded()
@ -314,7 +314,7 @@ public:
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); }
Q_INVOKABLE virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
virtual scriptable::ScriptableModelBase getScriptableModel(bool* ok = nullptr) override;
virtual bool replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointer model, int meshIndex, int partIndex) override;
void scaleToFit();
@ -407,7 +407,7 @@ protected:
int _blendNumber;
int _appliedBlendNumber;
QMutex _mutex;
mutable QMutex _mutex{ QMutex::Recursive };
bool _overrideModelTransform { false };
bool _triangleSetsValid { false };

View file

@ -0,0 +1,251 @@
//
// ModelScriptingInterface.cpp
// libraries/script-engine/src
//
// Created by Seth Alves on 2017-1-27.
// Copyright 2017 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 "ModelScriptingInterface.h"
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QtScript/QScriptValue>
#include <model-networking/SimpleMeshProxy.h>
#include "ScriptEngine.h"
#include "ScriptEngineLogging.h"
#include "OBJWriter.h"
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
_modelScriptEngine = qobject_cast<QScriptEngine*>(parent);
qScriptRegisterSequenceMetaType<QList<MeshProxy*>>(_modelScriptEngine);
qScriptRegisterMetaType(_modelScriptEngine, meshFaceToScriptValue, meshFaceFromScriptValue);
qScriptRegisterMetaType(_modelScriptEngine, qVectorMeshFaceToScriptValue, qVectorMeshFaceFromScriptValue);
}
QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
QList<MeshPointer> meshes;
foreach (const MeshProxy* meshProxy, in) {
meshes.append(meshProxy->getMeshPointer());
}
return writeOBJToString(meshes);
}
QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
// figure out the size of the resulting mesh
size_t totalVertexCount { 0 };
size_t totalColorCount { 0 };
size_t totalNormalCount { 0 };
size_t totalIndexCount { 0 };
foreach (const MeshProxy* meshProxy, in) {
MeshPointer mesh = meshProxy->getMeshPointer();
totalVertexCount += mesh->getNumVertices();
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(attributeTypeColor);
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
totalColorCount += numColors;
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
totalNormalCount += numNormals;
totalIndexCount += mesh->getNumIndices();
}
// alloc the resulting mesh
gpu::Resource::Size combinedVertexSize = totalVertexCount * sizeof(glm::vec3);
std::unique_ptr<unsigned char> combinedVertexData{ new unsigned char[combinedVertexSize] };
unsigned char* combinedVertexDataCursor = combinedVertexData.get();
gpu::Resource::Size combinedColorSize = totalColorCount * sizeof(glm::vec3);
std::unique_ptr<unsigned char> combinedColorData{ new unsigned char[combinedColorSize] };
unsigned char* combinedColorDataCursor = combinedColorData.get();
gpu::Resource::Size combinedNormalSize = totalNormalCount * sizeof(glm::vec3);
std::unique_ptr<unsigned char> combinedNormalData{ new unsigned char[combinedNormalSize] };
unsigned char* combinedNormalDataCursor = combinedNormalData.get();
gpu::Resource::Size combinedIndexSize = totalIndexCount * sizeof(uint32_t);
std::unique_ptr<unsigned char> combinedIndexData{ new unsigned char[combinedIndexSize] };
unsigned char* combinedIndexDataCursor = combinedIndexData.get();
uint32_t indexStartOffset { 0 };
foreach (const MeshProxy* meshProxy, in) {
MeshPointer mesh = meshProxy->getMeshPointer();
mesh->forEach(
[&](glm::vec3 position){
memcpy(combinedVertexDataCursor, &position, sizeof(position));
combinedVertexDataCursor += sizeof(position);
},
[&](glm::vec3 color){
memcpy(combinedColorDataCursor, &color, sizeof(color));
combinedColorDataCursor += sizeof(color);
},
[&](glm::vec3 normal){
memcpy(combinedNormalDataCursor, &normal, sizeof(normal));
combinedNormalDataCursor += sizeof(normal);
},
[&](uint32_t index){
index += indexStartOffset;
memcpy(combinedIndexDataCursor, &index, sizeof(index));
combinedIndexDataCursor += sizeof(index);
});
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
indexStartOffset += numVertices;
}
graphics::MeshPointer result(new graphics::Mesh());
gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedVertexBuffer = new gpu::Buffer(combinedVertexSize, combinedVertexData.get());
gpu::BufferPointer combinedVertexBufferPointer(combinedVertexBuffer);
gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement);
result->setVertexBuffer(combinedVertexBufferView);
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedColorsBuffer = new gpu::Buffer(combinedColorSize, combinedColorData.get());
gpu::BufferPointer combinedColorsBufferPointer(combinedColorsBuffer);
gpu::BufferView combinedColorsBufferView(combinedColorsBufferPointer, colorElement);
result->addAttribute(attributeTypeColor, combinedColorsBufferView);
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData.get());
gpu::BufferPointer combinedNormalsBufferPointer(combinedNormalsBuffer);
gpu::BufferView combinedNormalsBufferView(combinedNormalsBufferPointer, normalElement);
result->addAttribute(attributeTypeNormal, combinedNormalsBufferView);
gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW);
gpu::Buffer* combinedIndexesBuffer = new gpu::Buffer(combinedIndexSize, combinedIndexData.get());
gpu::BufferPointer combinedIndexesBufferPointer(combinedIndexesBuffer);
gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement);
result->setIndexBuffer(combinedIndexesBufferView);
std::vector<graphics::Mesh::Part> parts;
parts.emplace_back(graphics::Mesh::Part((graphics::Index)0, // startIndex
(graphics::Index)result->getNumIndices(), // numIndices
(graphics::Index)0, // baseVertex
graphics::Mesh::TRIANGLES)); // topology
result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part),
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
MeshProxy* resultProxy = new SimpleMeshProxy(result);
return meshToScriptValue(_modelScriptEngine, resultProxy);
}
QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) {
if (!meshProxy) {
return QScriptValue(false);
}
MeshPointer mesh = meshProxy->getMeshPointer();
if (!mesh) {
return QScriptValue(false);
}
const auto inverseTransposeTransform = glm::inverse(glm::transpose(transform));
graphics::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[&](glm::vec3 color){ return color; },
[&](glm::vec3 normal){ return glm::vec3(inverseTransposeTransform * glm::vec4(normal, 0.0f)); },
[&](uint32_t index){ return index; });
MeshProxy* resultProxy = new SimpleMeshProxy(result);
return meshToScriptValue(_modelScriptEngine, resultProxy);
}
QScriptValue ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) {
if (!meshProxy) {
return QScriptValue(false);
}
MeshPointer mesh = meshProxy->getMeshPointer();
if (!mesh) {
return QScriptValue(false);
}
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
return numVertices;
}
QScriptValue ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) {
if (!meshProxy) {
return QScriptValue(false);
}
MeshPointer mesh = meshProxy->getMeshPointer();
if (!mesh) {
return QScriptValue(false);
}
const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer();
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
if (vertexIndex < 0 || vertexIndex >= numVertices) {
return QScriptValue(false);
}
glm::vec3 pos = vertexBufferView.get<glm::vec3>(vertexIndex);
return vec3toScriptValue(_modelScriptEngine, pos);
}
QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices,
const QVector<glm::vec3>& normals,
const QVector<MeshFace>& faces) {
graphics::MeshPointer mesh(new graphics::Mesh());
// vertices
auto vertexBuffer = std::make_shared<gpu::Buffer>(vertices.size() * sizeof(glm::vec3), (gpu::Byte*)vertices.data());
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
gpu::BufferView vertexBufferView(vertexBufferPtr, 0, vertexBufferPtr->getSize(),
sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh->setVertexBuffer(vertexBufferView);
if (vertices.size() == normals.size()) {
// normals
auto normalBuffer = std::make_shared<gpu::Buffer>(normals.size() * sizeof(glm::vec3), (gpu::Byte*)normals.data());
auto normalBufferPtr = gpu::BufferPointer(normalBuffer);
gpu::BufferView normalBufferView(normalBufferPtr, 0, normalBufferPtr->getSize(),
sizeof(glm::vec3), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
mesh->addAttribute(gpu::Stream::NORMAL, normalBufferView);
} else {
qCDebug(scriptengine) << "ModelScriptingInterface::newMesh normals must be same length as vertices";
}
// indices (faces)
int VERTICES_PER_TRIANGLE = 3;
int indexBufferSize = faces.size() * sizeof(uint32_t) * VERTICES_PER_TRIANGLE;
unsigned char* indexData = new unsigned char[indexBufferSize];
unsigned char* indexDataCursor = indexData;
foreach(const MeshFace& meshFace, faces) {
for (int i = 0; i < VERTICES_PER_TRIANGLE; i++) {
memcpy(indexDataCursor, &meshFace.vertexIndices[i], sizeof(uint32_t));
indexDataCursor += sizeof(uint32_t);
}
}
auto indexBuffer = std::make_shared<gpu::Buffer>(indexBufferSize, (gpu::Byte*)indexData);
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
gpu::BufferView indexBufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW));
mesh->setIndexBuffer(indexBufferView);
// parts
std::vector<graphics::Mesh::Part> parts;
parts.emplace_back(graphics::Mesh::Part((graphics::Index)0, // startIndex
(graphics::Index)faces.size() * 3, // numIndices
(graphics::Index)0, // baseVertex
graphics::Mesh::TRIANGLES)); // topology
mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part),
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
MeshProxy* meshProxy = new SimpleMeshProxy(mesh);
return meshToScriptValue(_modelScriptEngine, meshProxy);
}

View file

@ -0,0 +1,39 @@
//
// ModelScriptingInterface.h
// libraries/script-engine/src
//
// Created by Seth Alves on 2017-1-27.
// Copyright 2017 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
//
#ifndef hifi_ModelScriptingInterface_h
#define hifi_ModelScriptingInterface_h
#include <QtCore/QObject>
#include <RegisteredMetaTypes.h>
class QScriptEngine;
class ModelScriptingInterface : public QObject {
Q_OBJECT
public:
ModelScriptingInterface(QObject* parent);
Q_INVOKABLE QString meshToOBJ(MeshProxyList in);
Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in);
Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy);
Q_INVOKABLE QScriptValue newMesh(const QVector<glm::vec3>& vertices,
const QVector<glm::vec3>& normals,
const QVector<MeshFace>& faces);
Q_INVOKABLE QScriptValue getVertexCount(MeshProxy* meshProxy);
Q_INVOKABLE QScriptValue getVertex(MeshProxy* meshProxy, int vertexIndex);
private:
QScriptEngine* _modelScriptEngine { nullptr };
};
#endif // hifi_ModelScriptingInterface_h

View file

@ -73,6 +73,8 @@
#include "WebSocketClass.h"
#include "RecordingScriptingInterface.h"
#include "ScriptEngines.h"
#include "ModelScriptingInterface.h"
#include <Profile.h>
@ -709,6 +711,10 @@ void ScriptEngine::init() {
registerGlobalObject("DebugDraw", &DebugDraw::getInstance());
registerGlobalObject("Model", new ModelScriptingInterface(this));
qScriptRegisterMetaType(this, meshToScriptValue, meshFromScriptValue);
qScriptRegisterMetaType(this, meshesToScriptValue, meshesFromScriptValue);
registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
}

View file

@ -855,3 +855,68 @@ QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const Animatio
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& details) {
// nothing for now...
}
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
return engine->newQObject(in, QScriptEngine::QtOwnership,
QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
}
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) {
out = qobject_cast<MeshProxy*>(value.toQObject());
}
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) {
// QScriptValueList result;
QScriptValue result = engine->newArray();
int i = 0;
foreach(MeshProxy* const meshProxy, in) {
result.setProperty(i++, meshToScriptValue(engine, meshProxy));
}
return result;
}
void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) {
QScriptValueIterator itr(value);
qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32();
while (itr.hasNext()) {
itr.next();
MeshProxy* meshProxy = qscriptvalue_cast<MeshProxyList::value_type>(itr.value());
if (meshProxy) {
out.append(meshProxy);
} else {
qDebug() << "null meshProxy";
}
}
}
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace) {
QScriptValue obj = engine->newObject();
obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices));
return obj;
}
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult) {
qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices);
}
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector) {
QScriptValue array = engine->newArray();
for (int i = 0; i < vector.size(); i++) {
array.setProperty(i, meshFaceToScriptValue(engine, vector.at(i)));
}
return array;
}
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result) {
int length = array.property("length").toInteger();
result.clear();
for (int i = 0; i < length; i++) {
MeshFace meshFace = MeshFace();
meshFaceFromScriptValue(array.property(i), meshFace);
result << meshFace;
}
}

View file

@ -315,9 +315,51 @@ Q_DECLARE_METATYPE(AnimationDetails);
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event);
namespace graphics {
class Mesh;
}
using MeshPointer = std::shared_ptr<graphics::Mesh>;
class MeshProxy : public QObject {
Q_OBJECT
public:
virtual MeshPointer getMeshPointer() const = 0;
Q_INVOKABLE virtual int getNumVertices() const = 0;
Q_INVOKABLE virtual glm::vec3 getPos3(int index) const = 0;
};
Q_DECLARE_METATYPE(MeshProxy*);
class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
Q_DECLARE_METATYPE(MeshProxyList);
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out);
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in);
void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out);
class MeshFace {
public:
MeshFace() {}
~MeshFace() {}
QVector<uint32_t> vertexIndices;
// TODO -- material...
};
Q_DECLARE_METATYPE(MeshFace)
Q_DECLARE_METATYPE(QVector<MeshFace>)
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace);
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult);
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector);
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result);
#endif // hifi_RegisteredMetaTypes_h

View file

@ -207,6 +207,10 @@ public:
void dump(const QString& prefix = "") const;
virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed
virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed
virtual void parentDeleted() { } // called on children of a deleted parent
protected:
const NestableType _nestableType; // EntityItem or an AvatarData
QUuid _id;
@ -218,10 +222,6 @@ protected:
mutable ReadWriteLockable _childrenLock;
mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children;
virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed
virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed
virtual void parentDeleted() { } // called on children of a deleted parent
// _queryAACube is used to decide where something lives in the octree
mutable AACube _queryAACube;
mutable bool _queryAACubeSet { false };