はじめに
インタラクティブモードは、Teigha グラフィックスシステムの新しい機能です。この機能により、描画プロセスに時間がかかっている場合に、自動的に中断することができます。もちろん、この場合、描画は完全に完了しませんが、中間的な再描画の結果がそれほど重要でない連続した複数の再描画において、この機能は役立ちます。
インタラクティブモードの使用
インタラクティブモードは OdGsView API を介して制御されます。ただし、対応するデバイスがこれをサポートしていない場合、このモードは効果がありません。OdGsBaseVectorizeDevice の次のメソッドは、デバイスがこのモードをサポートしているかどうかを確認します。
bool supportInteractiveViewMode() const;
また、OdGsBaseVectorizeDevice には、インタラクティブモードのサポートを手動で変更できるメソッドがあります。
void setSupportInteractiveViewMode( bool );
OdGsView API は、インタラクティブモード用に次のメソッドを提供します。
-
virtual void beginInteractivityMode( double frameRateInHz )
このメソッドは、ビューのインタラクティブモードを有効にします。frameRateInHz は、希望のフレームレート (FPS) を指定します。この値は、1 秒あたりの希望の最小フレーム数を定義します。言い換えれば、各再描画操作にかかる時間を制限したい場合 (例: 「X 秒以内」)、frameRateInHz はこの時間制限の逆比 (1 / X) である必要があります。
-
virtual bool isInInteractivity() const
このビューがインタラクティブモードの場合、true を返します。
-
virtual double interactivityFrameRate() const
beginInteractivityMode() で指定された希望のフレームレートを返します。
-
virtual void endInteractivity()
このメソッドは、ビューのインタラクティブモードを無効にします。
実装の詳細
ビューがインタラクティブモードの場合、OdGsBaseVectorizer::beginViewVectorization が呼び出されるたびに (通常は OdGsDevice::update() から)、特別なタイマーが開始され、OdGsBaseVectorizer::endViewVectorization で停止されます。OdGsBaseVectorizer::renderAbort への各要求は、このタイマーをチェックします。経過時間が 1 / interactivityFrameRate() を超えると、OdGsBaseVectorizer::renderAbort() は true を返し、レンダリングループは中断されます。
インタラクティブモードにはいくつかの制限があります。
- このモードは OdGsBaseVectorizer::renderAbort() に基づいているため、デバイスが renderAbort() 機能をサポートしていない場合、効果はありません。
- このモードは OdGsNode レベルで動作するため、描画に少数の大きな (描画に時間がかかる) ノード (例: 外部参照) しか含まれていない場合、視覚的な効果がない可能性があります。
- レンダリングループは renderAbort() によって中断されるのではなく、抑制されるだけの場合があります。この場合、インタラクティブモードは引き続き機能しますが、結果のフレームレートはプリセットと異なる場合があります。
現在、Teigha は以下のデバイスでインタラクティブモードをサポートしています: WinGDI、WinDirectX、および WinOpenGL。
例
OdaMfcApp サンプルアプリケーションは、Orbit コマンドにインタラクティブモードを使用します。コンソールコマンド「interactivity」を使用すると、このモードを無効または有効にし、希望のフレームレートを変更できます。
インタラクティブモードの使用法は、TD_DrawingExamplesCommon の EditorObject.cpp にあります。ヘルパークラスを使用してインタラクティブモードを有効/無効にします。
class ViewInteractivityMode
{
bool m_enabled;
OdGsView* m_pView;
public:
ViewInteractivityMode( OdRxVariantValue enable, OdRxVariantValue frameRate, OdGsView* pView )
{
m_enabled = false;
m_pView = pView;
if( !enable.isNull() )
{
m_enabled = (bool)(enable);
if( m_enabled && !frameRate.isNull() )
{
double rate = (double)(( (frameRate.get())->getDouble() ));
pView->beginInteractivity( rate );
}
}
}
~ViewInteractivityMode()
{
if( m_enabled ) m_pView->endInteractivity();
}
};
ViewInteractivityMode のコンストラクタは(必要に応じて)インタラクティブモードを有効にし、デストラクタはそれを無効にします。
関数 OdEx3dOrbitCmd::execute は、イベントループに入る前に ViewInteractivityMode のインスタンスを作成します。
void OdEx3dOrbitCmd::execute(OdEdCommandContext* pCmdCtx)
{
OdDbCommandContextPtr pDbCmdCtx(pCmdCtx);
OdDbDatabasePtr pDb = pDbCmdCtx->database();
OdSmartPtr<OdDbUserIO> pIO = pDbCmdCtx->userIO();
OdDbObjectPtr pVpObj = pDb->activeViewportId().safeOpenObject(OdDb::kForWrite);
OdDbAbstractViewportDataPtr pAVD(pVpObj);
OdGsView* pView = pAVD->gsView(pVpObj);
// There is one special case: layout with enabled 'draw viewports first' mode
{
if (!pDb->getTILEMODE())
{
OdDbLayoutPtr pLayout = pDb->currentLayoutId().openObject();
if (pLayout->drawViewportsFirst())
{
if (pView->device()->viewAt(pView->device()->numViews() - 1) == pView)
pView = pView->device()->viewAt(0);
}
}
}
//
OdRxVariantValue interactiveMode = (OdRxVariantValue)pCmdCtx->arbitraryData( OD_T("OdaMfcApp InteractiveMode" ) );
OdRxVariantValue interactiveFrameRate = (OdRxVariantValue)pCmdCtx->arbitraryData( OD_T("OdaMfcApp InteractiveFrameRate" ) );
ViewInteractivityMode mode( interactiveMode, interactiveFrameRate, pView );
OdStaticRxObject<RTOrbitTracker> tracker;
for(;;)
{
try
{
tracker.init(pView, pIO->getPoint(OD_T("Press ESC or ENTER to exit."),
OdEd::kInpThrowEmpty|OdEd::kGptNoUCS|OdEd::kGptNoOSnap|OdEd::kGptBeginDrag, 0, OdString::kEmpty, &tracker));
pIO->getPoint(OD_T("Press ESC or ENTER to exit."),
OdEd::kInpThrowEmpty|OdEd::kGptNoUCS|OdEd::kGptNoOSnap|OdEd::kGptEndDrag, 0, OdString::kEmpty, &tracker);
tracker.reset();
}
catch(const OdEdCancel)
{
break;
}
}
}
関数が終了すると、ViewInteractivityMode のインスタンスは自動的に削除され、OdGsView::endInteractivity() が呼び出されます。
以下にいくつかのサンプルを示します。最初のサンプルでは、フレームレートが十分に小さいため、Orbit コマンドの実行中にすべてのエンティティが表示されます。
ここではフレームレートが上がったため、描画の一部が消えました。
そしてここではフレームレートがさらに上がったため、元のエンティティのごく一部しか表示されません。