Update users of NetworkGeometry

This commit is contained in:
Zach Pomerantz 2016-03-23 19:21:38 -07:00
parent 7f05e4453b
commit 3e9e083df5
14 changed files with 158 additions and 204 deletions

View file

@ -466,8 +466,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
* (1.0f - ((float)(now - getHead()->getLookingAtMeStarted()))
/ (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND));
if (alpha > 0.0f) {
QSharedPointer<NetworkGeometry> geometry = _skeletonModel->getGeometry();
if (geometry && geometry->isLoaded()) {
if (_skeletonModel->isLoaded()) {
const auto& geometry = _skeletonModel->getFBXGeometry();
const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye
const float RADIUS_INCREMENT = 0.005f;
batch.setModelTransform(Transform());
@ -475,7 +475,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
glm::vec3 position = getHead()->getLeftEyePosition();
Transform transform;
transform.setTranslation(position);
float eyeDiameter = geometry->getFBXGeometry().leftEyeSize;
float eyeDiameter = geometry.leftEyeSize;
if (eyeDiameter == 0.0f) {
eyeDiameter = DEFAULT_EYE_DIAMETER;
}
@ -486,7 +486,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
position = getHead()->getRightEyePosition();
transform.setTranslation(position);
eyeDiameter = geometry->getFBXGeometry().rightEyeSize;
eyeDiameter = geometry.rightEyeSize;
if (eyeDiameter == 0.0f) {
eyeDiameter = DEFAULT_EYE_DIAMETER;
}
@ -815,7 +815,7 @@ int Avatar::getJointIndex(const QString& name) const {
Q_RETURN_ARG(int, result), Q_ARG(const QString&, name));
return result;
}
return _skeletonModel->isActive() ? _skeletonModel->getGeometry()->getFBXGeometry().getJointIndex(name) : -1;
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointIndex(name) : -1;
}
QStringList Avatar::getJointNames() const {
@ -825,7 +825,7 @@ QStringList Avatar::getJointNames() const {
Q_RETURN_ARG(QStringList, result));
return result;
}
return _skeletonModel->isActive() ? _skeletonModel->getGeometry()->getFBXGeometry().getJointNames() : QStringList();
return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointNames() : QStringList();
}
glm::vec3 Avatar::getJointPosition(int index) const {

View file

@ -1270,8 +1270,8 @@ void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene
void MyAvatar::initHeadBones() {
int neckJointIndex = -1;
if (_skeletonModel->getGeometry()) {
neckJointIndex = _skeletonModel->getGeometry()->getFBXGeometry().neckJointIndex;
if (_skeletonModel->isLoaded()) {
neckJointIndex = _skeletonModel->getFBXGeometry().neckJointIndex;
}
if (neckJointIndex == -1) {
return;

View file

@ -39,12 +39,12 @@ SkeletonModel::~SkeletonModel() {
}
void SkeletonModel::initJointStates() {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
_rig->initJointStates(geometry, modelOffset);
// Determine the default eye position for avatar scale = 1.0
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
int headJointIndex = geometry.headJointIndex;
if (0 > headJointIndex || headJointIndex >= _rig->getJointStateCount()) {
qCWarning(interfaceapp) << "Bad head joint! Got:" << headJointIndex << "jointCount:" << _rig->getJointStateCount();
}
@ -52,7 +52,7 @@ void SkeletonModel::initJointStates() {
getEyeModelPositions(leftEyePosition, rightEyePosition);
glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.0f;
int rootJointIndex = _geometry->getFBXGeometry().rootJointIndex;
int rootJointIndex = geometry.rootJointIndex;
glm::vec3 rootModelPosition;
getJointPosition(rootJointIndex, rootModelPosition);
@ -87,10 +87,12 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle
// Called within Model::simulate call, below.
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
const FBXGeometry& geometry = getFBXGeometry();
Head* head = _owningAvatar->getHead();
if (_owningAvatar->isMyAvatar()) {
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
const FBXGeometry& geometry = _geometry->getFBXGeometry();
Rig::HeadParameters headParams;
headParams.enableLean = qApp->isHMDMode();
@ -183,7 +185,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
// Thus this should really only be ... else if (_owningAvatar->getHead()->isLookingAtMe()) {...
// However, in the !isLookingAtMe case, the eyes aren't rotating the way they should right now.
// We will revisit that as priorities allow, and particularly after the new rig/animation/joints.
const FBXGeometry& geometry = _geometry->getFBXGeometry();
// If the head is not positioned, updateEyeJoints won't get the math right
glm::quat headOrientation;
@ -329,22 +330,23 @@ float SkeletonModel::getRightArmLength() const {
}
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().headJointIndex, headPosition);
return isActive() && getJointPositionInWorldFrame(getFBXGeometry().headJointIndex, headPosition);
}
bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition);
return isActive() && getJointPositionInWorldFrame(getFBXGeometry().neckJointIndex, neckPosition);
}
bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const {
return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition);
return isActive() && getJointPosition(getFBXGeometry().neckJointIndex, neckPosition);
}
bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
if (!isActive()) {
return false;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) &&
getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) {
return true;
@ -386,11 +388,11 @@ float VERY_BIG_MASS = 1.0e6f;
// virtual
void SkeletonModel::computeBoundingShape() {
if (_geometry == NULL || _rig->jointStatesEmpty()) {
if (!isLoaded() || _rig->jointStatesEmpty()) {
return;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
if (geometry.joints.isEmpty() || geometry.rootJointIndex == -1) {
// rootJointIndex == -1 if the avatar model has no skeleton
return;
@ -429,7 +431,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale
}
bool SkeletonModel::hasSkeleton() {
return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false;
return isActive() ? getFBXGeometry().rootJointIndex != -1 : false;
}
void SkeletonModel::onInvalidate() {

View file

@ -38,10 +38,10 @@ public:
void updateAttitude();
/// Returns the index of the left hand joint, or -1 if not found.
int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; }
int getLeftHandJointIndex() const { return isActive() ? getFBXGeometry().leftHandJointIndex : -1; }
/// Returns the index of the right hand joint, or -1 if not found.
int getRightHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().rightHandJointIndex : -1; }
int getRightHandJointIndex() const { return isActive() ? getFBXGeometry().rightHandJointIndex : -1; }
bool getLeftGrabPosition(glm::vec3& position) const;
bool getRightGrabPosition(glm::vec3& position) const;

View file

@ -43,7 +43,7 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu
}
_needsUpdateClusterMatrices = false;
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
glm::mat4 modelToWorld = glm::mat4_cast(modelOrientation);
for (int i = 0; i < _meshStates.size(); i++) {

View file

@ -421,8 +421,8 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer en
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
assert(modelEntityItem); // we need this!!!
ModelPointer model = modelEntityItem->getModel(this);
if (model) {
result = &model->getGeometry()->getFBXGeometry();
if (model && model->isLoaded()) {
result = &model->getFBXGeometry();
}
}
return result;
@ -446,11 +446,8 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
if (modelEntityItem->hasCompoundShapeURL()) {
ModelPointer model = modelEntityItem->getModel(this);
if (model) {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = model->getCollisionGeometry();
if (collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) {
result = &collisionNetworkGeometry->getFBXGeometry();
}
if (model && model->isCollisionLoaded()) {
result = &model->getCollisionFBXGeometry();
}
}
}

View file

@ -110,14 +110,16 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c
QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) {
// If textures are unset, revert to original textures
if (textures == "") {
return _originalTexturesMap;
return _originalTextures;
}
// TODO: Remove this line and enforce passing a texturemap as stringified JSON
QString jsonTextures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}";
QJsonParseError error;
QJsonDocument texturesAsJson = QJsonDocument::fromJson(jsonTextures.toUtf8(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << _textures;
return _originalTextures;
}
QJsonObject texturesAsJsonObject = texturesAsJson.object();
return texturesAsJsonObject.toVariantMap();
@ -131,44 +133,23 @@ void RenderableModelEntityItem::remapTextures() {
if (!_model->isLoaded()) {
return; // nothing to do if the model has not yet loaded
}
auto& geometry = _model->getGeometry()->getGeometry();
if (!_originalTexturesRead) {
const QSharedPointer<NetworkGeometry>& networkGeometry = _model->getGeometry();
if (networkGeometry) {
_originalTextures = networkGeometry->getTextureNames();
_originalTexturesMap = parseTexturesToMap(_originalTextures.join(",\n"));
_originalTexturesRead = true;
}
}
if (_currentTextures == _textures) {
return; // nothing to do if our recently mapped textures match our desired textures
}
// since we're changing here, we need to run through our current texture map
// and any textures in the recently mapped texture, that is not in our desired
// textures, we need to "unset"
QVariantMap currentTextureMap = parseTexturesToMap(_currentTextures);
QVariantMap textureMap = parseTexturesToMap(_textures);
_originalTextures = geometry->getTextures();
_originalTexturesRead = true;
foreach(const QString& key, currentTextureMap.keys()) {
// if the desired texture map (what we're setting the textures to) doesn't
// contain this texture, then remove it by setting the URL to null
if (!textureMap.contains(key)) {
QUrl noURL;
qCDebug(entitiesrenderer) << "Removing texture named" << key << "by replacing it with no URL";
_model->setTextureWithNameToURL(key, noURL);
}
// Default to _originalTextures to avoid remapping immediately and lagging on load
_currentTextures = _originalTextures;
}
// here's where we remap any textures if needed...
foreach(const QString& key, textureMap.keys()) {
QUrl newTextureURL = textureMap[key].toUrl();
qCDebug(entitiesrenderer) << "Updating texture named" << key << "to texture at URL" << newTextureURL;
_model->setTextureWithNameToURL(key, newTextureURL);
auto textures = parseTexturesToMap(_textures);
if (textures != _currentTextures) {
geometry->setTextures(textures);
_currentTextures = textures;
}
_currentTextures = _textures;
}
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
@ -519,8 +500,7 @@ bool RenderableModelEntityItem::needsToCallUpdate() const {
void RenderableModelEntityItem::update(const quint64& now) {
if (!_dimensionsInitialized && _model && _model->isActive()) {
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
if (renderNetworkGeometry && renderNetworkGeometry->isLoaded()) {
if (_model->isLoaded()) {
EntityItemProperties properties;
auto extents = _model->getMeshExtents();
properties.setDimensions(extents.maximum - extents.minimum);
@ -586,13 +566,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
return false;
}
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
(renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
if (_model->isLoaded() && _model->isCollisionLoaded()) {
// we have both URLs AND both geometries AND they are both fully loaded.
if (_needsInitialSimulation) {
// the _model's offset will be wrong until _needsInitialSimulation is false
PerformanceTimer perfTimer("_model->simulate");
@ -617,15 +592,12 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
adjustShapeInfoByRegistration(info);
} else {
updateModelBounds();
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
// should never fall in here when collision model not fully loaded
// hence we assert collisionNetworkGeometry is not NULL
assert(collisionNetworkGeometry);
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
const FBXGeometry& renderGeometry = renderNetworkGeometry->getFBXGeometry();
// hence we assert that all geometries exist and are loaded
assert(_model->isLoaded() && _model->isCollisionLoaded());
const FBXGeometry& renderGeometry = _model->getFBXGeometry();
const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry();
_points.clear();
unsigned int i = 0;
@ -727,10 +699,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
return collisionGeometry.convexHullContains(worldToEntity(point));
if (EntityItem::contains(point) && _model && _model->isCollisionLoaded()) {
return _model->getCollisionFBXGeometry().convexHullContains(worldToEntity(point));
}
return false;

View file

@ -85,9 +85,8 @@ private:
bool _needsInitialSimulation = true;
bool _needsModelReload = true;
EntityTreeRenderer* _myRenderer = nullptr;
QString _currentTextures;
QStringList _originalTextures;
QVariantMap _originalTexturesMap;
QVariantMap _currentTextures;
QVariantMap _originalTextures;
bool _originalTexturesRead = false;
QVector<QVector<glm::vec3>> _points;
bool _dimensionsInitialized = true;

View file

@ -529,9 +529,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable
}
QString textureNamesList = _textureNames.join(",\n");
QString textureNamesStr = QJsonDocument::fromVariant(_textureNames).toJson();
if (!skipDefaults) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesStr); // gettable, but not settable
}
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID);

View file

@ -245,8 +245,8 @@ public:
const glm::vec3& getNaturalPosition() const { return _naturalPosition; }
void calculateNaturalPosition(const glm::vec3& min, const glm::vec3& max);
const QStringList& getTextureNames() const { return _textureNames; }
void setTextureNames(const QStringList& value) { _textureNames = value; }
const QVariantMap& getTextureNames() const { return _textureNames; }
void setTextureNames(const QVariantMap& value) { _textureNames = value; }
QString getSimulatorIDAsString() const { return _simulationOwner.getID().toString().mid(1,36).toUpper(); }
@ -297,7 +297,7 @@ private:
// NOTE: The following are pseudo client only properties. They are only used in clients which can access
// properties of model geometry. But these properties are not serialized like other properties.
QVector<SittingPoint> _sittingPoints;
QStringList _textureNames;
QVariantMap _textureNames;
glm::vec3 _naturalDimensions;
glm::vec3 _naturalPosition;

View file

@ -45,14 +45,14 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr
}
}
MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const model::Mesh>& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
updateMeshPart(mesh, partIndex);
updateMaterial(material);
updateTransform(transform, offsetTransform);
}
void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) {
void MeshPartPayload::updateMeshPart(const std::shared_ptr<const model::Mesh>& drawMesh, int partIndex) {
_drawMesh = drawMesh;
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
@ -320,7 +320,9 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par
_model(model),
_meshIndex(_meshIndex),
_shapeID(shapeIndex) {
auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh;
assert(_model && _model->isLoaded());
auto& modelMesh = _model->getGeometry()->getGeometry()->getMeshes().at(_meshIndex);
updateMeshPart(modelMesh, partIndex);
updateTransform(transform, offsetTransform);
@ -328,20 +330,22 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par
}
void ModelMeshPartPayload::initCache() {
assert(_model->isLoaded());
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const FBXGeometry& geometry = _model->getFBXGeometry();
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
_isBlendShaped = !mesh.blendshapes.isEmpty();
}
auto networkMaterial = _model->_geometry->getShapeMaterial(_shapeID);
auto networkMaterial = _model->getGeometry()->getGeometry()->getShapeMaterial(_shapeID);
if (networkMaterial) {
_drawMaterial = networkMaterial->_material;
_drawMaterial = networkMaterial;
};
}
@ -380,8 +384,9 @@ Item::Bound ModelMeshPartPayload::getBound() const {
}
ShapeKey ModelMeshPartPayload::getShapeKey() const {
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
assert(_model->isLoaded());
const FBXGeometry& geometry = _model->getFBXGeometry();
const auto& networkMeshes = _model->getGeometry()->getGeometry()->getMeshes();
// guard against partially loaded meshes
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) {

View file

@ -24,12 +24,12 @@ class Model;
class MeshPartPayload {
public:
MeshPartPayload() {}
MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform);
MeshPartPayload(const std::shared_ptr<const model::Mesh>& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform);
typedef render::Payload<MeshPartPayload> Payload;
typedef Payload::DataPointer Pointer;
virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex);
virtual void updateMeshPart(const std::shared_ptr<const model::Mesh>& drawMesh, int partIndex);
virtual void notifyLocationChanged() {}
virtual void updateTransform(const Transform& transform, const Transform& offsetTransform);
@ -49,11 +49,11 @@ public:
virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool canCauterize = true) const;
// Payload resource cached values
model::MeshPointer _drawMesh;
std::shared_ptr<const model::Mesh> _drawMesh;
int _partIndex = 0;
model::Mesh::Part _drawPart;
model::MaterialPointer _drawMaterial;
std::shared_ptr<const model::Material> _drawMaterial;
model::Box _localBound;
Transform _drawTransform;

View file

@ -30,7 +30,7 @@
using namespace std;
static int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();
static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<std::weak_ptr<NetworkGeometry> >();
static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
#define HTTP_INVALID_COM "http://invalid.com"
@ -74,12 +74,12 @@ Model::~Model() {
AbstractViewStateInterface* Model::_viewState = NULL;
bool Model::needsFixupInScene() {
bool Model::needsFixupInScene() const {
if (readyToAddToScene()) {
// Once textures are loaded, fixup if they are now transparent
if (!_needsReload && _needsUpdateTransparentTextures && _geometry->isLoadedWithTextures()) {
if (_needsUpdateTransparentTextures && _geometry->getGeometry()->areTexturesLoaded()) {
_needsUpdateTransparentTextures = false;
if (_hasTransparentTextures != _geometry->hasTransparentTextures()) {
if (_hasTransparentTextures != _geometry->getGeometry()->hasTransparentTextures()) {
return true;
}
}
@ -150,19 +150,18 @@ void Model::enqueueLocationChange() {
}
void Model::initJointTransforms() {
if (!_geometry || !_geometry->isLoaded()) {
return;
if (isLoaded()) {
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
_rig->setModelOffset(modelOffset);
}
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
_rig->setModelOffset(modelOffset);
}
void Model::init() {
}
void Model::reset() {
if (_geometry && _geometry->isLoaded()) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (isLoaded()) {
const FBXGeometry& geometry = getFBXGeometry();
_rig->reset(geometry);
}
}
@ -171,17 +170,16 @@ bool Model::updateGeometry() {
PROFILE_RANGE(__FUNCTION__);
bool needFullUpdate = false;
if (!_geometry || !_geometry->isLoaded()) {
// geometry is not ready
if (!isLoaded()) {
return false;
}
_needsReload = false;
if (_rig->jointStatesEmpty() && _geometry->getFBXGeometry().joints.size() > 0) {
if (_rig->jointStatesEmpty() && getFBXGeometry().joints.size() > 0) {
initJointStates();
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
const FBXGeometry& fbxGeometry = getFBXGeometry();
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());
@ -205,7 +203,7 @@ bool Model::updateGeometry() {
// virtual
void Model::initJointStates() {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
_rig->initJointStates(geometry, modelOffset);
@ -248,7 +246,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
glm::vec3 subMeshSurfaceNormal;
int subMeshIndex = 0;
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
// If we hit the models box, then consider the submeshes...
_mutex.lock();
@ -367,7 +365,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
int numberOfMeshes = geometry.meshes.size();
_calculatedMeshBoxes.resize(numberOfMeshes);
_calculatedMeshTriangles.clear();
@ -478,7 +476,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
void Model::renderSetup(RenderArgs* args) {
// set up dilated textures on first render after load/simulate
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
if (_dilatedTextures.isEmpty()) {
foreach (const FBXMesh& mesh, geometry.meshes) {
QVector<QSharedPointer<Texture> > dilated;
@ -627,7 +625,7 @@ Extents Model::getBindExtents() const {
if (!isActive()) {
return Extents();
}
const Extents& bindExtents = _geometry->getFBXGeometry().bindExtents;
const Extents& bindExtents = getFBXGeometry().bindExtents;
Extents scaledExtents = { bindExtents.minimum * _scale, bindExtents.maximum * _scale };
return scaledExtents;
}
@ -636,12 +634,12 @@ Extents Model::getMeshExtents() const {
if (!isActive()) {
return Extents();
}
const Extents& extents = _geometry->getFBXGeometry().meshExtents;
const Extents& extents = getFBXGeometry().meshExtents;
// even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
// is captured in the offset matrix
glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
Extents scaledExtents = { minimum * _scale, maximum * _scale };
return scaledExtents;
}
@ -651,12 +649,12 @@ Extents Model::getUnscaledMeshExtents() const {
return Extents();
}
const Extents& extents = _geometry->getFBXGeometry().meshExtents;
const Extents& extents = getFBXGeometry().meshExtents;
// even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
// is captured in the offset matrix
glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
Extents scaledExtents = { minimum, maximum };
return scaledExtents;
@ -665,8 +663,8 @@ Extents Model::getUnscaledMeshExtents() const {
Extents Model::calculateScaledOffsetExtents(const Extents& extents,
glm::vec3 modelPosition, glm::quat modelOrientation) const {
// we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix
glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
Extents scaledOffsetExtents = { ((minimum + _offset) * _scale),
((maximum + _offset) * _scale) };
@ -686,7 +684,7 @@ AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPositio
glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const {
// we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix
glm::vec3 offsetPoint = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(point, 1.0f));
glm::vec3 offsetPoint = glm::vec3(getFBXGeometry().offset * glm::vec4(point, 1.0f));
glm::vec3 scaledPoint = ((offsetPoint + _offset) * _scale);
glm::vec3 rotatedPoint = _rotation * scaledPoint;
glm::vec3 translatedPoint = rotatedPoint + _translation;
@ -714,11 +712,11 @@ void Model::setJointTranslation(int index, bool valid, const glm::vec3& translat
}
int Model::getParentJointIndex(int jointIndex) const {
return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).parentIndex : -1;
return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).parentIndex : -1;
}
int Model::getLastFreeJointIndex(int jointIndex) const {
return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;
return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;
}
void Model::setURL(const QUrl& url) {
@ -743,29 +741,16 @@ void Model::setURL(const QUrl& url) {
invalidCalculatedMeshBoxes();
deleteGeometry();
_geometry.reset(new NetworkGeometry(url, false, QVariantHash()));
_geometry = DependencyManager::get<ModelCache>()->getGeometry(url);
onInvalidate();
}
const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad)
{
if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) {
_collisionGeometry.reset(new NetworkGeometry(_collisionUrl, delayLoad, QVariantHash()));
}
if (_collisionGeometry && _collisionGeometry->isLoaded()) {
return _collisionGeometry;
}
return QSharedPointer<NetworkGeometry>();
}
void Model::setCollisionModelURL(const QUrl& url) {
if (_collisionUrl == url) {
return;
}
_collisionUrl = url;
_collisionGeometry.reset(new NetworkGeometry(url, false, QVariantHash()));
_collisionGeometry = DependencyManager::get<ModelCache>()->getGeometry(url);
}
bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {
@ -815,13 +800,13 @@ QStringList Model::getJointNames() const {
Q_RETURN_ARG(QStringList, result));
return result;
}
return isActive() ? _geometry->getFBXGeometry().getJointNames() : QStringList();
return isActive() ? getFBXGeometry().getJointNames() : QStringList();
}
class Blender : public QRunnable {
public:
Blender(ModelPointer model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
virtual void run();
@ -830,12 +815,12 @@ private:
ModelPointer _model;
int _blendNumber;
QWeakPointer<NetworkGeometry> _geometry;
std::weak_ptr<NetworkGeometry> _geometry;
QVector<FBXMesh> _meshes;
QVector<float> _blendshapeCoefficients;
};
Blender::Blender(ModelPointer model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
Blender::Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
_model(model),
_blendNumber(blendNumber),
@ -878,7 +863,7 @@ void Blender::run() {
// post the result to the geometry cache, which will dispatch to the model if still alive
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
Q_ARG(const QWeakPointer<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
Q_ARG(const std::weak_ptr<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
Q_ARG(const QVector<glm::vec3>&, normals));
}
@ -1010,7 +995,7 @@ void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrient
return;
}
_needsUpdateClusterMatrices = false;
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
glm::mat4 zeroScale(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 0.0f),
@ -1067,26 +1052,26 @@ void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrient
}
void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
const QVector<int>& freeLineage = geometry.joints.at(endIndex).freeLineage;
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);
_rig->inverseKinematics(endIndex, targetPosition, targetRotation, priority, freeLineage, parentTransform);
}
bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
return _rig->restoreJointPosition(jointIndex, fraction, priority, freeLineage);
}
float Model::getLimbLength(int jointIndex) const {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const FBXGeometry& geometry = getFBXGeometry();
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
return _rig->getLimbLength(jointIndex, freeLineage, _scale, geometry.joints);
}
bool Model::maybeStartBlender() {
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
const FBXGeometry& fbxGeometry = getFBXGeometry();
if (fbxGeometry.hasBlendedMeshes()) {
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry,
fbxGeometry.meshes, _blendshapeCoefficients));
@ -1095,13 +1080,13 @@ bool Model::maybeStartBlender() {
return false;
}
void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
void Model::setBlendedVertices(int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
if (_geometry != geometry || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
if (_geometry != geometry.lock() || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
return;
}
_appliedBlendNumber = blendNumber;
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
const FBXGeometry& fbxGeometry = getFBXGeometry();
int index = 0;
for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
@ -1118,13 +1103,6 @@ void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeomet
}
}
void Model::setGeometry(const QSharedPointer<NetworkGeometry>& newGeometry) {
if (_geometry == newGeometry) {
return;
}
_geometry = newGeometry;
}
void Model::deleteGeometry() {
_blendedVertexBuffers.clear();
_meshStates.clear();
@ -1134,7 +1112,7 @@ void Model::deleteGeometry() {
AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition, glm::quat modelOrientation) const {
if (!_geometry || !_geometry->isLoaded()) {
if (!isLoaded()) {
return AABox();
}
@ -1143,10 +1121,10 @@ AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition
bool isSkinned = state.clusterMatrices.size() > 1;
if (isSkinned) {
// if we're skinned return the entire mesh extents because we can't know for sure our clusters don't move us
return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents, modelPosition, modelOrientation);
return calculateScaledOffsetAABox(getFBXGeometry().meshExtents, modelPosition, modelOrientation);
}
}
if (_geometry->getFBXGeometry().meshes.size() > meshIndex) {
if (getFBXGeometry().meshes.size() > meshIndex) {
// FIX ME! - This is currently a hack because for some mesh parts our efforts to calculate the bounding
// box of the mesh part fails. It seems to create boxes that are not consistent with where the
@ -1160,27 +1138,28 @@ AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition
// return _calculatedMeshBoxes[meshIndex];
//
// If we not skinned use the bounds of the subMesh for all it's parts
const FBXMesh& mesh = _geometry->getFBXGeometry().meshes.at(meshIndex);
const FBXMesh& mesh = getFBXGeometry().meshes.at(meshIndex);
return calculateScaledOffsetExtents(mesh.meshExtents, modelPosition, modelOrientation);
}
return AABox();
}
void Model::segregateMeshGroups() {
QSharedPointer<NetworkGeometry> networkGeometry;
NetworkGeometry::Pointer networkGeometry;
bool showingCollisionHull = false;
if (_showCollisionHull && _collisionGeometry) {
if (_collisionGeometry->isLoaded()) {
if (isCollisionLoaded()) {
networkGeometry = _collisionGeometry;
showingCollisionHull = true;
} else {
return;
}
} else {
assert(isLoaded());
networkGeometry = _geometry;
}
const FBXGeometry& geometry = networkGeometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = networkGeometry->getMeshes();
const FBXGeometry& geometry = networkGeometry->getGeometry()->getGeometry();
const auto& networkMeshes = networkGeometry->getGeometry()->getMeshes();
// all of our mesh vectors must match in size
auto geoMeshesSize = geometry.meshes.size();
@ -1208,7 +1187,7 @@ void Model::segregateMeshGroups() {
int shapeID = 0;
for (int i = 0; i < (int)networkMeshes.size(); i++) {
const FBXMesh& mesh = geometry.meshes.at(i);
const NetworkMesh& networkMesh = *(networkMeshes.at(i).get());
const auto& networkMesh = networkMeshes.at(i);
// Create the render payloads
int totalParts = mesh.parts.size();
@ -1220,7 +1199,7 @@ void Model::segregateMeshGroups() {
_collisionHullMaterial->setMetallic(0.02f);
_collisionHullMaterial->setRoughness(0.5f);
}
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset);
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh, partIndex, _collisionHullMaterial, transform, offset);
} else {
_renderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
}
@ -1285,7 +1264,7 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) {
}
void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber,
const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
const std::weak_ptr<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
if (model) {
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
}

View file

@ -78,9 +78,9 @@ public:
// new Scene/Engine rendering support
void setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene);
bool needsFixupInScene();
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) {
return !_needsReload && isRenderable() && isActive() && isLoaded();
bool needsFixupInScene() const;
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const {
return !_needsReload && isRenderable() && isActive();
}
bool initWhenReady(render::ScenePointer scene);
bool addToScene(std::shared_ptr<render::Scene> scene,
@ -92,7 +92,7 @@ public:
bool showCollisionHull = false);
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
void renderSetup(RenderArgs* args);
bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().empty()); }
bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && getGeometry()->getGeometry()->getMeshes().empty()); }
bool isVisible() const { return _isVisible; }
@ -102,11 +102,11 @@ public:
bool maybeStartBlender();
/// Sets blended vertices computed in a separate thread.
void setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
void setBlendedVertices(int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
bool isLoaded() const { return _geometry && _geometry->isLoaded(); }
bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); }
bool isLoaded() const { return _geometry && _geometry->getGeometry(); }
bool isCollisionLoaded() const { return _collisionGeometry && _collisionGeometry->getGeometry(); }
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
bool isWireframe() const { return _isWireframe; }
@ -123,12 +123,22 @@ public:
virtual void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation);
/// Returns a reference to the shared geometry.
const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; }
const NetworkGeometry::Pointer& getGeometry() const { return _geometry; }
/// Returns a reference to the shared collision geometry.
const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
bool isActive() const { return _geometry && _geometry->isLoaded(); }
/// Provided as a convenience, will crash if !isLoaded()
// And so that getGeometry() isn't chained everywhere
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); }
/// Provided as a convenience, will crash if !isCollisionLoaded()
const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return getCollisionGeometry()->getGeometry()->getGeometry(); }
Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url)
{ _geometry->setTextureWithNameToURL(name, url); }
// Set the model to use for collisions
Q_INVOKABLE void setCollisionModelURL(const QUrl& url);
const QUrl& getCollisionURL() const { return _collisionUrl; }
bool isActive() const { return isLoaded(); }
bool convexHullContains(glm::vec3 point);
@ -143,13 +153,6 @@ public:
BoxFace& face, glm::vec3& surfaceNormal,
QString& extraInfo, bool pickAgainstTriangles = false);
// Set the model to use for collisions
Q_INVOKABLE void setCollisionModelURL(const QUrl& url);
const QUrl& getCollisionURL() const { return _collisionUrl; }
/// Returns a reference to the shared collision geometry.
const QSharedPointer<NetworkGeometry> getCollisionGeometry(bool delayLoad = false);
void setOffset(const glm::vec3& offset);
const glm::vec3& getOffset() const { return _offset; }
@ -257,8 +260,7 @@ protected:
/// \return true if joint exists
bool getJointPosition(int jointIndex, glm::vec3& position) const;
QSharedPointer<NetworkGeometry> _geometry;
void setGeometry(const QSharedPointer<NetworkGeometry>& newGeometry);
NetworkGeometry::Pointer _geometry;
glm::vec3 _translation;
glm::quat _rotation;
@ -325,7 +327,7 @@ protected:
void deleteGeometry();
void initJointTransforms();
QSharedPointer<NetworkGeometry> _collisionGeometry;
NetworkGeometry::Pointer _collisionGeometry;
float _pupilDilation;
QVector<float> _blendshapeCoefficients;
@ -376,7 +378,7 @@ protected:
bool _readyWhenAdded { false };
bool _needsReload { true };
bool _needsUpdateClusterMatrices { true };
bool _needsUpdateTransparentTextures { true };
mutable bool _needsUpdateTransparentTextures { true };
bool _hasTransparentTextures { false };
bool _showCollisionHull { false };
@ -385,7 +387,7 @@ protected:
};
Q_DECLARE_METATYPE(ModelPointer)
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
Q_DECLARE_METATYPE(std::weak_ptr<NetworkGeometry>)
/// Handle management of pending models that need blending
class ModelBlender : public QObject, public Dependency {
@ -398,7 +400,7 @@ public:
void noteRequiresBlend(ModelPointer model);
public slots:
void setBlendedVertices(ModelPointer model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
void setBlendedVertices(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
private: