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++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}