mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-14 05:26:32 +02:00
Merge pull request #12026 from SamGondelman/burp3
Remove _model from ModelMeshPartPayload
This commit is contained in:
commit
a2c16ddf6a
10 changed files with 112 additions and 137 deletions
|
@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay()
|
|||
: _model(std::make_shared<Model>(nullptr, this)),
|
||||
_modelTextures(QVariantMap())
|
||||
{
|
||||
_model->init();
|
||||
_model->setLoadingPriority(_loadPriority);
|
||||
_isLoaded = false;
|
||||
}
|
||||
|
@ -38,7 +37,6 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) :
|
|||
_scaleToFit(modelOverlay->_scaleToFit),
|
||||
_loadPriority(modelOverlay->_loadPriority)
|
||||
{
|
||||
_model->init();
|
||||
_model->setLoadingPriority(_loadPriority);
|
||||
if (_url.isValid()) {
|
||||
_updateModel = true;
|
||||
|
|
|
@ -138,7 +138,6 @@ Avatar::~Avatar() {
|
|||
|
||||
void Avatar::init() {
|
||||
getHead()->init();
|
||||
_skeletonModel->init();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1209,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||
model->init();
|
||||
entity->setModel(model);
|
||||
withWriteLock([&] { _model = model; });
|
||||
}
|
||||
|
|
|
@ -40,17 +40,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform
|
|||
|
||||
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
||||
// Still relying on the raw data from the model
|
||||
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE);
|
||||
if (useCauterizedMesh) {
|
||||
ModelPointer model = _model.lock();
|
||||
if (model) {
|
||||
CauterizedModel* skeleton = static_cast<CauterizedModel*>(model.get());
|
||||
useCauterizedMesh = useCauterizedMesh && skeleton->getEnableCauterization();
|
||||
} else {
|
||||
useCauterizedMesh = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
|
||||
if (useCauterizedMesh) {
|
||||
if (_cauterizedClusterBuffer) {
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer);
|
||||
|
|
|
@ -21,9 +21,12 @@ public:
|
|||
|
||||
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }
|
||||
|
||||
private:
|
||||
gpu::BufferPointer _cauterizedClusterBuffer;
|
||||
Transform _cauterizedTransform;
|
||||
bool _enableCauterization { false };
|
||||
};
|
||||
|
||||
#endif // hifi_CauterizedMeshPartPayload_h
|
||||
|
|
|
@ -178,6 +178,12 @@ void CauterizedModel::updateRenderItems() {
|
|||
modelTransform.setTranslation(self->getTranslation());
|
||||
modelTransform.setRotation(self->getRotation());
|
||||
|
||||
bool isWireframe = self->isWireframe();
|
||||
bool isVisible = self->isVisible();
|
||||
bool isLayeredInFront = self->isLayeredInFront();
|
||||
bool isLayeredInHUD = self->isLayeredInHUD();
|
||||
bool enableCauterization = self->getEnableCauterization();
|
||||
|
||||
render::Transaction transaction;
|
||||
for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) {
|
||||
|
||||
|
@ -186,7 +192,10 @@ void CauterizedModel::updateRenderItems() {
|
|||
auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
|
||||
auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices);
|
||||
|
||||
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized](CauterizedMeshPartPayload& data) {
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
|
||||
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey,
|
||||
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) {
|
||||
data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized);
|
||||
|
||||
Transform renderTransform = modelTransform;
|
||||
|
@ -200,6 +209,11 @@ void CauterizedModel::updateRenderItems() {
|
|||
renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0]));
|
||||
}
|
||||
data.updateTransformForCauterizedMesh(renderTransform);
|
||||
|
||||
data.setEnableCauterization(enableCauterization);
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -325,7 +325,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
|
|||
_shapeID(shapeIndex) {
|
||||
|
||||
assert(model && model->isLoaded());
|
||||
_model = model;
|
||||
_blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex];
|
||||
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
|
||||
const Model::MeshState& state = model->getMeshState(_meshIndex);
|
||||
|
||||
|
@ -339,13 +339,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
|
|||
}
|
||||
updateTransformForSkinnedMesh(renderTransform, transform);
|
||||
|
||||
initCache();
|
||||
initCache(model);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::initCache() {
|
||||
ModelPointer model = _model.lock();
|
||||
assert(model && model->isLoaded());
|
||||
|
||||
void ModelMeshPartPayload::initCache(const ModelPointer& model) {
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
|
@ -355,6 +352,7 @@ void ModelMeshPartPayload::initCache() {
|
|||
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||
|
||||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||
_hasTangents = !mesh.tangents.isEmpty();
|
||||
}
|
||||
|
||||
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
|
||||
|
@ -388,94 +386,70 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
|
|||
_worldBound.transform(boundTransform);
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
||||
ModelPointer model = _model.lock();
|
||||
if (model) {
|
||||
if (!model->isVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
if (!isVisible) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
if (model->isLayeredInFront() || model->isLayeredInHUD()) {
|
||||
builder.withLayered();
|
||||
}
|
||||
if (isLayered) {
|
||||
builder.withLayered();
|
||||
}
|
||||
|
||||
if (_isBlendShaped || _isSkinned) {
|
||||
builder.withDeformed();
|
||||
}
|
||||
if (_isBlendShaped || _isSkinned) {
|
||||
builder.withDeformed();
|
||||
}
|
||||
|
||||
if (_drawMaterial) {
|
||||
auto matKey = _drawMaterial->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
if (_drawMaterial) {
|
||||
auto matKey = _drawMaterial->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
|
||||
_itemKey = builder.build();
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
return _itemKey;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
|
||||
if (isLayeredInFront) {
|
||||
_layer = Item::LAYER_3D_FRONT;
|
||||
} else if (isLayeredInHUD) {
|
||||
_layer = Item::LAYER_3D_HUD;
|
||||
} else {
|
||||
_layer = Item::LAYER_3D;
|
||||
}
|
||||
}
|
||||
|
||||
int ModelMeshPartPayload::getLayer() const {
|
||||
ModelPointer model = _model.lock();
|
||||
if (model) {
|
||||
if (model->isLayeredInFront()) {
|
||||
return Item::LAYER_3D_FRONT;
|
||||
} else if (model->isLayeredInHUD()) {
|
||||
return Item::LAYER_3D_HUD;
|
||||
}
|
||||
}
|
||||
return Item::LAYER_3D;
|
||||
return _layer;
|
||||
}
|
||||
|
||||
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||
// guard against partially loaded meshes
|
||||
ModelPointer model = _model.lock();
|
||||
if (!model || !model->isLoaded() || !model->getGeometry()) {
|
||||
return ShapeKey::Builder::invalid();
|
||||
void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe) {
|
||||
if (invalidateShapeKey) {
|
||||
_shapeKey = ShapeKey::Builder::invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
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()) {
|
||||
return ShapeKey::Builder::invalid();
|
||||
}
|
||||
|
||||
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||
|
||||
// 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
|
||||
return ShapeKey::Builder::invalid();
|
||||
}
|
||||
|
||||
|
||||
int vertexCount = mesh.vertices.size();
|
||||
if (vertexCount == 0) {
|
||||
// sanity check
|
||||
return ShapeKey::Builder::invalid(); // FIXME
|
||||
}
|
||||
|
||||
|
||||
model::MaterialKey drawMaterialKey;
|
||||
if (_drawMaterial) {
|
||||
drawMaterialKey = _drawMaterial->getKey();
|
||||
}
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents;
|
||||
bool hasSpecular = drawMaterialKey.isMetallicMap();
|
||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||
bool isUnlit = drawMaterialKey.isUnlit();
|
||||
|
||||
bool isSkinned = _isSkinned;
|
||||
bool wireframe = model->isWireframe();
|
||||
|
||||
if (wireframe) {
|
||||
if (isWireframe) {
|
||||
isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||
}
|
||||
|
||||
|
@ -500,10 +474,14 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
|||
if (isSkinned) {
|
||||
builder.withSkinned();
|
||||
}
|
||||
if (wireframe) {
|
||||
if (isWireframe) {
|
||||
builder.withWireframe();
|
||||
}
|
||||
return builder.build();
|
||||
_shapeKey = builder.build();
|
||||
}
|
||||
|
||||
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||
return _shapeKey;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
|
||||
|
@ -515,10 +493,9 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
|
|||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
|
||||
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));
|
||||
if (_blendedVertexBuffer) {
|
||||
batch.setInputBuffer(0, _blendedVertexBuffer, 0, sizeof(glm::vec3));
|
||||
batch.setInputBuffer(1, _blendedVertexBuffer, _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||
} else {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
@ -544,31 +521,9 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
|
|||
void ModelMeshPartPayload::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
|
||||
|
||||
ModelPointer model = _model.lock();
|
||||
if (!model || !model->isAddedToScene() || !model->isVisible()) {
|
||||
return; // bail asap
|
||||
}
|
||||
|
||||
if (_state == WAITING_TO_START) {
|
||||
if (model->isLoaded()) {
|
||||
_state = STARTED;
|
||||
model->setRenderItemsNeedUpdate();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_materialNeedsUpdate && model->getGeometry()->areTexturesLoaded()) {
|
||||
model->setRenderItemsNeedUpdate();
|
||||
_materialNeedsUpdate = false;
|
||||
}
|
||||
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
if (!getShapeKey().isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto locations = args->_shapePipeline->locations;
|
||||
|
|
|
@ -96,32 +96,32 @@ public:
|
|||
render::ShapeKey getShapeKey() const override; // shape interface
|
||||
void render(RenderArgs* args) override;
|
||||
|
||||
void setKey(bool isVisible, bool isLayered);
|
||||
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
|
||||
void setShapeKey(bool invalidateShapeKey, bool isWireframe);
|
||||
|
||||
// ModelMeshPartPayload functions to perform render
|
||||
void bindMesh(gpu::Batch& batch) override;
|
||||
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
void initCache();
|
||||
|
||||
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
|
||||
|
||||
gpu::BufferPointer _clusterBuffer;
|
||||
ModelWeakPointer _model;
|
||||
|
||||
int _meshIndex;
|
||||
int _shapeID;
|
||||
|
||||
bool _isSkinned{ false };
|
||||
bool _isBlendShaped { false };
|
||||
bool _materialNeedsUpdate { true };
|
||||
bool _hasTangents { false };
|
||||
|
||||
private:
|
||||
void initCache(const ModelPointer& model);
|
||||
|
||||
enum State : uint8_t {
|
||||
WAITING_TO_START = 0,
|
||||
STARTED = 1,
|
||||
};
|
||||
|
||||
mutable State _state { WAITING_TO_START } ;
|
||||
gpu::BufferPointer _blendedVertexBuffer;
|
||||
render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
|
||||
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
|
||||
int _layer { render::Item::LAYER_3D };
|
||||
};
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -210,6 +210,24 @@ int Model::getRenderInfoTextureCount() {
|
|||
return _renderInfoTextureCount;
|
||||
}
|
||||
|
||||
bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
|
||||
if (!getGeometry()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const auto& networkMeshes = getGeometry()->getMeshes();
|
||||
// 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 >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size()) {
|
||||
_needsFixupInScene = true; // trigger remove/add cycle
|
||||
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Model::updateRenderItems() {
|
||||
if (!_addedToScene) {
|
||||
return;
|
||||
|
@ -237,6 +255,11 @@ void Model::updateRenderItems() {
|
|||
Transform modelTransform = self->getTransform();
|
||||
modelTransform.setScale(glm::vec3(1.0f));
|
||||
|
||||
bool isWireframe = self->isWireframe();
|
||||
bool isVisible = self->isVisible();
|
||||
bool isLayeredInFront = self->isLayeredInFront();
|
||||
bool isLayeredInHUD = self->isLayeredInHUD();
|
||||
|
||||
render::Transaction transaction;
|
||||
for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
|
||||
|
||||
|
@ -244,13 +267,20 @@ void Model::updateRenderItems() {
|
|||
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
|
||||
auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterMatrices](ModelMeshPartPayload& data) {
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey,
|
||||
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
|
||||
data.updateClusterBuffer(clusterMatrices);
|
||||
Transform renderTransform = modelTransform;
|
||||
if (clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
|
||||
|
||||
data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
|
||||
data.setLayer(isLayeredInFront, isLayeredInHUD);
|
||||
data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -272,16 +302,6 @@ void Model::setRenderItemsNeedUpdate() {
|
|||
emit requestRenderUpdate();
|
||||
}
|
||||
|
||||
void Model::initJointTransforms() {
|
||||
if (isLoaded()) {
|
||||
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
|
||||
_rig.setModelOffset(modelOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::init() {
|
||||
}
|
||||
|
||||
void Model::reset() {
|
||||
if (isLoaded()) {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
|
|
|
@ -122,7 +122,6 @@ public:
|
|||
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
|
||||
bool isWireframe() const { return _isWireframe; }
|
||||
|
||||
void init();
|
||||
void reset();
|
||||
|
||||
void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint);
|
||||
|
@ -346,11 +345,7 @@ protected:
|
|||
// hook for derived classes to be notified when setUrl invalidates the current model.
|
||||
virtual void onInvalidate() {};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void deleteGeometry();
|
||||
void initJointTransforms();
|
||||
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
|
@ -419,6 +414,8 @@ protected:
|
|||
bool _isLayeredInFront { false };
|
||||
bool _isLayeredInHUD { false };
|
||||
|
||||
bool shouldInvalidatePayloadShapeKey(int meshIndex);
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
|
||||
|
|
Loading…
Reference in a new issue