V3d_View/Graphic3d_CView pair has been extended to define subview within the other V3d_View instance.
The initialization is done in form of V3d_View::SetWindow() taking parent V3d_View instance on input.
Subview definition includes dimensions defined as a fraction of a parent view and offset from a corner.
This scheme allows splitting window into several subviews automatically occupying entire viewport,
like splitting window into two vertial subviews (100%x50% + 100%x50%),
three horizontal subviews (33%x100% + 30%x100% + 30%x100%),
1 + 2 stacked subviews (50%x100% + 50%x50% + 50%x50%),
as well as thumbnail-alike subviews displayed on top of another larger view.
OpenGl_View::Redraw() blits content of subviews into the window within immediate redraw step.
AIS_ViewController::FlushViewEvents() has been extended
to re-calculate mouse input into local subview coordinates.
AIS_ViewController::handleViewRedraw() first redraws subviews and then parent views.
Introduced new callback AIS_ViewController::OnSubviewChanged()
to switch input focus to another subview on mouse click,
implemented by ViewerTest_EventManager (has to be done at application level).
vinit command has been extended with parameters -subview and -parent to create a subview.
In addition, view dimension arguments now can be defined as a fraction of screen size instead of pixels.
{
flushBuffers (theCtx, theView);
flushGestures(theCtx, theView);
+
+ if (theView->IsSubview())
+ {
+ // move input coordinates inside the view
+ const Graphic3d_Vec2i aDelta = theView->View()->SubviewTopLeft();
+ if (myGL.MoveTo.ToHilight || myGL.Dragging.ToStart)
+ {
+ myGL.MoveTo.Point -= aDelta;
+ }
+ if (myGL.Panning.ToStart)
+ {
+ myGL.Panning.PointStart -= aDelta;
+ }
+ if (myGL.Dragging.ToStart)
+ {
+ myGL.Dragging.PointStart -= aDelta;
+ }
+ if (myGL.Dragging.ToMove)
+ {
+ myGL.Dragging.PointTo -= aDelta;
+ }
+ if (myGL.OrbitRotation.ToStart)
+ {
+ myGL.OrbitRotation.PointStart -= Graphic3d_Vec2d (aDelta);
+ }
+ if (myGL.OrbitRotation.ToRotate)
+ {
+ myGL.OrbitRotation.PointTo -= Graphic3d_Vec2d (aDelta);
+ }
+ if (myGL.ViewRotation.ToStart)
+ {
+ myGL.ViewRotation.PointStart -= Graphic3d_Vec2d (aDelta);
+ }
+ if (myGL.ViewRotation.ToRotate)
+ {
+ myGL.ViewRotation.PointTo -= Graphic3d_Vec2d (aDelta);
+ }
+ for (Graphic3d_Vec2i& aPntIter : myGL.Selection.Points)
+ {
+ aPntIter -= aDelta;
+ }
+ for (Aspect_ScrollDelta& aZoomIter : myGL.ZoomActions)
+ {
+ aZoomIter.Point -= aDelta;
+ }
+ }
+
if (theToHandle)
{
HandleViewEvents (theCtx, theView);
//
}
+// =======================================================================
+// function : OnSubviewChanged
+// purpose :
+// =======================================================================
+void AIS_ViewController::OnSubviewChanged (const Handle(AIS_InteractiveContext)& ,
+ const Handle(V3d_View)& ,
+ const Handle(V3d_View)& )
+{
+ //
+}
+
// =======================================================================
// function : OnObjectDragged
// purpose :
void AIS_ViewController::handleViewRedraw (const Handle(AIS_InteractiveContext)& ,
const Handle(V3d_View)& theView)
{
+ Handle(V3d_View) aParentView = theView->IsSubview() ? theView->ParentView() : theView;
+
// manage animation state
if (!myViewAnimation.IsNull()
&& !myViewAnimation->IsStopped())
myToAskNextFrame = true;
}
- for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
+ for (int aSubViewPass = 0; aSubViewPass < 2; ++aSubViewPass)
{
- const Handle(V3d_View)& aView = aViewIter.Value();
- if (aView->IsInvalidated()
- || (myToAskNextFrame && aView == theView))
+ const bool isSubViewPass = (aSubViewPass == 0);
+ for (V3d_ListOfViewIterator aViewIter (theView->Viewer()->ActiveViewIterator()); aViewIter.More(); aViewIter.Next())
{
- if (aView->ComputedMode())
+ const Handle(V3d_View)& aView = aViewIter.Value();
+ if (isSubViewPass
+ && !aView->IsSubview())
{
- aView->Update();
+ for (const Handle(V3d_View)& aSubviewIter : aView->Subviews())
+ {
+ if (aSubviewIter->Viewer() != theView->Viewer())
+ {
+ if (aSubviewIter->IsInvalidated())
+ {
+ if (aSubviewIter->ComputedMode())
+ {
+ aSubviewIter->Update();
+ }
+ else
+ {
+ aSubviewIter->Redraw();
+ }
+ }
+ else if (aSubviewIter->IsInvalidatedImmediate())
+ {
+ aSubviewIter->RedrawImmediate();
+ }
+ }
+ }
+ continue;
}
- else
+ else if (!isSubViewPass
+ && aView->IsSubview())
{
- aView->Redraw();
+ continue;
+ }
+
+ if (aView->IsInvalidated()
+ || (myToAskNextFrame && aView == theView))
+ {
+ if (aView->ComputedMode())
+ {
+ aView->Update();
+ }
+ else
+ {
+ aView->Redraw();
+ }
+
+ if (aView->IsSubview())
+ {
+ aView->ParentView()->InvalidateImmediate();
+ }
+ }
+ else if (aView->IsInvalidatedImmediate())
+ {
+ if (aView->IsSubview())
+ {
+ aView->ParentView()->InvalidateImmediate();
+ }
+
+ aView->RedrawImmediate();
}
}
- else if (aView->IsInvalidatedImmediate())
- {
- aView->RedrawImmediate();
- }
+ }
+ if (theView->IsSubview()
+ && theView->Viewer() != aParentView->Viewer())
+ {
+ aParentView->RedrawImmediate();
}
if (myToAskNextFrame)
{
// ask more frames
- theView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
+ aParentView->Window()->InvalidateContent (Handle(Aspect_DisplayConnection)());
}
}
{
const bool wasImmediateUpdate = theView->SetImmediateUpdate (false);
+ Handle(V3d_View) aPickedView;
+ if (theView->IsSubview()
+ || !theView->Subviews().IsEmpty())
+ {
+ // activate another subview on mouse click
+ bool toPickSubview = false;
+ Graphic3d_Vec2i aClickPoint;
+ if (myGL.Selection.Tool == AIS_ViewSelectionTool_Picking
+ && !myGL.Selection.Points.IsEmpty())
+ {
+ aClickPoint = myGL.Selection.Points.Last();
+ toPickSubview = true;
+ }
+ else if (!myGL.ZoomActions.IsEmpty())
+ {
+ //aClickPoint = myGL.ZoomActions.Last().Point;
+ //toPickSubview = true;
+ }
+
+ if (toPickSubview)
+ {
+ if (theView->IsSubview())
+ {
+ aClickPoint += theView->View()->SubviewTopLeft();
+ }
+ Handle(V3d_View) aParent = !theView->IsSubview() ? theView : theView->ParentView();
+ aPickedView = aParent->PickSubview (aClickPoint);
+ }
+ }
+
handleViewOrientationKeys (theCtx, theView);
const AIS_WalkDelta aWalk = handleNavigationKeys (theCtx, theView);
handleXRInput (theCtx, theView, aWalk);
theView->SetImmediateUpdate (wasImmediateUpdate);
+ if (!aPickedView.IsNull()
+ && aPickedView != theView)
+ {
+ OnSubviewChanged (theCtx, theView, aPickedView);
+ }
+
// make sure to not process the same events twice
myGL.Reset();
myToAskNextFrame = false;
const Handle(V3d_View)& theView,
AIS_DragAction theAction);
+ //! Callback called by HandleViewEvents() on Selection of another (sub)view.
+ //! This method is expected to be called from rendering thread.
+ Standard_EXPORT virtual void OnSubviewChanged (const Handle(AIS_InteractiveContext)& theCtx,
+ const Handle(V3d_View)& theOldView,
+ const Handle(V3d_View)& theNewView);
+
//! Pick closest point under mouse cursor.
//! This method is expected to be called from rendering thread.
//! @param thePnt [out] result point
DEFINE_STANDARD_RTTIEXT(Aspect_Window, Standard_Transient)
public:
+ //! Returns True if the window <me> is virtual
+ Standard_EXPORT Standard_Boolean IsVirtual() const;
+
+ //! Setup the virtual state
+ Standard_EXPORT void SetVirtual (const Standard_Boolean theVirtual);
+
+ //! Returns window top-left corner.
+ Graphic3d_Vec2i TopLeft() const
+ {
+ Graphic3d_Vec2i aTopLeft, aBotRight;
+ Position (aTopLeft.x(), aTopLeft.y(), aBotRight.x(), aBotRight.y());
+ return aTopLeft;
+ }
+
+ //! Returns window dimensions.
+ Graphic3d_Vec2i Dimensions() const
+ {
+ Graphic3d_Vec2i aSize;
+ Size (aSize.x(), aSize.y());
+ return aSize;
+ }
+
+ //! Returns connection to Display or NULL.
+ const Handle(Aspect_DisplayConnection)& DisplayConnection() const { return myDisplay; }
+
+ //! Returns the window background.
+ Standard_EXPORT Aspect_Background Background() const;
+
+ //! Returns the current image background fill mode.
+ Standard_EXPORT Aspect_FillMethod BackgroundFillMethod() const;
+
+ //! Returns the window gradient background.
+ Standard_EXPORT Aspect_GradientBackground GradientBackground() const;
+
//! Modifies the window background.
- Standard_EXPORT void SetBackground (const Aspect_Background& ABack);
+ Standard_EXPORT void SetBackground (const Aspect_Background& theBack);
//! Modifies the window background.
- Standard_EXPORT void SetBackground (const Quantity_Color& color);
+ Standard_EXPORT void SetBackground (const Quantity_Color& theColor);
//! Modifies the window gradient background.
- Standard_EXPORT void SetBackground (const Aspect_GradientBackground& ABackground);
+ Standard_EXPORT void SetBackground (const Aspect_GradientBackground& theBackground);
//! Modifies the window gradient background.
Standard_EXPORT void SetBackground (const Quantity_Color& theFirstColor, const Quantity_Color& theSecondColor, const Aspect_GradientFillMethod theFillMethod);
+public:
+
+ //! Returns True if the window <me> is opened
+ //! and False if the window is closed.
+ Standard_EXPORT virtual Standard_Boolean IsMapped() const = 0;
+
//! Opens the window <me>.
Standard_EXPORT virtual void Map() const = 0;
//! and returns TRUE if the window is mapped at screen.
Standard_EXPORT virtual Standard_Boolean DoMapping() const = 0;
- //! Returns the window background.
- Standard_EXPORT Aspect_Background Background() const;
-
- //! Returns the current image background fill mode.
- Standard_EXPORT Aspect_FillMethod BackgroundFillMethod() const;
-
- //! Returns the window gradient background.
- Standard_EXPORT Aspect_GradientBackground GradientBackground() const;
-
- //! Returns True if the window <me> is opened
- //! and False if the window is closed.
- Standard_EXPORT virtual Standard_Boolean IsMapped() const = 0;
-
- //! Returns True if the window <me> is virtual
- Standard_EXPORT Standard_Boolean IsVirtual() const;
-
- //! Setup the virtual state
- Standard_EXPORT void SetVirtual (const Standard_Boolean theVirtual);
-
//! Returns The Window RATIO equal to the physical
//! WIDTH/HEIGHT dimensions
Standard_EXPORT virtual Standard_Real Ratio() const = 0;
//! Returns native Window FB config (GLXFBConfig on Xlib)
Standard_EXPORT virtual Aspect_FBConfig NativeFBConfig() const = 0;
- //! Returns connection to Display or NULL.
- const Handle(Aspect_DisplayConnection)& DisplayConnection() const { return myDisplay; }
-
//! Sets window title.
virtual void SetTitle (const TCollection_AsciiString& theTitle) { (void )theTitle; }
// function : SetWindow
// purpose :
// =======================================================================
-void D3DHost_View::SetWindow (const Handle(Aspect_Window)& theWindow,
+void D3DHost_View::SetWindow (const Handle(Graphic3d_CView)& theParentVIew,
+ const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext)
{
if (!myD3dWglFbo.IsNull())
myD3dDevice = NULL;
}
- OpenGl_View::SetWindow (theWindow, theContext);
+ OpenGl_View::SetWindow (theParentVIew, theWindow, theContext);
if (!myWindow.IsNull())
{
Standard_EXPORT virtual void ReleaseGlResources (const Handle(OpenGl_Context)& theCtx) Standard_OVERRIDE;
//! Creates and maps rendering window to the view.
- //! @param theWindow [in] the window.
- //! @param theContext [in] the rendering context. If NULL the context will be created internally.
- //! @param theDisplayCB [in] the display callback function. If is not a NULL value, then the callback will be
- //! invoked at the end of the OCC graphic traversal and just before the swap of buffers.
- //! @param theClientData [in] the client data for the callback.
- Standard_EXPORT virtual void SetWindow (const Handle(Aspect_Window)& theWindow,
+ Standard_EXPORT virtual void SetWindow (const Handle(Graphic3d_CView)& theParentVIew,
+ const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext) Standard_OVERRIDE;
//! Resizes the window.
TCollection_AsciiString aViewName = TCollection_AsciiString ("Driver1/Document_") + theArgVec[1] + "/View1";
if (!TPrsStd_AISViewer::Find (aRoot, aDocViewer))
{
- ViewerTest::ViewerInit (0, 0, 0, 0, aViewName.ToCString(), "");
+ ViewerTest::ViewerInit (aViewName);
aDocViewer = TPrsStd_AISViewer::New (aRoot, ViewerTest::GetAISContext());
}
#include <Graphic3d_CView.hxx>
+#include <Aspect_NeutralWindow.hxx>
#include <Aspect_OpenVRSession.hxx>
#include <Graphic3d_CubeMapPacked.hxx>
#include <Graphic3d_Layer.hxx>
//purpose :
//=======================================================================
Graphic3d_CView::Graphic3d_CView (const Handle(Graphic3d_StructureManager)& theMgr)
-: myBgColor (Quantity_NOC_BLACK),
- myBackgroundType (Graphic3d_TOB_NONE),
- myToUpdateSkydome (Standard_False),
- myStructureManager (theMgr),
- myCamera (new Graphic3d_Camera()),
- myHiddenObjects (new Graphic3d_NMapOfTransient()),
- myIsInComputedMode (Standard_False),
- myIsActive (Standard_False),
- myIsRemoved (Standard_False),
- myBackfacing (Graphic3d_TypeOfBackfacingModel_Auto),
- myVisualization (Graphic3d_TOV_WIREFRAME),
- myUnitFactor (1.0)
+: myId (0),
+ //
+ myParentView (nullptr),
+ myIsSubviewComposer (Standard_False),
+ mySubviewCorner (Aspect_TOTP_LEFT_UPPER),
+ mySubviewSize (1.0, 1.0),
+ //
+ myStructureManager (theMgr),
+ myCamera (new Graphic3d_Camera()),
+ myHiddenObjects (new Graphic3d_NMapOfTransient()),
+ myIsInComputedMode (Standard_False),
+ myIsActive (Standard_False),
+ myIsRemoved (Standard_False),
+ myBackfacing (Graphic3d_TypeOfBackfacingModel_Auto),
+ myVisualization (Graphic3d_TOV_WIREFRAME),
+ //
+ myBgColor (Quantity_NOC_BLACK),
+ myBackgroundType (Graphic3d_TOB_NONE),
+ myToUpdateSkydome (Standard_False),
+ //
+ myUnitFactor (1.0)
{
myId = myStructureManager->Identification (this);
}
return;
}
- Graphic3d_MapOfStructure aDisplayedStructs (myStructsDisplayed);
+ if (myParentView != nullptr)
+ {
+ myParentView->RemoveSubview (this);
+ myParentView = nullptr;
+ }
+ {
+ NCollection_Sequence<Handle(Graphic3d_CView)> aSubviews = mySubviews;
+ mySubviews.Clear();
+ for (const Handle(Graphic3d_CView)& aViewIter : aSubviews)
+ {
+ aViewIter->Remove();
+ }
+ }
+ Graphic3d_MapOfStructure aDisplayedStructs (myStructsDisplayed);
for (Graphic3d_MapIteratorOfMapOfStructure aStructIter (aDisplayedStructs); aStructIter.More(); aStructIter.Next())
{
Erase (aStructIter.Value());
myIsRemoved = Standard_True;
}
+// ========================================================================
+// function : AddSubview
+// purpose :
+// ========================================================================
+void Graphic3d_CView::AddSubview (const Handle(Graphic3d_CView)& theView)
+{
+ mySubviews.Append (theView);
+}
+
+// ========================================================================
+// function : RemoveSubview
+// purpose :
+// ========================================================================
+bool Graphic3d_CView::RemoveSubview (const Graphic3d_CView* theView)
+{
+ for (NCollection_Sequence<Handle(Graphic3d_CView)>::Iterator aViewIter (mySubviews); aViewIter.More(); aViewIter.Next())
+ {
+ if (aViewIter.Value() == theView)
+ {
+ mySubviews.Remove (aViewIter);
+ return true;
+ }
+ }
+ return false;
+}
+
+// ========================================================================
+// function : Resized
+// purpose :
+// ========================================================================
+void Graphic3d_CView::Resized()
+{
+ if (IsSubview())
+ {
+ Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast(Window());
+ SubviewResized (aWindow);
+ }
+}
+
+//! Calculate offset in pixels from fraction.
+static int getSubViewOffset (double theOffset, int theWinSize)
+{
+ if (theOffset >= 1.0)
+ {
+ return int(theOffset);
+ }
+ else
+ {
+ return int(theOffset * theWinSize);
+ }
+}
+
+// ========================================================================
+// function : SubviewResized
+// purpose :
+// ========================================================================
+void Graphic3d_CView::SubviewResized (const Handle(Aspect_NeutralWindow)& theWindow)
+{
+ if (!IsSubview()
+ || theWindow.IsNull())
+ {
+ return;
+ }
+
+ const Graphic3d_Vec2i aWinSize (myParentView->Window()->Dimensions());
+ Graphic3d_Vec2i aViewSize (Graphic3d_Vec2d(aWinSize) * mySubviewSize);
+ if (mySubviewSize.x() > 1.0)
+ {
+ aViewSize.x() = (int)mySubviewSize.x();
+ }
+ if (mySubviewSize.y() > 1.0)
+ {
+ aViewSize.y() = (int)mySubviewSize.y();
+ }
+
+ Graphic3d_Vec2i anOffset (getSubViewOffset (mySubviewOffset.x(), aWinSize.x()),
+ getSubViewOffset (mySubviewOffset.y(), aWinSize.y()));
+ mySubviewTopLeft = (aWinSize - aViewSize) / 2; // Aspect_TOTP_CENTER
+ if ((mySubviewCorner & Aspect_TOTP_LEFT) != 0)
+ {
+ mySubviewTopLeft.x() = anOffset.x();
+ }
+ else if ((mySubviewCorner & Aspect_TOTP_RIGHT) != 0)
+ {
+ mySubviewTopLeft.x() = Max (aWinSize.x() - anOffset.x() - aViewSize.x(), 0);
+ }
+
+ if ((mySubviewCorner & Aspect_TOTP_TOP) != 0)
+ {
+ mySubviewTopLeft.y() = anOffset.y();
+ }
+ else if ((mySubviewCorner & Aspect_TOTP_BOTTOM) != 0)
+ {
+ mySubviewTopLeft.y() = Max (aWinSize.y() - anOffset.y() - aViewSize.y(), 0);
+ }
+
+ mySubviewTopLeft += mySubviewMargins;
+ aViewSize -= mySubviewMargins * 2;
+
+ const int aRight = Min(mySubviewTopLeft.x() + aViewSize.x(), aWinSize.x());
+ aViewSize.x() = aRight - mySubviewTopLeft.x();
+
+ const int aBot = Min(mySubviewTopLeft.y() + aViewSize.y(), aWinSize.y());
+ aViewSize.y() = aBot - mySubviewTopLeft.y();
+
+ theWindow->SetSize (aViewSize.x(), aViewSize.y());
+}
+
// ========================================================================
// function : SetComputedMode
// purpose :
#include <Standard_Transient.hxx>
#include <TColStd_IndexedDataMapOfStringString.hxx>
+class Aspect_NeutralWindow;
class Aspect_XRSession;
class Graphic3d_CView;
class Graphic3d_Layer;
virtual Standard_Boolean IsInvalidated() = 0;
//! Handle changing size of the rendering window.
- virtual void Resized() = 0;
+ Standard_EXPORT virtual void Resized() = 0;
//! @param theDrawToFrontBuffer Advanced option to modify rendering mode:
//! 1. TRUE. Drawing immediate mode structures directly to the front buffer over the scene image.
virtual Standard_Boolean SetImmediateModeDrawToFront (const Standard_Boolean theDrawToFrontBuffer) = 0;
//! Creates and maps rendering window to the view.
- //! @param theWindow [in] the window.
- //! @param theContext [in] the rendering context. If NULL the context will be created internally.
- virtual void SetWindow (const Handle(Aspect_Window)& theWindow,
- const Aspect_RenderingContext theContext = NULL) = 0;
+ //! @param[in] theParentVIew parent view or NULL
+ //! @param[in] theWindow the window
+ //! @param[in] theContext the rendering context; if NULL the context will be created internally
+ virtual void SetWindow (const Handle(Graphic3d_CView)& theParentVIew,
+ const Handle(Aspect_Window)& theWindow,
+ const Aspect_RenderingContext theContext) = 0;
//! Returns the window associated to the view.
virtual Handle(Aspect_Window) Window() const = 0;
//! Dumps the content of me into the stream
Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+public: //! @name subview properties
+
+ //! Return TRUE if this is a subview of another view.
+ bool IsSubview() const { return myParentView != nullptr; }
+
+ //! Return parent View or NULL if this is not a subview.
+ Graphic3d_CView* ParentView() { return myParentView; }
+
+ //! Return TRUE if this is view performs rendering of subviews and nothing else; FALSE by default.
+ //! By default, view with subviews will render main scene and blit subviews on top of it.
+ //! Rendering of main scene might become redundant in case if subviews cover entire window of parent view.
+ //! This flag allows to disable rendering of the main scene in such scenarios
+ //! without creation of a dedicated V3d_Viewer instance just for composing subviews.
+ bool IsSubviewComposer() const { return myIsSubviewComposer; }
+
+ //! Set if this view should perform composing of subviews and nothing else.
+ void SetSubviewComposer (bool theIsComposer) { myIsSubviewComposer = theIsComposer; }
+
+ //! Return subview list.
+ const NCollection_Sequence<Handle(Graphic3d_CView)>& Subviews() const { return mySubviews; }
+
+ //! Add subview to the list.
+ Standard_EXPORT void AddSubview (const Handle(Graphic3d_CView)& theView);
+
+ //! Remove subview from the list.
+ Standard_EXPORT bool RemoveSubview (const Graphic3d_CView* theView);
+
+ //! Return subview position within parent view; Aspect_TOTP_LEFT_UPPER by default.
+ Aspect_TypeOfTriedronPosition SubviewCorner() const { return mySubviewCorner; }
+
+ //! Set subview position within parent view.
+ void SetSubviewCorner (Aspect_TypeOfTriedronPosition thePos) { mySubviewCorner = thePos; }
+
+ //! Return subview top-left position relative to parent view in pixels.
+ const Graphic3d_Vec2i& SubviewTopLeft() const { return mySubviewTopLeft; }
+
+ //! Return TRUE if subview size is set as proportions relative to parent view.
+ bool IsSubViewRelativeSize() const { return mySubviewSize.x() <= 1.0 && mySubviewSize.y() <= 1.0; }
+
+ //! Return subview dimensions; (1.0, 1.0) by default.
+ //! Values >= 2 define size in pixels;
+ //! Values <= 1.0 define size as fraction of parent view.
+ const Graphic3d_Vec2d& SubviewSize() const { return mySubviewSize; }
+
+ //! Set subview size relative to parent view.
+ void SetSubviewSize (const Graphic3d_Vec2d& theSize) { mySubviewSize = theSize; }
+
+ //! Return corner offset within parent view; (0.0,0.0) by default.
+ //! Values >= 2 define offset in pixels;
+ //! Values <= 1.0 define offset as fraction of parent view dimensions.
+ const Graphic3d_Vec2d& SubviewOffset() const { return mySubviewOffset; }
+
+ //! Set corner offset within parent view.
+ void SetSubviewOffset (const Graphic3d_Vec2d& theOffset) { mySubviewOffset = theOffset; }
+
+ //! Return subview margins in pixels; (0,0) by default
+ const Graphic3d_Vec2i& SubviewMargins() const { return mySubviewMargins; }
+
+ //! Set subview margins in pixels.
+ void SetSubviewMargins (const Graphic3d_Vec2i& theMargins) { mySubviewMargins = theMargins; }
+
+ //! Update subview position and dimensions.
+ Standard_EXPORT void SubviewResized (const Handle(Aspect_NeutralWindow)& theWindow);
+
private:
//! Adds the structure to display lists of the view.
Standard_Integer myId;
Graphic3d_RenderingParams myRenderParams;
- Quantity_ColorRGBA myBgColor;
- Handle(Graphic3d_TextureMap) myBackgroundImage;
- Handle(Graphic3d_CubeMap) myCubeMapBackground; //!< Cubemap displayed at background
- Handle(Graphic3d_CubeMap) myCubeMapIBL; //!< Cubemap used for environment lighting
- Handle(Graphic3d_TextureEnv) myTextureEnvData;
- Graphic3d_TypeOfBackground myBackgroundType; //!< Current type of background
- Aspect_SkydomeBackground mySkydomeAspect;
- Standard_Boolean myToUpdateSkydome;
+ NCollection_Sequence<Handle(Graphic3d_CView)> mySubviews; //!< list of child views
+ Graphic3d_CView* myParentView; //!< back-pointer to the parent view
+ Standard_Boolean myIsSubviewComposer; //!< flag to skip rendering of viewer contents
+ Aspect_TypeOfTriedronPosition mySubviewCorner; //!< position within parent view
+ Graphic3d_Vec2i mySubviewTopLeft; //!< subview top-left position relative to parent view
+ Graphic3d_Vec2i mySubviewMargins; //!< subview margins in pixels
+ Graphic3d_Vec2d mySubviewSize; //!< subview size
+ Graphic3d_Vec2d mySubviewOffset; //!< subview corner offset within parent view
Handle(Graphic3d_StructureManager) myStructureManager;
Handle(Graphic3d_Camera) myCamera;
Graphic3d_TypeOfBackfacingModel myBackfacing;
Graphic3d_TypeOfVisualization myVisualization;
+ Quantity_ColorRGBA myBgColor;
+ Handle(Graphic3d_TextureMap) myBackgroundImage;
+ Handle(Graphic3d_CubeMap) myCubeMapBackground; //!< Cubemap displayed at background
+ Handle(Graphic3d_CubeMap) myCubeMapIBL; //!< Cubemap used for environment lighting
+ Handle(Graphic3d_TextureEnv) myTextureEnvData;
+ Graphic3d_GraduatedTrihedron myGTrihedronData;
+ Graphic3d_TypeOfBackground myBackgroundType; //!< Current type of background
+ Aspect_SkydomeBackground mySkydomeAspect;
+ Standard_Boolean myToUpdateSkydome;
+
Handle(Aspect_XRSession) myXRSession;
Handle(Graphic3d_Camera) myBackXRCamera; //!< camera projection parameters to restore after closing XR session (FOV, aspect and similar)
Handle(Graphic3d_Camera) myBaseXRCamera; //!< neutral camera orientation defining coordinate system in which head tracking is defined
Handle(Graphic3d_Camera) myPosedXRCameraCopy; //!< neutral camera orientation copy at the beginning of processing input
Standard_Real myUnitFactor; //!< unit scale factor defined as scale factor for m (meters)
-protected:
-
- Graphic3d_GraduatedTrihedron myGTrihedronData;
-
};
#endif // _Graphic3d_CView_HeaderFile
}
// =======================================================================
-// function : Window
+// function : CreateRenderWindow
// purpose :
// =======================================================================
-Handle(OpenGl_Window) OpenGl_GraphicDriver::CreateRenderWindow (const Handle(Aspect_Window)& theWindow,
+Handle(OpenGl_Window) OpenGl_GraphicDriver::CreateRenderWindow (const Handle(Aspect_Window)& theNativeWindow,
+ const Handle(Aspect_Window)& theSizeWindow,
const Aspect_RenderingContext theContext)
{
Handle(OpenGl_Context) aShareCtx = GetSharedContext();
- Handle(OpenGl_Window) aWindow = new OpenGl_Window (this, theWindow, theContext, myCaps, aShareCtx);
+ Handle(OpenGl_Window) aWindow = new OpenGl_Window();
+ aWindow->Init (this, theNativeWindow, theSizeWindow, theContext, myCaps, aShareCtx);
return aWindow;
}
Standard_EXPORT virtual void RemoveView (const Handle(Graphic3d_CView)& theView) Standard_OVERRIDE;
- Standard_EXPORT virtual Handle(OpenGl_Window) CreateRenderWindow (const Handle(Aspect_Window)& theWindow, const Aspect_RenderingContext theContext);
+ //! Create OpenGL window from native window.
+ //! @param[in] theNativeWindow native window holder
+ //! @param[in] theSizeWindow object defining window dimensions
+ //! @param[in] theContext existing native rendering context
+ Standard_EXPORT virtual Handle(OpenGl_Window) CreateRenderWindow (const Handle(Aspect_Window)& theNativeWindow,
+ const Handle(Aspect_Window)& theSizeWindow,
+ const Aspect_RenderingContext theContext);
public:
#include <OpenGl_View.hxx>
+#include <Aspect_NeutralWindow.hxx>
#include <Aspect_RenderingContext.hxx>
-#include <Aspect_Window.hxx>
#include <Aspect_XRSession.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
#include <Graphic3d_Texture2Dmanual.hxx>
// =======================================================================
Handle(Aspect_Window) OpenGl_View::Window() const
{
- return myWindow->PlatformWindow();
+ return myWindow->SizeWindow();
}
// =======================================================================
// function : SetWindow
// purpose :
// =======================================================================
-void OpenGl_View::SetWindow (const Handle(Aspect_Window)& theWindow,
+void OpenGl_View::SetWindow (const Handle(Graphic3d_CView)& theParentVIew,
+ const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext)
{
- myWindow = myDriver->CreateRenderWindow (theWindow, theContext);
- Standard_ASSERT_RAISE (!myWindow.IsNull(),
- "OpenGl_View::SetWindow, "
- "Failed to create OpenGl window.");
+ if (theContext != nullptr
+ && !theParentVIew.IsNull())
+ {
+ throw Standard_ProgramError ("OpenGl_View::SetWindow(), internal error");
+ }
+
+ if (myParentView != nullptr)
+ {
+ myParentView->RemoveSubview (this);
+ myParentView = nullptr;
+ }
+
+ OpenGl_View* aParentView = dynamic_cast<OpenGl_View*> (theParentVIew.get());
+ if (!theParentVIew.IsNull())
+ {
+ if (aParentView == nullptr
+ || aParentView->GlWindow().IsNull()
+ || aParentView->GlWindow()->GetGlContext().IsNull())
+ {
+ throw Standard_ProgramError ("OpenGl_View::SetWindow(), internal error");
+ }
+
+ myParentView = aParentView;
+ myParentView->AddSubview (this);
+
+ Handle(Aspect_NeutralWindow) aSubWindow = Handle(Aspect_NeutralWindow)::DownCast(theWindow);
+ SubviewResized (aSubWindow);
+
+ const Handle(OpenGl_Window)& aParentGlWindow = aParentView->GlWindow();
+ Aspect_RenderingContext aRendCtx = aParentGlWindow->GetGlContext()->RenderingContext();
+ myWindow = myDriver->CreateRenderWindow (aParentGlWindow->PlatformWindow(), theWindow, aRendCtx);
+ }
+ else
+ {
+ myWindow = myDriver->CreateRenderWindow (theWindow, theWindow, theContext);
+ }
+ if (myWindow.IsNull())
+ {
+ throw Standard_ProgramError ("OpenGl_View::SetWindow, Failed to create OpenGl window");
+ }
myWorkspace = new OpenGl_Workspace (this, myWindow);
myWorldViewProjState.Reset();
// =======================================================================
void OpenGl_View::Resized()
{
- if (myWindow.IsNull())
- return;
-
- myWindow->Resize();
+ base_type::Resized();
+ if (!myWindow.IsNull())
+ {
+ myWindow->Resize();
+ }
}
// =======================================================================
const bool hasTextureMsaa = aCtx->HasTextureMultisampling();
bool toUseOit = myRenderParams.TransparencyMethod != Graphic3d_RTM_BLEND_UNORDERED
+ && !myIsSubviewComposer
&& checkOitCompatibility (aCtx, aNbSamples > 0);
- const bool toInitImmediateFbo = myTransientDrawToFront
+ const bool toInitImmediateFbo = myTransientDrawToFront && !myIsSubviewComposer
&& (!aCtx->caps->useSystemBuffer || (toUseOit && HasImmediateStructures()));
if ( aFrameBuffer == NULL
OpenGl_FrameBuffer* aFrameBuffer = myFBO.get();
bool toSwap = aCtx->IsRender()
&& !aCtx->caps->buffersNoSwap
- && aFrameBuffer == NULL
+ && aFrameBuffer == nullptr
&& (!IsActiveXR() || myRenderParams.ToMirrorComposer);
if ( aFrameBuffer == NULL
&& !aCtx->DefaultFrameBuffer().IsNull()
{
toSwap = false;
}
- else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip && toSwap)
+ else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
+ && toSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
}
}
// Swap the buffers
- if (toSwap)
+ if (toSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
if (!myMainSceneFbos[0]->IsValid())
Standard_True) || toSwap;
if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
&& toSwap
- && myFBO.get() == NULL
- && !aCtx->caps->buffersNoSwap)
+ && myFBO.get() == nullptr
+ && !aCtx->caps->buffersNoSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
}
if (toSwap
&& myFBO.get() == NULL
- && !aCtx->caps->buffersNoSwap)
+ && !aCtx->caps->buffersNoSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
}
render (theProjection, theDrawFbo, theOitAccumFbo, Standard_True);
+ blitSubviews (theProjection, theDrawFbo);
+
return !toCopyBackToFront;
}
+// =======================================================================
+// function : blitSubviews
+// purpose :
+// =======================================================================
+bool OpenGl_View::blitSubviews (const Graphic3d_Camera::Projection ,
+ OpenGl_FrameBuffer* theDrawFbo)
+{
+ const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
+ if (aCtx->arbFBOBlit == nullptr)
+ {
+ return false;
+ }
+
+ bool isChanged = false;
+ for (const Handle(Graphic3d_CView)& aChildIter : mySubviews)
+ {
+ OpenGl_View* aSubView = dynamic_cast<OpenGl_View*> (aChildIter.get());
+ const Handle(OpenGl_FrameBuffer)& aChildFbo = !aSubView->myImmediateSceneFbos[0].IsNull()
+ ? aSubView->myImmediateSceneFbos[0]
+ : aSubView->myMainSceneFbos[0];
+ if (aChildFbo.IsNull() || !aChildFbo->IsValid())
+ {
+ continue;
+ }
+
+ aChildFbo->BindReadBuffer (aCtx);
+ if (theDrawFbo != NULL
+ && theDrawFbo->IsValid())
+ {
+ theDrawFbo->BindDrawBuffer (aCtx);
+ }
+ else
+ {
+ aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
+ aCtx->SetFrameBufferSRGB (false);
+ }
+
+ Graphic3d_Vec2i aWinSize (aCtx->Viewport()[2], aCtx->Viewport()[3]); //aSubView->GlWindow()->PlatformWindow()->Dimensions();
+ Graphic3d_Vec2i aSubViewSize = aChildFbo->GetVPSize();
+ Graphic3d_Vec2i aSubViewPos = aSubView->SubviewTopLeft();
+ Graphic3d_Vec2i aDestSize = aSubViewSize;
+ if (aSubView->RenderingParams().RenderResolutionScale != 1.0f)
+ {
+ aDestSize = Graphic3d_Vec2i (Graphic3d_Vec2d(aDestSize) / Graphic3d_Vec2d(aSubView->RenderingParams().RenderResolutionScale));
+ }
+ aSubViewPos.y() = aWinSize.y() - aDestSize.y() - aSubViewPos.y();
+
+ const GLint aFilterGl = aDestSize == aSubViewSize ? GL_NEAREST : GL_LINEAR;
+ aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, aSubViewSize.x(), aSubViewSize.y(),
+ aSubViewPos.x(), aSubViewPos.y(), aSubViewPos.x() + aDestSize.x(), aSubViewPos.y() + aDestSize.y(),
+ GL_COLOR_BUFFER_BIT, aFilterGl);
+ const int anErr = aCtx->core11fwd->glGetError();
+ if (anErr != GL_NO_ERROR)
+ {
+ TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "FBO blitting has failed [Error " + OpenGl_Context::FormatGlError (anErr) + "]\n"
+ + " Please check your graphics driver settings or try updating driver.";
+ if (aChildFbo->NbSamples() != 0)
+ {
+ myToDisableMSAA = true;
+ aMsg += "\n MSAA settings should not be overridden by driver!";
+ }
+ aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
+ }
+
+ if (theDrawFbo != NULL
+ && theDrawFbo->IsValid())
+ {
+ theDrawFbo->BindBuffer (aCtx);
+ }
+ else
+ {
+ aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
+ aCtx->SetFrameBufferSRGB (false);
+ }
+ isChanged = true;
+ }
+
+ return isChanged;
+}
+
//=======================================================================
//function : renderShadowMap
//purpose :
OpenGl_FrameBuffer* theOitAccumFbo,
const Standard_Boolean theToDrawImmediate)
{
+ if (myIsSubviewComposer)
+ {
+ return;
+ }
+
myZLayers.UpdateCulling (myWorkspace, theToDrawImmediate);
- if ( myZLayers.NbStructures() <= 0 )
+ if (myZLayers.NbStructures() <= 0)
+ {
return;
+ }
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
Standard_Boolean toRenderGL = theToDrawImmediate ||
Standard_EXPORT Standard_Boolean SetImmediateModeDrawToFront (const Standard_Boolean theDrawToFrontBuffer) Standard_OVERRIDE;
//! Creates and maps rendering window to the view.
- //! @param theWindow [in] the window.
- //! @param theContext [in] the rendering context. If NULL the context will be created internally.
- Standard_EXPORT virtual void SetWindow (const Handle(Aspect_Window)& theWindow,
+ Standard_EXPORT virtual void SetWindow (const Handle(Graphic3d_CView)& theParentVIew,
+ const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext) Standard_OVERRIDE;
//! Returns window associated with the view.
OpenGl_FrameBuffer* theOitAccumFbo,
const Standard_Boolean theIsPartialUpdate = Standard_False);
+ //! Blit subviews into this view.
+ Standard_EXPORT bool blitSubviews (const Graphic3d_Camera::Projection theProjection,
+ OpenGl_FrameBuffer* theDrawFbo);
+
//! Blit image from/to specified buffers.
Standard_EXPORT bool blitBuffers (OpenGl_FrameBuffer* theReadFbo,
OpenGl_FrameBuffer* theDrawFbo,
// function : OpenGl_Window
// purpose :
// =======================================================================
-OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
- const Handle(Aspect_Window)& thePlatformWindow,
- Aspect_RenderingContext theGContext,
- const Handle(OpenGl_Caps)& theCaps,
- const Handle(OpenGl_Context)& theShareCtx)
-: myGlContext (new OpenGl_Context (theCaps)),
- myOwnGContext (theGContext == 0),
- myPlatformWindow (thePlatformWindow),
- mySwapInterval (theCaps->swapInterval)
+OpenGl_Window::OpenGl_Window()
+: myOwnGContext (false),
+ mySwapInterval (0)
{
- myPlatformWindow->Size (myWidth, myHeight);
+ //
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+void OpenGl_Window::Init (const Handle(OpenGl_GraphicDriver)& theDriver,
+ const Handle(Aspect_Window)& thePlatformWindow,
+ const Handle(Aspect_Window)& theSizeWindow,
+ Aspect_RenderingContext theGContext,
+ const Handle(OpenGl_Caps)& theCaps,
+ const Handle(OpenGl_Context)& theShareCtx)
+{
+ myGlContext = new OpenGl_Context (theCaps);
+ myOwnGContext = (theGContext == 0);
+ myPlatformWindow = thePlatformWindow;
+ mySizeWindow = theSizeWindow;
+ mySwapInterval = theCaps->swapInterval;
+
+ mySizeWindow->Size (mySize.x(), mySize.y());
Standard_Boolean isCoreProfile = Standard_False;
&& (EGLContext )theGContext == EGL_NO_CONTEXT))
{
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
- return;
}
EGLSurface anEglSurf = EGL_NO_SURFACE;
#if !defined(__EMSCRIPTEN__) // eglCreatePbufferSurface() is not implemented by Emscripten EGL
const int aSurfAttribs[] =
{
- EGL_WIDTH, myWidth,
- EGL_HEIGHT, myHeight,
+ EGL_WIDTH, mySize.x(),
+ EGL_HEIGHT, mySize.y(),
// EGL_KHR_gl_colorspace extension specifies if OpenGL should write into window buffer as into sRGB or RGB framebuffer
//EGL_GL_COLORSPACE_KHR, !theCaps->sRGBDisable ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR,
EGL_NONE
#if !defined(__EMSCRIPTEN__) // eglCreatePbufferSurface() is not implemented by Emscripten EGL
const int aSurfAttribs[] =
{
- EGL_WIDTH, myWidth,
- EGL_HEIGHT, myHeight,
+ EGL_WIDTH, mySize.x(),
+ EGL_HEIGHT, mySize.y(),
// EGL_KHR_gl_colorspace extension specifies if OpenGL should write into window buffer as into sRGB or RGB framebuffer
//EGL_GL_COLORSPACE_KHR, !theCaps->sRGBDisable ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR,
EGL_NONE
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: ChoosePixelFormat failed. Error code: ");
aMsg += (int )GetLastError();
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
DescribePixelFormat (aWindowDC, aPixelFrmtId, sizeof(aPixelFrmt), &aPixelFrmt);
TCollection_AsciiString aMsg("OpenGl_Window::CreateWindow: SetPixelFormat failed. Error code: ");
aMsg += (int )GetLastError();
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
// create GL context with extra options
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglCreateContext failed. Error code: ");
aMsg += (int )GetLastError();
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
}
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglShareLists failed. Error code: ");
aMsg += (int )GetLastError();
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
myGlContext->Init ((Aspect_Handle )aWindow, (Aspect_Handle )aWindowDC, (Aspect_RenderingContext )aGContext, isCoreProfile);
if (aVis.get() == NULL)
{
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: XGetVisualInfo is unable to choose needed configuration in existing OpenGL context. ");
- return;
}
else if (glXGetConfig (aDisp, aVis.get(), GLX_USE_GL, &isGl) != 0 || !isGl)
{
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: window Visual does not support GL rendering!");
- return;
}
// create new context
if (aGContext == NULL)
{
throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: glXCreateContext failed.");
- return;
}
}
#endif
myGlContext->Share (theShareCtx);
myGlContext->SetSwapInterval (mySwapInterval);
- Init();
+ init();
}
// =======================================================================
// =======================================================================
void OpenGl_Window::Resize()
{
- Standard_Integer aWidth = 0, aHeight = 0;
- myPlatformWindow->Size (aWidth, aHeight);
- if (myWidth == aWidth
- && myHeight == aHeight)
+ Graphic3d_Vec2i aWinSize;
+ mySizeWindow->Size (aWinSize.x(), aWinSize.y());
+ if (mySize == aWinSize)
{
// if the size is not changed - do nothing
return;
}
- myWidth = aWidth;
- myHeight = aHeight;
+ mySize = aWinSize;
- Init();
+ init();
}
// =======================================================================
-// function : Init
+// function : init
// purpose :
// =======================================================================
-void OpenGl_Window::Init()
+void OpenGl_Window::init()
{
if (!Activate())
+ {
return;
+ }
#if defined(HAVE_EGL)
if ((EGLSurface )myGlContext->myWindow == EGL_NO_SURFACE)
OpenGl_ColorFormats aColorFormats;
aColorFormats.Append (GL_RGBA8);
- if (!aDefFbo->InitRenderBuffer (myGlContext, Graphic3d_Vec2i (myWidth, myHeight), aColorFormats, GL_DEPTH24_STENCIL8))
+ if (!aDefFbo->InitRenderBuffer (myGlContext, mySize, aColorFormats, GL_DEPTH24_STENCIL8))
{
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
}
else if (!myPlatformWindow->IsVirtual())
{
- eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_WIDTH, &myWidth);
- eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &myHeight);
+ eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_WIDTH, &mySize.x());
+ eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &mySize.y());
}
#else
//
myGlContext->core11fwd->glDisable (GL_DITHER);
myGlContext->core11fwd->glDisable (GL_SCISSOR_TEST);
- const Standard_Integer aViewport[4] = { 0, 0, myWidth, myHeight };
+ const Standard_Integer aViewport[4] = { 0, 0, mySize.x(), mySize.y() };
myGlContext->ResizeViewport (aViewport);
myGlContext->SetDrawBuffer (GL_BACK);
if (myGlContext->core11ffp != NULL)
class OpenGl_Context;
class OpenGl_GraphicDriver;
-class OpenGl_Window;
DEFINE_STANDARD_HANDLE(OpenGl_Window,Standard_Transient)
//! This class represents low-level wrapper over window with GL context.
//! The window itself should be provided to constructor.
class OpenGl_Window : public Standard_Transient
{
+ DEFINE_STANDARD_RTTIEXT(OpenGl_Window, Standard_Transient)
public:
- //! Main constructor - prepare GL context for specified window.
- Standard_EXPORT OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
- const Handle(Aspect_Window)& thePlatformWindow,
- Aspect_RenderingContext theGContext,
- const Handle(OpenGl_Caps)& theCaps,
- const Handle(OpenGl_Context)& theShareCtx);
+ //! Empty constructor.
+ Standard_EXPORT OpenGl_Window();
+
+ //! Initialize the new window - prepare GL context for specified window.
+ //! Throws exception in case of failure.
+ Standard_EXPORT void Init (const Handle(OpenGl_GraphicDriver)& theDriver,
+ const Handle(Aspect_Window)& thePlatformWindow,
+ const Handle(Aspect_Window)& theSizeWindow,
+ Aspect_RenderingContext theGContext,
+ const Handle(OpenGl_Caps)& theCaps,
+ const Handle(OpenGl_Context)& theShareCtx);
//! Destructor
Standard_EXPORT virtual ~OpenGl_Window();
//! Resizes the window.
Standard_EXPORT virtual void Resize();
- Handle(Aspect_Window) PlatformWindow() { return myPlatformWindow; }
+ //! Return platform window.
+ const Handle(Aspect_Window)& PlatformWindow() { return myPlatformWindow; }
- Standard_Integer Width() const { return myWidth; }
- Standard_Integer Height() const { return myHeight; }
+ //! Return window object defining dimensions.
+ const Handle(Aspect_Window)& SizeWindow() { return mySizeWindow; }
- const Handle(OpenGl_Context)& GetGlContext() const { return myGlContext; }
+ Standard_Integer Width() const { return mySize.x(); }
+ Standard_Integer Height() const { return mySize.y(); }
- //! Activates GL context and setup viewport.
- Standard_EXPORT void Init();
+ //! Return OpenGL context.
+ const Handle(OpenGl_Context)& GetGlContext() const { return myGlContext; }
//! Makes GL context for this window active in current thread
Standard_EXPORT virtual Standard_Boolean Activate();
//! Sets swap interval for this window according to the context's settings.
Standard_EXPORT void SetSwapInterval (Standard_Boolean theToForceNoSync);
+protected:
+
+ //! Activates GL context and setup viewport.
+ Standard_EXPORT void init();
+
protected:
Handle(OpenGl_Context) myGlContext;
- Standard_Boolean myOwnGContext; //!< set to TRUE if GL context was not created by this class
+ Standard_Boolean myOwnGContext; //!< set to TRUE if GL context was not created by this class
Handle(Aspect_Window) myPlatformWindow; //!< software platform window wrapper
+ Handle(Aspect_Window) mySizeWindow; //!< window object defining dimensions
#if defined(__APPLE__)
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
UIView* myUIView;
#endif
- Standard_Integer myWidthPt; //!< window width in logical units
- Standard_Integer myHeightPt; //!< window height in logical units
+ Graphic3d_Vec2i mySizePt; //!< window width x height in logical units
#endif
- Standard_Integer myWidth; //!< window width in pixels
- Standard_Integer myHeight; //!< window height in pixels
+ Graphic3d_Vec2i mySize; //!< window width x height in pixels
Standard_Integer mySwapInterval;//!< last assigned swap interval (VSync) for this window
-public:
-
- DEFINE_STANDARD_RTTIEXT(OpenGl_Window,Standard_Transient) // Type definition
- DEFINE_STANDARD_ALLOC
-
};
#endif //_OpenGl_Window_Header
// function : OpenGl_Window
// purpose :
// =======================================================================
-OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
- const Handle(Aspect_Window)& thePlatformWindow,
- Aspect_RenderingContext theGContext,
- const Handle(OpenGl_Caps)& theCaps,
- const Handle(OpenGl_Context)& theShareCtx)
-: myGlContext (new OpenGl_Context (theCaps)),
- myOwnGContext (theGContext == 0),
- myPlatformWindow (thePlatformWindow),
+OpenGl_Window::OpenGl_Window()
+: myOwnGContext (false),
+ mySwapInterval (0)
+{
+ //
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+void OpenGl_Window::Init (const Handle(OpenGl_GraphicDriver)& theDriver,
+ const Handle(Aspect_Window)& thePlatformWindow,
+ const Handle(Aspect_Window)& theSizeWindow,
+ Aspect_RenderingContext theGContext,
+ const Handle(OpenGl_Caps)& theCaps,
+ const Handle(OpenGl_Context)& theShareCtx)
+{
+ myGlContext = new OpenGl_Context (theCaps);
+ myOwnGContext = (theGContext == 0);
+ myPlatformWindow = thePlatformWindow;
+ mySizeWindow = theSizeWindow;
#if defined(__APPLE__) && defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
- myUIView (NULL),
+ myUIView = NULL;
#endif
- mySwapInterval (theCaps->swapInterval)
-{
+ mySwapInterval = theCaps->swapInterval;
+
(void )theDriver;
- myPlatformWindow->Size (myWidth, myHeight);
+ mySizeWindow->Size (mySize.x(), mySize.y());
#if defined(__APPLE__)
- myWidthPt = myWidth;
- myHeightPt = myHeight;
+ mySizePt = mySize;
#endif
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
{
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: EAGLContext creation failed");
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
}
{
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: EAGLContext can not be assigned");
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
myGlContext->Init (aGLContext, Standard_False);
{
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: NSOpenGLContext creation failed");
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
- return;
}
if (aTryStereo == 0
myGlContext->Share (theShareCtx);
myGlContext->SetSwapInterval (mySwapInterval);
- Init();
+ init();
}
// =======================================================================
// If the size is not changed - do nothing
Standard_Integer aWidthPt = 0;
Standard_Integer aHeightPt = 0;
- myPlatformWindow->Size (aWidthPt, aHeightPt);
- if (myWidthPt == aWidthPt
- && myHeightPt == aHeightPt)
+ mySizeWindow->Size (aWidthPt, aHeightPt);
+ if (mySizePt.x() == aWidthPt
+ && mySizePt.y() == aHeightPt)
{
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
return;
NSRect aBounds = [aView bounds];
NSSize aRes = [aView convertSizeToBacking: aBounds.size];
- if (myWidth == Standard_Integer(aRes.width)
- && myHeight == Standard_Integer(aRes.height))
+ if (mySize.x() == Standard_Integer(aRes.width)
+ && mySize.y() == Standard_Integer(aRes.height))
{
return;
}
#endif
}
- myWidthPt = aWidthPt;
- myHeightPt = aHeightPt;
+ mySizePt.x() = aWidthPt;
+ mySizePt.y() = aHeightPt;
- Init();
+ init();
}
// =======================================================================
-// function : Init
+// function : init
// purpose :
// =======================================================================
-void OpenGl_Window::Init()
+void OpenGl_Window::init()
{
if (!Activate())
{
myGlContext->Functions()->glGenRenderbuffers (1, &aWinRBColor);
myGlContext->Functions()->glBindRenderbuffer (GL_RENDERBUFFER, aWinRBColor);
[aGLCtx renderbufferStorage: GL_RENDERBUFFER fromDrawable: anEaglLayer];
- myGlContext->Functions()->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myWidth);
- myGlContext->Functions()->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myHeight);
+ myGlContext->Functions()->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &mySize.x());
+ myGlContext->Functions()->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &mySize.y());
myGlContext->Functions()->glBindRenderbuffer (GL_RENDERBUFFER, 0);
- if (!aDefFbo->InitWithRB (myGlContext, Graphic3d_Vec2i (myWidth, myHeight), GL_RGBA8, GL_DEPTH24_STENCIL8, aWinRBColor))
+ if (!aDefFbo->InitWithRB (myGlContext, mySize, GL_RGBA8, GL_DEPTH24_STENCIL8, aWinRBColor))
{
TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
return;
}
- myWidth = aDefFbo->GetVPSizeX();
- myHeight = aDefFbo->GetVPSizeY();
+ mySize.x() = aDefFbo->GetVPSizeX();
+ mySize.y() = aDefFbo->GetVPSizeY();
}
myGlContext->SetDefaultFrameBuffer (aDefFbo);
aDefFbo->BindBuffer (myGlContext);
if ([aView respondsToSelector: @selector(convertSizeToBacking:)])
{
NSSize aRes = [aView convertSizeToBacking: aBounds.size];
- myWidth = Standard_Integer(aRes.width);
- myHeight = Standard_Integer(aRes.height);
+ mySize.x() = Standard_Integer(aRes.width);
+ mySize.y() = Standard_Integer(aRes.height);
}
else
{
- myWidth = Standard_Integer(aBounds.size.width);
- myHeight = Standard_Integer(aBounds.size.height);
+ mySize.x() = Standard_Integer(aBounds.size.width);
+ mySize.y() = Standard_Integer(aBounds.size.height);
}
- myWidthPt = Standard_Integer(aBounds.size.width);
- myHeightPt = Standard_Integer(aBounds.size.height);
+ mySizePt.x() = Standard_Integer(aBounds.size.width);
+ mySizePt.y() = Standard_Integer(aBounds.size.height);
#endif
myGlContext->core11fwd->glDisable (GL_DITHER);
myGlContext->core11fwd->glDisable (GL_SCISSOR_TEST);
- myGlContext->core11fwd->glViewport (0, 0, myWidth, myHeight);
+ myGlContext->core11fwd->glViewport (0, 0, mySize.x(), mySize.y());
if (myGlContext->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES)
{
myGlContext->core11fwd->glDrawBuffer (GL_BACK);
#include <Aspect_CircularGrid.hxx>
#include <Aspect_GradientBackground.hxx>
#include <Aspect_Grid.hxx>
+#include <Aspect_NeutralWindow.hxx>
#include <Aspect_RectangularGrid.hxx>
#include <Aspect_Window.hxx>
#include <Bnd_Box.hxx>
//=============================================================================
V3d_View::~V3d_View()
{
+ if (myParentView != nullptr)
+ {
+ myParentView->RemoveSubview (this);
+ myParentView = nullptr;
+ }
+ {
+ NCollection_Sequence<Handle(V3d_View)> aSubviews = mySubviews;
+ mySubviews.Clear();
+ for (const Handle(V3d_View)& aViewIter : aSubviews)
+ {
+ //aViewIter->Remove();
+ aViewIter->myParentView = nullptr;
+ aViewIter->MyWindow.Nullify();
+ aViewIter->myView->Remove();
+ if (aViewIter->MyViewer != nullptr)
+ {
+ aViewIter->MyViewer->SetViewOff (aViewIter);
+ }
+ }
+ }
+
if (!myView->IsRemoved())
{
myView->Remove();
Standard_Real aU1, aV1, aU2, aV2;
thePreviousView->Convert (theX1, theY1, aU1, aV1);
thePreviousView->Convert (theX2, theY2, aU2, aV2);
- myView->SetWindow (theWindow);
+ myView->SetWindow (Handle(Graphic3d_CView)(), theWindow, nullptr);
FitAll (aU1, aV1, aU2, aV2);
MyViewer->SetViewOn (this);
MyWindow = theWindow;
{
return;
}
+ if (myParentView != nullptr)
+ {
+ throw Standard_ProgramError ("V3d_View::SetWindow() called twice");
+ }
// method V3d_View::SetWindow() should assign the field MyWindow before calling Redraw()
MyWindow = theWindow;
- myView->SetWindow (theWindow, theContext);
+ myView->SetWindow (Handle(Graphic3d_CView)(), theWindow, theContext);
MyViewer->SetViewOn (this);
SetRatio();
if (myImmediateUpdate)
}
}
+//=============================================================================
+//function : SetWindow
+//purpose :
+//=============================================================================
+void V3d_View::SetWindow (const Handle(V3d_View)& theParentView,
+ const Graphic3d_Vec2d& theSize,
+ Aspect_TypeOfTriedronPosition theCorner,
+ const Graphic3d_Vec2d& theOffset,
+ const Graphic3d_Vec2i& theMargins)
+{
+ if (myView->IsRemoved())
+ {
+ return;
+ }
+
+ Handle(V3d_View) aParentView = !theParentView->IsSubview()
+ ? theParentView
+ : theParentView->ParentView();
+ if (aParentView != myParentView)
+ {
+ if (myParentView != nullptr)
+ {
+ throw Standard_ProgramError ("V3d_View::SetWindow() called twice");
+ }
+
+ myParentView = aParentView.get();
+ aParentView->AddSubview (this);
+ }
+
+ Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
+ aWindow->SetVirtual (true);
+ aWindow->SetSize (4, 4);
+ myView->SetSubviewCorner (theCorner);
+ myView->SetSubviewSize (theSize);
+ myView->SetSubviewOffset (theOffset);
+ myView->SetSubviewMargins (theMargins);
+
+ MyWindow = aWindow;
+ myView->SetWindow (aParentView->View(), aWindow, 0);
+ MyViewer->SetViewOn (this);
+ SetRatio();
+}
+
//=============================================================================
//function : Remove
//purpose :
myTrihedron->Erase();
}
- MyViewer->DelView (this);
+ if (myParentView != nullptr)
+ {
+ myParentView->RemoveSubview (this);
+ myParentView = nullptr;
+ }
+ {
+ NCollection_Sequence<Handle(V3d_View)> aSubviews = mySubviews;
+ mySubviews.Clear();
+ for (const Handle(V3d_View)& aViewIter : aSubviews)
+ {
+ aViewIter->Remove();
+ }
+ }
+
+ if (MyViewer != nullptr)
+ {
+ MyViewer->DelView (this);
+ MyViewer = nullptr;
+ }
myView->Remove();
- Handle(Aspect_Window)& aWin = const_cast<Handle(Aspect_Window)&> (MyWindow);
- aWin.Nullify();
+ MyWindow.Nullify();
+}
+
+// =======================================================================
+// function : AddSubview
+// purpose :
+// =======================================================================
+void V3d_View::AddSubview (const Handle(V3d_View)& theView)
+{
+ mySubviews.Append (theView);
+}
+
+// =======================================================================
+// function : RemoveSubview
+// purpose :
+// =======================================================================
+bool V3d_View::RemoveSubview (const V3d_View* theView)
+{
+ for (NCollection_Sequence<Handle(V3d_View)>::Iterator aViewIter (mySubviews); aViewIter.More(); aViewIter.Next())
+ {
+ if (aViewIter.Value() == theView)
+ {
+ mySubviews.Remove (aViewIter);
+ return true;
+ }
+ }
+ return false;
+}
+
+// =============================================================================
+// function : PickSubview
+// purpose :
+// =============================================================================
+Handle(V3d_View) V3d_View::PickSubview (const Graphic3d_Vec2i& thePnt) const
+{
+ if (thePnt.x() < 0
+ || thePnt.x() >= MyWindow->Dimensions().x()
+ || thePnt.y() < 0
+ || thePnt.y() >= MyWindow->Dimensions().y())
+ {
+ return Handle(V3d_View)();
+ }
+
+ // iterate in opposite direction - from front to bottom views
+ for (Standard_Integer aSubviewIter = mySubviews.Upper(); aSubviewIter >= mySubviews.Lower(); --aSubviewIter)
+ {
+ const Handle(V3d_View)& aSubview = mySubviews.Value (aSubviewIter);
+ if (thePnt.x() >= aSubview->View()->SubviewTopLeft().x()
+ && thePnt.x() < (aSubview->View()->SubviewTopLeft().x() + aSubview->Window()->Dimensions().x())
+ && thePnt.y() >= aSubview->View()->SubviewTopLeft().y()
+ && thePnt.y() < (aSubview->View()->SubviewTopLeft().y() + aSubview->Window()->Dimensions().y()))
+ {
+ return aSubview;
+ }
+ }
+
+ return this;
}
//=============================================================================
//! View->Move(15.,-5.,0.,False) (Next motion)
class V3d_View : public Standard_Transient
{
-
+ DEFINE_STANDARD_RTTIEXT(V3d_View, Standard_Transient)
public:
//! Initializes the view.
Standard_EXPORT void SetWindow (const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext = NULL);
+ //! Activates the view as subview of another view.
+ //! @param[in] theParentView parent view to put subview into
+ //! @param[in] theSize subview dimensions;
+ //! values >= 2 define size in pixels,
+ //! values <= 1.0 define size as a fraction of parent view
+ //! @param[in] theCorner corner within parent view
+ //! @param[in] theOffset offset from the corner;
+ //! values >= 1 define offset in pixels,
+ //! values < 1.0 define offset as a fraction of parent view
+ //! @param[in] theMargins subview margins in pixels
+ //!
+ //! Example: to split parent view horizontally into 2 subview,
+ //! define one subview with Size=(0.5,1.0),Offset=(0.0,0.0), and 2nd with Size=(0.5,1.0),Offset=(5.0,0.0);
+ Standard_EXPORT void SetWindow (const Handle(V3d_View)& theParentView,
+ const Graphic3d_Vec2d& theSize,
+ Aspect_TypeOfTriedronPosition theCorner = Aspect_TOTP_LEFT_UPPER,
+ const Graphic3d_Vec2d& theOffset = Graphic3d_Vec2d(),
+ const Graphic3d_Vec2i& theMargins = Graphic3d_Vec2i());
+
Standard_EXPORT void SetMagnify (const Handle(Aspect_Window)& theWindow,
const Handle(V3d_View)& thePreviousView,
const Standard_Integer theX1,
//! Dumps the content of me into the stream
Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
- DEFINE_STANDARD_RTTIEXT(V3d_View,Standard_Transient)
+public: //! @name subvew management
+
+ //! Return TRUE if this is a subview of another view.
+ bool IsSubview() const { return myParentView != nullptr; }
+
+ //! Return parent View or NULL if this is not a subview.
+ V3d_View* ParentView() { return myParentView; }
+
+ //! Return subview list.
+ const NCollection_Sequence<Handle(V3d_View)>& Subviews() const { return mySubviews; }
+
+ //! Pick subview from the given 2D point.
+ Standard_EXPORT Handle(V3d_View) PickSubview (const Graphic3d_Vec2i& thePnt) const;
+
+ //! Add subview to the list.
+ Standard_EXPORT void AddSubview (const Handle(V3d_View)& theView);
+
+ //! Remove subview from the list.
+ Standard_EXPORT bool RemoveSubview (const V3d_View* theView);
public: //! @name deprecated methods
private:
V3d_Viewer* MyViewer;
+
+ NCollection_Sequence<Handle(V3d_View)> mySubviews;
+ V3d_View* myParentView;
+
V3d_ListOfLight myActiveLights;
gp_Dir myDefaultViewAxis;
gp_Pnt myDefaultViewPoint;
// ========================================================================
void V3d_Viewer::Redraw() const
{
- for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
+ for (int aSubViewPass = 0; aSubViewPass < 2; ++aSubViewPass)
{
- aDefViewIter.Value()->Redraw();
+ // redraw subviews first
+ const bool isSubViewPass = (aSubViewPass == 0);
+ for (const Handle(V3d_View)& aViewIter : myDefinedViews)
+ {
+ if (isSubViewPass
+ && aViewIter->IsSubview())
+ {
+ aViewIter->Redraw();
+ }
+ else if (!isSubViewPass
+ && !aViewIter->IsSubview())
+ {
+ aViewIter->Redraw();
+ }
+ }
}
}
// ========================================================================
void V3d_Viewer::RedrawImmediate() const
{
- for (V3d_ListOfView::Iterator aDefViewIter (myDefinedViews); aDefViewIter.More(); aDefViewIter.Next())
+ for (int aSubViewPass = 0; aSubViewPass < 2; ++aSubViewPass)
{
- aDefViewIter.Value()->RedrawImmediate();
+ // redraw subviews first
+ const bool isSubViewPass = (aSubViewPass == 0);
+ for (const Handle(V3d_View)& aViewIter : myDefinedViews)
+ {
+ if (isSubViewPass
+ && aViewIter->IsSubview())
+ {
+ aViewIter->RedrawImmediate();
+ }
+ else if (!isSubViewPass
+ && !aViewIter->IsSubview())
+ {
+ aViewIter->RedrawImmediate();
+ }
+ }
}
}
// function : DelView
// purpose :
// ========================================================================
-void V3d_Viewer::DelView (const Handle(V3d_View)& theView)
+void V3d_Viewer::DelView (const V3d_View* theView)
{
- myActiveViews.Remove (theView);
- myDefinedViews.Remove (theView);
+ for (V3d_ListOfView::Iterator aViewIter (myActiveViews); aViewIter.More(); aViewIter.Next())
+ {
+ if (aViewIter.Value() == theView)
+ {
+ myActiveViews.Remove (aViewIter);
+ break;
+ }
+ }
+ for (V3d_ListOfView::Iterator aViewIter (myDefinedViews); aViewIter.More(); aViewIter.Next())
+ {
+ if (aViewIter.Value() == theView)
+ {
+ myDefinedViews.Remove (aViewIter);
+ break;
+ }
+ }
}
//=======================================================================
Standard_EXPORT void AddView (const Handle(V3d_View)& theView);
//! Delete View in Sequence Of Views.
- Standard_EXPORT void DelView (const Handle(V3d_View)& theView);
+ Standard_EXPORT void DelView (const V3d_View* theView);
private:
return Standard_True;
}
-//! Auxiliary method to parse transformation persistence flags
-inline Standard_Boolean parseTrsfPersCorner (const TCollection_AsciiString& theString,
- Aspect_TypeOfTriedronPosition& theCorner)
+// =============================================================================
+// function : ParseCorner
+// purpose :
+// =============================================================================
+Standard_Boolean ViewerTest::ParseCorner (Standard_CString theArg,
+ Aspect_TypeOfTriedronPosition& theCorner)
{
- TCollection_AsciiString aString (theString);
+ TCollection_AsciiString aString (theArg);
aString.LowerCase();
if (aString == "center")
{
}
else if (aString == "topleft"
|| aString == "leftupper"
- || aString == "upperleft")
+ || aString == "upperleft"
+ || aString == "left_upper"
+ || aString == "upper_left")
{
theCorner = Aspect_TOTP_LEFT_UPPER;
}
else if (aString == "bottomleft"
|| aString == "leftlower"
- || aString == "lowerleft")
+ || aString == "lowerleft"
+ || aString == "left_lower"
+ || aString == "lower_left")
{
theCorner = Aspect_TOTP_LEFT_LOWER;
}
else if (aString == "topright"
|| aString == "rightupper"
- || aString == "upperright")
+ || aString == "upperright"
+ || aString == "right_upper"
+ || aString == "upper_right")
{
theCorner = Aspect_TOTP_RIGHT_UPPER;
}
else if (aString == "bottomright"
|| aString == "lowerright"
- || aString == "rightlower")
+ || aString == "rightlower"
+ || aString == "right_lower"
+ || aString == "lower_right")
{
theCorner = Aspect_TOTP_RIGHT_LOWER;
}
if (anArgIter + 1 < theArgNb)
{
Aspect_TypeOfTriedronPosition aCorner = Aspect_TOTP_CENTER;
- if (parseTrsfPersCorner (theArgVec[anArgIter + 1], aCorner))
+ if (ViewerTest::ParseCorner (theArgVec[anArgIter + 1], aCorner))
{
++anArgIter;
aTrsfPers->SetCorner2d (aCorner);
#include <AIS_KindOfInteractive.hxx>
#include <Aspect_TypeOfLine.hxx>
#include <Aspect_TypeOfMarker.hxx>
+#include <Aspect_TypeOfTriedronPosition.hxx>
#include <Draw_Interpretor.hxx>
#include <Graphic3d_TypeOfShadingModel.hxx>
+#include <Graphic3d_Vec2.hxx>
#include <Graphic3d_ZLayerId.hxx>
#include <TCollection_AsciiString.hxx>
#include <TColStd_HArray1OfTransient.hxx>
class TopoDS_Shape;
class WNT_WClass;
+//! Parameters for creating new view.
+struct ViewerTest_VinitParams
+{
+ TCollection_AsciiString ViewName;
+ TCollection_AsciiString DisplayName;
+ Handle(V3d_View) ViewToClone;
+ Handle(V3d_View) ParentView;
+ Graphic3d_Vec2d Offset;
+ Graphic3d_Vec2d Size;
+ Aspect_TypeOfTriedronPosition Corner;
+ Graphic3d_Vec2i SubviewMargins;
+ Standard_Boolean IsVirtual;
+ Standard_Boolean IsComposer;
+
+ ViewerTest_VinitParams() : Corner (Aspect_TOTP_LEFT_UPPER), IsVirtual (false), IsComposer (false) {}
+};
+
class ViewerTest
{
public:
//! Loads all Draw commands of V2d & V3d. Used for plugin.
Standard_EXPORT static void Factory (Draw_Interpretor& theDI);
- //! Creates view with default or custom name
- //! and adds this name in map to manage multiple views.
+
+
+ //! Creates view with default or custom name and adds this name in map to manage multiple views.
//! Implemented in ViewerTest_ViewerCommands.cxx.
- //! @param thePxLeft left position of newly created window
- //! @param thePxTop top position of newly created window
- //! @param thePxWidth width of newly created window
- //! @param thePxHeight height of newly created window
- //! @param theViewName name of newly created View
- //! @oaram theDisplayName display name
- //! @param theViewToClone when specified, the new View will copy properties of existing one
- //! @param theIsVirtual force creation of virtual off-screen window within interactive session
- Standard_EXPORT static TCollection_AsciiString ViewerInit (const Standard_Integer thePxLeft = 0,
- const Standard_Integer thePxTop = 0,
- const Standard_Integer thePxWidth = 0,
- const Standard_Integer thePxHeight = 0,
- const TCollection_AsciiString& theViewName = "",
- const TCollection_AsciiString& theDisplayName = "",
- const Handle(V3d_View)& theViewToClone = Handle(V3d_View)(),
- const Standard_Boolean theIsVirtual = false);
+ Standard_EXPORT static TCollection_AsciiString ViewerInit (const ViewerTest_VinitParams& theParams);
+
+ //! Creates view.
+ static TCollection_AsciiString ViewerInit (const TCollection_AsciiString& theViewName = "")
+ {
+ ViewerTest_VinitParams aParams;
+ aParams.ViewName = theViewName;
+ return ViewerInit (aParams);
+ }
+
+ //! Creates view.
+ static TCollection_AsciiString ViewerInit (const Standard_Integer thePxLeft,
+ const Standard_Integer thePxTop,
+ const Standard_Integer thePxWidth,
+ const Standard_Integer thePxHeight,
+ const TCollection_AsciiString& theViewName,
+ const TCollection_AsciiString& theDisplayName = "",
+ const Handle(V3d_View)& theViewToClone = Handle(V3d_View)(),
+ const Standard_Boolean theIsVirtual = false)
+ {
+ ViewerTest_VinitParams aParams;
+ aParams.Offset.SetValues ((float )thePxLeft, (float)thePxTop);
+ aParams.Size.SetValues ((float)thePxWidth, (float)thePxHeight);
+ aParams.ViewName = theViewName;
+ aParams.DisplayName = theDisplayName;
+ aParams.ViewToClone = theViewToClone;
+ aParams.IsVirtual = theIsVirtual;
+ return ViewerInit (aParams);
+ }
Standard_EXPORT static void RemoveViewName (const TCollection_AsciiString& theName);
Standard_EXPORT static TCollection_AsciiString GetCurrentViewName();
+ //! Make the view active
+ Standard_EXPORT static void ActivateView (const Handle(V3d_View)& theView,
+ Standard_Boolean theToUpdate);
+
//! Removes view and clear all maps
//! with information about its resources if necessary
Standard_EXPORT static void RemoveView (const TCollection_AsciiString& theViewName,
return parseZLayer (theArg, true, theLayer);
}
+ //! Auxiliary method to parse transformation persistence flags
+ Standard_EXPORT static Standard_Boolean ParseCorner (Standard_CString theArg,
+ Aspect_TypeOfTriedronPosition& theCorner);
+
public: //! @name deprecated methods
//! Parses RGB(A) color argument(s) specified within theArgVec[0], theArgVec[1], theArgVec[2] and theArgVec[3].
if (!myContext.IsNull())
{
myContext->UpdateCurrentViewer();
+ if (!myView.IsNull()
+ && myView->IsSubview()
+ && myView->ParentView()->Viewer() != myContext->CurrentViewer())
+ {
+ myView->ParentView()->RedrawImmediate();
+ }
}
else if (!myView.IsNull())
{
myView->Redraw();
+ if (myView->IsSubview())
+ {
+ myView->ParentView()->RedrawImmediate();
+ }
}
}
}
return AIS_ViewController::UpdateMouseClick (thePoint, theButton, theModifiers, theIsDoubleClick);
}
+//=======================================================================
+//function : UpdateMouseButtons
+//purpose :
+//=======================================================================
+bool ViewerTest_EventManager::UpdateMouseScroll (const Aspect_ScrollDelta& theDelta)
+{
+ if (!myView.IsNull()
+ && (myView->IsSubview()
+ || !myView->Subviews().IsEmpty()))
+ {
+ Handle(V3d_View) aParent = !myView->IsSubview() ? myView : myView->ParentView();
+ Handle(V3d_View) aPickedView = aParent->PickSubview (theDelta.Point);
+ if (!aPickedView.IsNull()
+ && aPickedView != myView)
+ {
+ // switch input focus to another subview
+ OnSubviewChanged (myCtx, myView, aPickedView);
+ return true;
+ }
+ }
+
+ return AIS_ViewController::UpdateMouseScroll (theDelta);
+}
+
//=======================================================================
//function : UpdateMouseButtons
//purpose :
Aspect_VKeyFlags theModifiers,
bool theIsEmulated)
{
+ if (!myView.IsNull()
+ && myMousePressed == Aspect_VKeyMouse_NONE
+ && theButtons != Aspect_VKeyMouse_NONE
+ && (myView->IsSubview()
+ || !myView->Subviews().IsEmpty()))
+ {
+ Handle(V3d_View) aParent = !myView->IsSubview() ? myView : myView->ParentView();
+ Handle(V3d_View) aPickedView = aParent->PickSubview (thePoint);
+ if (!aPickedView.IsNull()
+ && aPickedView != myView)
+ {
+ // switch input focus to another subview
+ OnSubviewChanged (myCtx, myView, aPickedView);
+ }
+ }
+
SetAllowRotation (!ViewerTest_V3dView::IsCurrentViewIn2DMode());
if (theButtons == Aspect_VKeyMouse_LeftButton)
//==============================================================================
void ViewerTest_EventManager::ProcessConfigure (bool theIsResized)
{
- if (!myView.IsNull())
+ if (myView.IsNull())
{
- if (!theIsResized
- // track window moves to reverse stereo pair
- && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_RowInterlaced
- && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ColumnInterlaced
- && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ChessBoard)
- {
- return;
- }
+ return;
+ }
- myView->Window()->DoResize();
- myView->MustBeResized();
- myView->Invalidate();
- FlushViewEvents (myCtx, myView, true);
+ if (!theIsResized
+ // track window moves to reverse stereo pair
+ && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_RowInterlaced
+ && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ColumnInterlaced
+ && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ChessBoard)
+ {
+ return;
+ }
+
+ Handle(V3d_View) aParent = !myView->IsSubview()
+ ? myView
+ : myView->ParentView();
+ aParent->Window()->DoResize();
+ aParent->MustBeResized();
+ aParent->Invalidate();
+ for (const Handle(V3d_View)& aChildIter : aParent->Subviews())
+ {
+ aChildIter->Window()->DoResize();
+ aChildIter->MustBeResized();
+ aChildIter->Invalidate();
}
+
+ FlushViewEvents (myCtx, myView, true);
+}
+
+//==============================================================================
+//function : OnSubviewChanged
+//purpose :
+//==============================================================================
+void ViewerTest_EventManager::OnSubviewChanged (const Handle(AIS_InteractiveContext)& ,
+ const Handle(V3d_View)& ,
+ const Handle(V3d_View)& theNewView)
+{
+ ViewerTest::ActivateView (theNewView, false);
}
//==============================================================================
myPickPntArgVec[2] = theArgZ;
}
+ //! Update mouse scroll event.
+ Standard_EXPORT virtual bool UpdateMouseScroll (const Aspect_ScrollDelta& theDelta) Standard_OVERRIDE;
+
//! Handle mouse button click event.
Standard_EXPORT virtual bool UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
Aspect_VKeyMouse theButton,
//! Handle KeyPress event.
Standard_EXPORT void ProcessKeyPress (Aspect_VKey theKey);
+ //! Callback called on Selection of another (sub)view.
+ //! This method is expected to be called from rendering thread.
+ Standard_EXPORT virtual void OnSubviewChanged (const Handle(AIS_InteractiveContext)& theCtx,
+ const Handle(V3d_View)& theOldView,
+ const Handle(V3d_View)& theNewView) Standard_OVERRIDE;
+
protected:
//! Register hot-keys for specified Action.
Handle(V3d_View) aView;
if (!aDumpFile.IsEmpty())
{
- ViewerTest::ViewerInit (0, 0, anImgParams.Width, anImgParams.Height, "TmpDriver/TmpViewer/TmpView");
+ ViewerTest_VinitParams aParams;
+ aParams.Size.SetValues ((float )anImgParams.Width, (float)anImgParams.Height);
+ aParams.ViewName = "TmpDriver/TmpViewer/TmpView";
+ ViewerTest::ViewerInit (aParams);
aView = ViewerTest::CurrentView();
aView->SetImmediateUpdate (false);
aView->SetBgGradientStyle (Aspect_GradientFillMethod_None, false);
//purpose : Create the window viewer and initialize all the global variable
//==============================================================================
-TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
- const Standard_Integer thePxTop,
- const Standard_Integer thePxWidth,
- const Standard_Integer thePxHeight,
- const TCollection_AsciiString& theViewName,
- const TCollection_AsciiString& theDisplayName,
- const Handle(V3d_View)& theViewToClone,
- const Standard_Boolean theIsVirtual)
+TCollection_AsciiString ViewerTest::ViewerInit (const ViewerTest_VinitParams& theParams)
{
// Default position and dimension of the viewer window.
// Note that left top corner is set to be sufficiently small to have
// window fit in the small screens (actual for remote desktops, see #23003).
// The position corresponds to the window's client area, thus some
// gap is added for window frame to be visible.
- Standard_Integer aPxLeft = 20, aPxTop = 40;
- Standard_Integer aPxWidth = 409, aPxHeight = 409;
+ Graphic3d_Vec2d aPxTopLeft (20, 40);
+ Graphic3d_Vec2d aPxSize (409, 409);
Standard_Boolean isDefViewSize = Standard_True;
Standard_Boolean toCreateViewer = Standard_False;
- const Standard_Boolean isVirtual = Draw_VirtualWindows || theIsVirtual;
- if (!theViewToClone.IsNull())
+ const Standard_Boolean isVirtual = Draw_VirtualWindows || theParams.IsVirtual;
+ if (!theParams.ViewToClone.IsNull())
{
- theViewToClone->Window()->Size (aPxWidth, aPxHeight);
+ Graphic3d_Vec2i aCloneSize;
+ theParams.ViewToClone->Window()->Size (aCloneSize.x(), aCloneSize.y());
+ aPxSize = Graphic3d_Vec2d (aCloneSize);
isDefViewSize = Standard_False;
#if !defined(__EMSCRIPTEN__)
(void )isDefViewSize;
}
Handle(Graphic3d_GraphicDriver) aGraphicDriver;
- ViewerTest_Names aViewNames(theViewName);
+ ViewerTest_Names aViewNames (theParams.ViewName);
if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
{
aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
}
- if (thePxLeft != 0)
- {
- aPxLeft = thePxLeft;
- }
- if (thePxTop != 0)
- {
- aPxTop = thePxTop;
- }
- if (thePxWidth != 0)
- {
- isDefViewSize = Standard_False;
- aPxWidth = thePxWidth;
- }
- if (thePxHeight != 0)
- {
- isDefViewSize = Standard_False;
- aPxHeight = thePxHeight;
- }
-
// Get graphic driver (create it or get from another view)
const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
if (isNewDriver)
{
// Get connection string
#if defined(HAVE_XLIB)
- if (!theDisplayName.IsEmpty())
+ if (!theParams.DisplayName.IsEmpty())
{
- SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
+ SetDisplayConnection (new Aspect_DisplayConnection (theParams.DisplayName));
}
else
{
SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
}
#else
- (void)theDisplayName; // avoid warning on unused argument
SetDisplayConnection (new Aspect_DisplayConnection ());
#endif
aGraphicDriver = ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName());
}
- //Dispose the window if input parameters are default
- if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
- {
- Standard_Integer aTop = 0,
- aLeft = 0,
- aRight = 0,
- aBottom = 0,
- aScreenWidth = 0,
- aScreenHeight = 0;
-
- // Get screen resolution
+ // Get screen resolution
+ Graphic3d_Vec2i aScreenSize;
#if defined(_WIN32)
- RECT aWindowSize;
- GetClientRect(GetDesktopWindow(), &aWindowSize);
- aScreenHeight = aWindowSize.bottom;
- aScreenWidth = aWindowSize.right;
+ RECT aWindowSize;
+ GetClientRect(GetDesktopWindow(), &aWindowSize);
+ aScreenSize.SetValues (aWindowSize.right, aWindowSize.bottom);
#elif defined(HAVE_XLIB)
- ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
- Screen* aScreen = DefaultScreenOfDisplay(aDispX);
- aScreenWidth = WidthOfScreen(aScreen);
- aScreenHeight = HeightOfScreen(aScreen);
+ ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
+ Screen* aScreen = DefaultScreenOfDisplay(aDispX);
+ aScreenSize.x() = WidthOfScreen(aScreen);
+ aScreenSize.y() = HeightOfScreen(aScreen);
#elif defined(__APPLE__)
- GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
+ GetCocoaScreenResolution (aScreenSize.x(), aScreenSize.y());
#else
- // not implemented
+ // not implemented
#endif
- TCollection_AsciiString anOverlappedViewId("");
+ if (!theParams.ParentView.IsNull())
+ {
+ aPxTopLeft.SetValues (0, 0);
+ }
+ if (theParams.Offset.x() != 0)
+ {
+ aPxTopLeft.x() = theParams.Offset.x();
+ }
+ if (theParams.Offset.y() != 0)
+ {
+ aPxTopLeft.y() = theParams.Offset.y();
+ }
+ if (theParams.Size.x() != 0)
+ {
+ isDefViewSize = Standard_False;
+ aPxSize.x() = theParams.Size.x();
+ if (aPxSize.x() <= 1.0
+ && aScreenSize.x() > 0
+ && theParams.ParentView.IsNull())
+ {
+ aPxSize.x() = aPxSize.x() * double(aScreenSize.x());
+ }
+ }
+ if (theParams.Size.y() != 0)
+ {
+ isDefViewSize = Standard_False;
+ aPxSize.y() = theParams.Size.y();
+ if (aPxSize.y() <= 1.0
+ && aScreenSize.y() > 0
+ && theParams.ParentView.IsNull())
+ {
+ aPxSize.y() = aPxSize.y() * double(aScreenSize.y());
+ }
+ }
- while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
+ //Dispose the window if input parameters are default
+ if (!ViewerTest_myViews.IsEmpty()
+ && theParams.ParentView.IsNull()
+ && theParams.Offset.x() == 0
+ && theParams.Offset.y() == 0)
+ {
+ Standard_Integer aTop = 0, aLeft = 0, aRight = 0, aBottom = 0;
+ TCollection_AsciiString anOverlappedViewId("");
+ while (IsWindowOverlapped ((int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
+ (int )aPxTopLeft.x() + (int )aPxSize.x(),
+ (int )aPxTopLeft.y() + (int )aPxSize.y(), anOverlappedViewId))
{
ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
- if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
- && aRight + 2*aPxWidth + 40 > aScreenWidth)
+ if (IsWindowOverlapped (aRight + 20, (int )aPxTopLeft.y(), aRight + 20 + (int )aPxSize.x(),
+ (int )aPxTopLeft.y() + (int )aPxSize.y(), anOverlappedViewId)
+ && aRight + 2 * aPxSize.x() + 40 > aScreenSize.x())
{
- if (aBottom + aPxHeight + 40 > aScreenHeight)
+ if (aBottom + aPxSize.y() + 40 > aScreenSize.y())
{
- aPxLeft = 20;
- aPxTop = 40;
+ aPxTopLeft.x() = 20;
+ aPxTopLeft.y() = 40;
break;
}
- aPxLeft = 20;
- aPxTop = aBottom + 40;
+ aPxTopLeft.x() = 20;
+ aPxTopLeft.y() = aBottom + 40;
}
else
- aPxLeft = aRight + 20;
+ {
+ aPxTopLeft.x() = aRight + 20;
+ }
}
}
}
// Create window
-#if defined(_WIN32)
- VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
- isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
- aPxLeft, aPxTop,
- aPxWidth, aPxHeight,
- Quantity_NOC_BLACK);
- VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
-#elif defined(HAVE_XLIB)
- VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
- aTitle.ToCString(),
- aPxLeft, aPxTop,
- aPxWidth, aPxHeight);
-#elif defined(__APPLE__)
- VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
- aPxLeft, aPxTop,
- aPxWidth, aPxHeight);
- ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
-#elif defined(__EMSCRIPTEN__)
- // current EGL implementation in Emscripten supports only one global WebGL canvas returned by Module.canvas property;
- // the code should be revised for handling multiple canvas elements (which is technically also possible)
- TCollection_AsciiString aCanvasId = getModuleCanvasId();
- if (!aCanvasId.IsEmpty())
+ if (!theParams.ParentView.IsNull())
{
- aCanvasId = TCollection_AsciiString("#") + aCanvasId;
+ VT_GetWindow() = Handle(ViewerTest_Window)::DownCast (theParams.ParentView->Window());
}
-
- VT_GetWindow() = new Wasm_Window (aCanvasId);
- Graphic3d_Vec2i aRealSize;
- VT_GetWindow()->Size (aRealSize.x(), aRealSize.y());
- if (!isDefViewSize || (aRealSize.x() <= 0 && aRealSize.y() <= 0))
+ else
{
- // Wasm_Window wraps an existing HTML element without creating a new one.
- // Keep size defined on a web page instead of defaulting to 409x409 (as in case of other platform),
- // but resize canvas if vinit has been called with explicitly specified dimensions.
- VT_GetWindow()->SetSizeLogical (Graphic3d_Vec2d (aPxWidth, aPxHeight));
+ #if defined(_WIN32)
+ VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
+ isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
+ (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
+ (int )aPxSize.x(), (int )aPxSize.y(),
+ Quantity_NOC_BLACK);
+ VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
+ #elif defined(HAVE_XLIB)
+ VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
+ aTitle.ToCString(),
+ (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
+ (int )aPxSize.x(), (int )aPxSize.y());
+ #elif defined(__APPLE__)
+ VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
+ (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
+ (int )aPxSize.x(), (int )aPxSize.y());
+ ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
+ #elif defined(__EMSCRIPTEN__)
+ // current EGL implementation in Emscripten supports only one global WebGL canvas returned by Module.canvas property;
+ // the code should be revised for handling multiple canvas elements (which is technically also possible)
+ TCollection_AsciiString aCanvasId = getModuleCanvasId();
+ if (!aCanvasId.IsEmpty())
+ {
+ aCanvasId = TCollection_AsciiString("#") + aCanvasId;
+ }
+
+ VT_GetWindow() = new Wasm_Window (aCanvasId);
+ Graphic3d_Vec2i aRealSize;
+ VT_GetWindow()->Size (aRealSize.x(), aRealSize.y());
+ if (!isDefViewSize || (aRealSize.x() <= 0 && aRealSize.y() <= 0))
+ {
+ // Wasm_Window wraps an existing HTML element without creating a new one.
+ // Keep size defined on a web page instead of defaulting to 409x409 (as in case of other platform),
+ // but resize canvas if vinit has been called with explicitly specified dimensions.
+ VT_GetWindow()->SetSizeLogical (Graphic3d_Vec2d (aPxSize));
+ }
+ #else
+ // not implemented
+ VT_GetWindow() = new Aspect_NeutralWindow();
+ VT_GetWindow()->SetSize ((int )aPxSize.x(), (int )aPxSize.y());
+ #endif
+ VT_GetWindow()->SetVirtual (isVirtual);
}
-#else
- // not implemented
- VT_GetWindow() = new Aspect_NeutralWindow();
- VT_GetWindow()->SetSize (aPxWidth, aPxHeight);
-#endif
- VT_GetWindow()->SetVirtual (isVirtual);
// View setup
Handle(V3d_View) aView;
- if (!theViewToClone.IsNull())
+ if (!theParams.ViewToClone.IsNull())
{
- aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
+ aView = new ViewerTest_V3dView (a3DViewer, theParams.ViewToClone);
}
else
{
aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
}
- aView->SetWindow (VT_GetWindow());
+ aView->View()->SetSubviewComposer (theParams.IsComposer);
+ if (!theParams.ParentView.IsNull())
+ {
+ aView->SetWindow (theParams.ParentView, aPxSize, theParams.Corner, aPxTopLeft, theParams.SubviewMargins);
+ }
+ else
+ {
+ aView->SetWindow (VT_GetWindow());
+ }
ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
ViewerTest::CurrentView(aView);
//==============================================================================
static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
{
- TCollection_AsciiString aViewName, aDisplayName;
- Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
- Standard_Boolean isVirtual = false;
- Handle(V3d_View) aCopyFrom;
+ ViewerTest_VinitParams aParams;
TCollection_AsciiString aName, aValue;
int is2dMode = -1, aDpiAware = -1;
for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
if (anArgIt + 1 < theArgsNb
&& anArgCase == "-name")
{
- aViewName = theArgVec[++anArgIt];
+ aParams.ViewName = theArgVec[++anArgIt];
}
else if (anArgIt + 1 < theArgsNb
&& (anArgCase == "-left"
- || anArgCase == "-l"))
+ || anArgCase == "-l")
+ && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Offset.x()))
{
- aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
+ ++anArgIt;
}
else if (anArgIt + 1 < theArgsNb
&& (anArgCase == "-top"
- || anArgCase == "-t"))
+ || anArgCase == "-t")
+ && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Offset.y()))
{
- aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
+ ++anArgIt;
}
else if (anArgIt + 1 < theArgsNb
&& (anArgCase == "-width"
- || anArgCase == "-w"))
+ || anArgCase == "-w")
+ && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Size.x()))
{
- aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
+ ++anArgIt;
}
else if (anArgIt + 1 < theArgsNb
&& (anArgCase == "-height"
- || anArgCase == "-h"))
+ || anArgCase == "-h")
+ && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Size.y()))
{
- aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
+ ++anArgIt;
+ }
+ else if (anArgIt + 1 < theArgsNb
+ && (anArgCase == "-pos"
+ || anArgCase == "-position"
+ || anArgCase == "-corner")
+ && ViewerTest::ParseCorner (theArgVec[anArgIt + 1], aParams.Corner))
+ {
+ ++anArgIt;
+ }
+ else if (anArgIt + 2 < theArgsNb
+ && anArgCase == "-margins"
+ && Draw::ParseInteger (theArgVec[anArgIt + 1], aParams.SubviewMargins.x())
+ && Draw::ParseInteger (theArgVec[anArgIt + 2], aParams.SubviewMargins.y()))
+ {
+ anArgIt += 2;
}
else if (anArgCase == "-virtual"
|| anArgCase == "-offscreen")
{
- isVirtual = true;
- if (anArgIt + 1 < theArgsNb
- && Draw::ParseOnOff (theArgVec[anArgIt + 1], isVirtual))
- {
- ++anArgIt;
- }
+ aParams.IsVirtual = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
+ }
+ else if (anArgCase == "-composer")
+ {
+ aParams.IsComposer = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
}
else if (anArgCase == "-exitonclose")
{
- ViewerTest_EventManager::ToExitOnCloseView() = true;
- if (anArgIt + 1 < theArgsNb
- && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
- {
- ++anArgIt;
- }
+ ViewerTest_EventManager::ToExitOnCloseView() = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
}
else if (anArgCase == "-closeonescape"
|| anArgCase == "-closeonesc")
{
- ViewerTest_EventManager::ToCloseViewOnEscape() = true;
- if (anArgIt + 1 < theArgsNb
- && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
- {
- ++anArgIt;
- }
+ ViewerTest_EventManager::ToCloseViewOnEscape() = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
}
else if (anArgCase == "-2d_mode"
|| anArgCase == "-2dmode"
|| anArgCase == "-2d")
{
- bool toEnable = true;
- if (anArgIt + 1 < theArgsNb
- && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
- {
- ++anArgIt;
- }
+ bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
is2dMode = toEnable ? 1 : 0;
}
else if (anArgIt + 1 < theArgsNb
&& (anArgCase == "-disp"
|| anArgCase == "-display"))
{
- aDisplayName = theArgVec[++anArgIt];
+ aParams.DisplayName = theArgVec[++anArgIt];
}
else if (anArgCase == "-dpiaware")
{
aDpiAware = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt) ? 1 : 0;
}
else if (!ViewerTest::CurrentView().IsNull()
- && aCopyFrom.IsNull()
+ && aParams.ViewToClone.IsNull()
&& (anArgCase == "-copy"
|| anArgCase == "-clone"
|| anArgCase == "-cloneactive"
|| anArgCase == "-cloneactiveview"))
{
- aCopyFrom = ViewerTest::CurrentView();
+ aParams.ViewToClone = ViewerTest::CurrentView();
+ }
+ else if (!ViewerTest::CurrentView().IsNull()
+ && aParams.ParentView.IsNull()
+ && anArgCase == "-subview")
+ {
+ aParams.ParentView = ViewerTest::CurrentView();
+ if (aParams.ParentView.IsNull())
+ {
+ Message::SendFail() << "Syntax error: cannot create of subview without parent";
+ return 1;
+ }
+ if (aParams.ParentView->IsSubview())
+ {
+ aParams.ParentView = aParams.ParentView->ParentView();
+ }
+ }
+ else if (!ViewerTest::CurrentView().IsNull()
+ && aParams.ParentView.IsNull()
+ && anArgCase == "-parent"
+ && anArgIt + 1 < theArgsNb)
+ {
+ TCollection_AsciiString aParentStr (theArgVec[++anArgIt]);
+ ViewerTest_Names aViewNames (aParentStr);
+ if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
+ {
+ Message::SendFail() << "Syntax error: parent view '" << aParentStr << "' not found";
+ return 1;
+ }
+
+ aParams.ParentView = ViewerTest_myViews.Find1(aViewNames.GetViewName());
+ if (aParams.ParentView->IsSubview())
+ {
+ aParams.ParentView = aParams.ParentView->ParentView();
+ }
}
// old syntax
else if (ViewerTest::SplitParameter (anArg, aName, aValue))
aName.LowerCase();
if (aName == "name")
{
- aViewName = aValue;
+ aParams.ViewName = aValue;
}
else if (aName == "l"
|| aName == "left")
{
- aPxLeft = aValue.IntegerValue();
+ aParams.Offset.x() = (float)aValue.RealValue();
}
else if (aName == "t"
|| aName == "top")
{
- aPxTop = aValue.IntegerValue();
+ aParams.Offset.y() = (float)aValue.RealValue();
}
else if (aName == "disp"
|| aName == "display")
{
- aDisplayName = aValue;
+ aParams.DisplayName = aValue;
}
else if (aName == "w"
|| aName == "width")
{
- aPxWidth = aValue.IntegerValue();
+ aParams.Size.x() = (float )aValue.RealValue();
}
else if (aName == "h"
|| aName == "height")
{
- aPxHeight = aValue.IntegerValue();
+ aParams.Size.y() = (float)aValue.RealValue();
}
else
{
return 1;
}
}
- else if (aViewName.IsEmpty())
+ else if (aParams.ViewName.IsEmpty())
{
- aViewName = anArg;
+ aParams.ViewName = anArg;
}
else
{
#else
(void )aDpiAware;
#if !defined(HAVE_XLIB)
- if (!aDisplayName.IsEmpty())
+ if (!aParams.DisplayName.IsEmpty())
{
- aDisplayName.Clear();
+ aParams.DisplayName.Clear();
Message::SendWarning() << "Warning: display parameter will be ignored.\n";
}
#endif
#endif
- ViewerTest_Names aViewNames (aViewName);
+ ViewerTest_Names aViewNames (aParams.ViewName);
if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
{
TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
return 0;
}
- TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
- aViewName, aDisplayName, aCopyFrom, isVirtual);
+ TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aParams);
if (is2dMode != -1)
{
ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
void ActivateView (const TCollection_AsciiString& theViewName,
Standard_Boolean theToUpdate = Standard_True)
{
- const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
- if (aView.IsNull())
+ if (const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName))
+ {
+ ViewerTest::ActivateView (aView, theToUpdate);
+ }
+}
+
+//==============================================================================
+//function : ActivateView
+//purpose :
+//==============================================================================
+void ViewerTest::ActivateView (const Handle(V3d_View)& theView,
+ Standard_Boolean theToUpdate)
+{
+ Handle(V3d_View) aView = theView;
+ const TCollection_AsciiString* aViewName = ViewerTest_myViews.Seek2 (aView);
+ if (aViewName == nullptr)
{
return;
}
Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
- if (!anAISContext.IsNull())
+ if (anAISContext.IsNull())
+ {
+ return;
+ }
+
+ if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
{
- if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
+ if (!aCurrentView->Window().IsNull())
{
aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
}
+ }
- ViewerTest::CurrentView (aView);
- ViewerTest::SetAISContext (anAISContext);
- aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
- VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(ViewerTest::CurrentView()->Window());
- SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
- if (theToUpdate)
- {
- ViewerTest::CurrentView()->Redraw();
- }
+ ViewerTest::CurrentView (aView);
+ ViewerTest::SetAISContext (anAISContext);
+ if (aView->IsSubview())
+ {
+ aView->ParentView()->Window()->SetTitle (TCollection_AsciiString("3D View - ") + *aViewName + "(*)");
+ VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(aView->View()->ParentView()->Window());
+ }
+ else
+ {
+ VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(aView->Window());
+ }
+ if (!VT_GetWindow().IsNull())
+ {
+ VT_GetWindow()->SetTitle (TCollection_AsciiString("3D View - ") + *aViewName + "(*)");
+ }
+ SetDisplayConnection(aView->Viewer()->Driver()->GetDisplayConnection());
+ if (theToUpdate)
+ {
+ aView->Redraw();
}
}
return;
}
+ Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
+ Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
+ ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+ aRedrawer.Stop (aView);
+ if (!aView->Subviews().IsEmpty())
+ {
+ NCollection_Sequence<Handle(V3d_View)> aSubviews = aView->Subviews();
+ for (const Handle(V3d_View)& aSubviewIter : aSubviews)
+ {
+ RemoveView (aSubviewIter, isContextRemoved);
+ }
+ }
+
// Activate another view if it's active now
if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
{
if (ViewerTest_myViews.Extent() > 1)
{
- TCollection_AsciiString aNewViewName;
for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
anIter.More(); anIter.Next())
{
if (anIter.Key1() != theViewName)
{
- aNewViewName = anIter.Key1();
+ ActivateView (anIter.Value(), true);
break;
}
}
- ActivateView (aNewViewName);
}
else
{
}
// Delete view
- Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
- Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
- ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
- aRedrawer.Stop (aView);
-
- // Remove view resources
ViewerTest_myViews.UnBind1(theViewName);
- aView->Window()->Unmap();
+ if (!aView->Window().IsNull())
+ {
+ aView->Window()->Unmap();
+ }
aView->Remove();
#if defined(HAVE_XLIB)
{
if (++anArgIter >= theArgNb)
{
- Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
+ Message::SendFail() << "Syntax error at '" << anArg << "'";
return 1;
}
- TCollection_AsciiString aPosName (theArgVec[anArgIter]);
- aPosName.LowerCase();
- if (aPosName == "center")
- {
- aPosition = Aspect_TOTP_CENTER;
- }
- else if (aPosName == "left_lower"
- || aPosName == "lower_left"
- || aPosName == "leftlower"
- || aPosName == "lowerleft")
- {
- aPosition = Aspect_TOTP_LEFT_LOWER;
- }
- else if (aPosName == "left_upper"
- || aPosName == "upper_left"
- || aPosName == "leftupper"
- || aPosName == "upperleft")
- {
- aPosition = Aspect_TOTP_LEFT_UPPER;
- }
- else if (aPosName == "right_lower"
- || aPosName == "lower_right"
- || aPosName == "rightlower"
- || aPosName == "lowerright")
- {
- aPosition = Aspect_TOTP_RIGHT_LOWER;
- }
- else if (aPosName == "right_upper"
- || aPosName == "upper_right"
- || aPosName == "rightupper"
- || aPosName == "upperright")
- {
- aPosition = Aspect_TOTP_RIGHT_UPPER;
- }
- else
+ if (!ViewerTest::ParseCorner (theArgVec[anArgIter], aPosition))
{
- Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
+ Message::SendFail() << "Syntax error at '" << anArg << "' - unknown position '" << theArgVec[anArgIter] << "'";
return 1;
}
}
theDI.Eval (aCommand.ToCString());
}
- Standard_Integer aPxLeft = 0;
- Standard_Integer aPxTop = 0;
- Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
- Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
- ? int(anImgRef->SizeY() * 2)
- : int(anImgRef->SizeY());
- TCollection_AsciiString aDisplayName;
- TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
- aViewName, aDisplayName);
+ ViewerTest_VinitParams aParams;
+ aParams.ViewName = aViewName;
+ aParams.Size.x() = float(anImgRef->SizeX() * 2);
+ aParams.Size.y() = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
+ ? float(anImgRef->SizeY() * 2)
+ : float(anImgRef->SizeY());
+ TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aParams);
Standard_Real aRatio = anImgRef->Ratio();
Standard_Real aSizeX = 1.0;
addCmd ("vinit", VInit, /* [vinit] */ R"(
vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]
- [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {on|off}=off] [-2d_mode {on|off}=off]
- [-display displayName] [-dpiAware {on|off}]
+ [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {0|1}]=0 [-2d_mode {0|1}]=0
+ [-display displayName] [-dpiAware {0|1}]=0
+ [-subview] [-parent OtherView] [-composer {0|1}]=0 [-margins DX DY]=0
Creates new View window with specified name viewName.
By default the new view is created in the viewer and in graphic driver shared with active view.
-name {driverName/viewerName/viewName | viewerName/viewName | viewName}
-exitOnClose when specified, closing the view will exit application.
-closeOnEscape when specified, view will be closed on pressing Escape.
-virtual create an offscreen window within interactive session
+ -subview create a subview within another view
-2d_mode when on, view will not react on rotate scene events
-dpiAware override dpi aware hint (Windows platform)
Additional commands for operations with views: vclose, vactivate, vviewlist.
TCollection_AsciiString aViewName = TCollection_AsciiString ("Driver1/Document_") + argv[1] + "/View1";
if (!TPrsStd_AISViewer::Find (aRoot, aDocViewer))
{
- ViewerTest::ViewerInit (0, 0, 0, 0, aViewName.ToCString(), "");
+ ViewerTest::ViewerInit (aViewName);
aDocViewer = TPrsStd_AISViewer::New (aRoot, ViewerTest::GetAISContext());
}
aD1->Open(anApp);
TCollection_AsciiString aViewName ("Driver1/DummyDocument/View1");
- ViewerTest::ViewerInit (0, 0, 0, 0, aViewName.ToCString(), "");
+ ViewerTest::ViewerInit (aViewName);
TPrsStd_AISViewer::New (aD1->GetData()->Root(), ViewerTest::GetAISContext());
// get shape tool for shape verification
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/RootView + V2/ViewLeft + V3/ViewRight"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/RootView -width 1024 -height 512 -composer 0
+vbackground GRAY20
+
+vinit V2/ViewLeft -subView -width 0.5 -height 1.0
+vbackground GRAY30
+
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vviewcube vc
+
+vinit V3/ViewRight -parent V1/RootView -width 0.5 -height 1.0 -left 0.5
+vbackground GRAY40
+psphere s 1
+vdisplay -dispMode 1 s
+vaspects s -material SILVER
+vfit
+vzbufftrihedron
+
+vactivate V1/RootView
+vdump $::imagedir/${::casename}.png
+
+vactivate V2/ViewLeft
+vdump $::imagedir/${::casename}_left.png
+
+vactivate V3/ViewRight
+vdump $::imagedir/${::casename}_right.png
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/RootView + V2/ViewLeft + V3/ViewRight + SSAA"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/RootView -width 1024 -height 512 -composer 1
+vbackground GRAY20
+
+vinit V2/ViewLeft -subView -width 0.5 -height 1.0
+vrenderparams -rendScale 2
+vbackground GRAY30
+
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vviewcube vc
+
+vinit V3/ViewRight -parent V1/RootView -width 0.5 -height 1.0 -left 0.5
+vrenderparams -rendScale 2
+vbackground GRAY40
+psphere s 1
+vdisplay -dispMode 1 s
+vaspects s -material SILVER
+vfit
+vzbufftrihedron
+
+vactivate V1/RootView
+vdump $::imagedir/${::casename}.png
+
+vactivate V2/ViewLeft
+vdump $::imagedir/${::casename}_left.png
+
+vactivate V3/ViewRight
+vdump $::imagedir/${::casename}_right.png
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/RootView + V2/ViewLeft + V2/ViewRightTop + V2/ViewRightBottom"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/RootView -width 768 -height 512 -composer 1
+vbackground GRAY20
+
+vinit V2/ViewLeft -parent V1/RootView -width 0.5 -height 1.0
+vbackground GRAY30
+vaxo
+vcamera -persp
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vzbufftrihedron
+
+vinit V2/ViewRightTop -parent V1/RootView -width 0.5 -height 0.5 -corner topRight
+vbackground GRAY40
+vaxo
+vfit
+
+vinit V2/ViewRightBottom -parent V1/RootView -width 0.5 -height 0.5 -corner bottomRight
+vbackground GRAY50
+vaxo
+vfit
+
+vactivate V1/RootView
+vdump $::imagedir/${::casename}.png
+
+vactivate V2/ViewLeft
+vdump $::imagedir/${::casename}_left.png
+
+vactivate V2/ViewRightTop
+vdump $::imagedir/${::casename}_righttop.png
+
+vactivate V2/ViewRightBottom
+vdump $::imagedir/${::casename}_rightbottom.png
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/RootView + V2/View + V2/ThumbView at corner"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/RootView -width 380 -height 520
+vbackground GRAY20
+
+vinit V2/View -parent V1/RootView -width 1.0 -height 1.0
+vbackground GRAY30
+vaxo
+vcamera -persp
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vzbufftrihedron
+
+vinit V2/ThumbView -parent V1/RootView -width 0.25 -height 0.25 -corner bottomRight -top 10 -left 10
+vbackground GRAY40
+vaxo
+vfit
+
+vactivate V1/RootView
+vdump $::imagedir/${::casename}.png
+
+vactivate V2/View
+vdump $::imagedir/${::casename}_view.png
+
+vactivate V2/ThumbView
+vdump $::imagedir/${::casename}_thumb.png
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/RootView + V1/ThumbView at corner"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/RootView -width 380 -height 520 -composer 0
+vbackground GRAY20
+vaxo
+vcamera -persp
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vzbufftrihedron
+
+vinit V1/ThumbView -parent V1/RootView -width 0.25 -height 0.25 -corner bottomRight -top 10 -left 10
+vbackground GRAY40
+vaxo
+vfit
+
+vactivate V1/RootView
+vdump $::imagedir/${::casename}.png
+
+vactivate V1/ThumbView
+vdump $::imagedir/${::casename}_thumb.png
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/CompView + V1/ThumbView at corner"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/CompView -width 380 -height 520 -composer 1
+vbackground GRAY20
+vaxo
+vcamera -persp
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vzbufftrihedron
+
+vinit V1/ThumbView -parent V1/CompView -width 0.25 -height 0.25 -corner bottomRight -top 10 -left 10
+vbackground GRAY40
+vaxo
+vfit
+
+vactivate V1/CompView
+vdump $::imagedir/${::casename}.png
+
+vactivate V1/ThumbView
+vdump $::imagedir/${::casename}_thumb.png
--- /dev/null
+puts "========"
+puts "0032886: Visualization, V3d_View - introduce interface for creating a subview"
+puts "V1/CompView + V2/ViewLeft + V2/ViewRightTop + V2/ViewRightBottom + margins"
+puts "========"
+
+pload MODELING VISUALIZATION
+vinit V1/CompView -width 768 -height 512 -composer 1
+vbackground GRAY20
+
+vinit V2/ViewLeft -parent V1/CompView -width 0.5 -height 1.0 -margins 2 2
+vbackground GRAY30
+vaxo
+vcamera -persp
+box b 1 2 3
+vdisplay -dispMode 1 b
+vaspects b -faceBoundaryDraw 1
+vfit
+vviewcube vc
+
+vinit V2/ViewRightTop -parent V1/CompView -width 0.5 -height 0.5 -corner topRight -margins 2 2
+vbackground GRAY40
+vaxo
+vfit
+verase vc -view
+
+vinit V3/ViewRightBottom -parent V1/CompView -width 0.5 -height 0.5 -corner bottomRight -margins 2 2
+vbackground GRAY50
+psphere s 1
+vdisplay -dispMode 1 s
+vaspects s -material SILVER
+vaxo
+vfit
+vzbufftrihedron
+
+vinit V3/ThumbView -parent V1/CompView -width 100 -height 150 -corner topLeft -top 10 -left 10 -margins 2 2
+vbackground GRAY40
+vaxo
+vfit
+
+vactivate V1/CompView
+vdump $::imagedir/${::casename}.png
+
+vactivate V2/ViewLeft
+vdump $::imagedir/${::casename}_left.png
+
+vactivate V2/ViewRightTop
+vdump $::imagedir/${::casename}_righttop.png
+
+vactivate V3/ThumbView
+vdump $::imagedir/${::casename}_thumb.png
+
+vactivate V3/ViewRightBottom
+vdump $::imagedir/${::casename}_rightbottom.png