mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
CR fedback and cleanup
This commit is contained in:
parent
5791ca4c51
commit
be8d79f53f
36 changed files with 890 additions and 645 deletions
|
@ -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());
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
|
||||
#include <procedural/ProceduralSkybox.h>
|
||||
#include <graphics/Skybox.h>
|
||||
#include <ModelScriptingInterface.h>
|
||||
#include "FrameTimingsScriptingInterface.h"
|
||||
|
||||
#include "Sound.h"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
|
251
libraries/script-engine/src/ModelScriptingInterface.cpp
Normal file
251
libraries/script-engine/src/ModelScriptingInterface.cpp
Normal 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);
|
||||
}
|
39
libraries/script-engine/src/ModelScriptingInterface.h
Normal file
39
libraries/script-engine/src/ModelScriptingInterface.h
Normal 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
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
|
|
Loading…
Reference in a new issue