You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmRender/nmVTKScene.cpp

121 lines
3.2 KiB
C++

#include "nmVTKScene.h"
#include "nmVTKRenderLayer.h"
#include <QCoreApplication>
#include <QThread>
#include <vtkRenderer.h>
namespace {
// Release 构建也会通过返回值拒绝跨线程操作,断言用于尽早暴露调用错误。
bool isSceneGuiThread()
{
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == NULL ||
pApplication->thread() == QThread::currentThread();
}
}
nmVTKScene::nmVTKScene(vtkRenderer* pRenderer)
: m_pRenderer(pRenderer)
{
Q_ASSERT(isSceneGuiThread());
// Scene 不增加 Renderer 引用计数,生命周期由外层容器统一编排。
}
nmVTKScene::~nmVTKScene()
{
Q_ASSERT(isSceneGuiThread());
// 即使在 Release 中违反线程约束,也优先解除 Renderer 对 Prop 的引用。
clearLayers();
m_pRenderer = NULL;
}
bool nmVTKScene::addLayer(nmVTKRenderLayer* pLayer)
{
Q_ASSERT(isSceneGuiThread());
if(!isSceneGuiThread() || pLayer == NULL || m_pRenderer == NULL) {
return false;
}
const QString sLayerId = pLayer->getLayerId();
if(sLayerId.isEmpty() || m_mapLayers.contains(sLayerId)) {
// 加入失败时绝不删除图层,所有权仍由调用方负责。
return false;
}
// 先认领所有权再挂载,阻止同一裸指针同时进入两个 Scene 的所有权容器。
if(!pLayer->claimSceneOwnership(this)) {
return false;
}
if(!pLayer->attach(m_pRenderer)) {
// attach 失败不会留下 Renderer 引用,也不会改变图层所有权。
pLayer->releaseSceneOwnership(this);
return false;
}
// 只有挂载成功后才写入所有权容器。
m_mapLayers.insert(sLayerId, pLayer);
return true;
}
nmVTKRenderLayer* nmVTKScene::getLayer(const QString& sLayerId) const
{
Q_ASSERT(isSceneGuiThread());
if(!isSceneGuiThread()) {
return NULL;
}
return m_mapLayers.value(sLayerId, NULL);
}
bool nmVTKScene::removeLayer(const QString& sLayerId)
{
Q_ASSERT(isSceneGuiThread());
if(!isSceneGuiThread() || !m_mapLayers.contains(sLayerId)) {
return false;
}
nmVTKRenderLayer* pLayer = m_mapLayers.take(sLayerId);
if(pLayer != NULL) {
// 删除前先从 Renderer 移除 Prop避免留下悬空引用。
pLayer->detach();
pLayer->releaseSceneOwnership(this);
delete pLayer;
}
return true;
}
void nmVTKScene::clear()
{
Q_ASSERT(isSceneGuiThread());
if(!isSceneGuiThread()) {
return;
}
clearLayers();
}
void nmVTKScene::clearLayers()
{
// 先从所有权容器摘除,再 detach 和 delete避免析构回调重入时重复命中。
while(!m_mapLayers.isEmpty()) {
QMap<QString, nmVTKRenderLayer*>::iterator oIterator =
m_mapLayers.begin();
nmVTKRenderLayer* pLayer = oIterator.value();
m_mapLayers.erase(oIterator);
if(pLayer != NULL) {
pLayer->detach();
pLayer->releaseSceneOwnership(this);
delete pLayer;
}
}
}
int nmVTKScene::getLayerCount() const
{
Q_ASSERT(isSceneGuiThread());
return isSceneGuiThread() ? m_mapLayers.size() : 0;
}