From f7db877b7f5d0fa00e5435221df6753ad5dd6e4b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 22 May 2017 17:29:15 -0700 Subject: [PATCH] payload keeps weak pointer to Model --- .../src/CauterizedMeshPartPayload.cpp | 14 ++- .../src/CauterizedMeshPartPayload.h | 2 +- .../render-utils/src/CauterizedModel.cpp | 11 +- .../render-utils/src/MeshPartPayload.cpp | 102 ++++++++++-------- libraries/render-utils/src/MeshPartPayload.h | 6 +- libraries/render-utils/src/Model.cpp | 11 +- 6 files changed, 85 insertions(+), 61 deletions(-) diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 2e3d0385cd..f3ee846d39 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -17,7 +17,7 @@ using namespace render; -CauterizedMeshPartPayload::CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) +CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} void CauterizedMeshPartPayload::updateTransformForCauterizedMesh( @@ -29,8 +29,16 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh( void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { // Still relying on the raw data from the model - CauterizedModel* skeleton = static_cast(_model); - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE) && skeleton->getEnableCauterization(); + bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE); + if (useCauterizedMesh) { + ModelPointer model = _model.lock(); + if (model) { + CauterizedModel* skeleton = static_cast(model.get()); + useCauterizedMesh = useCauterizedMesh && skeleton->getEnableCauterization(); + } else { + useCauterizedMesh = false; + } + } if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 010cd6fcb6..5e3135ea84 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -13,7 +13,7 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload { public: - CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); + CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); void updateTransformForCauterizedMesh(const Transform& renderTransform, const gpu::BufferPointer& buffer); diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 14625952ea..067ef45aed 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -78,7 +78,7 @@ void CauterizedModel::createVisibleRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - auto ptr = std::make_shared(this, i, partIndex, shapeID, transform, offset); + auto ptr = std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::static_pointer_cast(ptr); shapeID++; } @@ -207,11 +207,12 @@ void CauterizedModel::updateRenderItems() { QList keys = self->getRenderItems().keys(); foreach (auto itemID, keys) { transaction.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) { - if (data._model && data._model->isLoaded()) { + ModelPointer model = data._model.lock(); + if (model && model->isLoaded()) { // Ensure the model geometry was not reset between frames - if (deleteGeometryCounter == data._model->getGeometryCounter()) { + if (deleteGeometryCounter == model->getGeometryCounter()) { // this stuff identical to what happens in regular Model - const Model::MeshState& state = data._model->getMeshState(data._meshIndex); + const Model::MeshState& state = model->getMeshState(data._meshIndex); Transform renderTransform = modelTransform; if (state.clusterMatrices.size() == 1) { renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0])); @@ -219,7 +220,7 @@ void CauterizedModel::updateRenderItems() { data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer); // this stuff for cauterized mesh - CauterizedModel* cModel = static_cast(data._model); + CauterizedModel* cModel = static_cast(model.get()); const Model::MeshState& cState = cModel->getCauterizeMeshState(data._meshIndex); renderTransform = modelTransform; if (cState.clusterMatrices.size() == 1) { diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2e08420073..b4fd7e7d2a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,7 +14,6 @@ #include #include "DeferredLightingEffect.h" -#include "Model.h" #include "EntityItem.h" using namespace render; @@ -321,13 +320,13 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren } } -ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : - _model(model), +ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : _meshIndex(_meshIndex), _shapeID(shapeIndex) { - assert(_model && _model->isLoaded()); - auto& modelMesh = _model->getGeometry()->getMeshes().at(_meshIndex); + assert(model && model->isLoaded()); + _model = model; + auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); updateMeshPart(modelMesh, partIndex); updateTransform(transform, offsetTransform); @@ -335,20 +334,21 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par } void ModelMeshPartPayload::initCache() { - assert(_model->isLoaded()); + ModelPointer model = _model.lock(); + assert(model && 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->getFBXGeometry(); + const FBXGeometry& geometry = model->getFBXGeometry(); const FBXMesh& mesh = geometry.meshes.at(_meshIndex); _isBlendShaped = !mesh.blendshapes.isEmpty(); } - auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID); + auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); if (networkMaterial) { _drawMaterial = networkMaterial; } @@ -370,29 +370,31 @@ ItemKey ModelMeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); - if (!_model->isVisible()) { - builder.withInvisible(); - } + ModelPointer model = _model.lock(); + if (model) { + if (!model->isVisible()) { + builder.withInvisible(); + } - if (_model->isLayeredInFront()) { - builder.withLayered(); - } + if (model->isLayeredInFront()) { + builder.withLayered(); + } - if (_isBlendShaped || _isSkinned) { - builder.withDeformed(); - } + if (_isBlendShaped || _isSkinned) { + builder.withDeformed(); + } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); - if (matKey.isTranslucent()) { + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); + } + } + + if (_fadeState != FADE_COMPLETE) { builder.withTransparent(); } } - - if (_fadeState != FADE_COMPLETE) { - builder.withTransparent(); - } - return builder.build(); } @@ -400,7 +402,8 @@ int ModelMeshPartPayload::getLayer() const { // MAgic number while we are defining the layering mechanism: const int LAYER_3D_FRONT = 1; const int LAYER_3D = 0; - if (_model->isLayeredInFront()) { + ModelPointer model = _model.lock(); + if (model && model->isLayeredInFront()) { return LAYER_3D_FRONT; } else { return LAYER_3D; @@ -410,15 +413,16 @@ int ModelMeshPartPayload::getLayer() const { ShapeKey ModelMeshPartPayload::getShapeKey() const { // guard against partially loaded meshes - if (!_model || !_model->isLoaded() || !_model->getGeometry()) { + ModelPointer model = _model.lock(); + if (!model || !model->isLoaded() || !model->getGeometry()) { return ShapeKey::Builder::invalid(); } - const FBXGeometry& geometry = _model->getFBXGeometry(); - const auto& networkMeshes = _model->getGeometry()->getMeshes(); + const FBXGeometry& geometry = model->getFBXGeometry(); + const auto& networkMeshes = model->getGeometry()->getMeshes(); // guard against partially loaded meshes - if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) { + if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)model->_meshStates.size()) { return ShapeKey::Builder::invalid(); } @@ -427,8 +431,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { - _model->_needsFixupInScene = true; // trigger remove/add cycle - _model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid + model->_needsFixupInScene = true; // trigger remove/add cycle + model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid return ShapeKey::Builder::invalid(); } @@ -452,7 +456,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { bool isUnlit = drawMaterialKey.isUnlit(); bool isSkinned = _isSkinned; - bool wireframe = _model->isWireframe(); + bool wireframe = model->isWireframe(); if (wireframe) { isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false; @@ -488,18 +492,22 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { if (!_isBlendShaped) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); - batch.setInputFormat((_drawMesh->getVertexFormat())); - batch.setInputStream(0, _drawMesh->getVertexStream()); } else { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); - batch.setInputFormat((_drawMesh->getVertexFormat())); - batch.setInputBuffer(0, _model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3)); - batch.setInputBuffer(1, _model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); - batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); + ModelPointer model = _model.lock(); + if (model) { + batch.setInputBuffer(0, model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3)); + batch.setInputBuffer(1, model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3)); + batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2)); + } else { + batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); + batch.setInputFormat((_drawMesh->getVertexFormat())); + batch.setInputStream(0, _drawMesh->getVertexStream()); + } } if (_fadeState != FADE_COMPLETE) { @@ -530,7 +538,10 @@ float ModelMeshPartPayload::computeFadeAlpha() { if (fadeAlpha >= 1.0f) { _fadeState = FADE_COMPLETE; // when fade-in completes we flag model for one last "render item update" - _model->setRenderItemsNeedUpdate(); + ModelPointer model = _model.lock(); + if (model) { + model->setRenderItemsNeedUpdate(); + } return 1.0f; } return Interpolate::simpleNonLinearBlend(fadeAlpha); @@ -539,26 +550,27 @@ float ModelMeshPartPayload::computeFadeAlpha() { void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!_model->addedToScene() || !_model->isVisible()) { + ModelPointer model = _model.lock(); + if (!model || !model->addedToScene() || !model->isVisible()) { return; // bail asap } if (_fadeState == FADE_WAITING_TO_START) { - if (_model->isLoaded()) { + if (model->isLoaded()) { if (EntityItem::getEntitiesShouldFadeFunction()()) { _fadeStartTime = usecTimestampNow(); _fadeState = FADE_IN_PROGRESS; } else { _fadeState = FADE_COMPLETE; } - _model->setRenderItemsNeedUpdate(); + model->setRenderItemsNeedUpdate(); } else { return; } } - if (_materialNeedsUpdate && _model->getGeometry()->areTexturesLoaded()) { - _model->setRenderItemsNeedUpdate(); + if (_materialNeedsUpdate && model->getGeometry()->areTexturesLoaded()) { + model->setRenderItemsNeedUpdate(); _materialNeedsUpdate = false; } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 11d1bbf6a7..5d12e60ce3 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -21,6 +21,8 @@ #include +#include "Model.h" + const uint8_t FADE_WAITING_TO_START = 0; const uint8_t FADE_IN_PROGRESS = 1; const uint8_t FADE_COMPLETE = 2; @@ -83,7 +85,7 @@ namespace render { class ModelMeshPartPayload : public MeshPartPayload { public: - ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); + ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; @@ -110,7 +112,7 @@ public: void computeAdjustedLocalBound(const QVector& clusterMatrices); gpu::BufferPointer _clusterBuffer; - Model* _model; + ModelWeakPointer _model; int _meshIndex; int _shapeID; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index e09afa3f31..a6a1c9fa9d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -236,13 +236,14 @@ void Model::updateRenderItems() { render::Transaction transaction; foreach (auto itemID, self->_modelMeshRenderItemsMap.keys()) { transaction.updateItem(itemID, [deleteGeometryCounter](ModelMeshPartPayload& data) { - if (data._model && data._model->isLoaded()) { + ModelPointer model = data._model.lock(); + if (model && model->isLoaded()) { // Ensure the model geometry was not reset between frames - if (deleteGeometryCounter == data._model->_deleteGeometryCounter) { - Transform modelTransform = data._model->getTransform(); + if (deleteGeometryCounter == model->_deleteGeometryCounter) { + Transform modelTransform = model->getTransform(); modelTransform.setScale(glm::vec3(1.0f)); - const Model::MeshState& state = data._model->getMeshState(data._meshIndex); + const Model::MeshState& state = model->getMeshState(data._meshIndex); Transform renderTransform = modelTransform; if (state.clusterMatrices.size() == 1) { renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0])); @@ -1223,7 +1224,7 @@ void Model::createVisibleRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - _modelMeshRenderItems << std::make_shared(this, i, partIndex, shapeID, transform, offset); + _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); shapeID++; } }