0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands.cxx
1 // Created on: 1998-09-01
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #if defined(_WIN32)
18   #include <windows.h>
19 #endif
20
21 #include <ViewerTest.hxx>
22
23 #include <AIS_AnimationAxisRotation.hxx>
24 #include <AIS_AnimationCamera.hxx>
25 #include <AIS_AnimationObject.hxx>
26 #include <AIS_Axis.hxx>
27 #include <AIS_CameraFrustum.hxx>
28 #include <AIS_ColorScale.hxx>
29 #include <AIS_InteractiveContext.hxx>
30 #include <AIS_LightSource.hxx>
31 #include <AIS_ListOfInteractive.hxx>
32 #include <AIS_Manipulator.hxx>
33 #include <AIS_ViewCube.hxx>
34 #include <AIS_Shape.hxx>
35 #include <AIS_Point.hxx>
36 #include <Aspect_DisplayConnection.hxx>
37 #include <Aspect_Grid.hxx>
38 #include <Aspect_TypeOfLine.hxx>
39 #include <Draw_Appli.hxx>
40 #include <Draw_Interpretor.hxx>
41 #include <Draw_ProgressIndicator.hxx>
42 #include <gp_Dir.hxx>
43 #include <gp_Pln.hxx>
44 #include <gp_Pnt.hxx>
45 #include <Geom_Axis2Placement.hxx>
46 #include <Geom_CartesianPoint.hxx>
47 #include <Graphic3d_ArrayOfPolylines.hxx>
48 #include <Graphic3d_AspectFillArea3d.hxx>
49 #include <Graphic3d_ClipPlane.hxx>
50 #include <Graphic3d_CubeMapPacked.hxx>
51 #include <Graphic3d_CubeMapSeparate.hxx>
52 #include <Graphic3d_GraduatedTrihedron.hxx>
53 #include <Graphic3d_GraphicDriver.hxx>
54 #include <Graphic3d_GraphicDriverFactory.hxx>
55 #include <Graphic3d_NameOfTextureEnv.hxx>
56 #include <Graphic3d_Texture2D.hxx>
57 #include <Graphic3d_TextureEnv.hxx>
58 #include <Graphic3d_TextureParams.hxx>
59 #include <Graphic3d_TypeOfTextureFilter.hxx>
60 #include <Image_AlienPixMap.hxx>
61 #include <Image_Diff.hxx>
62 #include <Image_VideoRecorder.hxx>
63 #include <Message.hxx>
64 #include <Message_ProgressScope.hxx>
65 #include <NCollection_DataMap.hxx>
66 #include <NCollection_List.hxx>
67 #include <NCollection_LocalArray.hxx>
68 #include <OSD_Parallel.hxx>
69 #include <OSD_Timer.hxx>
70 #include <Prs3d_ShadingAspect.hxx>
71 #include <Prs3d_DatumAspect.hxx>
72 #include <Prs3d_Drawer.hxx>
73 #include <Prs3d_LineAspect.hxx>
74 #include <Prs3d_Text.hxx>
75 #include <Select3D_SensitivePrimitiveArray.hxx>
76 #include <TColStd_HSequenceOfAsciiString.hxx>
77 #include <TColStd_SequenceOfInteger.hxx>
78 #include <TColStd_HSequenceOfReal.hxx>
79 #include <ViewerTest_AutoUpdater.hxx>
80 #include <ViewerTest_ContinuousRedrawer.hxx>
81 #include <ViewerTest_EventManager.hxx>
82 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
83 #include <ViewerTest_CmdParser.hxx>
84 #include <ViewerTest_V3dView.hxx>
85 #include <V3d_AmbientLight.hxx>
86 #include <V3d_DirectionalLight.hxx>
87 #include <V3d_PositionalLight.hxx>
88 #include <V3d_SpotLight.hxx>
89 #include <V3d_Trihedron.hxx>
90 #include <V3d_Viewer.hxx>
91 #include <UnitsAPI.hxx>
92
93 #include <tcl.h>
94
95 #if defined(_WIN32)
96   #include <WNT_WClass.hxx>
97   #include <WNT_Window.hxx>
98 #elif defined(HAVE_XLIB)
99   #include <Xw_Window.hxx>
100   #include <X11/Xlib.h>
101   #include <X11/Xutil.h>
102 #elif defined(__APPLE__)
103   #include <Cocoa_Window.hxx>
104 #elif defined(__EMSCRIPTEN__)
105   #include <Wasm_Window.hxx>
106   #include <emscripten/emscripten.h>
107 #else
108   #include <Aspect_NeutralWindow.hxx>
109 #endif
110
111 //==============================================================================
112 //  VIEWER GLOBAL VARIABLES
113 //==============================================================================
114
115 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
116 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
117
118 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
119 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
120
121 #if defined(_WIN32)
122 typedef WNT_Window ViewerTest_Window;
123 #elif defined(HAVE_XLIB)
124 typedef Xw_Window ViewerTest_Window;
125 static void VProcessEvents(ClientData,int);
126 #elif defined(__APPLE__)
127 typedef Cocoa_Window ViewerTest_Window;
128 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
129 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
130 #elif defined(__EMSCRIPTEN__)
131 typedef Wasm_Window ViewerTest_Window;
132 #else
133 typedef Aspect_NeutralWindow ViewerTest_Window;
134 #endif
135
136 #if defined(__EMSCRIPTEN__)
137 //! Return DOM id of default WebGL canvas from Module.canvas.
138 EM_JS(char*, occJSModuleCanvasId, (), {
139   const aCanvasId = Module.canvas.id;
140   const aNbBytes  = lengthBytesUTF8 (aCanvasId) + 1;
141   const aStrPtr   = Module._malloc (aNbBytes);
142   stringToUTF8 (aCanvasId, aStrPtr, aNbBytes);
143   return aStrPtr;
144 });
145
146 //! Return DOM id of default WebGL canvas from Module.canvas.
147 static TCollection_AsciiString getModuleCanvasId()
148 {
149   char* aRawId = occJSModuleCanvasId();
150   TCollection_AsciiString anId (aRawId != NULL ? aRawId : "");
151   free (aRawId);
152   return anId;
153 }
154 #endif
155
156 namespace
157 {
158   static Handle(ViewerTest_Window)& VT_GetWindow()
159   {
160     static Handle(ViewerTest_Window) aWindow;
161     return aWindow;
162   }
163
164   static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
165   {
166     static Handle(Aspect_DisplayConnection) aDisplayConnection;
167     return aDisplayConnection;
168   }
169
170   using ViewerTest_ViewerCommandsViewMap = NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>;
171   using ViewerTest_ViewerCommandsInteractiveContextMap = NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>;
172   using ViewerTest_ViewerCommandsGraphicDriverMap = NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>;
173
174   static void SetDisplayConnection(const Handle(Aspect_DisplayConnection)& theDisplayConnection)
175   {
176     GetDisplayConnection() = theDisplayConnection;
177   }
178
179   static ViewerTest_ViewerCommandsInteractiveContextMap ViewerTest_myContexts;
180   static ViewerTest_ViewerCommandsGraphicDriverMap ViewerTest_myDrivers;
181 }
182
183 ViewerTest_ViewerCommandsViewMap ViewerTest_myViews;
184
185 static struct
186 {
187   Quantity_Color FlatColor;
188   Quantity_Color GradientColor1;
189   Quantity_Color GradientColor2;
190   Aspect_GradientFillMethod FillMethod;
191
192   //! Sets the gradient filling for a background in a default viewer.
193   void SetDefaultGradient()
194   {
195     for (ViewerTest_ViewerCommandsInteractiveContextMap::Iterator aCtxIter (ViewerTest_myContexts);
196          aCtxIter.More(); aCtxIter.Next())
197     {
198       const Handle (V3d_Viewer)& aViewer = aCtxIter.Key2()->CurrentViewer();
199       aViewer->SetDefaultBgGradientColors (GradientColor1, GradientColor2, FillMethod);
200     }
201   }
202
203   //! Sets the color used for filling a background in a default viewer.
204   void SetDefaultColor()
205   {
206     for (ViewerTest_ViewerCommandsInteractiveContextMap::Iterator aCtxIter (ViewerTest_myContexts);
207          aCtxIter.More(); aCtxIter.Next())
208     {
209       const Handle (V3d_Viewer)& aViewer = aCtxIter.Key2()->CurrentViewer();
210       aViewer->SetDefaultBackgroundColor (FlatColor);
211     }
212   }
213
214 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GradientFillMethod_None };
215
216 //==============================================================================
217 //  EVENT GLOBAL VARIABLES
218 //==============================================================================
219
220 #ifdef _WIN32
221 static LRESULT WINAPI AdvViewerWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
222 #endif
223
224 //==============================================================================
225 //function : WClass
226 //purpose  :
227 //==============================================================================
228
229 const Handle(WNT_WClass)& ViewerTest::WClass()
230 {
231   static Handle(WNT_WClass) theWClass;
232 #if defined(_WIN32)
233   if (theWClass.IsNull())
234   {
235     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
236                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
237                                 ::LoadCursor (NULL, IDC_ARROW));
238   }
239 #endif
240   return theWClass;
241 }
242
243 //==============================================================================
244 //function : CreateName
245 //purpose  : Create numerical name for new object in theMap
246 //==============================================================================
247 template <typename ObjectType>
248 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
249                                     const TCollection_AsciiString& theDefaultString)
250 {
251   if (theObjectMap.IsEmpty())
252     return theDefaultString + TCollection_AsciiString(1);
253
254   Standard_Integer aNextKey = 1;
255   Standard_Boolean isFound = Standard_False;
256   while (!isFound)
257   {
258     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
259     // Look for objects with default names
260     if (theObjectMap.IsBound1(aStringKey))
261     {
262       aNextKey++;
263     }
264     else
265       isFound = Standard_True;
266   }
267
268   return theDefaultString + TCollection_AsciiString(aNextKey);
269 }
270
271 //==============================================================================
272 //structure : ViewerTest_Names
273 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
274 //==============================================================================
275 struct ViewerTest_Names
276 {
277 private:
278   TCollection_AsciiString myDriverName;
279   TCollection_AsciiString myViewerName;
280   TCollection_AsciiString myViewName;
281
282 public:
283
284   const TCollection_AsciiString& GetDriverName () const
285   {
286     return myDriverName;
287   }
288   void SetDriverName (const TCollection_AsciiString& theDriverName)
289   {
290     myDriverName = theDriverName;
291   }
292   const TCollection_AsciiString& GetViewerName () const
293   {
294     return myViewerName;
295   }
296   void SetViewerName (const TCollection_AsciiString& theViewerName)
297   {
298     myViewerName = theViewerName;
299   }
300   const TCollection_AsciiString& GetViewName () const
301   {
302     return myViewName;
303   }
304   void SetViewName (const TCollection_AsciiString& theViewName)
305   {
306     myViewName = theViewName;
307   }
308
309   //===========================================================================
310   //function : Constructor for ViewerTest_Names
311   //purpose  : Get view, viewer, driver names from custom string
312   //===========================================================================
313
314   ViewerTest_Names (const TCollection_AsciiString& theInputString)
315   {
316     TCollection_AsciiString aName(theInputString);
317     if (theInputString.IsEmpty())
318     {
319       // Get current configuration
320       if (ViewerTest_myDrivers.IsEmpty())
321         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
322           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
323       else
324         myDriverName = ViewerTest_myDrivers.Find2
325         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
326
327       if(ViewerTest_myContexts.IsEmpty())
328       {
329         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
330           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
331       }
332       else
333       {
334         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
335       }
336
337       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
338     }
339     else
340     {
341       // There is at least view name
342       Standard_Integer aParserNumber = 0;
343       for (Standard_Integer i = 0; i < 3; ++i)
344       {
345         Standard_Integer aParserPos = aName.SearchFromEnd("/");
346         if(aParserPos != -1)
347         {
348           aParserNumber++;
349           aName.Split(aParserPos-1);
350         }
351         else
352           break;
353       }
354       if (aParserNumber == 0)
355       {
356         // Only view name
357         if (!ViewerTest::GetAISContext().IsNull())
358         {
359           myDriverName = ViewerTest_myDrivers.Find2
360           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
361           myViewerName = ViewerTest_myContexts.Find2
362           (ViewerTest::GetAISContext());
363         }
364         else
365         {
366           // There is no opened contexts here, need to create names for viewer and driver
367           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
368             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
369
370           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
371             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
372         }
373         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
374       }
375       else if (aParserNumber == 1)
376       {
377         // Here is viewerName/viewName
378         if (!ViewerTest::GetAISContext().IsNull())
379           myDriverName = ViewerTest_myDrivers.Find2
380           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
381         else
382         {
383           // There is no opened contexts here, need to create name for driver
384           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
385             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
386         }
387         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
388
389         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
390       }
391       else
392       {
393         //Here is driverName/viewerName/viewName
394         myDriverName = TCollection_AsciiString(aName);
395
396         TCollection_AsciiString aViewerName(theInputString);
397         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
398         myViewerName = TCollection_AsciiString(aViewerName);
399
400         myViewName = TCollection_AsciiString(theInputString);
401       }
402     }
403   }
404 };
405
406 //==============================================================================
407 //function : FindContextByView
408 //purpose  : Find AIS_InteractiveContext by View
409 //==============================================================================
410
411 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
412 {
413   Handle(AIS_InteractiveContext) anAISContext;
414
415   for (ViewerTest_ViewerCommandsInteractiveContextMap::Iterator
416        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
417   {
418     if (anIter.Key2()->CurrentViewer() == theView->Viewer())
419        return anIter.Key2();
420   }
421   return anAISContext;
422 }
423
424 //==============================================================================
425 //function : IsWindowOverlapped
426 //purpose  : Check if theWindow overlapp another view
427 //==============================================================================
428
429 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
430                                      const Standard_Integer thePxTop,
431                                      const Standard_Integer thePxRight,
432                                      const Standard_Integer thePxBottom,
433                                      TCollection_AsciiString& theViewId)
434 {
435   for(ViewerTest_ViewerCommandsViewMap::Iterator
436       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
437   {
438     Standard_Integer aTop = 0,
439       aLeft = 0,
440       aRight = 0,
441       aBottom = 0;
442     anIter.Key2()->Window()->Position(aLeft, aTop, aRight, aBottom);
443     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
444         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
445         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
446         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
447     {
448       theViewId = anIter.Key1();
449       return Standard_True;
450     }
451   }
452   return Standard_False;
453 }
454
455 // Workaround: to create and delete non-orthographic views outside ViewerTest
456 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
457 {
458   ViewerTest_myViews.UnBind1 (theName);
459 }
460
461 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
462                                const Handle(V3d_View)& theView)
463 {
464   ViewerTest_myViews.Bind (theName, theView);
465 }
466
467 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
468 {
469   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
470 }
471
472 //==============================================================================
473 //function : ViewerInit
474 //purpose  : Create the window viewer and initialize all the global variable
475 //==============================================================================
476
477 TCollection_AsciiString ViewerTest::ViewerInit (const ViewerTest_VinitParams& theParams)
478 {
479   // Default position and dimension of the viewer window.
480   // Note that left top corner is set to be sufficiently small to have
481   // window fit in the small screens (actual for remote desktops, see #23003).
482   // The position corresponds to the window's client area, thus some
483   // gap is added for window frame to be visible.
484   Graphic3d_Vec2d aPxTopLeft (20, 40);
485   Graphic3d_Vec2d aPxSize (409, 409);
486   Standard_Boolean isDefViewSize = Standard_True;
487   Standard_Boolean toCreateViewer = Standard_False;
488   const Standard_Boolean isVirtual = Draw_VirtualWindows || theParams.IsVirtual;
489   if (!theParams.ViewToClone.IsNull())
490   {
491     Graphic3d_Vec2i aCloneSize;
492     theParams.ViewToClone->Window()->Size (aCloneSize.x(), aCloneSize.y());
493     aPxSize = Graphic3d_Vec2d (aCloneSize);
494     isDefViewSize = Standard_False;
495   #if !defined(__EMSCRIPTEN__)
496     (void )isDefViewSize;
497   #endif
498   }
499
500   Handle(Graphic3d_GraphicDriverFactory) aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
501   if (aFactory.IsNull())
502   {
503     Draw::GetInterpretor().Eval ("pload OPENGL");
504     aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
505     if (aFactory.IsNull())
506     {
507       Draw::GetInterpretor().Eval ("pload GLES");
508       aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
509       if (aFactory.IsNull())
510       {
511         throw Standard_ProgramError("Error: no graphic driver factory found");
512       }
513     }
514   }
515
516   Handle(Graphic3d_GraphicDriver) aGraphicDriver;
517   ViewerTest_Names aViewNames (theParams.ViewName);
518   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
519   {
520     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
521   }
522
523   // Get graphic driver (create it or get from another view)
524   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
525   if (isNewDriver)
526   {
527     // Get connection string
528   #if defined(HAVE_XLIB)
529     if (!theParams.DisplayName.IsEmpty())
530     {
531       SetDisplayConnection (new Aspect_DisplayConnection (theParams.DisplayName));
532     }
533     else
534     {
535       Aspect_XDisplay* aDispX = NULL;
536       // create dedicated display connection instead of reusing Tk connection
537       // so that to proceed events independently through VProcessEvents()/ViewerMainLoop() callbacks
538       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
539       Tcl_Interp* aTclInterp = aCommands.Interp();
540       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
541       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
542       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
543     }
544   #else
545     SetDisplayConnection (new Aspect_DisplayConnection ());
546   #endif
547
548     aGraphicDriver = aFactory->CreateDriver (GetDisplayConnection());
549     if (isVirtual)
550     {
551       // don't waste the time waiting for VSync when window is not displayed on the screen
552       aGraphicDriver->SetVerticalSync (false);
553     }
554
555     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
556     toCreateViewer = Standard_True;
557   }
558   else
559   {
560     aGraphicDriver = ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName());
561   }
562
563   // Get screen resolution
564   Graphic3d_Vec2i aScreenSize;
565 #if defined(_WIN32)
566   RECT aWindowSize;
567   GetClientRect(GetDesktopWindow(), &aWindowSize);
568   aScreenSize.SetValues (aWindowSize.right, aWindowSize.bottom);
569 #elif defined(HAVE_XLIB)
570   ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
571   Screen* aScreen = DefaultScreenOfDisplay(aDispX);
572   aScreenSize.x() = WidthOfScreen(aScreen);
573   aScreenSize.y() = HeightOfScreen(aScreen);
574 #elif defined(__APPLE__)
575   GetCocoaScreenResolution (aScreenSize.x(), aScreenSize.y());
576 #else
577   // not implemented
578 #endif
579
580   if (!theParams.ParentView.IsNull())
581   {
582     aPxTopLeft.SetValues (0, 0);
583   }
584   if (theParams.Offset.x() != 0)
585   {
586     aPxTopLeft.x() = theParams.Offset.x();
587   }
588   if (theParams.Offset.y() != 0)
589   {
590     aPxTopLeft.y() = theParams.Offset.y();
591   }
592   if (theParams.Size.x() != 0)
593   {
594     isDefViewSize = Standard_False;
595     aPxSize.x() = theParams.Size.x();
596     if (aPxSize.x() <= 1.0
597      && aScreenSize.x() > 0
598      && theParams.ParentView.IsNull())
599     {
600       aPxSize.x() = aPxSize.x() * double(aScreenSize.x());
601     }
602   }
603   if (theParams.Size.y() != 0)
604   {
605     isDefViewSize = Standard_False;
606     aPxSize.y() = theParams.Size.y();
607     if (aPxSize.y() <= 1.0
608      && aScreenSize.y() > 0
609      && theParams.ParentView.IsNull())
610     {
611       aPxSize.y() = aPxSize.y() * double(aScreenSize.y());
612     }
613   }
614
615   //Dispose the window if input parameters are default
616   if (!ViewerTest_myViews.IsEmpty()
617     && theParams.ParentView.IsNull()
618     && theParams.Offset.x() == 0
619     && theParams.Offset.y() == 0)
620   {
621     Standard_Integer aTop = 0, aLeft = 0, aRight = 0, aBottom = 0;
622     TCollection_AsciiString anOverlappedViewId("");
623     while (IsWindowOverlapped ((int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
624                                (int )aPxTopLeft.x() + (int )aPxSize.x(),
625                                (int )aPxTopLeft.y() + (int )aPxSize.y(), anOverlappedViewId))
626     {
627       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
628
629       if (IsWindowOverlapped (aRight + 20, (int )aPxTopLeft.y(), aRight + 20 + (int )aPxSize.x(),
630                               (int )aPxTopLeft.y() + (int )aPxSize.y(), anOverlappedViewId)
631         && aRight + 2 * aPxSize.x() + 40 > aScreenSize.x())
632       {
633         if (aBottom + aPxSize.y() + 40 > aScreenSize.y())
634         {
635           aPxTopLeft.x() = 20;
636           aPxTopLeft.y() = 40;
637           break;
638         }
639         aPxTopLeft.x() = 20;
640         aPxTopLeft.y() = aBottom + 40;
641       }
642       else
643       {
644         aPxTopLeft.x() = aRight + 20;
645       }
646     }
647   }
648
649   // Get viewer name
650   TCollection_AsciiString aTitle("3D View - ");
651   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
652
653   // Change name of current active window
654   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
655   {
656     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
657   }
658
659   // Create viewer
660   Handle(V3d_Viewer) a3DViewer;
661   // If it's the single view, we first look for empty context
662   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
663   {
664     ViewerTest_ViewerCommandsInteractiveContextMap::Iterator
665       anIter(ViewerTest_myContexts);
666     if (anIter.More())
667       ViewerTest::SetAISContext (anIter.Key2());
668     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
669   }
670   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
671   {
672     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
673     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
674   }
675   else if (a3DViewer.IsNull())
676   {
677     toCreateViewer = Standard_True;
678     a3DViewer = new V3d_Viewer(aGraphicDriver);
679     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
680     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
681                                            ViewerTest_DefaultBackground.GradientColor2,
682                                            ViewerTest_DefaultBackground.FillMethod);
683   }
684
685   // AIS context setup
686   if (ViewerTest::GetAISContext().IsNull() ||
687       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
688   {
689     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
690     ViewerTest::SetAISContext (aContext);
691     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
692   }
693   else
694   {
695     ViewerTest::ResetEventManager();
696   }
697
698   // Create window
699   if (!theParams.ParentView.IsNull())
700   {
701     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast (theParams.ParentView->Window());
702   }
703   else
704   {
705   #if defined(_WIN32)
706     VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
707                                      isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
708                                      (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
709                                      (int )aPxSize.x(), (int )aPxSize.y(),
710                                      Quantity_NOC_BLACK);
711     VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
712   #elif defined(HAVE_XLIB)
713     VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
714                                     aTitle.ToCString(),
715                                     (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
716                                     (int )aPxSize.x(), (int )aPxSize.y());
717   #elif defined(__APPLE__)
718     VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
719                                        (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
720                                        (int )aPxSize.x(), (int )aPxSize.y());
721     ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
722   #elif defined(__EMSCRIPTEN__)
723     // current EGL implementation in Emscripten supports only one global WebGL canvas returned by Module.canvas property;
724     // the code should be revised for handling multiple canvas elements (which is technically also possible)
725     TCollection_AsciiString aCanvasId = getModuleCanvasId();
726     if (!aCanvasId.IsEmpty())
727     {
728       aCanvasId = TCollection_AsciiString("#") + aCanvasId;
729     }
730
731     VT_GetWindow() = new Wasm_Window (aCanvasId);
732     Graphic3d_Vec2i aRealSize;
733     VT_GetWindow()->Size (aRealSize.x(), aRealSize.y());
734     if (!isDefViewSize || (aRealSize.x() <= 0 && aRealSize.y() <= 0))
735     {
736       // Wasm_Window wraps an existing HTML element without creating a new one.
737       // Keep size defined on a web page instead of defaulting to 409x409 (as in case of other platform),
738       // but resize canvas if vinit has been called with explicitly specified dimensions.
739       VT_GetWindow()->SetSizeLogical (Graphic3d_Vec2d (aPxSize));
740     }
741   #else
742     // not implemented
743     VT_GetWindow() = new Aspect_NeutralWindow();
744     VT_GetWindow()->SetSize ((int )aPxSize.x(), (int )aPxSize.y());
745   #endif
746     VT_GetWindow()->SetVirtual (isVirtual);
747   }
748
749   // View setup
750   Handle(V3d_View) aView;
751   if (!theParams.ViewToClone.IsNull())
752   {
753     aView = new ViewerTest_V3dView (a3DViewer, theParams.ViewToClone);
754   }
755   else
756   {
757     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
758   }
759
760   aView->View()->SetSubviewComposer (theParams.IsComposer);
761   if (!theParams.ParentView.IsNull())
762   {
763     aView->SetWindow (theParams.ParentView, aPxSize, theParams.Corner, aPxTopLeft, theParams.SubviewMargins);
764   }
765   else
766   {
767     aView->SetWindow (VT_GetWindow());
768   }
769   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
770
771   ViewerTest::CurrentView(aView);
772   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
773
774   // Setup for X11 or NT
775   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
776   ViewerTest_EventManager::SetupWindowCallbacks (VT_GetWindow());
777
778   // Set parameters for V3d_View and V3d_Viewer
779   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
780   aV3dView->SetComputedMode(Standard_False);
781
782   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
783   if (toCreateViewer)
784   {
785     a3DViewer->SetDefaultLights();
786     a3DViewer->SetLightOn();
787   }
788
789 #if defined(HAVE_XLIB)
790   if (isNewDriver)
791   {
792     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
793     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
794   }
795 #endif
796
797   VT_GetWindow()->Map();
798
799   // Set the handle of created view in the event manager
800   ViewerTest::ResetEventManager();
801
802   ViewerTest::CurrentView()->Redraw();
803
804   aView.Nullify();
805   a3DViewer.Nullify();
806
807   return aViewNames.GetViewName();
808 }
809
810 //==============================================================================
811 //function : RedrawAllViews
812 //purpose  : Redraw all created views
813 //==============================================================================
814 void ViewerTest::RedrawAllViews()
815 {
816   ViewerTest_ViewerCommandsViewMap::Iterator aViewIt(ViewerTest_myViews);
817   for (; aViewIt.More(); aViewIt.Next())
818   {
819     const Handle(V3d_View)& aView = aViewIt.Key2();
820     aView->Redraw();
821   }
822 }
823
824 //==============================================================================
825 //function : VDriver
826 //purpose  :
827 //==============================================================================
828 static int VDriver (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
829 {
830   if (theArgsNb == 1)
831   {
832     theDi << "Registered: ";
833     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
834          aFactoryIter.More(); aFactoryIter.Next())
835     {
836       const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
837       theDi << aFactory->Name() << " ";
838     }
839
840     theDi << "\n";
841     theDi << "Default: ";
842     if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
843     {
844       theDi << aFactory->Name();
845     }
846     else
847     {
848       theDi << "NONE";
849     }
850     return 0;
851   }
852
853   TCollection_AsciiString aNewActive;
854   bool toLoad = false;
855   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
856   {
857     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
858     anArgCase.LowerCase();
859     if (anArgCase == "-list")
860     {
861       for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
862            aFactoryIter.More(); aFactoryIter.Next())
863       {
864         const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
865         theDi << aFactory->Name() << " ";
866       }
867     }
868     else if ((anArgCase == "-default"
869            || anArgCase == "-load")
870           && aNewActive.IsEmpty())
871     {
872       toLoad = (anArgCase == "-load");
873       if (anArgIter + 1 < theArgsNb)
874       {
875         aNewActive = theArgVec[++anArgIter];
876       }
877       else if (toLoad)
878       {
879         theDi << "Syntax error at '" << theArgVec[anArgIter] << "'";
880         return 1;
881       }
882       else
883       {
884         if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
885         {
886           theDi << aFactory->Name();
887         }
888         else
889         {
890           theDi << "NONE";
891         }
892       }
893     }
894     else if (aNewActive.IsEmpty())
895     {
896       aNewActive = theArgVec[anArgIter];
897     }
898     else
899     {
900       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
901       return 1;
902     }
903   }
904
905   if (!aNewActive.IsEmpty())
906   {
907     const TCollection_AsciiString aNameCopy = aNewActive;
908     if (TCollection_AsciiString::IsSameString (aNewActive, "gl", false)
909      || TCollection_AsciiString::IsSameString (aNewActive, "opengl", false)
910      || TCollection_AsciiString::IsSameString (aNewActive, "tkopengl", false))
911     {
912       aNewActive = "tkopengl";
913     }
914     else if (TCollection_AsciiString::IsSameString (aNewActive, "gles", false)
915           || TCollection_AsciiString::IsSameString (aNewActive, "opengles", false)
916           || TCollection_AsciiString::IsSameString (aNewActive, "tkopengles", false))
917     {
918       aNewActive = "tkopengles";
919     }
920     else if (TCollection_AsciiString::IsSameString (aNewActive, "d3d", false)
921           || TCollection_AsciiString::IsSameString (aNewActive, "d3dhost", false)
922           || TCollection_AsciiString::IsSameString (aNewActive, "tkd3dhost", false))
923     {
924       aNewActive = "tkd3dhost";
925     }
926
927     if (toLoad)
928     {
929       if (aNewActive == "tkopengl")
930       {
931         Draw::GetInterpretor().Eval ("pload OPENGL");
932       }
933       else if (aNewActive == "tkopengles")
934       {
935         Draw::GetInterpretor().Eval ("pload GLES");
936       }
937       else if (aNewActive == "tkd3dhost")
938       {
939         Draw::GetInterpretor().Eval ("pload D3DHOST");
940       }
941       else
942       {
943         theDi << "Syntax error: unable to load plugin for unknown driver factory '" << aNameCopy << "'";
944         return 1;
945       }
946     }
947
948     bool isFound = false;
949     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
950          aFactoryIter.More(); aFactoryIter.Next())
951     {
952       Handle(Graphic3d_GraphicDriverFactory) aFactory = aFactoryIter.Value();
953       if (TCollection_AsciiString::IsSameString (aFactory->Name(), aNewActive, false))
954       {
955         Graphic3d_GraphicDriverFactory::RegisterFactory (aFactory, true);
956         isFound = true;
957         break;
958       }
959     }
960
961     if (!isFound)
962     {
963       theDi << "Syntax error: driver factory '" << aNameCopy << "' not found";
964       return 1;
965     }
966   }
967
968   return 0;
969 }
970
971 //==============================================================================
972 //function : Vinit
973 //purpose  : Create the window viewer and initialize all the global variable
974 //    Use Tcl_CreateFileHandler on UNIX to catch the X11 Viewer event
975 //==============================================================================
976 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
977 {
978   ViewerTest_VinitParams aParams;
979   TCollection_AsciiString aName, aValue;
980   int is2dMode = -1, aDpiAware = -1;
981   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
982   {
983     const TCollection_AsciiString anArg = theArgVec[anArgIt];
984     TCollection_AsciiString anArgCase = anArg;
985     anArgCase.LowerCase();
986     if (anArgIt + 1 < theArgsNb
987      && anArgCase == "-name")
988     {
989       aParams.ViewName = theArgVec[++anArgIt];
990     }
991     else if (anArgIt + 1 < theArgsNb
992           && (anArgCase == "-left"
993            || anArgCase == "-l")
994            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Offset.x()))
995     {
996       ++anArgIt;
997     }
998     else if (anArgIt + 1 < theArgsNb
999           && (anArgCase == "-top"
1000            || anArgCase == "-t")
1001            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Offset.y()))
1002     {
1003       ++anArgIt;
1004     }
1005     else if (anArgIt + 1 < theArgsNb
1006           && (anArgCase == "-width"
1007            || anArgCase == "-w")
1008            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Size.x()))
1009     {
1010       ++anArgIt;
1011     }
1012     else if (anArgIt + 1 < theArgsNb
1013           && (anArgCase == "-height"
1014            || anArgCase == "-h")
1015            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Size.y()))
1016     {
1017       ++anArgIt;
1018     }
1019     else if (anArgIt + 1 < theArgsNb
1020           && (anArgCase == "-pos"
1021            || anArgCase == "-position"
1022            || anArgCase == "-corner")
1023           && ViewerTest::ParseCorner (theArgVec[anArgIt + 1], aParams.Corner))
1024     {
1025       ++anArgIt;
1026     }
1027     else if (anArgIt + 2 < theArgsNb
1028           && anArgCase == "-margins"
1029           && Draw::ParseInteger (theArgVec[anArgIt + 1], aParams.SubviewMargins.x())
1030           && Draw::ParseInteger (theArgVec[anArgIt + 2], aParams.SubviewMargins.y()))
1031     {
1032       anArgIt += 2;
1033     }
1034     else if (anArgCase == "-virtual"
1035           || anArgCase == "-offscreen")
1036     {
1037       aParams.IsVirtual = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1038     }
1039     else if (anArgCase == "-composer")
1040     {
1041       aParams.IsComposer = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
1042     }
1043     else if (anArgCase == "-exitonclose")
1044     {
1045       ViewerTest_EventManager::ToExitOnCloseView() = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1046     }
1047     else if (anArgCase == "-closeonescape"
1048           || anArgCase == "-closeonesc")
1049     {
1050       ViewerTest_EventManager::ToCloseViewOnEscape() = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1051     }
1052     else if (anArgCase == "-2d_mode"
1053           || anArgCase == "-2dmode"
1054           || anArgCase == "-2d")
1055     {
1056       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1057       is2dMode = toEnable ? 1 : 0;
1058     }
1059     else if (anArgIt + 1 < theArgsNb
1060           && (anArgCase == "-disp"
1061            || anArgCase == "-display"))
1062     {
1063       aParams.DisplayName = theArgVec[++anArgIt];
1064     }
1065     else if (anArgCase == "-dpiaware")
1066     {
1067       aDpiAware = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt) ? 1 : 0;
1068     }
1069     else if (!ViewerTest::CurrentView().IsNull()
1070           &&  aParams.ViewToClone.IsNull()
1071           && (anArgCase == "-copy"
1072            || anArgCase == "-clone"
1073            || anArgCase == "-cloneactive"
1074            || anArgCase == "-cloneactiveview"))
1075     {
1076       aParams.ViewToClone = ViewerTest::CurrentView();
1077     }
1078     else if (!ViewerTest::CurrentView().IsNull()
1079            && aParams.ParentView.IsNull()
1080            && anArgCase == "-subview")
1081     {
1082       aParams.ParentView = ViewerTest::CurrentView();
1083       if (aParams.ParentView.IsNull())
1084       {
1085         Message::SendFail() << "Syntax error: cannot create of subview without parent";
1086         return 1;
1087       }
1088       if (aParams.ParentView->IsSubview())
1089       {
1090         aParams.ParentView = aParams.ParentView->ParentView();
1091       }
1092     }
1093     else if (!ViewerTest::CurrentView().IsNull()
1094            && aParams.ParentView.IsNull()
1095            && anArgCase == "-parent"
1096            && anArgIt + 1 < theArgsNb)
1097     {
1098       TCollection_AsciiString aParentStr (theArgVec[++anArgIt]);
1099       ViewerTest_Names aViewNames (aParentStr);
1100       if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1101       {
1102         Message::SendFail() << "Syntax error: parent view '" << aParentStr << "' not found";
1103         return 1;
1104       }
1105
1106       aParams.ParentView = ViewerTest_myViews.Find1(aViewNames.GetViewName());
1107       if (aParams.ParentView->IsSubview())
1108       {
1109         aParams.ParentView = aParams.ParentView->ParentView();
1110       }
1111     }
1112     // old syntax
1113     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
1114     {
1115       aName.LowerCase();
1116       if (aName == "name")
1117       {
1118         aParams.ViewName = aValue;
1119       }
1120       else if (aName == "l"
1121             || aName == "left")
1122       {
1123         aParams.Offset.x() = (float)aValue.RealValue();
1124       }
1125       else if (aName == "t"
1126             || aName == "top")
1127       {
1128         aParams.Offset.y() = (float)aValue.RealValue();
1129       }
1130       else if (aName == "disp"
1131             || aName == "display")
1132       {
1133         aParams.DisplayName = aValue;
1134       }
1135       else if (aName == "w"
1136             || aName == "width")
1137       {
1138         aParams.Size.x() = (float )aValue.RealValue();
1139       }
1140       else if (aName == "h"
1141             || aName == "height")
1142       {
1143         aParams.Size.y() = (float)aValue.RealValue();
1144       }
1145       else
1146       {
1147         Message::SendFail() << "Syntax error: unknown argument " << anArg;
1148         return 1;
1149       }
1150     }
1151     else if (aParams.ViewName.IsEmpty())
1152     {
1153       aParams.ViewName = anArg;
1154     }
1155     else
1156     {
1157       Message::SendFail() << "Syntax error: unknown argument " << anArg;
1158       return 1;
1159     }
1160   }
1161
1162 #if defined(_WIN32)
1163   if (aDpiAware != -1)
1164   {
1165     typedef void* (WINAPI *SetThreadDpiAwarenessContext_t)(void*);
1166     if (HMODULE aUser32Module = GetModuleHandleW (L"User32"))
1167     {
1168       SetThreadDpiAwarenessContext_t aSetDpiAware = (SetThreadDpiAwarenessContext_t )GetProcAddress (aUser32Module, "SetThreadDpiAwarenessContext");
1169       if (aDpiAware == 1)
1170       {
1171         // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
1172         if (aSetDpiAware ((void* )-4) == NULL)
1173         {
1174           // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE for older systems
1175           if (aSetDpiAware ((void* )-3) == NULL)
1176           {
1177             Message::SendFail() << "Error: unable to enable DPI awareness";
1178           }
1179         }
1180       }
1181       else
1182       {
1183         // DPI_AWARENESS_CONTEXT_UNAWARE
1184         if (aSetDpiAware ((void* )-1) == NULL)
1185         {
1186           Message::SendFail() << "Error: unable to disable DPI awareness";
1187         }
1188       }
1189     }
1190   }
1191 #else
1192   (void )aDpiAware;
1193 #if !defined(HAVE_XLIB)
1194   if (!aParams.DisplayName.IsEmpty())
1195   {
1196     aParams.DisplayName.Clear();
1197     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
1198   }
1199 #endif
1200 #endif
1201
1202   ViewerTest_Names aViewNames (aParams.ViewName);
1203   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1204   {
1205     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
1206     theDi.Eval (aCommand.ToCString());
1207     if (is2dMode != -1)
1208     {
1209       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1210     }
1211     return 0;
1212   }
1213
1214   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aParams);
1215   if (is2dMode != -1)
1216   {
1217     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1218   }
1219   theDi << aViewId;
1220   return 0;
1221 }
1222
1223 //! Parse HLR algo type.
1224 static Standard_Boolean parseHlrAlgoType (const char* theName,
1225                                           Prs3d_TypeOfHLR& theType)
1226 {
1227   TCollection_AsciiString aName (theName);
1228   aName.LowerCase();
1229   if (aName == "polyalgo")
1230   {
1231     theType = Prs3d_TOH_PolyAlgo;
1232   }
1233   else if (aName == "algo")
1234   {
1235     theType = Prs3d_TOH_Algo;
1236   }
1237   else
1238   {
1239     return Standard_False;
1240   }
1241   return Standard_True;
1242 }
1243
1244 //==============================================================================
1245 //function : VHLR
1246 //purpose  : hidden lines removal algorithm
1247 //==============================================================================
1248
1249 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
1250 {
1251   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1252   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1253   if (aView.IsNull())
1254   {
1255     Message::SendFail ("Error: no active viewer");
1256     return 1;
1257   }
1258
1259   Standard_Boolean hasHlrOnArg = Standard_False;
1260   Standard_Boolean hasShowHiddenArg = Standard_False;
1261   Standard_Boolean isHLROn = Standard_False;
1262   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
1263   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
1264   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1265   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1266   {
1267     TCollection_AsciiString anArg (argv[anArgIter]);
1268     anArg.LowerCase();
1269     if (anUpdateTool.parseRedrawMode (anArg))
1270     {
1271       continue;
1272     }
1273     else if (anArg == "-showhidden"
1274           && anArgIter + 1 < argc
1275           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
1276     {
1277       ++anArgIter;
1278       hasShowHiddenArg = Standard_True;
1279       continue;
1280     }
1281     else if ((anArg == "-type"
1282            || anArg == "-algo"
1283            || anArg == "-algotype")
1284           && anArgIter + 1 < argc
1285           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1286     {
1287       ++anArgIter;
1288       continue;
1289     }
1290     else if (!hasHlrOnArg
1291           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
1292     {
1293       hasHlrOnArg = Standard_True;
1294       continue;
1295     }
1296     // old syntax
1297     else if (!hasShowHiddenArg
1298           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
1299     {
1300       hasShowHiddenArg = Standard_True;
1301       continue;
1302     }
1303     else
1304     {
1305       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
1306       return 1;
1307     }
1308   }
1309   if (!hasHlrOnArg)
1310   {
1311     di << "HLR:        " << aView->ComputedMode() << "\n";
1312     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
1313     di << "HlrAlgo:    ";
1314     switch (aCtx->DefaultDrawer()->TypeOfHLR())
1315     {
1316       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
1317       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
1318       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
1319     }
1320     anUpdateTool.Invalidate();
1321     return 0;
1322   }
1323
1324   Standard_Boolean toRecompute = Standard_False;
1325   if (aTypeOfHLR != Prs3d_TOH_NotSet
1326    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
1327   {
1328     toRecompute = Standard_True;
1329     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1330   }
1331   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
1332   {
1333     toRecompute = Standard_True;
1334     if (toShowHidden)
1335     {
1336       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
1337     }
1338     else
1339     {
1340       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
1341     }
1342   }
1343
1344   // redisplay shapes
1345   if (aView->ComputedMode() && isHLROn && toRecompute)
1346   {
1347     AIS_ListOfInteractive aListOfShapes;
1348     aCtx->DisplayedObjects (aListOfShapes);
1349     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
1350     {
1351       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
1352       {
1353         aCtx->Redisplay (aShape, Standard_False);
1354       }
1355     }
1356   }
1357
1358   aView->SetComputedMode (isHLROn);
1359   return 0;
1360 }
1361
1362 //==============================================================================
1363 //function : VHLRType
1364 //purpose  : change type of using HLR algorithm
1365 //==============================================================================
1366
1367 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
1368 {
1369   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1370   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1371   if (aView.IsNull())
1372   {
1373     Message::SendFail ("Error: no active viewer");
1374     return 1;
1375   }
1376
1377   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
1378   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1379   AIS_ListOfInteractive aListOfShapes;
1380   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1381   {
1382     TCollection_AsciiString anArg (argv[anArgIter]);
1383     anArg.LowerCase();
1384     if (anUpdateTool.parseRedrawMode (anArg))
1385     {
1386       continue;
1387     }
1388     else if ((anArg == "-type"
1389            || anArg == "-algo"
1390            || anArg == "-algotype")
1391           && anArgIter + 1 < argc
1392           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1393     {
1394       ++anArgIter;
1395       continue;
1396     }
1397     // old syntax
1398     else if (aTypeOfHLR == Prs3d_TOH_NotSet
1399           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
1400     {
1401       continue;
1402     }
1403     else
1404     {
1405       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
1406       TCollection_AsciiString aName (argv[anArgIter]);
1407       if (!aMap.IsBound2 (aName))
1408       {
1409         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
1410         return 1;
1411       }
1412
1413       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
1414       if (aShape.IsNull())
1415       {
1416         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
1417         return 1;
1418       }
1419       aListOfShapes.Append (aShape);
1420       continue;
1421     }
1422   }
1423   if (aTypeOfHLR == Prs3d_TOH_NotSet)
1424   {
1425     Message::SendFail ("Syntax error: wrong number of arguments");
1426     return 1;
1427   }
1428
1429   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
1430   if (isGlobal)
1431   {
1432     aCtx->DisplayedObjects (aListOfShapes);
1433     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1434   }
1435
1436   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
1437   {
1438     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
1439     if (aShape.IsNull())
1440     {
1441       continue;
1442     }
1443
1444     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
1445                             && aView->ComputedMode();
1446     if (!isGlobal
1447      || aShape->TypeOfHLR() != aTypeOfHLR)
1448     {
1449       aShape->SetTypeOfHLR (aTypeOfHLR);
1450     }
1451     if (toUpdateShape)
1452     {
1453       aCtx->Redisplay (aShape, Standard_False);
1454     }
1455   }
1456   return 0;
1457 }
1458
1459 //==============================================================================
1460 //function : FindViewIdByWindowHandle
1461 //purpose  : Find theView Id in the map of views by window handle
1462 //==============================================================================
1463 #if defined(_WIN32) || defined(HAVE_XLIB)
1464 static TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
1465 {
1466   for (ViewerTest_ViewerCommandsViewMap::Iterator
1467        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1468   {
1469     Aspect_Drawable aWindowHandle = anIter.Key2()->Window()->NativeHandle();
1470     if (aWindowHandle == theWindowHandle)
1471       return anIter.Key1();
1472   }
1473   return TCollection_AsciiString("");
1474 }
1475 #endif
1476
1477 //! Make the view active
1478 void ActivateView (const TCollection_AsciiString& theViewName,
1479                    Standard_Boolean theToUpdate = Standard_True)
1480 {
1481   if (const Handle(V3d_View)& aView = ViewerTest_myViews.Find1(theViewName))
1482   {
1483     ViewerTest::ActivateView (aView, theToUpdate);
1484   }
1485 }
1486
1487 //==============================================================================
1488 //function : ActivateView
1489 //purpose  :
1490 //==============================================================================
1491 void ViewerTest::ActivateView (const Handle(V3d_View)& theView,
1492                                Standard_Boolean theToUpdate)
1493 {
1494   const Handle(V3d_View)& aView = theView;
1495   const TCollection_AsciiString* aViewName = ViewerTest_myViews.Seek2 (aView);
1496   if (aViewName == nullptr)
1497   {
1498     return;
1499   }
1500
1501   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
1502   if (anAISContext.IsNull())
1503   {
1504     return;
1505   }
1506
1507   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1508   {
1509     if (!aCurrentView->Window().IsNull())
1510     {
1511       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1512     }
1513   }
1514
1515   ViewerTest::CurrentView (aView);
1516   ViewerTest::SetAISContext (anAISContext);
1517   if (aView->IsSubview())
1518   {
1519     aView->ParentView()->Window()->SetTitle (TCollection_AsciiString("3D View - ") + *aViewName + "(*)");
1520     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(aView->View()->ParentView()->Window());
1521   }
1522   else
1523   {
1524     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(aView->Window());
1525   }
1526   if (!VT_GetWindow().IsNull())
1527   {
1528     VT_GetWindow()->SetTitle (TCollection_AsciiString("3D View - ") + *aViewName + "(*)");
1529   }
1530   SetDisplayConnection(aView->Viewer()->Driver()->GetDisplayConnection());
1531   if (theToUpdate)
1532   {
1533     aView->Redraw();
1534   }
1535 }
1536
1537 //==============================================================================
1538 //function : RemoveView
1539 //purpose  :
1540 //==============================================================================
1541 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
1542                              const Standard_Boolean  theToRemoveContext)
1543 {
1544   if (!ViewerTest_myViews.IsBound2 (theView))
1545   {
1546     return;
1547   }
1548
1549   const TCollection_AsciiString& aViewName = ViewerTest_myViews.Find2 (theView);
1550   RemoveView (aViewName, theToRemoveContext);
1551 }
1552
1553 //==============================================================================
1554 //function : RemoveView
1555 //purpose  : Close and remove view from display, clear maps if necessary
1556 //==============================================================================
1557 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
1558 {
1559   if (!ViewerTest_myViews.IsBound1(theViewName))
1560   {
1561     Message::SendFail() << "Wrong view name";
1562     return;
1563   }
1564
1565   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1566   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
1567   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
1568   aRedrawer.Stop (aView);
1569   if (!aView->Subviews().IsEmpty())
1570   {
1571     NCollection_Sequence<Handle(V3d_View)> aSubviews = aView->Subviews();
1572     for (const Handle(V3d_View)& aSubviewIter : aSubviews)
1573     {
1574       RemoveView (aSubviewIter, isContextRemoved);
1575     }
1576   }
1577
1578   // Activate another view if it's active now
1579   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
1580   {
1581     if (ViewerTest_myViews.Extent() > 1)
1582     {
1583       for (ViewerTest_ViewerCommandsViewMap::Iterator anIter (ViewerTest_myViews);
1584            anIter.More(); anIter.Next())
1585       {
1586         if (anIter.Key1() != theViewName)
1587         {
1588           ActivateView (anIter.Key2(), true);
1589           break;
1590         }
1591       }
1592     }
1593     else
1594     {
1595       VT_GetWindow().Nullify();
1596       ViewerTest::CurrentView (Handle(V3d_View)());
1597       if (isContextRemoved)
1598       {
1599         Handle(AIS_InteractiveContext) anEmptyContext;
1600         ViewerTest::SetAISContext(anEmptyContext);
1601       }
1602     }
1603   }
1604
1605   // Delete view, name will be removed too
1606   const TCollection_AsciiString aCopyString(theViewName);
1607   ViewerTest_myViews.UnBind1(theViewName);
1608   if (!aView->Window().IsNull())
1609   {
1610     aView->Window()->Unmap();
1611   }
1612   aView->Remove();
1613
1614 #if defined(HAVE_XLIB)
1615   XFlush ((::Display* )GetDisplayConnection()->GetDisplayAspect());
1616 #endif
1617
1618   // Keep context opened only if the closed view is last to avoid
1619   // unused empty contexts
1620   if (!aCurrentContext.IsNull())
1621   {
1622     // Check if there are more defined views in the viewer
1623     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
1624      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
1625     {
1626       // Remove driver if there is no viewers that use it
1627       Standard_Boolean isRemoveDriver = Standard_True;
1628       for(ViewerTest_ViewerCommandsInteractiveContextMap::Iterator
1629           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
1630       {
1631         if (aCurrentContext != anIter.Key2() &&
1632           aCurrentContext->CurrentViewer()->Driver() == anIter.Key2()->CurrentViewer()->Driver())
1633         {
1634           isRemoveDriver = Standard_False;
1635           break;
1636         }
1637       }
1638
1639       aCurrentContext->RemoveAll (Standard_False);
1640       if(isRemoveDriver)
1641       {
1642         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
1643       #if defined(HAVE_XLIB)
1644         Tcl_DeleteFileHandler (XConnectionNumber ((::Display* )aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplayAspect()));
1645       #endif
1646       }
1647
1648       ViewerTest_myContexts.UnBind2(aCurrentContext);
1649     }
1650   }
1651   Message::SendInfo() << "3D View - " << aCopyString << " was deleted.\n";
1652   if (ViewerTest_EventManager::ToExitOnCloseView())
1653   {
1654     Draw_Interprete ("exit");
1655   }
1656 }
1657
1658 //==============================================================================
1659 //function : VClose
1660 //purpose  : Remove the view defined by its name
1661 //==============================================================================
1662
1663 static int VClose (Draw_Interpretor& /*theDi*/,
1664                    Standard_Integer  theArgsNb,
1665                    const char**      theArgVec)
1666 {
1667   NCollection_List<TCollection_AsciiString> aViewList;
1668   if (theArgsNb > 1)
1669   {
1670     TCollection_AsciiString anArg (theArgVec[1]);
1671     anArg.UpperCase();
1672     if (anArg.IsEqual ("ALL")
1673      || anArg.IsEqual ("*"))
1674     {
1675       for (ViewerTest_ViewerCommandsViewMap::Iterator anIter (ViewerTest_myViews);
1676            anIter.More(); anIter.Next())
1677       {
1678         aViewList.Append (anIter.Key1());
1679       }
1680       if (aViewList.IsEmpty())
1681       {
1682         std::cout << "No view to close\n";
1683         return 0;
1684       }
1685     }
1686     else
1687     {
1688       ViewerTest_Names aViewName (theArgVec[1]);
1689       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
1690       {
1691         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
1692         return 1;
1693       }
1694       aViewList.Append (aViewName.GetViewName());
1695     }
1696   }
1697   else
1698   {
1699     // close active view
1700     if (ViewerTest::CurrentView().IsNull())
1701     {
1702       Message::SendFail ("Error: no active view");
1703       return 1;
1704     }
1705     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1706   }
1707
1708   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
1709   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
1710        anIter.More(); anIter.Next())
1711   {
1712     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
1713   }
1714
1715   return 0;
1716 }
1717
1718 //==============================================================================
1719 //function : VActivate
1720 //purpose  : Activate the view defined by its ID
1721 //==============================================================================
1722
1723 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1724 {
1725   if (theArgsNb == 1)
1726   {
1727     theDi.Eval("vviewlist");
1728     return 0;
1729   }
1730
1731   TCollection_AsciiString aNameString;
1732   Standard_Boolean toUpdate = Standard_True;
1733   Standard_Boolean toActivate = Standard_True;
1734   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
1735   {
1736     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1737     anArg.LowerCase();
1738     if (toUpdate
1739      && anArg == "-noupdate")
1740     {
1741       toUpdate = Standard_False;
1742     }
1743     else if (toActivate
1744           && aNameString.IsEmpty()
1745           && anArg == "none")
1746     {
1747       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1748       VT_GetWindow().Nullify();
1749       ViewerTest::CurrentView (Handle(V3d_View)());
1750       ViewerTest::ResetEventManager();
1751       theDi << theArgVec[0] << ": all views are inactive\n";
1752       toActivate = Standard_False;
1753     }
1754     else if (toActivate
1755           && aNameString.IsEmpty())
1756     {
1757       aNameString = theArgVec[anArgIter];
1758     }
1759     else
1760     {
1761       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
1762       return 1;
1763     }
1764   }
1765
1766   if (!toActivate)
1767   {
1768     return 0;
1769   }
1770   else if (aNameString.IsEmpty())
1771   {
1772     Message::SendFail ("Syntax error: wrong number of arguments");
1773     return 1;
1774   }
1775
1776   // Check if this view exists in the viewer with the driver
1777   ViewerTest_Names aViewNames (aNameString);
1778   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
1779   {
1780     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
1781     return 1;
1782   }
1783
1784   // Check if it is active already
1785   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
1786   {
1787     theDi << theArgVec[0] << ": the view is active already\n";
1788     return 0;
1789   }
1790
1791   ActivateView (aViewNames.GetViewName(), toUpdate);
1792   return 0;
1793 }
1794
1795 //==============================================================================
1796 //function : VViewList
1797 //purpose  : Print current list of views per viewer and graphic driver ID
1798 //           shared between viewers
1799 //==============================================================================
1800
1801 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1802 {
1803   if (theArgsNb > 2)
1804   {
1805     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
1806           << "Usage: " << theArgVec[0] << " name";
1807     return 1;
1808   }
1809   if (ViewerTest_myContexts.Size() < 1)
1810     return 0;
1811
1812   Standard_Boolean isTreeView =
1813     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
1814
1815   if (isTreeView)
1816   {
1817     theDi << theArgVec[0] <<":\n";
1818   }
1819
1820   for (ViewerTest_ViewerCommandsGraphicDriverMap::Iterator aDriverIter (ViewerTest_myDrivers);
1821        aDriverIter.More(); aDriverIter.Next())
1822   {
1823     if (isTreeView)
1824       theDi << aDriverIter.Key1() << ":\n";
1825
1826     for (ViewerTest_ViewerCommandsInteractiveContextMap::Iterator
1827       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
1828     {
1829       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
1830       {
1831         if (isTreeView)
1832         {
1833           TCollection_AsciiString aContextName(aContextIter.Key1());
1834           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
1835         }
1836
1837         for (ViewerTest_ViewerCommandsViewMap::Iterator aViewIter (ViewerTest_myViews);
1838              aViewIter.More(); aViewIter.Next())
1839         {
1840           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
1841           {
1842             TCollection_AsciiString aViewName(aViewIter.Key1());
1843             if (isTreeView)
1844             {
1845               if (aViewIter.Key2() == ViewerTest::CurrentView())
1846                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
1847               else
1848                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
1849             }
1850             else
1851             {
1852               theDi << aViewName << " ";
1853             }
1854           }
1855         }
1856       }
1857     }
1858   }
1859   return 0;
1860 }
1861
1862 //==============================================================================
1863 //function : GetMousePosition
1864 //purpose  :
1865 //==============================================================================
1866 void ViewerTest::GetMousePosition (Standard_Integer& theX,
1867                                    Standard_Integer& theY)
1868 {
1869   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
1870   {
1871     theX = aViewCtrl->LastMousePosition().x();
1872     theY = aViewCtrl->LastMousePosition().y();
1873   }
1874 }
1875
1876 //==============================================================================
1877 //function : VViewProj
1878 //purpose  : Switch view projection
1879 //==============================================================================
1880 static int VViewProj (Draw_Interpretor& ,
1881                       Standard_Integer theNbArgs,
1882                       const char** theArgVec)
1883 {
1884   static Standard_Boolean isYup = Standard_False;
1885   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
1886   if (aView.IsNull())
1887   {
1888     Message::SendFail ("Error: no active viewer");
1889     return 1;
1890   }
1891
1892   TCollection_AsciiString aCmdName (theArgVec[0]);
1893   Standard_Boolean isGeneralCmd = Standard_False;
1894   if (aCmdName == "vfront")
1895   {
1896     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1897   }
1898   else if (aCmdName == "vback")
1899   {
1900     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1901   }
1902   else if (aCmdName == "vtop")
1903   {
1904     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1905   }
1906   else if (aCmdName == "vbottom")
1907   {
1908     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1909   }
1910   else if (aCmdName == "vleft")
1911   {
1912     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1913   }
1914   else if (aCmdName == "vright")
1915   {
1916     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1917   }
1918   else if (aCmdName == "vaxo")
1919   {
1920     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1921   }
1922   else
1923   {
1924     isGeneralCmd = Standard_True;
1925     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
1926     {
1927       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
1928       anArgCase.LowerCase();
1929       if (anArgCase == "-zup")
1930       {
1931         isYup = Standard_False;
1932       }
1933       else if (anArgCase == "-yup")
1934       {
1935         isYup = Standard_True;
1936       }
1937       else if (anArgCase == "-front"
1938             || anArgCase == "front"
1939             || anArgCase == "-f"
1940             || anArgCase == "f")
1941       {
1942         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1943       }
1944       else if (anArgCase == "-back"
1945             || anArgCase == "back"
1946             || anArgCase == "-b"
1947             || anArgCase == "b")
1948       {
1949         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1950       }
1951       else if (anArgCase == "-top"
1952             || anArgCase == "top"
1953             || anArgCase == "-t"
1954             || anArgCase == "t")
1955       {
1956         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1957       }
1958       else if (anArgCase == "-bottom"
1959             || anArgCase == "bottom"
1960             || anArgCase == "-bot"
1961             || anArgCase == "bot"
1962             || anArgCase == "-b"
1963             || anArgCase == "b")
1964       {
1965         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1966       }
1967       else if (anArgCase == "-left"
1968             || anArgCase == "left"
1969             || anArgCase == "-l"
1970             || anArgCase == "l")
1971       {
1972         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1973       }
1974       else if (anArgCase == "-right"
1975             || anArgCase == "right"
1976             || anArgCase == "-r"
1977             || anArgCase == "r")
1978       {
1979         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1980       }
1981       else if (anArgCase == "-axoleft"
1982             || anArgCase == "-leftaxo"
1983             || anArgCase == "axoleft"
1984             || anArgCase == "leftaxo")
1985       {
1986         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
1987       }
1988       else if (anArgCase == "-axo"
1989             || anArgCase == "axo"
1990             || anArgCase == "-a"
1991             || anArgCase == "a"
1992             || anArgCase == "-axoright"
1993             || anArgCase == "-rightaxo"
1994             || anArgCase == "axoright"
1995             || anArgCase == "rightaxo")
1996       {
1997         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1998       }
1999       else if (anArgCase == "+x")
2000       {
2001         aView->SetProj (V3d_Xpos, isYup);
2002       }
2003       else if (anArgCase == "-x")
2004       {
2005         aView->SetProj (V3d_Xneg, isYup);
2006       }
2007       else if (anArgCase == "+y")
2008       {
2009         aView->SetProj (V3d_Ypos, isYup);
2010       }
2011       else if (anArgCase == "-y")
2012       {
2013         aView->SetProj (V3d_Yneg, isYup);
2014       }
2015       else if (anArgCase == "+z")
2016       {
2017         aView->SetProj (V3d_Zpos, isYup);
2018       }
2019       else if (anArgCase == "-z")
2020       {
2021         aView->SetProj (V3d_Zneg, isYup);
2022       }
2023       else if (anArgCase == "+x+y+z")
2024       {
2025         aView->SetProj (V3d_XposYposZpos, isYup);
2026       }
2027       else if (anArgCase == "+x+y-z")
2028       {
2029         aView->SetProj (V3d_XposYposZneg, isYup);
2030       }
2031       else if (anArgCase == "+x-y+z")
2032       {
2033         aView->SetProj (V3d_XposYnegZpos, isYup);
2034       }
2035       else if (anArgCase == "+x-y-z")
2036       {
2037         aView->SetProj (V3d_XposYnegZneg, isYup);
2038       }
2039       else if (anArgCase == "-x+y+z")
2040       {
2041         aView->SetProj (V3d_XnegYposZpos, isYup);
2042       }
2043       else if (anArgCase == "-x+y-z")
2044       {
2045         aView->SetProj (V3d_XnegYposZneg, isYup);
2046       }
2047       else if (anArgCase == "-x-y+z")
2048       {
2049         aView->SetProj (V3d_XnegYnegZpos, isYup);
2050       }
2051       else if (anArgCase == "-x-y-z")
2052       {
2053         aView->SetProj (V3d_XnegYnegZneg, isYup);
2054       }
2055       else if (anArgCase == "+x+y")
2056       {
2057         aView->SetProj (V3d_XposYpos, isYup);
2058       }
2059       else if (anArgCase == "+x-y")
2060       {
2061         aView->SetProj (V3d_XposYneg, isYup);
2062       }
2063       else if (anArgCase == "-x+y")
2064       {
2065         aView->SetProj (V3d_XnegYpos, isYup);
2066       }
2067       else if (anArgCase == "-x-y")
2068       {
2069         aView->SetProj (V3d_XnegYneg, isYup);
2070       }
2071       else if (anArgCase == "+x+z")
2072       {
2073         aView->SetProj (V3d_XposZpos, isYup);
2074       }
2075       else if (anArgCase == "+x-z")
2076       {
2077         aView->SetProj (V3d_XposZneg, isYup);
2078       }
2079       else if (anArgCase == "-x+z")
2080       {
2081         aView->SetProj (V3d_XnegZpos, isYup);
2082       }
2083       else if (anArgCase == "-x-z")
2084       {
2085         aView->SetProj (V3d_XnegZneg, isYup);
2086       }
2087       else if (anArgCase == "+y+z")
2088       {
2089         aView->SetProj (V3d_YposZpos, isYup);
2090       }
2091       else if (anArgCase == "+y-z")
2092       {
2093         aView->SetProj (V3d_YposZneg, isYup);
2094       }
2095       else if (anArgCase == "-y+z")
2096       {
2097         aView->SetProj (V3d_YnegZpos, isYup);
2098       }
2099       else if (anArgCase == "-y-z")
2100       {
2101         aView->SetProj (V3d_YnegZneg, isYup);
2102       }
2103       else if (anArgIter + 1 < theNbArgs
2104             && anArgCase == "-frame"
2105             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2106       {
2107         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2108         aFrameDef.LowerCase();
2109         gp_Dir aRight, anUp;
2110         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2111         {
2112           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2113           return 1;
2114         }
2115
2116         if (aFrameDef.Value (2) == 'x')
2117         {
2118           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2119         }
2120         else if (aFrameDef.Value (2) == 'y')
2121         {
2122           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2123         }
2124         else if (aFrameDef.Value (2) == 'z')
2125         {
2126           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2127         }
2128         else
2129         {
2130           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2131           return 1;
2132         }
2133
2134         if (aFrameDef.Value (4) == 'x')
2135         {
2136           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2137         }
2138         else if (aFrameDef.Value (4) == 'y')
2139         {
2140           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2141         }
2142         else if (aFrameDef.Value (4) == 'z')
2143         {
2144           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2145         }
2146         else
2147         {
2148           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2149           return 1;
2150         }
2151
2152         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2153         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2154         const gp_Dir aDir = anUp.Crossed (aRight);
2155         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2156         aCamera->SetDirection (aDir);
2157         aCamera->SetUp (anUp);
2158         aCamera->OrthogonalizeUp();
2159
2160         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2161         aView->Update();
2162       }
2163       else
2164       {
2165         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2166         return 1;
2167       }
2168     }
2169   }
2170
2171   if (!isGeneralCmd
2172     && theNbArgs != 1)
2173   {
2174     Message::SendFail ("Syntax error: wrong number of arguments");
2175     return 1;
2176   }
2177   return 0;
2178 }
2179
2180 //==============================================================================
2181 //function : VHelp
2182 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
2183 //Draw arg : No args
2184 //==============================================================================
2185
2186 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
2187 {
2188   di << "=========================\n";
2189   di << "F : FitAll\n";
2190   di << "T : TopView\n";
2191   di << "B : BottomView\n";
2192   di << "R : RightView\n";
2193   di << "L : LeftView\n";
2194   di << "Backspace : AxonometricView\n";
2195
2196   di << "=========================\n";
2197   di << "W, S : Fly   forward/backward\n";
2198   di << "A, D : Slide left/right\n";
2199   di << "Q, E : Bank  left/right\n";
2200   di << "-, + : Change flying speed\n";
2201   di << "Arrows : look left/right/up/down\n";
2202   di << "Arrows+Shift : slide left/right/up/down\n";
2203
2204   di << "=========================\n";
2205   di << "S + Ctrl : Shading\n";
2206   di << "W + Ctrl : Wireframe\n";
2207   di << "H : HiddenLineRemoval\n";
2208   di << "U : Unset display mode\n";
2209   di << "Delete : Remove selection from viewer\n";
2210
2211   di << "=========================\n";
2212   di << "Selection mode \n";
2213   di << "0 : Shape\n";
2214   di << "1 : Vertex\n";
2215   di << "2 : Edge\n";
2216   di << "3 : Wire\n";
2217   di << "4 : Face\n";
2218   di << "5 : Shell\n";
2219   di << "6 : Solid\n";
2220   di << "7 : Compound\n";
2221
2222   di << "=========================\n";
2223   di << "< : Hilight next detected\n";
2224   di << "> : Hilight previous detected\n";
2225
2226   return 0;
2227 }
2228
2229 #ifdef _WIN32
2230
2231 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
2232                                            UINT theMsg,
2233                                            WPARAM wParam,
2234                                            LPARAM lParam )
2235 {
2236   if (ViewerTest_myViews.IsEmpty())
2237   {
2238     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2239   }
2240
2241   switch (theMsg)
2242   {
2243     case WM_CLOSE:
2244     {
2245       // Delete view from map of views
2246       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
2247       return 0;
2248     }
2249     case WM_ACTIVATE:
2250     {
2251       if (LOWORD(wParam) == WA_CLICKACTIVE
2252        || LOWORD(wParam) == WA_ACTIVE
2253        || ViewerTest::CurrentView().IsNull())
2254       {
2255         // Activate inactive window
2256         if (VT_GetWindow().IsNull()
2257          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
2258         {
2259           ActivateView (FindViewIdByWindowHandle (theWinHandle));
2260         }
2261       }
2262       return 0;
2263     }
2264     default:
2265     {
2266       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2267       if (!aView.IsNull()
2268        && !VT_GetWindow().IsNull())
2269       {
2270         MSG aMsg = {};
2271         aMsg.hwnd = theWinHandle;
2272         aMsg.message = theMsg;
2273         aMsg.wParam = wParam;
2274         aMsg.lParam = lParam;
2275         if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg))
2276         {
2277           return 0;
2278         }
2279       }
2280     }
2281   }
2282   return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2283 }
2284
2285 //==============================================================================
2286 //function : ViewerMainLoop
2287 //purpose  : Get a Event on the view and dispatch it
2288 //==============================================================================
2289
2290 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2291 {
2292   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
2293   if (aViewCtrl.IsNull()
2294    || theNbArgs < 4)
2295   {
2296     return 0;
2297   }
2298
2299   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2300
2301   std::cout << "Start picking\n";
2302
2303   MSG aMsg;
2304   aMsg.wParam = 1;
2305   while (aViewCtrl->ToPickPoint())
2306   {
2307     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
2308     if (GetMessageW (&aMsg, NULL, 0, 0))
2309     {
2310       TranslateMessage (&aMsg);
2311       DispatchMessageW (&aMsg);
2312     }
2313   }
2314
2315   std::cout << "Picking done\n";
2316   return 0;
2317 }
2318
2319 #elif defined(HAVE_XLIB)
2320
2321 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2322 {
2323   static XEvent aReport;
2324   const Standard_Boolean toPick = theNbArgs > 0;
2325   if (theNbArgs > 0)
2326   {
2327     if (ViewerTest::CurrentEventManager().IsNull())
2328     {
2329       return 0;
2330     }
2331     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2332   }
2333
2334   Display* aDisplay = (Display* )GetDisplayConnection()->GetDisplayAspect();
2335   XNextEvent (aDisplay, &aReport);
2336
2337   // Handle event for the chosen display connection
2338   switch (aReport.type)
2339   {
2340     case ClientMessage:
2341     {
2342       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
2343       {
2344         // Close the window
2345         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
2346         return toPick ? 0 : 1;
2347       }
2348       break;
2349     }
2350     case FocusIn:
2351     {
2352       // Activate inactive view
2353       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
2354       if (aWindow != aReport.xfocus.window)
2355       {
2356         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
2357       }
2358       break;
2359     }
2360     default:
2361     {
2362       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2363       if (!aView.IsNull()
2364        && !VT_GetWindow().IsNull())
2365       {
2366         VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aReport);
2367       }
2368       break;
2369     }
2370   }
2371   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
2372 }
2373
2374 //==============================================================================
2375 //function : VProcessEvents
2376 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
2377 //==============================================================================
2378 static void VProcessEvents (ClientData theDispX, int)
2379 {
2380   Display* aDispX = (Display* )theDispX;
2381   Handle(Aspect_DisplayConnection) aDispConn;
2382   for (ViewerTest_ViewerCommandsGraphicDriverMap::Iterator
2383        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
2384   {
2385     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
2386     if ((Display* )aDispConnTmp->GetDisplayAspect() == aDispX)
2387     {
2388       aDispConn = aDispConnTmp;
2389       break;
2390     }
2391   }
2392   if (aDispConn.IsNull())
2393   {
2394     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
2395     return;
2396   }
2397
2398   // process new events in queue
2399   SetDisplayConnection (aDispConn);
2400   int aNbRemain = 0;
2401   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
2402   {
2403     const int anEventResult = ViewerMainLoop (0, NULL);
2404     if (anEventResult == 0)
2405     {
2406       return;
2407     }
2408
2409     aNbRemain = XPending (aDispX);
2410     if (++anEventIter >= aNbEventsMax
2411      || aNbRemain <= 0)
2412     {
2413       break;
2414     }
2415   }
2416
2417   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
2418   // it is possible that new events will arrive to queue before the end of this callback
2419   // so that either this callback should go into an infinite loop (blocking processing of other events)
2420   // or to keep unprocessed events till the next queue update (which can arrive not soon).
2421   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
2422   if (aNbRemain != 0)
2423   {
2424     XEvent aDummyEvent;
2425     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
2426     aDummyEvent.type = ClientMessage;
2427     aDummyEvent.xclient.format = 32;
2428     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
2429     XFlush (aDispX);
2430   }
2431
2432   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
2433   {
2434     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
2435   }
2436 }
2437 #elif !defined(__APPLE__)
2438 // =======================================================================
2439 // function : ViewerMainLoop
2440 // purpose  :
2441 // =======================================================================
2442 int ViewerMainLoop (Standard_Integer , const char** )
2443 {
2444   // unused
2445   return 0;
2446 }
2447 #endif
2448
2449 //==============================================================================
2450 //function : VFit
2451 //purpose  :
2452 //==============================================================================
2453
2454 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
2455 {
2456   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2457   if (aView.IsNull())
2458   {
2459     Message::SendFail ("Error: no active viewer");
2460     return 1;
2461   }
2462
2463   Standard_Boolean toFit = Standard_True;
2464   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2465   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2466   {
2467     TCollection_AsciiString anArg (theArgv[anArgIter]);
2468     anArg.LowerCase();
2469     if (anUpdateTool.parseRedrawMode (anArg))
2470     {
2471       continue;
2472     }
2473     else if (anArg == "-selected")
2474     {
2475       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
2476       toFit = Standard_False;
2477     }
2478     else
2479     {
2480       Message::SendFail() << "Syntax error at '" << anArg << "'";
2481     }
2482   }
2483
2484   if (toFit)
2485   {
2486     aView->FitAll (0.01, Standard_False);
2487   }
2488   return 0;
2489 }
2490
2491 //=======================================================================
2492 //function : VFitArea
2493 //purpose  : Fit view to show area located between two points
2494 //         : given in world 2D or 3D coordinates.
2495 //=======================================================================
2496 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
2497 {
2498   Handle(V3d_View) aView = ViewerTest::CurrentView();
2499   if (aView.IsNull())
2500   {
2501     Message::SendFail ("Error: No active viewer");
2502     return 1;
2503   }
2504
2505   // Parse arguments.
2506   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
2507   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
2508
2509   if (theArgNb == 5)
2510   {
2511     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2512     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2513     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
2514     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
2515   }
2516   else if (theArgNb == 7)
2517   {
2518     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2519     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2520     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
2521     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
2522     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
2523     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
2524   }
2525   else
2526   {
2527     Message::SendFail ("Syntax error: Invalid number of arguments");
2528     theDI.PrintHelp(theArgVec[0]);
2529     return 1;
2530   }
2531
2532   // Convert model coordinates to view space
2533   Handle(Graphic3d_Camera) aCamera = aView->Camera();
2534   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
2535   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
2536
2537   // Determine fit area
2538   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
2539   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
2540
2541   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
2542
2543   if (aDiagonal < Precision::Confusion())
2544   {
2545     Message::SendFail ("Error: view area is too small");
2546     return 1;
2547   }
2548
2549   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
2550   return 0;
2551 }
2552
2553 //==============================================================================
2554 //function : VZFit
2555 //purpose  : ZFitall, no DRAW arguments
2556 //Draw arg : No args
2557 //==============================================================================
2558 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
2559 {
2560   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
2561
2562   if (aCurrentView.IsNull())
2563   {
2564     Message::SendFail ("Error: no active viewer");
2565     return 1;
2566   }
2567
2568   if (theArgsNb == 1)
2569   {
2570     aCurrentView->ZFitAll();
2571     aCurrentView->Redraw();
2572     return 0;
2573   }
2574
2575   Standard_Real aScale = 1.0;
2576
2577   if (theArgsNb >= 2)
2578   {
2579     aScale = Draw::Atoi (theArgVec[1]);
2580   }
2581
2582   aCurrentView->ZFitAll (aScale);
2583   aCurrentView->Redraw();
2584
2585   return 0;
2586 }
2587
2588 //==============================================================================
2589 //function : VRepaint
2590 //purpose  :
2591 //==============================================================================
2592 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
2593 {
2594   Handle(V3d_View) aView = ViewerTest::CurrentView();
2595   if (aView.IsNull())
2596   {
2597     Message::SendFail ("Error: no active viewer");
2598     return 1;
2599   }
2600
2601   Standard_Boolean isImmediateUpdate = Standard_False;
2602   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2603   {
2604     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2605     anArg.LowerCase();
2606     if (anArg == "-immediate"
2607      || anArg == "-imm")
2608     {
2609       isImmediateUpdate = Standard_True;
2610       if (anArgIter + 1 < theArgNb
2611        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
2612       {
2613         ++anArgIter;
2614       }
2615     }
2616     else if (anArg == "-continuous"
2617           || anArg == "-cont"
2618           || anArg == "-fps"
2619           || anArg == "-framerate")
2620     {
2621       Standard_Real aFps = -1.0;
2622       if (anArgIter + 1 < theArgNb
2623        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
2624       {
2625         aFps = Draw::Atof (theArgVec[++anArgIter]);
2626       }
2627
2628       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2629       ViewerTest::CurrentEventManager()->SetContinuousRedraw (false);
2630       if (aFps >= 1.0)
2631       {
2632         aRedrawer.Start (aView, aFps);
2633       }
2634       else if (aFps < 0.0)
2635       {
2636         if (ViewerTest::GetViewerFromContext()->ActiveViews().Extent() == 1)
2637         {
2638           aRedrawer.Stop();
2639           ViewerTest::CurrentEventManager()->SetContinuousRedraw (true);
2640           ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
2641           continue;
2642         }
2643         aRedrawer.Start (aView, aFps);
2644       }
2645       else
2646       {
2647         aRedrawer.Stop();
2648       }
2649     }
2650     else
2651     {
2652       Message::SendFail() << "Syntax error at '" << anArg << "'";
2653       return 1;
2654     }
2655   }
2656
2657   if (isImmediateUpdate)
2658   {
2659     aView->RedrawImmediate();
2660   }
2661   else
2662   {
2663     aView->Redraw();
2664   }
2665   return 0;
2666 }
2667
2668 //==============================================================================
2669 //function : VClear
2670 //purpose  : Remove all the object from the viewer
2671 //Draw arg : No args
2672 //==============================================================================
2673
2674 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
2675 {
2676   Handle(V3d_View) V = ViewerTest::CurrentView();
2677   if(!V.IsNull())
2678     ViewerTest::Clear();
2679   return 0;
2680 }
2681
2682 //==============================================================================
2683 //function : VPick
2684 //purpose  :
2685 //==============================================================================
2686
2687 static int VPick (Draw_Interpretor& ,
2688                   Standard_Integer theNbArgs,
2689                   const char** theArgVec)
2690 {
2691   if (ViewerTest::CurrentView().IsNull())
2692   {
2693     return 1;
2694   }
2695
2696   if (theNbArgs < 4)
2697   {
2698     Message::SendFail ("Syntax error: wrong number of arguments");
2699     return 1;
2700   }
2701
2702   while (ViewerMainLoop (theNbArgs, theArgVec))
2703   {
2704     //
2705   }
2706
2707   return 0;
2708 }
2709
2710 //! Parse image fill method.
2711 static bool parseImageMode (const TCollection_AsciiString& theName,
2712                             Aspect_FillMethod& theMode)
2713 {
2714   TCollection_AsciiString aName = theName;
2715   aName.LowerCase();
2716   if (aName == "none")
2717   {
2718     theMode = Aspect_FM_NONE;
2719   }
2720   else if (aName == "centered")
2721   {
2722     theMode = Aspect_FM_CENTERED;
2723   }
2724   else if (aName == "tiled")
2725   {
2726     theMode = Aspect_FM_TILED;
2727   }
2728   else if (aName == "stretch")
2729   {
2730     theMode = Aspect_FM_STRETCH;
2731   }
2732   else
2733   {
2734     return false;
2735   }
2736   return true;
2737 }
2738
2739 //! Parse gradient fill method.
2740 static bool parseGradientMode (const TCollection_AsciiString& theName,
2741                                Aspect_GradientFillMethod& theMode)
2742 {
2743   TCollection_AsciiString aName = theName;
2744   aName.LowerCase();
2745   if (aName == "none")
2746   {
2747     theMode = Aspect_GradientFillMethod_None;
2748   }
2749   else if (aName == "hor"
2750         || aName == "horizontal")
2751   {
2752     theMode = Aspect_GradientFillMethod_Horizontal;
2753   }
2754   else if (aName == "ver"
2755         || aName == "vert"
2756         || aName == "vertical")
2757   {
2758     theMode = Aspect_GradientFillMethod_Vertical;
2759   }
2760   else if (aName == "diag"
2761         || aName == "diagonal"
2762         || aName == "diag1"
2763         || aName == "diagonal1")
2764   {
2765     theMode = Aspect_GradientFillMethod_Diagonal1;
2766   }
2767   else if (aName == "diag2"
2768         || aName == "diagonal2")
2769   {
2770     theMode = Aspect_GradientFillMethod_Diagonal2;
2771   }
2772   else if (aName == "corner1")
2773   {
2774     theMode = Aspect_GradientFillMethod_Corner1;
2775   }
2776   else if (aName == "corner2")
2777   {
2778     theMode = Aspect_GradientFillMethod_Corner2;
2779   }
2780   else if (aName == "corner3")
2781   {
2782     theMode = Aspect_GradientFillMethod_Corner3;
2783   }
2784   else if (aName == "corner4")
2785   {
2786     theMode = Aspect_GradientFillMethod_Corner4;
2787   }
2788   else if (aName == "ellip"
2789         || aName == "elliptical")
2790   {
2791     theMode = Aspect_GradientFillMethod_Elliptical;
2792   }
2793   else
2794   {
2795     return false;
2796   }
2797   return true;
2798 }
2799
2800 //==============================================================================
2801 //function : VBackground
2802 //purpose  :
2803 //==============================================================================
2804 static int VBackground (Draw_Interpretor& theDI,
2805                         Standard_Integer  theNbArgs,
2806                         const char**      theArgVec)
2807 {
2808   if (theNbArgs < 2)
2809   {
2810     theDI << "Syntax error: wrong number of arguments";
2811     return 1;
2812   }
2813
2814   const TCollection_AsciiString aCmdName (theArgVec[0]);
2815   bool isDefault = aCmdName == "vsetdefaultbg";
2816   Standard_Integer aNbColors = 0;
2817   Quantity_ColorRGBA aColors[2];
2818
2819   Aspect_GradientFillMethod aGradientMode = Aspect_GradientFillMethod_None;
2820   bool hasGradientMode = false;
2821
2822   TCollection_AsciiString anImagePath;
2823   Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
2824   bool hasImageMode = false;
2825
2826   bool isSkydomeBg = false;
2827   Aspect_SkydomeBackground aSkydomeAspect;
2828
2829   NCollection_Sequence<TCollection_AsciiString> aCubeMapSeq;
2830   Graphic3d_CubeMapOrder aCubeOrder = Graphic3d_CubeMapOrder::Default();
2831   bool isCubeZInverted = false;
2832   bool isSRgb = true;
2833
2834   int toUseIBL = 1;
2835
2836   Handle(V3d_View) aView = ViewerTest::CurrentView();
2837   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
2838   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2839   {
2840     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2841     anArg.LowerCase();
2842     if (anUpdateTool.parseRedrawMode (anArg))
2843     {
2844       continue;
2845     }
2846     else if (anArg == "-default"
2847           || anArg == "-def")
2848     {
2849       isDefault = true;
2850     }
2851     else if (anArgIter + 1 < theNbArgs
2852           && (anArg == "-imagefile"
2853            || anArg == "-imgfile"
2854            || anArg == "-image"
2855            || anArg == "-img"))
2856     {
2857       anImagePath = theArgVec[++anArgIter];
2858     }
2859     else if (anArg == "-skydome"
2860           || anArg == "-sky")
2861     {
2862       isSkydomeBg = true;
2863     }
2864     else if (anArgIter + 3 < theNbArgs
2865           && isSkydomeBg
2866           && anArg == "-sundir")
2867     {
2868       float aX = (float) Draw::Atof (theArgVec[++anArgIter]);
2869       float aY = (float) Draw::Atof (theArgVec[++anArgIter]);
2870       float aZ = (float) Draw::Atof (theArgVec[++anArgIter]);
2871       aSkydomeAspect.SetSunDirection (gp_Dir(aX, aY, aZ));
2872     }
2873     else if (anArgIter + 1 < theNbArgs
2874           && isSkydomeBg
2875           && anArg == "-cloud")
2876     {
2877       float aCloudy = (float) Draw::Atof (theArgVec[++anArgIter]);
2878       aSkydomeAspect.SetCloudiness (aCloudy);
2879     }
2880     else if (anArgIter + 1 < theNbArgs
2881           && isSkydomeBg
2882           && anArg == "-time")
2883     {
2884       float aTime = (float) Draw::Atof (theArgVec[++anArgIter]);
2885       aSkydomeAspect.SetTimeParameter (aTime);
2886     }
2887     else if (anArgIter + 1 < theNbArgs
2888           && isSkydomeBg
2889           && anArg == "-fog")
2890     {
2891       float aFoggy = (float) Draw::Atof (theArgVec[++anArgIter]);
2892       aSkydomeAspect.SetFogginess (aFoggy);
2893     }
2894     else if (anArgIter + 1 < theNbArgs
2895           && isSkydomeBg
2896           && anArg == "-size")
2897     {
2898       Standard_Integer aSize = Draw::Atoi (theArgVec[++anArgIter]);
2899       aSkydomeAspect.SetSize (aSize);
2900     }
2901     else if (anArgIter + 1 < theNbArgs
2902           && aCubeMapSeq.IsEmpty()
2903           && (anArg == "-cubemap"
2904            || anArg == "-cmap"
2905            || anArg == "-cm"))
2906     {
2907       aCubeMapSeq.Append (theArgVec[++anArgIter]);
2908       for (Standard_Integer aCubeSideIter = 1; anArgIter + aCubeSideIter < theNbArgs; ++aCubeSideIter)
2909       {
2910         TCollection_AsciiString aSideArg (theArgVec[anArgIter + aCubeSideIter]);
2911         if (!aSideArg.IsEmpty()
2912           && aSideArg.Value (1) == '-')
2913         {
2914           break;
2915         }
2916
2917         aCubeMapSeq.Append (aSideArg);
2918         if (aCubeMapSeq.Size() == 6)
2919         {
2920           anArgIter += 5;
2921           break;
2922         }
2923       }
2924
2925       if (aCubeMapSeq.Size() > 1
2926        && aCubeMapSeq.Size() < 6)
2927       {
2928         aCubeMapSeq.Remove (2, aCubeMapSeq.Size());
2929       }
2930     }
2931     else if (anArgIter + 6 < theNbArgs
2932           && anArg == "-order")
2933     {
2934       for (Standard_Integer aCubeSideIter = 0; aCubeSideIter < 6; ++aCubeSideIter)
2935       {
2936         Standard_Integer aSideArg = 0;
2937         if (!Draw::ParseInteger (theArgVec[anArgIter + aCubeSideIter + 1], aSideArg)
2938          || aSideArg < 0
2939          || aSideArg > 5)
2940         {
2941           theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2942           return 1;
2943         }
2944         aCubeOrder.Set ((Graphic3d_CubeMapSide )aCubeSideIter, (unsigned char )aSideArg);
2945       }
2946       if (!aCubeOrder.IsValid())
2947       {
2948         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2949         return 1;
2950       }
2951       anArgIter += 6;
2952     }
2953     else if (anArg == "-invertedz"
2954           || anArg == "-noinvertedz"
2955           || anArg == "-invz"
2956           || anArg == "-noinvz")
2957     {
2958       isCubeZInverted = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2959     }
2960     else if (anArg == "-pbrenv"
2961           || anArg == "-nopbrenv"
2962           || anArg == "-ibl"
2963           || anArg == "-noibl")
2964     {
2965       toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2966       if (anArgIter + 1 < theNbArgs)
2967       {
2968         TCollection_AsciiString anIblArg (theArgVec[anArgIter + 1]);
2969         anIblArg.LowerCase();
2970         if (anIblArg == "keep"
2971          || anIblArg == "-1")
2972         {
2973           toUseIBL = -1;
2974           ++anArgIter;
2975         }
2976         else if (anIblArg == "ibl"
2977               || anIblArg == "1"
2978               || anIblArg == "on")
2979         {
2980           toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2981           ++anArgIter;
2982         }
2983         else if (anIblArg == "noibl"
2984               || anIblArg == "0"
2985               || anIblArg == "off")
2986         {
2987           toUseIBL = !anArg.StartsWith ("-no") ? 0 : 1;
2988           ++anArgIter;
2989         }
2990       }
2991     }
2992     else if (anArg == "-srgb"
2993           || anArg == "-nosrgb")
2994     {
2995       isSRgb = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2996     }
2997     else if (aNbColors < 2
2998           && (anArg == "-color"
2999            || anArg == "-col"))
3000     {
3001       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - (anArgIter + 1),
3002                                                      theArgVec + (anArgIter + 1),
3003                                                      aColors[aNbColors].ChangeRGB());
3004       if (aNbParsed == 0)
3005       {
3006         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3007         return 1;
3008       }
3009       anArgIter += aNbParsed;
3010       ++aNbColors;
3011     }
3012     else if (anArgIter + 1 < theNbArgs
3013           && (anArg == "-gradientmode"
3014            || anArg == "-gradmode"
3015            || anArg == "-gradmd"
3016            || anArg == "-grmode"
3017            || anArg == "-grmd")
3018           && parseGradientMode (theArgVec[anArgIter + 1], aGradientMode))
3019     {
3020       ++anArgIter;
3021       hasGradientMode = true;
3022     }
3023     else if (anArgIter + 1 < theNbArgs
3024           && (anArg == "-imagemode"
3025            || anArg == "-imgmode"
3026            || anArg == "-imagemd"
3027            || anArg == "-imgmd")
3028           && parseImageMode (theArgVec[anArgIter + 1], anImageMode))
3029     {
3030       ++anArgIter;
3031       hasImageMode = true;
3032     }
3033     else if (aNbColors == 0
3034           && anArgIter + 2 < theNbArgs
3035           && (anArg == "-gradient"
3036            || anArg == "-grad"
3037            || anArg == "-gr"))
3038     {
3039       Standard_Integer aNbParsed1 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
3040                                                       theArgVec + (anArgIter + 1),
3041                                                       aColors[aNbColors].ChangeRGB());
3042       anArgIter += aNbParsed1;
3043       ++aNbColors;
3044       if (aNbParsed1 == 0)
3045       {
3046         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3047         return 1;
3048       }
3049       Standard_Integer aNbParsed2 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
3050                                                       theArgVec + (anArgIter + 1),
3051                                                       aColors[aNbColors].ChangeRGB());
3052       anArgIter += aNbParsed2;
3053       ++aNbColors;
3054       if (aNbParsed2 == 0)
3055       {
3056         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3057         return 1;
3058       }
3059     }
3060     else if (parseGradientMode (theArgVec[anArgIter], aGradientMode))
3061     {
3062       hasGradientMode = true;
3063     }
3064     else if (aNbColors < 2
3065           && (Quantity_ColorRGBA::ColorFromName(theArgVec[anArgIter], aColors[aNbColors])
3066            || Quantity_ColorRGBA::ColorFromHex (theArgVec[anArgIter], aColors[aNbColors])))
3067     {
3068       ++aNbColors;
3069     }
3070     else if (anImagePath.IsEmpty()
3071          &&  aNbColors == 0
3072          && !hasGradientMode
3073          &&  aCubeMapSeq.IsEmpty())
3074     {
3075       anImagePath = theArgVec[anArgIter];
3076     }
3077     else
3078     {
3079       theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3080       return 1;
3081     }
3082   }
3083
3084   if (!isDefault
3085    && aView.IsNull())
3086   {
3087     theDI << "Error: no active viewer";
3088     return 1;
3089   }
3090   else if (isDefault
3091        &&  aNbColors == 0
3092        && !hasGradientMode)
3093   {
3094     theDI << "Syntax error at '-default'";
3095     return 1;
3096   }
3097
3098   if (aNbColors == 1)
3099   {
3100     if (isDefault)
3101     {
3102       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
3103       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
3104       ViewerTest_DefaultBackground.FillMethod     = Aspect_GradientFillMethod_None;
3105       ViewerTest_DefaultBackground.FlatColor      = aColors[0].GetRGB();
3106       ViewerTest_DefaultBackground.SetDefaultGradient();
3107       ViewerTest_DefaultBackground.SetDefaultColor();
3108     }
3109     else
3110     {
3111       aView->SetBgGradientStyle (hasGradientMode ? aGradientMode : Aspect_GradientFillMethod_None);
3112       aView->SetBackgroundColor (aColors[0].GetRGB());
3113       if (toUseIBL != -1)
3114       {
3115         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
3116       }
3117     }
3118   }
3119   else if (aNbColors == 2)
3120   {
3121     if (isDefault)
3122     {
3123       ViewerTest_DefaultBackground.GradientColor1 = aColors[0].GetRGB();
3124       ViewerTest_DefaultBackground.GradientColor2 = aColors[1].GetRGB();
3125       if (hasGradientMode)
3126       {
3127         ViewerTest_DefaultBackground.FillMethod = aGradientMode;
3128       }
3129       else if (ViewerTest_DefaultBackground.FillMethod == Aspect_GradientFillMethod_None)
3130       {
3131         ViewerTest_DefaultBackground.FillMethod = Aspect_GradientFillMethod_Vertical;
3132       }
3133       ViewerTest_DefaultBackground.SetDefaultGradient();
3134     }
3135     else
3136     {
3137       if (!hasGradientMode)
3138       {
3139         aGradientMode = aView->GradientBackground().BgGradientFillMethod();
3140         if (aGradientMode == Aspect_GradientFillMethod_None)
3141         {
3142           aGradientMode = Aspect_GradientFillMethod_Vertical;
3143         }
3144       }
3145       aView->SetBgGradientColors (aColors[0].GetRGB(), aColors[1].GetRGB(), aGradientMode);
3146       if (toUseIBL != -1)
3147       {
3148         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
3149       }
3150     }
3151   }
3152   else if (hasGradientMode)
3153   {
3154     if (isDefault)
3155     {
3156       ViewerTest_DefaultBackground.FillMethod = aGradientMode;
3157       ViewerTest_DefaultBackground.SetDefaultGradient();
3158     }
3159     else
3160     {
3161       aView->SetBgGradientStyle (aGradientMode);
3162     }
3163   }
3164
3165   if (!anImagePath.IsEmpty())
3166   {
3167     Handle(Graphic3d_Texture2D) aTextureMap = new Graphic3d_Texture2D (anImagePath);
3168     aTextureMap->DisableModulate();
3169     aTextureMap->SetColorMap (isSRgb);
3170     if (!aTextureMap->IsDone())
3171     {
3172       theDI << "Syntax error at '" << anImagePath << "'";
3173       return 1;
3174     }
3175     aView->SetBackgroundImage (aTextureMap, anImageMode);
3176   }
3177   else if (hasImageMode)
3178   {
3179     aView->SetBgImageStyle (anImageMode);
3180   }
3181
3182   if (isSkydomeBg)
3183   {
3184     aView->SetBackgroundSkydome (aSkydomeAspect, toUseIBL != -1);
3185   }
3186
3187   if (!aCubeMapSeq.IsEmpty())
3188   {
3189     Handle(Graphic3d_CubeMap) aCubeMap;
3190     if (aCubeMapSeq.Size() == 1)
3191     {
3192       aCubeMap = new Graphic3d_CubeMapPacked (aCubeMapSeq.First(), aCubeOrder.Validated());
3193     }
3194     else
3195     {
3196       NCollection_Array1<TCollection_AsciiString> aCubeMapArr (0, 5);
3197       Standard_Integer aCubeSide = 0;
3198       for (NCollection_Sequence<TCollection_AsciiString>::Iterator aFileIter (aCubeMapSeq); aFileIter.More(); aFileIter.Next(), ++aCubeSide)
3199       {
3200         aCubeMapArr[aCubeSide] = aFileIter.Value();
3201       }
3202       aCubeMap = new Graphic3d_CubeMapSeparate (aCubeMapArr);
3203     }
3204
3205     aCubeMap->SetZInversion (isCubeZInverted);
3206     aCubeMap->SetColorMap (isSRgb);
3207
3208     aCubeMap->GetParams()->SetFilter (Graphic3d_TOTF_BILINEAR);
3209     aCubeMap->GetParams()->SetRepeat (false);
3210     aCubeMap->GetParams()->SetTextureUnit (Graphic3d_TextureUnit_EnvMap);
3211
3212     aView->SetBackgroundCubeMap (aCubeMap, toUseIBL != -1);
3213   }
3214   if (toUseIBL != -1
3215   && !aView.IsNull())
3216   {
3217     aView->SetImageBasedLighting (toUseIBL == 1);
3218   }
3219
3220   return 0;
3221 }
3222
3223 //==============================================================================
3224 //function : VScale
3225 //purpose  : View Scaling
3226 //==============================================================================
3227
3228 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3229 {
3230   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3231   if ( V3dView.IsNull() ) return 1;
3232
3233   if ( argc != 4 ) {
3234     di << argv[0] << "Invalid number of arguments\n";
3235     return 1;
3236   }
3237   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3238   return 0;
3239 }
3240 //==============================================================================
3241 //function : VZBuffTrihedron
3242 //purpose  :
3243 //==============================================================================
3244
3245 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3246                             Standard_Integer  theArgNb,
3247                             const char**      theArgVec)
3248 {
3249   Handle(V3d_View) aView = ViewerTest::CurrentView();
3250   if (aView.IsNull())
3251   {
3252     Message::SendFail ("Error: no active viewer");
3253     return 1;
3254   }
3255
3256   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3257
3258   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3259   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3260   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
3261   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
3262   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
3263   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3264   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3265   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3266   Standard_Real                 aScale        = 0.1;
3267   Standard_Real                 aSizeRatio    = 0.8;
3268   Standard_Real                 anArrowDiam   = 0.05;
3269   Standard_Integer              aNbFacets     = 12;
3270   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3271   {
3272     Standard_CString        anArg = theArgVec[anArgIter];
3273     TCollection_AsciiString aFlag (anArg);
3274     aFlag.LowerCase();
3275     if (anUpdateTool.parseRedrawMode (aFlag))
3276     {
3277       continue;
3278     }
3279     else if (aFlag == "-on")
3280     {
3281       continue;
3282     }
3283     else if (aFlag == "-off")
3284     {
3285       aView->TriedronErase();
3286       return 0;
3287     }
3288     else if (aFlag == "-pos"
3289           || aFlag == "-position"
3290           || aFlag == "-corner")
3291     {
3292       if (++anArgIter >= theArgNb)
3293       {
3294         Message::SendFail() << "Syntax error at '" << anArg << "'";
3295         return 1;
3296       }
3297
3298       if (!ViewerTest::ParseCorner (theArgVec[anArgIter], aPosition))
3299       {
3300         Message::SendFail() << "Syntax error at '" << anArg << "' - unknown position '" << theArgVec[anArgIter] << "'";
3301         return 1;
3302       }
3303     }
3304     else if (aFlag == "-type")
3305     {
3306       if (++anArgIter >= theArgNb)
3307       {
3308         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3309         return 1;
3310       }
3311
3312       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
3313       aTypeName.LowerCase();
3314       if (aTypeName == "wireframe"
3315        || aTypeName == "wire")
3316       {
3317         aVisType = V3d_WIREFRAME;
3318       }
3319       else if (aTypeName == "zbuffer"
3320             || aTypeName == "shaded")
3321       {
3322         aVisType = V3d_ZBUFFER;
3323       }
3324       else
3325       {
3326         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
3327       }
3328     }
3329     else if (aFlag == "-scale")
3330     {
3331       if (++anArgIter >= theArgNb)
3332       {
3333         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3334         return 1;
3335       }
3336
3337       aScale = Draw::Atof (theArgVec[anArgIter]);
3338     }
3339     else if (aFlag == "-size"
3340           || aFlag == "-sizeratio")
3341     {
3342       if (++anArgIter >= theArgNb)
3343       {
3344         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3345         return 1;
3346       }
3347
3348       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
3349     }
3350     else if (aFlag == "-arrowdiam"
3351           || aFlag == "-arrowdiameter")
3352     {
3353       if (++anArgIter >= theArgNb)
3354       {
3355         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3356         return 1;
3357       }
3358
3359       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
3360     }
3361     else if (aFlag == "-nbfacets")
3362     {
3363       if (++anArgIter >= theArgNb)
3364       {
3365         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3366         return 1;
3367       }
3368
3369       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
3370     }
3371     else if (aFlag == "-colorlabel"
3372           || aFlag == "-colorlabels"
3373           || aFlag == "-colorlabelx"
3374           || aFlag == "-colorlabely"
3375           || aFlag == "-colorlabelz"
3376           || aFlag == "-colorarrowx"
3377           || aFlag == "-colorarrowy"
3378           || aFlag == "-colorarrowz")
3379     {
3380       Quantity_Color aColor;
3381       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
3382                                                      theArgVec + anArgIter + 1,
3383                                                      aColor);
3384       if (aNbParsed == 0)
3385       {
3386         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3387         return 1;
3388       }
3389
3390       if (aFlag == "-colorarrowx")
3391       {
3392         anArrowColorX = aColor;
3393       }
3394       else if (aFlag == "-colorarrowy")
3395       {
3396         anArrowColorY = aColor;
3397       }
3398       else if (aFlag == "-colorarrowz")
3399       {
3400         anArrowColorZ = aColor;
3401       }
3402       else if (aFlag == "-colorlabelx")
3403       {
3404         aLabelsColorX = aColor;
3405       }
3406       else if (aFlag == "-colorlabely")
3407       {
3408         aLabelsColorY = aColor;
3409       }
3410       else if (aFlag == "-colorlabelz")
3411       {
3412         aLabelsColorZ = aColor;
3413       }
3414       else
3415       {
3416         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
3417       }
3418       anArgIter += aNbParsed;
3419     }
3420     else
3421     {
3422       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3423       return 1;
3424     }
3425   }
3426
3427   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
3428   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
3429   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
3430   aTrihedron->SetSizeRatio    (aSizeRatio);
3431   aTrihedron->SetNbFacets     (aNbFacets);
3432   aTrihedron->SetArrowDiameter(anArrowDiam);
3433   aTrihedron->SetScale        (aScale);
3434   aTrihedron->SetPosition     (aPosition);
3435   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
3436   aTrihedron->Display (aView);
3437
3438   aView->ZFitAll();
3439   return 0;
3440 }
3441
3442 //==============================================================================
3443 //function : VRotate
3444 //purpose  : Camera Rotating
3445 //==============================================================================
3446
3447 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
3448 {
3449   Handle(V3d_View) aView = ViewerTest::CurrentView();
3450   if (aView.IsNull())
3451   {
3452     Message::SendFail ("Error: no active viewer");
3453     return 1;
3454   }
3455
3456   Standard_Boolean hasFlags = Standard_False;
3457   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3458   {
3459     Standard_CString        anArg (theArgVec[anArgIter]);
3460     TCollection_AsciiString aFlag (anArg);
3461     aFlag.LowerCase();
3462     if (aFlag == "-mousestart"
3463      || aFlag == "-mousefrom")
3464     {
3465       hasFlags = Standard_True;
3466       if (anArgIter + 2 >= theArgNb)
3467       {
3468         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3469         return 1;
3470       }
3471
3472       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3473       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3474       aView->StartRotation (anX, anY);
3475     }
3476     else if (aFlag == "-mousemove")
3477     {
3478       hasFlags = Standard_True;
3479       if (anArgIter + 2 >= theArgNb)
3480       {
3481         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3482         return 1;
3483       }
3484
3485       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3486       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3487       aView->Rotation (anX, anY);
3488     }
3489     else if (theArgNb != 4
3490           && theArgNb != 7)
3491     {
3492       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3493       return 1;
3494     }
3495   }
3496
3497   if (hasFlags)
3498   {
3499     return 0;
3500   }
3501   else if (theArgNb == 4)
3502   {
3503     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3504     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3505     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3506     aView->Rotate (anAX, anAY, anAZ);
3507     return 0;
3508   }
3509   else if (theArgNb == 7)
3510   {
3511     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3512     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3513     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3514
3515     Standard_Real anX = Draw::Atof (theArgVec[4]);
3516     Standard_Real anY = Draw::Atof (theArgVec[5]);
3517     Standard_Real anZ = Draw::Atof (theArgVec[6]);
3518
3519     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
3520     return 0;
3521   }
3522
3523   Message::SendFail ("Error: Invalid number of arguments");
3524   return 1;
3525 }
3526
3527 //==============================================================================
3528 //function : VZoom
3529 //purpose  : View zoom in / out (relative to current zoom)
3530 //==============================================================================
3531
3532 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3533   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3534   if ( V3dView.IsNull() ) {
3535     return 1;
3536   }
3537
3538   if ( argc == 2 ) {
3539     Standard_Real coef = Draw::Atof(argv[1]);
3540     if ( coef <= 0.0 ) {
3541       di << argv[1] << "Invalid value\n";
3542       return 1;
3543     }
3544     V3dView->SetZoom( Draw::Atof(argv[1]) );
3545     return 0;
3546   } else {
3547     di << argv[0] << " Invalid number of arguments\n";
3548     return 1;
3549   }
3550 }
3551
3552 //==============================================================================
3553 //function : VPan
3554 //purpose  : View panning (in pixels)
3555 //==============================================================================
3556
3557 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3558   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3559   if ( V3dView.IsNull() ) return 1;
3560
3561   if ( argc == 3 ) {
3562     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
3563     return 0;
3564   } else {
3565     di << argv[0] << " Invalid number of arguments\n";
3566     return 1;
3567   }
3568 }
3569
3570 //==============================================================================
3571 //function : VPlace
3572 //purpose  : Place the point (in pixels) at the center of the window
3573 //==============================================================================
3574 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
3575 {
3576   Handle(V3d_View) aView = ViewerTest::CurrentView();
3577   if (aView.IsNull())
3578   {
3579     Message::SendFail ("Error: no active viewer");
3580     return 1;
3581   }
3582
3583   if (theArgNb != 3)
3584   {
3585     Message::SendFail ("Syntax error: wrong number of arguments");
3586     return 1;
3587   }
3588
3589   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
3590
3591   return 0;
3592 }
3593
3594 static int VColorScale (Draw_Interpretor& theDI,
3595                         Standard_Integer  theArgNb,
3596                         const char**      theArgVec)
3597 {
3598   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
3599   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
3600   if (aContext.IsNull())
3601   {
3602     Message::SendFail ("Error: no active viewer");
3603     return 1;
3604   }
3605   if (theArgNb <= 1)
3606   {
3607     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
3608     return 1;
3609   }
3610
3611   Handle(AIS_ColorScale) aColorScale;
3612   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
3613   {
3614     // find existing object
3615     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
3616     if (aColorScale.IsNull())
3617     {
3618       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
3619       return 1;
3620     }
3621   }
3622
3623   if (theArgNb <= 2)
3624   {
3625     if (aColorScale.IsNull())
3626     {
3627       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
3628       return 1;
3629     }
3630
3631     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
3632           << "Min range: "            << aColorScale->GetMin() << "\n"
3633           << "Max range: "            << aColorScale->GetMax() << "\n"
3634           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
3635           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
3636           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
3637           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
3638           << "Label position: ";
3639     switch (aColorScale->GetLabelPosition())
3640     {
3641       case Aspect_TOCSP_NONE:
3642         theDI << "None\n";
3643         break;
3644       case Aspect_TOCSP_LEFT:
3645         theDI << "Left\n";
3646         break;
3647       case Aspect_TOCSP_RIGHT:
3648         theDI << "Right\n";
3649         break;
3650       case Aspect_TOCSP_CENTER:
3651         theDI << "Center\n";
3652         break;
3653     }
3654     return 0;
3655   }
3656
3657   if (aColorScale.IsNull())
3658   {
3659     aColorScale = new AIS_ColorScale();
3660     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
3661     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
3662   }
3663
3664   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
3665   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
3666   {
3667     Standard_CString        anArg = theArgVec[anArgIter];
3668     TCollection_AsciiString aFlag (anArg);
3669     aFlag.LowerCase();
3670     if (anUpdateTool.parseRedrawMode (aFlag))
3671     {
3672       continue;
3673     }
3674     else if (aFlag == "-range")
3675     {
3676       if (anArgIter + 3 >= theArgNb)
3677       {
3678         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
3679         return 1;
3680       }
3681
3682       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
3683       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
3684       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
3685       if (!aRangeMin.IsRealValue (Standard_True)
3686        || !aRangeMax.IsRealValue (Standard_True))
3687       {
3688         Message::SendFail ("Syntax error: the range values should be real");
3689         return 1;
3690       }
3691       else if (!aNbIntervals.IsIntegerValue())
3692       {
3693         Message::SendFail ("Syntax error: the number of intervals should be integer");
3694         return 1;
3695       }
3696
3697       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
3698       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
3699     }
3700     else if (aFlag == "-font")
3701     {
3702       if (anArgIter + 1 >= theArgNb)
3703       {
3704         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3705         return 1;
3706       }
3707       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
3708       if (!aFontArg.IsIntegerValue())
3709       {
3710         Message::SendFail ("Syntax error: HeightFont value should be integer");
3711         return 1;
3712       }
3713
3714       aColorScale->SetTextHeight (aFontArg.IntegerValue());
3715       anArgIter += 1;
3716     }
3717     else if (aFlag == "-textpos")
3718     {
3719       if (anArgIter + 1 >= theArgNb)
3720       {
3721         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3722         return 1;
3723       }
3724
3725       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
3726       aTextPosArg.LowerCase();
3727       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
3728       if (aTextPosArg == "none")
3729       {
3730         aLabPosition = Aspect_TOCSP_NONE;
3731       }
3732       else if (aTextPosArg == "left")
3733       {
3734         aLabPosition = Aspect_TOCSP_LEFT;
3735       }
3736       else if (aTextPosArg == "right")
3737       {
3738         aLabPosition = Aspect_TOCSP_RIGHT;
3739       }
3740       else if (aTextPosArg == "center")
3741       {
3742         aLabPosition = Aspect_TOCSP_CENTER;
3743       }
3744       else
3745       {
3746         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
3747         return 1;
3748       }
3749       aColorScale->SetLabelPosition (aLabPosition);
3750     }
3751     else if (aFlag == "-logarithmic"
3752           || aFlag == "-log")
3753     {
3754       if (anArgIter + 1 >= theArgNb)
3755       {
3756         Message::SendFail() << "Synta error at argument '" << anArg << "'";
3757         return 1;
3758       }
3759
3760       Standard_Boolean IsLog;
3761       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
3762       {
3763         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3764         return 1;
3765       }
3766       aColorScale->SetLogarithmic (IsLog);
3767     }
3768     else if (aFlag == "-huerange"
3769           || aFlag == "-hue")
3770     {
3771       if (anArgIter + 2 >= theArgNb)
3772       {
3773         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3774         return 1;
3775       }
3776
3777       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
3778       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
3779       aColorScale->SetHueRange (aHueMin, aHueMax);
3780     }
3781     else if (aFlag == "-colorrange")
3782     {
3783       Quantity_Color aColorMin, aColorMax;
3784       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3785                                                       theArgVec + (anArgIter + 1),
3786                                                       aColorMin);
3787       anArgIter += aNbParsed1;
3788       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3789                                                       theArgVec + (anArgIter + 1),
3790                                                       aColorMax);
3791       anArgIter += aNbParsed2;
3792       if (aNbParsed1 == 0
3793        || aNbParsed2 == 0)
3794       {
3795         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3796         return 1;
3797       }
3798
3799       aColorScale->SetColorRange (aColorMin, aColorMax);
3800     }
3801     else if (aFlag == "-reversed"
3802           || aFlag == "-inverted"
3803           || aFlag == "-topdown"
3804           || aFlag == "-bottomup")
3805     {
3806       Standard_Boolean toEnable = Standard_True;
3807       if (anArgIter + 1 < theArgNb
3808        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
3809       {
3810         ++anArgIter;
3811       }
3812       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
3813     }
3814     else if (aFlag == "-smooth"
3815           || aFlag == "-smoothtransition")
3816     {
3817       Standard_Boolean toEnable = Standard_True;
3818       if (anArgIter + 1 < theArgNb
3819        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3820       {
3821         ++anArgIter;
3822       }
3823       aColorScale->SetSmoothTransition (toEnable);
3824     }
3825     else if (aFlag == "-xy")
3826     {
3827       if (anArgIter + 2 >= theArgNb)
3828       {
3829         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3830         return 1;
3831       }
3832
3833       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
3834       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
3835       if (!anX.IsIntegerValue()
3836        || !anY.IsIntegerValue())
3837       {
3838         Message::SendFail ("Syntax error: coordinates should be integer values");
3839         return 1;
3840       }
3841
3842       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
3843     }
3844     else if (aFlag == "-width"
3845           || aFlag == "-w"
3846           || aFlag == "-breadth")
3847     {
3848       if (anArgIter + 1 >= theArgNb)
3849       {
3850         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3851         return 1;
3852       }
3853
3854       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
3855       if (!aBreadth.IsIntegerValue())
3856       {
3857         Message::SendFail ("Syntax error: a width should be an integer value");
3858         return 1;
3859       }
3860       aColorScale->SetBreadth (aBreadth.IntegerValue());
3861     }
3862     else if (aFlag == "-height"
3863           || aFlag == "-h")
3864     {
3865       if (anArgIter + 1 >= theArgNb)
3866       {
3867         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3868         return 1;
3869       }
3870
3871       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
3872       if (!aHeight.IsIntegerValue())
3873       {
3874         Message::SendFail ("Syntax error: a width should be an integer value");
3875         return 1;
3876       }
3877       aColorScale->SetHeight (aHeight.IntegerValue());
3878     }
3879     else if (aFlag == "-color")
3880     {
3881       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3882       {
3883         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
3884         return 1;
3885       }
3886       else if (anArgIter + 2 >= theArgNb)
3887       {
3888         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3889         return 1;
3890       }
3891
3892       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
3893       if (!anInd.IsIntegerValue())
3894       {
3895         Message::SendFail ("Syntax error: Index value should be integer");
3896         return 1;
3897       }
3898       const Standard_Integer anIndex = anInd.IntegerValue();
3899       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
3900       {
3901         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
3902         return 1;
3903       }
3904
3905       Quantity_Color aColor;
3906       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3907                                                      theArgVec + (anArgIter + 1),
3908                                                      aColor);
3909       if (aNbParsed == 0)
3910       {
3911         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3912         return 1;
3913       }
3914       aColorScale->SetIntervalColor (aColor, anIndex);
3915       aColorScale->SetColorType (Aspect_TOCSD_USER);
3916       anArgIter += aNbParsed;
3917     }
3918     else if (aFlag == "-label")
3919     {
3920       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3921       {
3922         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
3923         return 1;
3924       }
3925       else if (anArgIter + 2 >= theArgNb)
3926       {
3927         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3928         return 1;
3929       }
3930
3931       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
3932       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
3933       {
3934         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
3935         return 1;
3936       }
3937
3938       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
3939       aColorScale->SetLabel     (aText, anIndex);
3940       aColorScale->SetLabelType (Aspect_TOCSD_USER);
3941       anArgIter += 2;
3942     }
3943     else if (aFlag == "-labelat"
3944           || aFlag == "-labat"
3945           || aFlag == "-labelatborder"
3946           || aFlag == "-labatborder"
3947           || aFlag == "-labelatcenter"
3948           || aFlag == "-labatcenter")
3949     {
3950       Standard_Boolean toEnable = Standard_True;
3951       if (aFlag == "-labelat"
3952        || aFlag == "-labat")
3953       {
3954         Standard_Integer aLabAtBorder = -1;
3955         if (++anArgIter >= theArgNb)
3956         {
3957           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
3958           anAtBorder.LowerCase();
3959           if (anAtBorder == "border")
3960           {
3961             aLabAtBorder = 1;
3962           }
3963           else if (anAtBorder == "center")
3964           {
3965             aLabAtBorder = 0;
3966           }
3967         }
3968         if (aLabAtBorder == -1)
3969         {
3970           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3971           return 1;
3972         }
3973         toEnable = (aLabAtBorder == 1);
3974       }
3975       else if (anArgIter + 1 < theArgNb
3976             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3977       {
3978         ++anArgIter;
3979       }
3980       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
3981                                   || aFlag == "-labatcenter"
3982                                    ? !toEnable
3983                                    :  toEnable);
3984     }
3985     else if (aFlag == "-colors")
3986     {
3987       Aspect_SequenceOfColor aSeq;
3988       for (;;)
3989       {
3990         Quantity_Color aColor;
3991         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3992                                                        theArgVec + (anArgIter + 1),
3993                                                        aColor);
3994         if (aNbParsed == 0)
3995         {
3996           break;
3997         }
3998         anArgIter += aNbParsed;
3999         aSeq.Append (aColor);
4000       }
4001       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4002       {
4003         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4004                             << aColorScale->GetNumberOfIntervals() << " intervals";
4005         return 1;
4006       }
4007
4008       aColorScale->SetColors    (aSeq);
4009       aColorScale->SetColorType (Aspect_TOCSD_USER);
4010     }
4011     else if (aFlag == "-uniform")
4012     {
4013       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4014       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4015       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4016       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4017       aColorScale->SetColorType (Aspect_TOCSD_USER);
4018     }
4019     else if (aFlag == "-labels"
4020           || aFlag == "-freelabels")
4021     {
4022       if (anArgIter + 1 >= theArgNb)
4023       {
4024         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4025         return 1;
4026       }
4027
4028       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4029                                  ? aColorScale->GetNumberOfIntervals() + 1
4030                                  : aColorScale->GetNumberOfIntervals();
4031       if (aFlag == "-freelabels")
4032       {
4033         ++anArgIter;
4034         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4035       }
4036       if (anArgIter + aNbLabels >= theArgNb)
4037       {
4038         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4039         return 1;
4040       }
4041
4042       TColStd_SequenceOfExtendedString aSeq;
4043       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4044       {
4045         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
4046       }
4047       aColorScale->SetLabels (aSeq);
4048       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4049     }
4050     else if (aFlag == "-title")
4051     {
4052       if (anArgIter + 1 >= theArgNb)
4053       {
4054         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4055         return 1;
4056       }
4057
4058       Standard_Boolean isTwoArgs = Standard_False;
4059       if (anArgIter + 2 < theArgNb)
4060       {
4061         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4062         aSecondArg.LowerCase();
4063       Standard_DISABLE_DEPRECATION_WARNINGS
4064         if (aSecondArg == "none")
4065         {
4066           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4067           isTwoArgs = Standard_True;
4068         }
4069         else if (aSecondArg == "left")
4070         {
4071           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4072           isTwoArgs = Standard_True;
4073         }
4074         else if (aSecondArg == "right")
4075         {
4076           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4077           isTwoArgs = Standard_True;
4078         }
4079         else if (aSecondArg == "center")
4080         {
4081           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4082           isTwoArgs = Standard_True;
4083         }
4084       Standard_ENABLE_DEPRECATION_WARNINGS
4085       }
4086
4087       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
4088       aColorScale->SetTitle (aTitle);
4089       if (isTwoArgs)
4090       {
4091         anArgIter += 1;
4092       }
4093       anArgIter += 1;
4094     }
4095     else if (aFlag == "-demoversion"
4096           || aFlag == "-demo")
4097     {
4098       aColorScale->SetPosition (0, 0);
4099       aColorScale->SetTextHeight (16);
4100       aColorScale->SetRange (0.0, 100.0);
4101       aColorScale->SetNumberOfIntervals (10);
4102       aColorScale->SetBreadth (0);
4103       aColorScale->SetHeight  (0);
4104       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4105       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4106       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4107     }
4108     else if (aFlag == "-findcolor")
4109     {
4110       if (anArgIter + 1 >= theArgNb)
4111       {
4112         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4113         return 1;
4114       }
4115
4116       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4117
4118       if (!anArg1.IsRealValue (Standard_True))
4119       {
4120         Message::SendFail ("Syntax error: the value should be real");
4121         return 1;
4122       }
4123
4124       Quantity_Color aColor;
4125       aColorScale->FindColor (anArg1.RealValue(), aColor);
4126       theDI << Quantity_Color::StringName (aColor.Name());
4127       return 0;
4128     }
4129     else
4130     {
4131       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4132       return 1;
4133     }
4134   }
4135
4136   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4137   aView->Window()->Size (aWinWidth, aWinHeight);
4138   if (aColorScale->GetBreadth() == 0)
4139   {
4140     aColorScale->SetBreadth (aWinWidth);
4141   }
4142   if (aColorScale->GetHeight() == 0)
4143   {
4144     aColorScale->SetHeight (aWinHeight);
4145   }
4146   aColorScale->SetToUpdate();
4147   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4148   return 0;
4149 }
4150
4151 //==============================================================================
4152 //function : VGraduatedTrihedron
4153 //purpose  : Displays or hides a graduated trihedron
4154 //==============================================================================
4155 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4156                                   Quantity_Color& theColor)
4157 {
4158   Quantity_NameOfColor aColorName;
4159   TCollection_AsciiString aVal = theValue;
4160   aVal.UpperCase();
4161   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4162   {
4163     return Standard_False;
4164   }
4165   theColor = Quantity_Color (aColorName);
4166   return Standard_True;
4167 }
4168
4169 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4170 {
4171   if (theArgNum < 2)
4172   {
4173     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4174                         << theArgs[0] <<"' for more information";
4175     return 1;
4176   }
4177
4178   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4179   TCollection_AsciiString aParseKey;
4180   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4181   {
4182     TCollection_AsciiString anArg (theArgs [anArgIt]);
4183
4184     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4185     {
4186       aParseKey = anArg;
4187       aParseKey.Remove (1);
4188       aParseKey.LowerCase();
4189       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4190       continue;
4191     }
4192
4193     if (aParseKey.IsEmpty())
4194     {
4195       continue;
4196     }
4197
4198     aMapOfArgs(aParseKey)->Append (anArg);
4199   }
4200
4201   // Check parameters
4202   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4203        aMapIt.More(); aMapIt.Next())
4204   {
4205     const TCollection_AsciiString& aKey = aMapIt.Key();
4206     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4207
4208     // Bool key, without arguments
4209     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4210         && anArgs->IsEmpty())
4211     {
4212       continue;
4213     }
4214
4215     // One argument
4216     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4217           && anArgs->Length() == 1)
4218     {
4219       continue;
4220     }
4221
4222     // On/off arguments
4223     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4224         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4225         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4226         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4227         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4228     {
4229       continue;
4230     }
4231
4232     // One string argument
4233     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4234           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4235           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4236     {
4237       continue;
4238     }
4239
4240     // One integer argument
4241     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4242           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4243           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4244           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4245          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4246     {
4247       continue;
4248     }
4249
4250     // One real argument
4251     if ( aKey.IsEqual ("arrowlength")
4252          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
4253     {
4254       continue;
4255     }
4256
4257     // Two string arguments
4258     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
4259          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4260     {
4261       continue;
4262     }
4263
4264     TCollection_AsciiString aLowerKey;
4265     aLowerKey  = "-";
4266     aLowerKey += aKey;
4267     aLowerKey.LowerCase();
4268     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
4269                         << "Type help for more information";
4270     return 1;
4271   }
4272
4273   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
4274   if (anAISContext.IsNull())
4275   {
4276     Message::SendFail ("Error: no active viewer");
4277     return 1;
4278   }
4279
4280   Standard_Boolean toDisplay = Standard_True;
4281   Quantity_Color aColor;
4282   Graphic3d_GraduatedTrihedron aTrihedronData;
4283   // Process parameters
4284   Handle(TColStd_HSequenceOfAsciiString) aValues;
4285   if (aMapOfArgs.Find ("off", aValues))
4286   {
4287     toDisplay = Standard_False;
4288   }
4289
4290   // AXES NAMES
4291   if (aMapOfArgs.Find ("xname", aValues))
4292   {
4293     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
4294   }
4295   if (aMapOfArgs.Find ("yname", aValues))
4296   {
4297     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
4298   }
4299   if (aMapOfArgs.Find ("zname", aValues))
4300   {
4301     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
4302   }
4303   if (aMapOfArgs.Find ("xdrawname", aValues))
4304   {
4305     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4306   }
4307   if (aMapOfArgs.Find ("ydrawname", aValues))
4308   {
4309     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4310   }
4311   if (aMapOfArgs.Find ("zdrawname", aValues))
4312   {
4313     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4314   }
4315   if (aMapOfArgs.Find ("xnameoffset", aValues))
4316   {
4317     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4318   }
4319   if (aMapOfArgs.Find ("ynameoffset", aValues))
4320   {
4321     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4322   }
4323   if (aMapOfArgs.Find ("znameoffset", aValues))
4324   {
4325     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4326   }
4327
4328   // COLORS
4329   if (aMapOfArgs.Find ("xnamecolor", aValues))
4330   {
4331     if (!GetColor (aValues->Value(1), aColor))
4332     {
4333       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
4334       return 1;
4335     }
4336     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
4337   }
4338   if (aMapOfArgs.Find ("ynamecolor", aValues))
4339   {
4340     if (!GetColor (aValues->Value(1), aColor))
4341     {
4342       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
4343       return 1;
4344     }
4345     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
4346   }
4347   if (aMapOfArgs.Find ("znamecolor", aValues))
4348   {
4349     if (!GetColor (aValues->Value(1), aColor))
4350     {
4351       Message::SendFail ("Syntax error: -znamecolor wrong color name");
4352       return 1;
4353     }
4354     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
4355   }
4356   if (aMapOfArgs.Find ("xcolor", aValues))
4357   {
4358     if (!GetColor (aValues->Value(1), aColor))
4359     {
4360       Message::SendFail ("Syntax error: -xcolor wrong color name");
4361       return 1;
4362     }
4363     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
4364   }
4365   if (aMapOfArgs.Find ("ycolor", aValues))
4366   {
4367     if (!GetColor (aValues->Value(1), aColor))
4368     {
4369       Message::SendFail ("Syntax error: -ycolor wrong color name");
4370       return 1;
4371     }
4372     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
4373   }
4374   if (aMapOfArgs.Find ("zcolor", aValues))
4375   {
4376     if (!GetColor (aValues->Value(1), aColor))
4377     {
4378       Message::SendFail ("Syntax error: -zcolor wrong color name");
4379       return 1;
4380     }
4381     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
4382   }
4383
4384   // TICKMARKS
4385   if (aMapOfArgs.Find ("xticks", aValues))
4386   {
4387     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4388   }
4389   if (aMapOfArgs.Find ("yticks", aValues))
4390   {
4391     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4392   }
4393   if (aMapOfArgs.Find ("zticks", aValues))
4394   {
4395     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4396   }
4397   if (aMapOfArgs.Find ("xticklength", aValues))
4398   {
4399     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4400   }
4401   if (aMapOfArgs.Find ("yticklength", aValues))
4402   {
4403     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4404   }
4405   if (aMapOfArgs.Find ("zticklength", aValues))
4406   {
4407     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4408   }
4409   if (aMapOfArgs.Find ("xdrawticks", aValues))
4410   {
4411     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4412   }
4413   if (aMapOfArgs.Find ("ydrawticks", aValues))
4414   {
4415     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4416   }
4417   if (aMapOfArgs.Find ("zdrawticks", aValues))
4418   {
4419     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4420   }
4421
4422   // VALUES
4423   if (aMapOfArgs.Find ("xdrawvalues", aValues))
4424   {
4425     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4426   }
4427   if (aMapOfArgs.Find ("ydrawvalues", aValues))
4428   {
4429     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4430   }
4431   if (aMapOfArgs.Find ("zdrawvalues", aValues))
4432   {
4433     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4434   }
4435   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
4436   {
4437     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4438   }
4439   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
4440   {
4441     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4442   }
4443   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
4444   {
4445     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4446   }
4447
4448   // ARROWS
4449   if (aMapOfArgs.Find ("arrowlength", aValues))
4450   {
4451     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
4452   }
4453
4454   // FONTS
4455   if (aMapOfArgs.Find ("namefont", aValues))
4456   {
4457     aTrihedronData.SetNamesFont (aValues->Value(1));
4458   }
4459   if (aMapOfArgs.Find ("valuesfont", aValues))
4460   {
4461     aTrihedronData.SetValuesFont (aValues->Value(1));
4462   }
4463
4464   if (aMapOfArgs.Find ("drawgrid", aValues))
4465   {
4466     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
4467   }
4468   if (aMapOfArgs.Find ("drawaxes", aValues))
4469   {
4470     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
4471   }
4472
4473   // The final step: display of erase trihedron
4474   if (toDisplay)
4475   {
4476     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
4477   }
4478   else
4479   {
4480     ViewerTest::CurrentView()->GraduatedTrihedronErase();
4481   }
4482
4483   ViewerTest::GetAISContext()->UpdateCurrentViewer();
4484   ViewerTest::CurrentView()->Redraw();
4485
4486   return 0;
4487 }
4488
4489 //==============================================================================
4490 //function : VTile
4491 //purpose  :
4492 //==============================================================================
4493 static int VTile (Draw_Interpretor& theDI,
4494                   Standard_Integer  theArgNb,
4495                   const char**      theArgVec)
4496 {
4497   Handle(V3d_View) aView = ViewerTest::CurrentView();
4498   if (aView.IsNull())
4499   {
4500     Message::SendFail ("Error: no active viewer");
4501     return 1;
4502   }
4503
4504   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
4505   if (theArgNb < 2)
4506   {
4507     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
4508           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
4509           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
4510     return 0;
4511   }
4512
4513   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
4514   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4515   {
4516     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4517     anArg.LowerCase();
4518     if (anArg == "-lowerleft"
4519      || anArg == "-upperleft")
4520     {
4521       if (anArgIter + 3 < theArgNb)
4522       {
4523         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4524         return 1;
4525       }
4526       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
4527       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4528       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4529     }
4530     else if (anArg == "-total"
4531           || anArg == "-totalsize"
4532           || anArg == "-viewsize")
4533     {
4534       if (anArgIter + 3 < theArgNb)
4535       {
4536         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4537         return 1;
4538       }
4539       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4540       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4541       if (aTile.TotalSize.x() < 1
4542        || aTile.TotalSize.y() < 1)
4543       {
4544         Message::SendFail ("Error: total size is incorrect");
4545         return 1;
4546       }
4547     }
4548     else if (anArg == "-tilesize")
4549     {
4550       if (anArgIter + 3 < theArgNb)
4551       {
4552         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4553         return 1;
4554       }
4555
4556       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4557       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4558       if (aTile.TileSize.x() < 1
4559        || aTile.TileSize.y() < 1)
4560       {
4561         Message::SendFail ("Error: tile size is incorrect");
4562         return 1;
4563       }
4564     }
4565     else if (anArg == "-unset")
4566     {
4567       aView->Camera()->SetTile (Graphic3d_CameraTile());
4568       aView->Redraw();
4569       return 0;
4570     }
4571   }
4572
4573   if (aTile.TileSize.x() < 1
4574    || aTile.TileSize.y() < 1)
4575   {
4576     Message::SendFail ("Error: tile size is undefined");
4577     return 1;
4578   }
4579   else if (aTile.TotalSize.x() < 1
4580         || aTile.TotalSize.y() < 1)
4581   {
4582     Message::SendFail ("Error: total size is undefined");
4583     return 1;
4584   }
4585
4586   aView->Camera()->SetTile (aTile);
4587   aView->Redraw();
4588   return 0;
4589 }
4590
4591 //! Format ZLayer ID.
4592 inline const char* formZLayerId (const Standard_Integer theLayerId)
4593 {
4594   switch (theLayerId)
4595   {
4596     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
4597     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
4598     case Graphic3d_ZLayerId_Top:     return "[TOP]";
4599     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
4600     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
4601     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
4602   }
4603   return "";
4604 }
4605
4606 //! Print the ZLayer information.
4607 inline void printZLayerInfo (Draw_Interpretor& theDI,
4608                              const Graphic3d_ZLayerSettings& theLayer)
4609 {
4610   if (!theLayer.Name().IsEmpty())
4611   {
4612     theDI << "  Name: " << theLayer.Name() << "\n";
4613   }
4614   if (theLayer.IsImmediate())
4615   {
4616     theDI << "  Immediate: TRUE\n";
4617   }
4618   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
4619   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
4620   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
4621   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
4622   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
4623   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
4624   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
4625   {
4626     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
4627   }
4628 }
4629
4630 //==============================================================================
4631 //function : VZLayer
4632 //purpose  : Test z layer operations for v3d viewer
4633 //==============================================================================
4634 static int VZLayer (Draw_Interpretor& theDI,
4635                     Standard_Integer  theArgNb,
4636                     const char**      theArgVec)
4637 {
4638   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
4639   if (aContextAIS.IsNull())
4640   {
4641     Message::SendFail ("Error: no active viewer");
4642     return 1;
4643   }
4644
4645   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
4646   if (theArgNb < 2)
4647   {
4648     TColStd_SequenceOfInteger aLayers;
4649     aViewer->GetAllZLayers (aLayers);
4650     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4651     {
4652       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
4653       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
4654       printZLayerInfo (theDI, aSettings);
4655     }
4656     return 0;
4657   }
4658
4659   Standard_Integer anArgIter = 1;
4660   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4661   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
4662   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
4663   {
4664     ++anArgIter;
4665   }
4666
4667   {
4668     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
4669     if (aFirstArg.IsIntegerValue())
4670     {
4671       ++anArgIter;
4672       aLayerId = aFirstArg.IntegerValue();
4673     }
4674     else
4675     {
4676       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
4677       {
4678         ++anArgIter;
4679       }
4680     }
4681   }
4682
4683   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
4684   for (; anArgIter < theArgNb; ++anArgIter)
4685   {
4686     // perform operation
4687     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4688     anArg.LowerCase();
4689     if (anUpdateTool.parseRedrawMode (anArg))
4690     {
4691       //
4692     }
4693     else if (anArg == "-add"
4694           || anArg == "add")
4695     {
4696       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4697       if (!aViewer->AddZLayer (aLayerId))
4698       {
4699         Message::SendFail ("Error: can not add a new z layer");
4700         return 0;
4701       }
4702
4703       theDI << aLayerId;
4704     }
4705     else if (anArg == "-insertbefore"
4706           && anArgIter + 1 < theArgNb
4707           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4708     {
4709       ++anArgIter;
4710       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4711       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4712       {
4713         Message::SendFail ("Error: can not add a new z layer");
4714         return 0;
4715       }
4716
4717       theDI << aLayerId;
4718     }
4719     else if (anArg == "-insertafter"
4720           && anArgIter + 1 < theArgNb
4721           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4722     {
4723       ++anArgIter;
4724       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4725       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4726       {
4727         Message::SendFail ("Error: can not add a new z layer");
4728         return 0;
4729       }
4730
4731       theDI << aLayerId;
4732     }
4733     else if (anArg == "-del"
4734           || anArg == "-delete"
4735           || anArg == "del")
4736     {
4737       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4738       {
4739         if (++anArgIter >= theArgNb)
4740         {
4741           Message::SendFail ("Syntax error: id of z layer to remove is missing");
4742           return 1;
4743         }
4744
4745         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4746       }
4747
4748       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
4749        || aLayerId == Graphic3d_ZLayerId_Default
4750        || aLayerId == Graphic3d_ZLayerId_Top
4751        || aLayerId == Graphic3d_ZLayerId_Topmost
4752        || aLayerId == Graphic3d_ZLayerId_TopOSD
4753        || aLayerId == Graphic3d_ZLayerId_BotOSD)
4754       {
4755         Message::SendFail ("Syntax error: standard Z layer can not be removed");
4756         return 1;
4757       }
4758
4759       // move all object displayed in removing layer to default layer
4760       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
4761            anObjIter.More(); anObjIter.Next())
4762       {
4763         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
4764         if (aPrs.IsNull()
4765          || aPrs->ZLayer() != aLayerId)
4766         {
4767           continue;
4768         }
4769         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
4770       }
4771
4772       if (!aViewer->RemoveZLayer (aLayerId))
4773       {
4774         Message::SendFail ("Z layer can not be removed");
4775       }
4776       else
4777       {
4778         theDI << aLayerId << " ";
4779       }
4780     }
4781     else if (anArg == "-get"
4782           || anArg == "get")
4783     {
4784       TColStd_SequenceOfInteger aLayers;
4785       aViewer->GetAllZLayers (aLayers);
4786       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4787       {
4788         theDI << aLayeriter.Value() << " ";
4789       }
4790
4791       theDI << "\n";
4792     }
4793     else if (anArg == "-name")
4794     {
4795       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4796       {
4797         Message::SendFail ("Syntax error: id of Z layer is missing");
4798         return 1;
4799       }
4800
4801       if (++anArgIter >= theArgNb)
4802       {
4803         Message::SendFail ("Syntax error: name is missing");
4804         return 1;
4805       }
4806
4807       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4808       aSettings.SetName (theArgVec[anArgIter]);
4809       aViewer->SetZLayerSettings (aLayerId, aSettings);
4810     }
4811     else if (anArg == "-origin")
4812     {
4813       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4814       {
4815         Message::SendFail ("Syntax error: id of Z layer is missing");
4816         return 1;
4817       }
4818
4819       if (anArgIter + 2 >= theArgNb)
4820       {
4821         Message::SendFail ("Syntax error: origin coordinates are missing");
4822         return 1;
4823       }
4824
4825       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4826       gp_XYZ anOrigin;
4827       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
4828       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
4829       anOrigin.SetZ (0.0);
4830       if (anArgIter + 3 < theArgNb)
4831       {
4832         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
4833         anArgIter += 3;
4834       }
4835       else
4836       {
4837         anArgIter += 2;
4838       }
4839       aSettings.SetOrigin (anOrigin);
4840       aViewer->SetZLayerSettings (aLayerId, aSettings);
4841     }
4842     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4843           && anArgIter + 1 < theArgNb
4844           && (anArg == "-cullingdistance"
4845            || anArg == "-cullingdist"
4846            || anArg == "-culldistance"
4847            || anArg == "-culldist"
4848            || anArg == "-distcull"
4849            || anArg == "-distculling"
4850            || anArg == "-distanceculling"))
4851     {
4852       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4853       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
4854       aSettings.SetCullingDistance (aDist);
4855       aViewer->SetZLayerSettings (aLayerId, aSettings);
4856     }
4857     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4858           && anArgIter + 1 < theArgNb
4859           && (anArg == "-cullingsize"
4860            || anArg == "-cullsize"
4861            || anArg == "-sizecull"
4862            || anArg == "-sizeculling"))
4863     {
4864       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4865       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
4866       aSettings.SetCullingSize (aSize);
4867       aViewer->SetZLayerSettings (aLayerId, aSettings);
4868     }
4869     else if (anArg == "-settings"
4870           || anArg == "settings")
4871     {
4872       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4873       {
4874         if (++anArgIter >= theArgNb)
4875         {
4876           Message::SendFail ("Syntax error: id of Z layer is missing");
4877           return 1;
4878         }
4879
4880         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4881       }
4882
4883       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4884       printZLayerInfo (theDI, aSettings);
4885     }
4886     else if (anArg == "-enable"
4887           || anArg == "enable"
4888           || anArg == "-disable"
4889           || anArg == "disable")
4890     {
4891       const Standard_Boolean toEnable = anArg == "-enable"
4892                                      || anArg == "enable";
4893       if (++anArgIter >= theArgNb)
4894       {
4895         Message::SendFail ("Syntax error: option name is missing");
4896         return 1;
4897       }
4898
4899       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
4900       aSubOp.LowerCase();
4901       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4902       {
4903         if (++anArgIter >= theArgNb)
4904         {
4905           Message::SendFail ("Syntax error: id of Z layer is missing");
4906           return 1;
4907         }
4908
4909         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4910       }
4911
4912       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4913       if (aSubOp == "depthtest"
4914        || aSubOp == "test")
4915       {
4916         aSettings.SetEnableDepthTest (toEnable);
4917       }
4918       else if (aSubOp == "depthwrite"
4919             || aSubOp == "write")
4920       {
4921         aSettings.SetEnableDepthWrite (toEnable);
4922       }
4923       else if (aSubOp == "depthclear"
4924             || aSubOp == "clear")
4925       {
4926         aSettings.SetClearDepth (toEnable);
4927       }
4928       else if (aSubOp == "depthoffset"
4929             || aSubOp == "offset")
4930       {
4931         Graphic3d_PolygonOffset aParams;
4932         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
4933         if (toEnable)
4934         {
4935           if (anArgIter + 2 >= theArgNb)
4936           {
4937             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
4938             return 1;
4939           }
4940
4941           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4942           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4943         }
4944         aSettings.SetPolygonOffset (aParams);
4945       }
4946       else if (aSubOp == "positiveoffset"
4947             || aSubOp == "poffset")
4948       {
4949         if (toEnable)
4950         {
4951           aSettings.SetDepthOffsetPositive();
4952         }
4953         else
4954         {
4955           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
4956         }
4957       }
4958       else if (aSubOp == "negativeoffset"
4959             || aSubOp == "noffset")
4960       {
4961         if (toEnable)
4962         {
4963           aSettings.SetDepthOffsetNegative();
4964         }
4965         else
4966         {
4967           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
4968         }
4969       }
4970       else if (aSubOp == "textureenv")
4971       {
4972         aSettings.SetEnvironmentTexture (toEnable);
4973       }
4974       else if (aSubOp == "raytracing")
4975       {
4976         aSettings.SetRaytracable (toEnable);
4977       }
4978
4979       aViewer->SetZLayerSettings (aLayerId, aSettings);
4980     }
4981     else
4982     {
4983       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
4984       return 1;
4985     }
4986   }
4987
4988   return 0;
4989 }
4990
4991 // The interactive presentation of 2d layer item
4992 // for "vlayerline" command it provides a presentation of
4993 // line with user-defined linewidth, linetype and transparency.
4994 class V3d_LineItem : public AIS_InteractiveObject
4995 {
4996 public:
4997   // CASCADE RTTI
4998   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
4999
5000   // constructor
5001   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5002                                Standard_Real X2, Standard_Real Y2,
5003                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5004                                Standard_Real theWidth    = 0.5,
5005                                Standard_Real theTransp   = 1.0);
5006
5007 private:
5008
5009   virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
5010                         const Handle(Prs3d_Presentation)& thePrs,
5011                         const Standard_Integer theMode) Standard_OVERRIDE;
5012
5013   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& ,
5014                                  const Standard_Integer ) Standard_OVERRIDE
5015   {}
5016
5017 private:
5018
5019   Standard_Real       myX1, myY1, myX2, myY2;
5020   Aspect_TypeOfLine   myType;
5021   Standard_Real       myWidth;
5022 };
5023
5024 // default constructor for line item
5025 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5026                            Standard_Real X2, Standard_Real Y2,
5027                            Aspect_TypeOfLine theType,
5028                            Standard_Real theWidth,
5029                            Standard_Real theTransp) :
5030   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5031   myType(theType), myWidth(theWidth)
5032 {
5033   SetTransparency (1-theTransp);
5034 }
5035
5036 // render line
5037 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager)& ,
5038                             const Handle(Prs3d_Presentation)& thePresentation,
5039                             const Standard_Integer )
5040 {
5041   thePresentation->Clear();
5042   Quantity_Color aColor (Quantity_NOC_RED);
5043   Standard_Integer aWidth, aHeight;
5044   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5045   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
5046   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5047   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5048   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5049   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5050   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5051   aGroup->AddPrimitiveArray (aPrim);
5052 }
5053
5054 //=============================================================================
5055 //function : VLayerLine
5056 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5057 //         : linewidth, transparency coefficient
5058 //============================================================================
5059 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5060 {
5061   // get the active view
5062   Handle(V3d_View) aView = ViewerTest::CurrentView();
5063   if (aView.IsNull())
5064   {
5065     di << "Call vinit before!\n";
5066     return 1;
5067   }
5068   else if (argc < 5)
5069   {
5070     di << "Use: " << argv[0];
5071     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5072     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5073     di << "              0 - solid  \n";
5074     di << "              1 - dashed \n";
5075     di << "              2 - dot    \n";
5076     di << "              3 - dashdot\n";
5077     di << " transparency : { 0.0 - 1.0 } \n";
5078     di << "                  0.0 - transparent\n";
5079     di << "                  1.0 - visible    \n";
5080     return 1;
5081   }
5082
5083   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5084   // get the input params
5085   Standard_Real X1 = Draw::Atof(argv[1]);
5086   Standard_Real Y1 = Draw::Atof(argv[2]);
5087   Standard_Real X2 = Draw::Atof(argv[3]);
5088   Standard_Real Y2 = Draw::Atof(argv[4]);
5089
5090   Standard_Real aWidth = 0.5;
5091   Standard_Real aTransparency = 1.0;
5092
5093   // has width
5094   if (argc > 5)
5095     aWidth = Draw::Atof(argv[5]);
5096
5097   // select appropriate line type
5098   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5099   if (argc > 6
5100   && !ViewerTest::ParseLineType (argv[6], aLineType))
5101   {
5102     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5103     return 1;
5104   }
5105
5106   // has transparency
5107   if (argc > 7)
5108   {
5109     aTransparency = Draw::Atof(argv[7]);
5110     if (aTransparency < 0 || aTransparency > 1.0)
5111       aTransparency = 1.0;
5112   }
5113
5114   static Handle (V3d_LineItem) aLine;
5115   if (!aLine.IsNull())
5116   {
5117     aContext->Erase (aLine, Standard_False);
5118   }
5119   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5120                             aLineType, aWidth,
5121                             aTransparency);
5122
5123   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5124   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5125   aLine->SetToUpdate();
5126   aContext->Display (aLine, Standard_True);
5127
5128   return 0;
5129 }
5130
5131
5132 //==============================================================================
5133 //function : VGrid
5134 //purpose  :
5135 //==============================================================================
5136
5137 static int VGrid (Draw_Interpretor& /*theDI*/,
5138                   Standard_Integer  theArgNb,
5139                   const char**      theArgVec)
5140 {
5141   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5142   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5143   if (aView.IsNull() || aViewer.IsNull())
5144   {
5145     Message::SendFail ("Error: no active viewer");
5146     return 1;
5147   }
5148
5149   Aspect_GridType     aType = aViewer->GridType();
5150   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5151   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5152   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5153   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5154   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5155   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5156   {
5157     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5158     anArg.LowerCase();
5159     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5160     {
5161       continue;
5162     }
5163     else if (anArgIter + 1 < theArgNb
5164           && anArg == "-type")
5165     {
5166       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5167       anArgNext.LowerCase();
5168       if (anArgNext == "r"
5169        || anArgNext == "rect"
5170        || anArgNext == "rectangular")
5171       {
5172         aType = Aspect_GT_Rectangular;
5173       }
5174       else if (anArgNext == "c"
5175             || anArgNext == "circ"
5176             || anArgNext == "circular")
5177       {
5178         aType = Aspect_GT_Circular;
5179       }
5180       else
5181       {
5182         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5183         return 1;
5184       }
5185     }
5186     else if (anArgIter + 1 < theArgNb
5187           && anArg == "-mode")
5188     {
5189       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5190       anArgNext.LowerCase();
5191       if (anArgNext == "l"
5192        || anArgNext == "line"
5193        || anArgNext == "lines")
5194       {
5195         aMode = Aspect_GDM_Lines;
5196       }
5197       else if (anArgNext == "p"
5198             || anArgNext == "point"
5199             || anArgNext == "points")
5200       {
5201         aMode = Aspect_GDM_Points;
5202       }
5203       else
5204       {
5205         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5206         return 1;
5207       }
5208     }
5209     else if (anArgIter + 2 < theArgNb
5210           && (anArg == "-origin"
5211            || anArg == "-orig"))
5212     {
5213       hasOrigin = true;
5214       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5215                               Draw::Atof (theArgVec[anArgIter + 2]));
5216       anArgIter += 2;
5217     }
5218     else if (anArgIter + 2 < theArgNb
5219           && anArg == "-step")
5220     {
5221       hasStep = true;
5222       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5223                             Draw::Atof (theArgVec[anArgIter + 2]));
5224       if (aNewStepXY.x() <= 0.0
5225        || aNewStepXY.y() <= 0.0)
5226       {
5227         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5228         return 1;
5229       }
5230       anArgIter += 2;
5231     }
5232     else if (anArgIter + 1 < theArgNb
5233           && (anArg == "-angle"
5234            || anArg == "-rotangle"
5235            || anArg == "-rotationangle"))
5236     {
5237       hasRotAngle = true;
5238       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5239     }
5240     else if (anArgIter + 1 < theArgNb
5241           && (anArg == "-zoffset"
5242            || anArg == "-dz"))
5243     {
5244       hasZOffset = true;
5245       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5246     }
5247     else if (anArgIter + 1 < theArgNb
5248           && anArg == "-radius")
5249     {
5250       hasSize = true;
5251       ++anArgIter;
5252       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
5253       if (aNewStepXY.x() <= 0.0)
5254       {
5255         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
5256         return 1;
5257       }
5258     }
5259     else if (anArgIter + 2 < theArgNb
5260           && anArg == "-size")
5261     {
5262       hasSize = true;
5263       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5264                             Draw::Atof (theArgVec[anArgIter + 2]));
5265       if (aNewStepXY.x() <= 0.0
5266        || aNewStepXY.y() <= 0.0)
5267       {
5268         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5269         return 1;
5270       }
5271       anArgIter += 2;
5272     }
5273     else if (anArg == "r"
5274           || anArg == "rect"
5275           || anArg == "rectangular")
5276     {
5277       aType = Aspect_GT_Rectangular;
5278     }
5279     else if (anArg == "c"
5280           || anArg == "circ"
5281           || anArg == "circular")
5282     {
5283       aType = Aspect_GT_Circular;
5284     }
5285     else if (anArg == "l"
5286           || anArg == "line"
5287           || anArg == "lines")
5288     {
5289       aMode = Aspect_GDM_Lines;
5290     }
5291     else if (anArg == "p"
5292           || anArg == "point"
5293           || anArg == "points")
5294     {
5295       aMode = Aspect_GDM_Points;
5296     }
5297     else if (anArgIter + 1 >= theArgNb
5298           && anArg == "off")
5299     {
5300       aViewer->DeactivateGrid();
5301       return 0;
5302     }
5303     else
5304     {
5305       Message::SendFail() << "Syntax error at '" << anArg << "'";
5306       return 1;
5307     }
5308   }
5309
5310   if (aType == Aspect_GT_Rectangular)
5311   {
5312     Graphic3d_Vec2d anOrigXY, aStepXY;
5313     Standard_Real aRotAngle = 0.0;
5314     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5315     if (hasOrigin)
5316     {
5317       anOrigXY = aNewOriginXY;
5318     }
5319     if (hasStep)
5320     {
5321       aStepXY = aNewStepXY;
5322     }
5323     if (hasRotAngle)
5324     {
5325       aRotAngle = aNewRotAngle;
5326     }
5327     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5328     if (hasSize || hasZOffset)
5329     {
5330       Graphic3d_Vec3d aSize;
5331       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5332       if (hasSize)
5333       {
5334         aSize.x() = aNewSizeXY.x();
5335         aSize.y() = aNewSizeXY.y();
5336       }
5337       if (hasZOffset)
5338       {
5339         aSize.z() = aNewZOffset;
5340       }
5341       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5342     }
5343   }
5344   else if (aType == Aspect_GT_Circular)
5345   {
5346     Graphic3d_Vec2d anOrigXY;
5347     Standard_Real aRadiusStep;
5348     Standard_Integer aDivisionNumber;
5349     Standard_Real aRotAngle = 0.0;
5350     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5351     if (hasOrigin)
5352     {
5353       anOrigXY = aNewOriginXY;
5354     }
5355     if (hasStep)
5356     {
5357       aRadiusStep     = aNewStepXY[0];
5358       aDivisionNumber = (int )aNewStepXY[1];
5359       if (aDivisionNumber < 1)
5360       {
5361         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
5362         return 1;
5363       }
5364     }
5365     if (hasRotAngle)
5366     {
5367       aRotAngle = aNewRotAngle;
5368     }
5369
5370     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5371     if (hasSize || hasZOffset)
5372     {
5373       Standard_Real aRadius = 0.0, aZOffset = 0.0;
5374       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
5375       if (hasSize)
5376       {
5377         aRadius = aNewSizeXY.x();
5378         if (aNewSizeXY.y() != 0.0)
5379         {
5380           Message::SendFail ("Syntax error: circular size should be specified as radius");
5381           return 1;
5382         }
5383       }
5384       if (hasZOffset)
5385       {
5386         aZOffset = aNewZOffset;
5387       }
5388       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
5389     }
5390   }
5391   aViewer->ActivateGrid (aType, aMode);
5392   return 0;
5393 }
5394
5395 //==============================================================================
5396 //function : VPriviledgedPlane
5397 //purpose  :
5398 //==============================================================================
5399
5400 static int VPriviledgedPlane (Draw_Interpretor& theDI,
5401                               Standard_Integer  theArgNb,
5402                               const char**      theArgVec)
5403 {
5404   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
5405   {
5406     Message::SendFail ("Error: wrong number of arguments! See usage:");
5407     theDI.PrintHelp (theArgVec[0]);
5408     return 1;
5409   }
5410
5411   // get the active viewer
5412   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5413   if (aViewer.IsNull())
5414   {
5415     Message::SendFail ("Error: no active viewer");
5416     return 1;
5417   }
5418
5419   if (theArgNb == 1)
5420   {
5421     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
5422     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
5423     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
5424     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
5425     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
5426           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
5427           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
5428     return 0;
5429   }
5430
5431   Standard_Integer anArgIdx = 1;
5432   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
5433   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
5434   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
5435   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
5436   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
5437   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
5438
5439   gp_Ax3 aPriviledgedPlane;
5440   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
5441   gp_Dir aNorm (aNormX, aNormY, aNormZ);
5442   if (theArgNb > 7)
5443   {
5444     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
5445     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
5446     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
5447     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
5448     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
5449   }
5450   else
5451   {
5452     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
5453   }
5454
5455   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
5456
5457   return 0;
5458 }
5459
5460 //==============================================================================
5461 //function : VConvert
5462 //purpose  :
5463 //==============================================================================
5464
5465 static int VConvert (Draw_Interpretor& theDI,
5466                      Standard_Integer  theArgNb,
5467                      const char**      theArgVec)
5468 {
5469   // get the active view
5470   Handle(V3d_View) aView = ViewerTest::CurrentView();
5471   if (aView.IsNull())
5472   {
5473     Message::SendFail ("Error: no active viewer");
5474     return 1;
5475   }
5476
5477   enum { Model, Ray, View, Window, Grid } aMode = Model;
5478
5479   // access coordinate arguments
5480   TColStd_SequenceOfReal aCoord;
5481   Standard_Integer anArgIdx = 1;
5482   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
5483   {
5484     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5485     if (!anArg.IsRealValue (Standard_True))
5486     {
5487       break;
5488     }
5489     aCoord.Append (anArg.RealValue());
5490   }
5491
5492   // non-numeric argument too early
5493   if (aCoord.IsEmpty())
5494   {
5495     Message::SendFail ("Error: wrong number of arguments! See usage:");
5496     theDI.PrintHelp (theArgVec[0]);
5497     return 1;
5498   }
5499
5500   // collect all other arguments and options
5501   for (; anArgIdx < theArgNb; ++anArgIdx)
5502   {
5503     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5504     anArg.LowerCase();
5505     if      (anArg == "window") aMode = Window;
5506     else if (anArg == "view")   aMode = View;
5507     else if (anArg == "grid")   aMode = Grid;
5508     else if (anArg == "ray")    aMode = Ray;
5509     else
5510     {
5511       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
5512       theDI.PrintHelp (theArgVec[0]);
5513       return 1;
5514     }
5515   }
5516
5517   // complete input checks
5518   if ((aCoord.Length() == 1 && theArgNb > 3) ||
5519       (aCoord.Length() == 2 && theArgNb > 4) ||
5520       (aCoord.Length() == 3 && theArgNb > 5))
5521   {
5522     Message::SendFail ("Error: wrong number of arguments! See usage:");
5523     theDI.PrintHelp (theArgVec[0]);
5524     return 1;
5525   }
5526
5527   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
5528   Standard_Integer aXYp[2] = {0, 0};
5529
5530   // convert one-dimensional coordinate
5531   if (aCoord.Length() == 1)
5532   {
5533     switch (aMode)
5534     {
5535       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
5536       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
5537       default:
5538         Message::SendFail ("Error: wrong arguments! See usage:");
5539         theDI.PrintHelp (theArgVec[0]);
5540         return 1;
5541     }
5542   }
5543
5544   // convert 2D coordinates from projection or view reference space
5545   if (aCoord.Length() == 2)
5546   {
5547     switch (aMode)
5548     {
5549       case Model :
5550         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5551         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5552         return 0;
5553
5554       case View :
5555         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
5556         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
5557         return 0;
5558
5559       case Window :
5560         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
5561         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5562         return 0;
5563
5564       case Grid :
5565         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5566         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
5567         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5568         return 0;
5569
5570       case Ray :
5571         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
5572                                 (Standard_Integer) aCoord (2),
5573                                 aXYZ[0], aXYZ[1], aXYZ[2],
5574                                 aXYZ[3], aXYZ[4], aXYZ[5]);
5575         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5576         return 0;
5577
5578       default:
5579         Message::SendFail ("Error: wrong arguments! See usage:");
5580         theDI.PrintHelp (theArgVec[0]);
5581         return 1;
5582     }
5583   }
5584
5585   // convert 3D coordinates from view reference space
5586   else if (aCoord.Length() == 3)
5587   {
5588     switch (aMode)
5589     {
5590       case Window :
5591         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
5592         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5593         return 0;
5594
5595       case Grid :
5596         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
5597         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5598         return 0;
5599
5600       default:
5601         Message::SendFail ("Error: wrong arguments! See usage:");
5602         theDI.PrintHelp (theArgVec[0]);
5603         return 1;
5604     }
5605   }
5606
5607   return 0;
5608 }
5609
5610 //==============================================================================
5611 //function : VFps
5612 //purpose  :
5613 //==============================================================================
5614
5615 static int VFps (Draw_Interpretor& theDI,
5616                  Standard_Integer  theArgNb,
5617                  const char**      theArgVec)
5618 {
5619   // get the active view
5620   Handle(V3d_View) aView = ViewerTest::CurrentView();
5621   if (aView.IsNull())
5622   {
5623     Message::SendFail ("Error: no active viewer");
5624     return 1;
5625   }
5626
5627   Standard_Integer aFramesNb = -1;
5628   Standard_Real aDuration = -1.0;
5629   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5630   {
5631     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5632     anArg.LowerCase();
5633     if (aDuration < 0.0
5634      && anArgIter + 1 < theArgNb
5635      && (anArg == "-duration"
5636       || anArg == "-dur"
5637       || anArg == "-time"))
5638     {
5639       aDuration = Draw::Atof (theArgVec[++anArgIter]);
5640     }
5641     else if (aFramesNb < 0
5642           && anArg.IsIntegerValue())
5643     {
5644       aFramesNb = anArg.IntegerValue();
5645       if (aFramesNb <= 0)
5646       {
5647         Message::SendFail() << "Syntax error at '" << anArg << "'";
5648         return 1;
5649       }
5650     }
5651     else
5652     {
5653       Message::SendFail() << "Syntax error at '" << anArg << "'";
5654       return 1;
5655     }
5656   }
5657   if (aFramesNb < 0 && aDuration < 0.0)
5658   {
5659     aFramesNb = 100;
5660   }
5661
5662   // the time is meaningless for first call
5663   // due to async OpenGl rendering
5664   aView->Redraw();
5665
5666   // redraw view in loop to estimate average values
5667   OSD_Timer aTimer;
5668   aTimer.Start();
5669   Standard_Integer aFrameIter = 1;
5670   for (;; ++aFrameIter)
5671   {
5672     aView->Redraw();
5673     if ((aFramesNb > 0
5674       && aFrameIter >= aFramesNb)
5675      || (aDuration > 0.0
5676       && aTimer.ElapsedTime() >= aDuration))
5677     {
5678       break;
5679     }
5680   }
5681   aTimer.Stop();
5682   Standard_Real aCpu;
5683   const Standard_Real aTime = aTimer.ElapsedTime();
5684   aTimer.OSD_Chronometer::Show (aCpu);
5685
5686   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
5687   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
5688
5689   // return statistics
5690   theDI << "FPS: " << aFpsAver << "\n"
5691         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
5692
5693   // compute additional statistics in ray-tracing mode
5694   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
5695   if (aParams.Method == Graphic3d_RM_RAYTRACING)
5696   {
5697     Graphic3d_Vec2i aWinSize (0, 0);
5698     aView->Window()->Size (aWinSize.x(), aWinSize.y());
5699
5700     // 1 shadow ray and 1 secondary ray pew each bounce
5701     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
5702     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
5703   }
5704
5705   return 0;
5706 }
5707
5708
5709 //==============================================================================
5710 //function : VMemGpu
5711 //purpose  :
5712 //==============================================================================
5713
5714 static int VMemGpu (Draw_Interpretor& theDI,
5715                     Standard_Integer  theArgNb,
5716                     const char**      theArgVec)
5717 {
5718   // get the context
5719   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5720   if (aContextAIS.IsNull())
5721   {
5722     Message::SendFail ("Error: no active viewer");
5723     return 1;
5724   }
5725
5726   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
5727   if (aDriver.IsNull())
5728   {
5729     Message::SendFail ("Error: graphic driver not available");
5730     return 1;
5731   }
5732
5733   Standard_Size aFreeBytes = 0;
5734   TCollection_AsciiString anInfo;
5735   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
5736   {
5737     Message::SendFail ("Error: information not available");
5738     return 1;
5739   }
5740
5741   if (theArgNb > 1 && *theArgVec[1] == 'f')
5742   {
5743     theDI << Standard_Real (aFreeBytes);
5744   }
5745   else
5746   {
5747     theDI << anInfo;
5748   }
5749
5750   return 0;
5751 }
5752
5753 // ==============================================================================
5754 // function : VReadPixel
5755 // purpose  :
5756 // ==============================================================================
5757 static int VReadPixel (Draw_Interpretor& theDI,
5758                        Standard_Integer  theArgNb,
5759                        const char**      theArgVec)
5760 {
5761   // get the active view
5762   Handle(V3d_View) aView = ViewerTest::CurrentView();
5763   if (aView.IsNull())
5764   {
5765     Message::SendFail ("Error: no active viewer");
5766     return 1;
5767   }
5768   else if (theArgNb < 3)
5769   {
5770     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
5771                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
5772     return 1;
5773   }
5774
5775   Image_Format         aFormat     = Image_Format_RGBA;
5776   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
5777
5778   Standard_Integer aWidth, aHeight;
5779   aView->Window()->Size (aWidth, aHeight);
5780   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
5781   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
5782   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
5783   {
5784     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
5785     return 1;
5786   }
5787
5788   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
5789   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
5790   {
5791     TCollection_AsciiString aParam (theArgVec[anIter]);
5792     aParam.LowerCase();
5793     if (aParam == "-rgb"
5794      || aParam == "rgb"
5795      || aParam == "-srgb"
5796      || aParam == "srgb")
5797     {
5798       aFormat     = Image_Format_RGB;
5799       aBufferType = Graphic3d_BT_RGB;
5800       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
5801     }
5802     else if (aParam == "-hls"
5803           || aParam == "hls")
5804     {
5805       aFormat     = Image_Format_RGB;
5806       aBufferType = Graphic3d_BT_RGB;
5807       toShowHls   = Standard_True;
5808     }
5809     else if (aParam == "-rgbf"
5810           || aParam == "rgbf")
5811     {
5812       aFormat     = Image_Format_RGBF;
5813       aBufferType = Graphic3d_BT_RGB;
5814     }
5815     else if (aParam == "-rgba"
5816           || aParam == "rgba"
5817           || aParam == "-srgba"
5818           || aParam == "srgba")
5819     {
5820       aFormat     = Image_Format_RGBA;
5821       aBufferType = Graphic3d_BT_RGBA;
5822       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
5823     }
5824     else if (aParam == "-rgbaf"
5825           || aParam == "rgbaf")
5826     {
5827       aFormat     = Image_Format_RGBAF;
5828       aBufferType = Graphic3d_BT_RGBA;
5829     }
5830     else if (aParam == "-depth"
5831           || aParam == "depth")
5832     {
5833       aFormat     = Image_Format_GrayF;
5834       aBufferType = Graphic3d_BT_Depth;
5835     }
5836     else if (aParam == "-name"
5837           || aParam == "name")
5838     {
5839       toShowName = Standard_True;
5840     }
5841     else if (aParam == "-hex"
5842           || aParam == "hex")
5843     {
5844       toShowHex = Standard_True;
5845     }
5846     else
5847     {
5848       Message::SendFail() << "Syntax error at '" << aParam << "'";
5849       return 1;
5850     }
5851   }
5852
5853   Image_PixMap anImage;
5854   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
5855   {
5856     Message::SendFail ("Error: image allocation failed");
5857     return 1;
5858   }
5859   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
5860   {
5861     Message::SendFail ("Error: image dump failed");
5862     return 1;
5863   }
5864
5865   // redirect possible warning messages that could have been added by ToPixMap
5866   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
5867   // contaminate result of the command
5868   Standard_CString aWarnLog = theDI.Result();
5869   if (aWarnLog != NULL && aWarnLog[0] != '\0')
5870   {
5871     std::cout << aWarnLog << std::endl;
5872   }
5873   theDI.Reset();
5874
5875   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
5876   if (toShowName)
5877   {
5878     if (aBufferType == Graphic3d_BT_RGBA)
5879     {
5880       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
5881     }
5882     else
5883     {
5884       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
5885     }
5886   }
5887   else if (toShowHex)
5888   {
5889     if (aBufferType == Graphic3d_BT_RGBA)
5890     {
5891       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
5892     }
5893     else
5894     {
5895       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
5896     }
5897   }
5898   else
5899   {
5900     switch (aBufferType)
5901     {
5902       default:
5903       case Graphic3d_BT_RGB:
5904       {
5905         if (toShowHls)
5906         {
5907           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
5908         }
5909         else if (toShow_sRGB)
5910         {
5911           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
5912           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
5913         }
5914         else
5915         {
5916           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
5917         }
5918         break;
5919       }
5920       case Graphic3d_BT_RGBA:
5921       {
5922         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
5923         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
5924         break;
5925       }
5926       case Graphic3d_BT_Depth:
5927       {
5928         theDI << aColor.GetRGB().Red();
5929         break;
5930       }
5931     }
5932   }
5933
5934   return 0;
5935 }
5936
5937 //! Auxiliary presentation for an image plane.
5938 class ViewerTest_ImagePrs : public AIS_InteractiveObject
5939 {
5940 public:
5941   //! Main constructor.
5942   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
5943                        const Standard_Real theWidth,
5944                        const Standard_Real theHeight,
5945                        const TCollection_AsciiString& theLabel)
5946   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
5947   {
5948     SetDisplayMode (0);
5949     SetHilightMode (1);
5950     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
5951     {
5952       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
5953       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
5954       Graphic3d_MaterialAspect aMat;
5955       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
5956       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
5957       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
5958       aMat.SetSpecularColor (Quantity_NOC_BLACK);
5959       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
5960       aFillAspect->SetFrontMaterial (aMat);
5961       aFillAspect->SetTextureMap (new Graphic3d_Texture2D (theImage));
5962       aFillAspect->SetTextureMapOn();
5963     }
5964     {
5965       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
5966       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
5967       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
5968       myDrawer->SetTextAspect (aTextAspect);
5969     }
5970     {
5971       const gp_Dir aNorm (0.0, 0.0, 1.0);
5972       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
5973       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
5974       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
5975       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
5976       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
5977       myTris->AddEdge (1);
5978       myTris->AddEdge (2);
5979       myTris->AddEdge (3);
5980       myTris->AddEdge (3);
5981       myTris->AddEdge (2);
5982       myTris->AddEdge (4);
5983
5984       myRect = new Graphic3d_ArrayOfPolylines (4);
5985       myRect->AddVertex (myTris->Vertice (1));
5986       myRect->AddVertex (myTris->Vertice (3));
5987       myRect->AddVertex (myTris->Vertice (4));
5988       myRect->AddVertex (myTris->Vertice (2));
5989     }
5990   }
5991
5992   //! Returns TRUE for accepted display modes.
5993   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
5994
5995   //! Compute presentation.
5996   virtual void Compute (const Handle(PrsMgr_PresentationManager)& ,
5997                         const Handle(Prs3d_Presentation)& thePrs,
5998                         const Standard_Integer theMode) Standard_OVERRIDE
5999   {
6000     switch (theMode)
6001     {
6002       case 0:
6003       {
6004         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
6005         aGroup->AddPrimitiveArray (myTris);
6006         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
6007         aGroup->AddPrimitiveArray (myRect);
6008         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
6009         return;
6010       }
6011       case 1:
6012       {
6013         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
6014         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
6015         aGroup->AddPrimitiveArray (myRect);
6016         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
6017         return;
6018       }
6019     }
6020   }
6021
6022   //! Compute selection.
6023   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
6024   {
6025     if (theMode == 0)
6026     {
6027       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
6028       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
6029       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
6030       theSel->Add (aSensitive);
6031     }
6032   }
6033
6034 private:
6035   Handle(Graphic3d_ArrayOfTriangles) myTris;
6036   Handle(Graphic3d_ArrayOfPolylines) myRect;
6037   TCollection_AsciiString myLabel;
6038   Standard_Real myWidth;
6039   Standard_Real myHeight;
6040 };
6041
6042 //==============================================================================
6043 //function : VDiffImage
6044 //purpose  : The draw-command compares two images.
6045 //==============================================================================
6046
6047 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
6048 {
6049   if (theArgNb < 3)
6050   {
6051     Message::SendFail ("Syntax error: not enough arguments");
6052     return 1;
6053   }
6054
6055   Standard_Integer anArgIter = 1;
6056   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
6057   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
6058   TCollection_AsciiString aDiffImagePath;
6059   Standard_Real    aTolColor        = -1.0;
6060   Standard_Integer toBlackWhite     = -1;
6061   Standard_Integer isBorderFilterOn = -1;
6062   Standard_Boolean isOldSyntax = Standard_False;
6063   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
6064   for (; anArgIter < theArgNb; ++anArgIter)
6065   {
6066     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6067     anArg.LowerCase();
6068     if (anArgIter + 1 < theArgNb
6069      && (anArg == "-toleranceofcolor"
6070       || anArg == "-tolerancecolor"
6071       || anArg == "-tolerance"
6072       || anArg == "-toler"))
6073     {
6074       aTolColor = Atof (theArgVec[++anArgIter]);
6075       if (aTolColor < 0.0 || aTolColor > 1.0)
6076       {
6077         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6078         return 1;
6079       }
6080     }
6081     else if (anArg == "-blackwhite")
6082     {
6083       Standard_Boolean toEnable = Standard_True;
6084       if (anArgIter + 1 < theArgNb
6085        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6086       {
6087         ++anArgIter;
6088       }
6089       toBlackWhite = toEnable ? 1 : 0;
6090     }
6091     else if (anArg == "-borderfilter")
6092     {
6093       Standard_Boolean toEnable = Standard_True;
6094       if (anArgIter + 1 < theArgNb
6095        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6096       {
6097         ++anArgIter;
6098       }
6099       isBorderFilterOn = toEnable ? 1 : 0;
6100     }
6101     else if (anArg == "-exitonclose")
6102     {
6103       ViewerTest_EventManager::ToExitOnCloseView() = true;
6104       if (anArgIter + 1 < theArgNb
6105        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
6106       {
6107         ++anArgIter;
6108       }
6109     }
6110     else if (anArg == "-closeonescape"
6111           || anArg == "-closeonesc")
6112     {
6113       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
6114       if (anArgIter + 1 < theArgNb
6115        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
6116       {
6117         ++anArgIter;
6118       }
6119     }
6120     else if (anArgIter + 3 < theArgNb
6121           && anArg == "-display")
6122     {
6123       aViewName   = theArgVec[++anArgIter];
6124       aPrsNameRef = theArgVec[++anArgIter];
6125       aPrsNameNew = theArgVec[++anArgIter];
6126       if (anArgIter + 1 < theArgNb
6127       && *theArgVec[anArgIter + 1] != '-')
6128       {
6129         aPrsNameDiff = theArgVec[++anArgIter];
6130       }
6131     }
6132     else if (aTolColor < 0.0
6133           && anArg.IsRealValue (Standard_True))
6134     {
6135       isOldSyntax = Standard_True;
6136       aTolColor = anArg.RealValue();
6137       if (aTolColor < 0.0 || aTolColor > 1.0)
6138       {
6139         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6140         return 1;
6141       }
6142     }
6143     else if (isOldSyntax
6144           && toBlackWhite == -1
6145           && (anArg == "0" || anArg == "1"))
6146     {
6147       toBlackWhite = anArg == "1" ? 1 : 0;
6148     }
6149     else if (isOldSyntax
6150           && isBorderFilterOn == -1
6151           && (anArg == "0" || anArg == "1"))
6152     {
6153       isBorderFilterOn = anArg == "1" ? 1 : 0;
6154     }
6155     else if (aDiffImagePath.IsEmpty())
6156     {
6157       aDiffImagePath = theArgVec[anArgIter];
6158     }
6159     else
6160     {
6161       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6162       return 1;
6163     }
6164   }
6165
6166   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
6167   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
6168   if (!anImgRef->Load (anImgPathRef))
6169   {
6170     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
6171     return 1;
6172   }
6173   if (!anImgNew->Load (anImgPathNew))
6174   {
6175     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
6176     return 1;
6177   }
6178
6179   // compare the images
6180   Image_Diff aComparer;
6181   Standard_Integer aDiffColorsNb = -1;
6182   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
6183   {
6184     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
6185     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
6186     aDiffColorsNb = aComparer.Compare();
6187     theDI << aDiffColorsNb << "\n";
6188   }
6189
6190   // save image of difference
6191   Handle(Image_AlienPixMap) aDiff;
6192   if (aDiffColorsNb > 0
6193   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
6194   {
6195     aDiff = new Image_AlienPixMap();
6196     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
6197     {
6198       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
6199       return 1;
6200     }
6201     aComparer.SaveDiffImage (*aDiff);
6202     if (!aDiffImagePath.IsEmpty()
6203      && !aDiff->Save (aDiffImagePath))
6204     {
6205       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
6206       return 1;
6207     }
6208   }
6209
6210   if (aViewName.IsEmpty())
6211   {
6212     return 0;
6213   }
6214
6215   ViewerTest_Names aViewNames (aViewName);
6216   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
6217   {
6218     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
6219     theDI.Eval (aCommand.ToCString());
6220   }
6221
6222   ViewerTest_VinitParams aParams;
6223   aParams.ViewName = aViewName;
6224   aParams.Size.x() = float(anImgRef->SizeX() * 2);
6225   aParams.Size.y() = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
6226                    ? float(anImgRef->SizeY() * 2)
6227                    : float(anImgRef->SizeY());
6228   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aParams);
6229
6230   Standard_Real aRatio = anImgRef->Ratio();
6231   Standard_Real aSizeX = 1.0;
6232   Standard_Real aSizeY = aSizeX / aRatio;
6233   {
6234     OSD_Path aPath (anImgPathRef);
6235     TCollection_AsciiString aLabelRef;
6236     if (!aPath.Name().IsEmpty())
6237     {
6238       aLabelRef = aPath.Name() + aPath.Extension();
6239     }
6240     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
6241
6242     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
6243     gp_Trsf aTrsfRef;
6244     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
6245     anImgRefPrs->SetLocalTransformation (aTrsfRef);
6246     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
6247   }
6248   {
6249     OSD_Path aPath (anImgPathNew);
6250     TCollection_AsciiString aLabelNew;
6251     if (!aPath.Name().IsEmpty())
6252     {
6253       aLabelNew = aPath.Name() + aPath.Extension();
6254     }
6255     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
6256
6257     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
6258     gp_Trsf aTrsfRef;
6259     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
6260     anImgNewPrs->SetLocalTransformation (aTrsfRef);
6261     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
6262   }
6263   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
6264   if (!aDiff.IsNull())
6265   {
6266     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
6267     gp_Trsf aTrsfDiff;
6268     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
6269     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
6270   }
6271   if (!aPrsNameDiff.IsEmpty())
6272   {
6273     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
6274   }
6275   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
6276   ViewerTest::CurrentView()->FitAll();
6277   return 0;
6278 }
6279
6280 //=======================================================================
6281 //function : VSelect
6282 //purpose  : Emulates different types of selection by mouse:
6283 //           1) single click selection
6284 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
6285 //           3) selection with polygon having corners at
6286 //           pixel positions (x1,y1),...,(xn,yn)
6287 //           4) any of these selections with shift button pressed
6288 //=======================================================================
6289 static Standard_Integer VSelect (Draw_Interpretor& ,
6290                                  Standard_Integer theNbArgs,
6291                                  const char** theArgVec)
6292 {
6293   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
6294   if (aCtx.IsNull())
6295   {
6296     Message::SendFail ("Error: no active viewer");
6297     return 1;
6298   }
6299
6300   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
6301   bool toAllowOverlap = false;
6302   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
6303   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6304   {
6305     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6306     anArg.LowerCase();
6307     if (anArg == "-allowoverlap")
6308     {
6309       toAllowOverlap = true;
6310       if (anArgIter + 1 < theNbArgs
6311        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
6312       {
6313         ++anArgIter;
6314       }
6315     }
6316     else if (anArg == "-replace")
6317     {
6318       aSelScheme = AIS_SelectionScheme_Replace;
6319     }
6320     else if (anArg == "-replaceextra")
6321     {
6322       aSelScheme = AIS_SelectionScheme_ReplaceExtra;
6323     }
6324     else if (anArg == "-xor"
6325           || anArg == "-shift")
6326     {
6327       aSelScheme = AIS_SelectionScheme_XOR;
6328     }
6329     else if (anArg == "-add")
6330     {
6331       aSelScheme = AIS_SelectionScheme_Add;
6332     }
6333     else if (anArg == "-remove")
6334     {
6335       aSelScheme = AIS_SelectionScheme_Remove;
6336     }
6337     else if (anArgIter + 1 < theNbArgs
6338           && anArg.IsIntegerValue()
6339           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
6340     {
6341       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
6342       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
6343     }
6344     else if (anArgIter + 1 == theNbArgs
6345           && anArg.IsIntegerValue())
6346     {
6347       if (anArg.IntegerValue() == 1)
6348       {
6349         aSelScheme = AIS_SelectionScheme_XOR;
6350       }
6351     }
6352     else
6353     {
6354       Message::SendFail() << "Syntax error at '" << anArg << "'";
6355       return 1;
6356     }
6357   }
6358
6359   if (toAllowOverlap)
6360   {
6361     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
6362   }
6363
6364   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
6365   if (aPnts.IsEmpty())
6366   {
6367     aCtx->SelectDetected (aSelScheme);
6368     aCtx->CurrentViewer()->Invalidate();
6369   }
6370   else if (aPnts.Length() == 2)
6371   {
6372     if (toAllowOverlap
6373      && aPnts.First().y() < aPnts.Last().y())
6374     {
6375       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6376     }
6377     else if (!toAllowOverlap
6378            && aPnts.First().y() > aPnts.Last().y())
6379     {
6380       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6381     }
6382
6383     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6384   }
6385   else
6386   {
6387     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6388   }
6389   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
6390   return 0;
6391 }
6392
6393 //=======================================================================
6394 //function : VMoveTo
6395 //purpose  : Emulates cursor movement to defined pixel position
6396 //=======================================================================
6397 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
6398                                 Standard_Integer theNbArgs,
6399                                 const char**     theArgVec)
6400 {
6401   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6402   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6403   if (aContext.IsNull())
6404   {
6405     Message::SendFail ("Error: no active viewer");
6406     return 1;
6407   }
6408
6409   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
6410   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6411   {
6412     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6413     anArgStr.LowerCase();
6414     if (anArgStr == "-reset"
6415      || anArgStr == "-clear")
6416     {
6417       if (anArgIter + 1 < theNbArgs)
6418       {
6419         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
6420         return 1;
6421       }
6422
6423       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
6424                                        && aContext->CurrentViewer()->GridEcho();
6425       if (toEchoGrid)
6426       {
6427         aContext->CurrentViewer()->HideGridEcho (aView);
6428       }
6429       if (aContext->ClearDetected() || toEchoGrid)
6430       {
6431         aContext->CurrentViewer()->RedrawImmediate();
6432       }
6433       return 0;
6434     }
6435     else if (aMousePos.x() == IntegerLast()
6436           && anArgStr.IsIntegerValue())
6437     {
6438       aMousePos.x() = anArgStr.IntegerValue();
6439     }
6440     else if (aMousePos.y() == IntegerLast()
6441           && anArgStr.IsIntegerValue())
6442     {
6443       aMousePos.y() = anArgStr.IntegerValue();
6444     }
6445     else
6446     {
6447       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6448       return 1;
6449     }
6450   }
6451
6452   if (aMousePos.x() == IntegerLast()
6453    || aMousePos.y() == IntegerLast())
6454   {
6455     Message::SendFail ("Syntax error: wrong number of arguments");
6456     return 1;
6457   }
6458
6459   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
6460   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
6461   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
6462
6463   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
6464   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
6465   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
6466   {
6467     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
6468     {
6469       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
6470       break;
6471     }
6472   }
6473   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
6474   return 0;
6475 }
6476
6477 //=======================================================================
6478 //function : VSelectByAxis
6479 //purpose  :
6480 //=======================================================================
6481 static Standard_Integer VSelectByAxis (Draw_Interpretor& theDI,
6482                                        Standard_Integer theNbArgs,
6483                                        const char**     theArgVec)
6484 {
6485   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6486   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6487   if (aContext.IsNull())
6488   {
6489     Message::SendFail ("Error: no active viewer");
6490     return 1;
6491   }
6492
6493   TCollection_AsciiString aName;
6494   gp_XYZ anAxisLocation(RealLast(), RealLast(), RealLast());
6495   gp_XYZ anAxisDirection(RealLast(), RealLast(), RealLast());
6496   Standard_Boolean isOnlyTop = true;
6497   Standard_Boolean toShowNormal = false;
6498   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6499   {
6500     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6501     anArgStr.LowerCase();
6502     if (anArgStr == "-display")
6503     {
6504       if (anArgIter + 1 >= theNbArgs)
6505       {
6506         Message::SendFail() << "Syntax error at argument '" << anArgStr << "'";
6507         return 1;
6508       }
6509       aName = theArgVec[++anArgIter];
6510     }
6511     else if (anArgStr == "-onlytop")
6512     {
6513       isOnlyTop = true;
6514       if (anArgIter + 1 < theNbArgs
6515         && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOnlyTop))
6516       {
6517         ++anArgIter;
6518       }
6519     }
6520     else if (anArgStr == "-shownormal")
6521     {
6522       toShowNormal = true;
6523       if (anArgIter + 1 < theNbArgs
6524         && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShowNormal))
6525       {
6526         ++anArgIter;
6527       }
6528     }
6529     else if (Precision::IsInfinite(anAxisLocation.X())
6530           && anArgStr.IsRealValue())
6531     {
6532       anAxisLocation.SetX (anArgStr.RealValue());
6533     }
6534     else if (Precision::IsInfinite(anAxisLocation.Y())
6535           && anArgStr.IsRealValue())
6536     {
6537       anAxisLocation.SetY (anArgStr.RealValue());
6538     }
6539     else if (Precision::IsInfinite(anAxisLocation.Z())
6540           && anArgStr.IsRealValue())
6541     {
6542       anAxisLocation.SetZ (anArgStr.RealValue());
6543     }
6544     else if (Precision::IsInfinite(anAxisDirection.X())
6545           && anArgStr.IsRealValue())
6546     {
6547       anAxisDirection.SetX (anArgStr.RealValue());
6548     }
6549     else if (Precision::IsInfinite(anAxisDirection.Y())
6550           && anArgStr.IsRealValue())
6551     {
6552       anAxisDirection.SetY (anArgStr.RealValue());
6553     }
6554     else if (Precision::IsInfinite(anAxisDirection.Z())
6555           && anArgStr.IsRealValue())
6556     {
6557       anAxisDirection.SetZ (anArgStr.RealValue());
6558     }
6559     else
6560     {
6561       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6562       return 1;
6563     }
6564   }
6565
6566   if (Precision::IsInfinite (anAxisLocation.X()) ||
6567       Precision::IsInfinite (anAxisLocation.Y()) ||
6568       Precision::IsInfinite (anAxisLocation.Z()) ||
6569       Precision::IsInfinite (anAxisDirection.X()) ||
6570       Precision::IsInfinite (anAxisDirection.Y()) ||
6571       Precision::IsInfinite (anAxisDirection.Z()))
6572   {
6573     Message::SendFail() << "Invalid axis location and direction";
6574     return 1;
6575   }
6576
6577   gp_Ax1 anAxis(anAxisLocation, anAxisDirection);
6578   gp_Pnt aTopPnt;
6579   if (!ViewerTest::CurrentEventManager()->PickAxis (aTopPnt, aContext, aView, anAxis))
6580   {
6581     theDI << "There are no any intersections with this axis.";
6582     return 0;
6583   }
6584   NCollection_Sequence<gp_Pnt> aPoints;
6585   NCollection_Sequence<Graphic3d_Vec3> aNormals;
6586   NCollection_Sequence<Standard_Real> aNormalLengths;
6587   for (Standard_Integer aPickIter = 1; aPickIter <= aContext->MainSelector()->NbPicked(); ++aPickIter)
6588   {
6589     const SelectMgr_SortCriterion& aPickedData = aContext->MainSelector()->PickedData (aPickIter);
6590     aPoints.Append (aPickedData.Point);
6591     aNormals.Append (aPickedData.Normal);
6592     Standard_Real aNormalLength = 1.0;
6593     if (!aPickedData.Entity.IsNull())
6594     {
6595       aNormalLength = 0.2 * aPickedData.Entity->BoundingBox().Size().maxComp();
6596     }
6597     aNormalLengths.Append (aNormalLength);
6598   }
6599   if (!aName.IsEmpty())
6600   {
6601     Standard_Boolean wasAuto = aContext->GetAutoActivateSelection();
6602     aContext->SetAutoActivateSelection (false);
6603
6604     // Display axis
6605     Quantity_Color anAxisColor = Quantity_NOC_GREEN;
6606     Handle(Geom_Axis2Placement) anAx2Axis =
6607       new Geom_Axis2Placement (gp_Ax2(anAxisLocation, anAxisDirection));
6608     Handle(AIS_Axis) anAISAxis = new AIS_Axis (gp_Ax1 (anAxisLocation, anAxisDirection));
6609     anAISAxis->SetColor (anAxisColor);
6610     ViewerTest::Display (TCollection_AsciiString (aName) + "_axis", anAISAxis, false);
6611
6612     // Display axis start point
6613     Handle(AIS_Point) anAISStartPnt = new AIS_Point (new Geom_CartesianPoint (anAxisLocation));
6614     anAISStartPnt->SetMarker (Aspect_TOM_O);
6615     anAISStartPnt->SetColor (anAxisColor);
6616     ViewerTest::Display (TCollection_AsciiString(aName) + "_start", anAISStartPnt, false);
6617
6618     Standard_Integer anIndex = 0;
6619     for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter(aPoints); aPntIter.More(); aPntIter.Next(), anIndex++)
6620     {
6621       const gp_Pnt& aPoint = aPntIter.Value();
6622
6623       // Display normals in intersection points
6624       if (toShowNormal)
6625       {
6626         const Graphic3d_Vec3& aNormal = aNormals.Value (anIndex + 1);
6627         Standard_Real aNormalLength = aNormalLengths.Value (anIndex + 1);
6628         if (aNormal.SquareModulus() > ShortRealEpsilon())
6629         {
6630           gp_Dir aNormalDir ((Standard_Real)aNormal.x(), (Standard_Real)aNormal.y(), (Standard_Real)aNormal.z());
6631           Handle(AIS_Axis) anAISNormal = new AIS_Axis (gp_Ax1 (aPoint, aNormalDir), aNormalLength);
6632           anAISNormal->SetColor (Quantity_NOC_BLUE);
6633           anAISNormal->SetInfiniteState (false);
6634           ViewerTest::Display (TCollection_AsciiString(aName) + "_normal_" + anIndex, anAISNormal, false);
6635         }
6636       }
6637
6638       // Display intersection points
6639       Handle(Geom_CartesianPoint) anIntersectPnt = new Geom_CartesianPoint (aPoint);
6640       Handle(AIS_Point) anAISIntersectPoint = new AIS_Point (anIntersectPnt);
6641       anAISIntersectPoint->SetMarker (Aspect_TOM_PLUS);
6642       anAISIntersectPoint->SetColor (Quantity_NOC_RED);
6643       ViewerTest::Display (TCollection_AsciiString(aName) + "_intersect_" + anIndex, anAISIntersectPoint, true);
6644     }
6645
6646     aContext->SetAutoActivateSelection (wasAuto);
6647   }
6648
6649   Standard_Integer anIndex = 0;
6650   for (NCollection_Sequence<gp_Pnt>::Iterator anIter(aPoints); anIter.More(); anIter.Next(), anIndex++)
6651   {
6652     const gp_Pnt& aPnt = anIter.Value();
6653     theDI << aPnt.X() << " " << aPnt.Y() << " " << aPnt.Z() << "\n";
6654   }
6655   return 0;
6656 }
6657
6658 namespace
6659 {
6660   //! Global map storing all animations registered in ViewerTest.
6661   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
6662
6663   //! The animation calling the Draw Harness command.
6664   class ViewerTest_AnimationProc : public AIS_Animation
6665   {
6666     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationProc, AIS_Animation)
6667   public:
6668
6669     //! Main constructor.
6670     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
6671                               Draw_Interpretor* theDI,
6672                               const TCollection_AsciiString& theCommand)
6673     : AIS_Animation (theAnimationName),
6674       myDrawInter(theDI),
6675       myCommand  (theCommand)
6676     {
6677       //
6678     }
6679
6680   protected:
6681
6682     //! Evaluate the command.
6683     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
6684     {
6685       TCollection_AsciiString aCmd = myCommand;
6686       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
6687       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
6688       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
6689       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
6690       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
6691       myDrawInter->Eval (aCmd.ToCString());
6692     }
6693
6694     //! Find the keyword in the command and replace it with value.
6695     //! @return the position of the keyword to pass value
6696     void replace (TCollection_AsciiString&       theCmd,
6697                   const TCollection_AsciiString& theKey,
6698                   const TCollection_AsciiString& theVal)
6699     {
6700       TCollection_AsciiString aCmd (theCmd);
6701       aCmd.LowerCase();
6702       const Standard_Integer aPos = aCmd.Search (theKey);
6703       if (aPos == -1)
6704       {
6705         return;
6706       }
6707
6708       TCollection_AsciiString aPart1, aPart2;
6709       Standard_Integer aPart1To = aPos - 1;
6710       if (aPart1To >= 1
6711        && aPart1To <= theCmd.Length())
6712       {
6713         aPart1 = theCmd.SubString (1, aPart1To);
6714       }
6715
6716       Standard_Integer aPart2From = aPos + theKey.Length();
6717       if (aPart2From >= 1
6718        && aPart2From <= theCmd.Length())
6719       {
6720         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
6721       }
6722
6723       theCmd = aPart1 + theVal + aPart2;
6724     }
6725
6726   protected:
6727
6728     Draw_Interpretor*       myDrawInter;
6729     TCollection_AsciiString myCommand;
6730
6731   };
6732
6733   //! Auxiliary animation holder.
6734   class ViewerTest_AnimationHolder : public AIS_AnimationCamera
6735   {
6736     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationHolder, AIS_AnimationCamera)
6737   public:
6738     ViewerTest_AnimationHolder (const Handle(AIS_Animation)& theAnim,
6739                                 const Handle(V3d_View)& theView,
6740                                 const Standard_Boolean theIsFreeView)
6741     : AIS_AnimationCamera ("ViewerTest_AnimationHolder", Handle(V3d_View)())
6742     {
6743       if (theAnim->Timer().IsNull())
6744       {
6745         theAnim->SetTimer (new Media_Timer());
6746       }
6747       myTimer = theAnim->Timer();
6748       myView = theView;
6749       if (theIsFreeView)
6750       {
6751         myCamStart = new Graphic3d_Camera (theView->Camera());
6752       }
6753       Add (theAnim);
6754     }
6755
6756     //! Start playback.
6757     virtual void StartTimer (const Standard_Real    theStartPts,
6758                              const Standard_Real    thePlaySpeed,
6759                              const Standard_Boolean theToUpdate,
6760                              const Standard_Boolean theToStopTimer) Standard_OVERRIDE
6761     {
6762       base_type::StartTimer (theStartPts, thePlaySpeed, theToUpdate, theToStopTimer);
6763       if (theToStopTimer)
6764       {
6765         abortPlayback();
6766       }
6767     }
6768
6769     //! Pause animation.
6770     virtual void Pause() Standard_OVERRIDE
6771     {
6772       myState = AnimationState_Paused;
6773       // default implementation would stop all children,
6774       // but we want to keep wrapped animation paused
6775       myAnimations.First()->Pause();
6776       abortPlayback();
6777     }
6778
6779     //! Stop animation.
6780     virtual void Stop() Standard_OVERRIDE
6781     {
6782       base_type::Stop();
6783       abortPlayback();
6784     }
6785
6786     //! Process one step of the animation according to the input time progress, including all children.
6787     virtual void updateWithChildren (const AIS_AnimationProgress& thePosition) Standard_OVERRIDE
6788     {
6789       Handle(V3d_View) aView = myView;
6790       if (!aView.IsNull()
6791        && !myCamStart.IsNull())
6792       {
6793         myCamStart->Copy (aView->Camera());
6794       }
6795       base_type::updateWithChildren (thePosition);
6796       if (!aView.IsNull()
6797        && !myCamStart.IsNull())
6798       {
6799         aView->Camera()->Copy (myCamStart);
6800       }
6801     }
6802   private:
6803     void abortPlayback()
6804     {
6805       if (!myView.IsNull())
6806       {
6807         myView.Nullify();
6808       }
6809     }
6810   };
6811
6812   //! Replace the animation with the new one.
6813   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
6814                                 Handle(AIS_Animation)&       theAnimation,
6815                                 const Handle(AIS_Animation)& theAnimationNew)
6816   {
6817     theAnimationNew->CopyFrom (theAnimation);
6818     if (!theParentAnimation.IsNull())
6819     {
6820       theParentAnimation->Replace (theAnimation, theAnimationNew);
6821     }
6822     else
6823     {
6824       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
6825       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
6826     }
6827     theAnimation = theAnimationNew;
6828   }
6829
6830   //! Parse the point.
6831   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
6832   {
6833     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
6834     if (!anXYZ[0].IsRealValue (Standard_True)
6835      || !anXYZ[1].IsRealValue (Standard_True)
6836      || !anXYZ[2].IsRealValue (Standard_True))
6837     {
6838       return Standard_False;
6839     }
6840
6841     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
6842     return Standard_True;
6843   }
6844
6845   //! Parse the quaternion.
6846   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
6847   {
6848     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
6849     if (!anXYZW[0].IsRealValue (Standard_True)
6850      || !anXYZW[1].IsRealValue (Standard_True)
6851      || !anXYZW[2].IsRealValue (Standard_True)
6852      || !anXYZW[3].IsRealValue (Standard_True))
6853     {
6854       return Standard_False;
6855     }
6856
6857     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
6858     return Standard_True;
6859   }
6860
6861   //! Auxiliary class for flipping image upside-down.
6862   class ImageFlipper
6863   {
6864   public:
6865
6866     //! Empty constructor.
6867     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
6868
6869     //! Perform flipping.
6870     Standard_Boolean FlipY (Image_PixMap& theImage)
6871     {
6872       if (theImage.IsEmpty()
6873        || theImage.SizeX() == 0
6874        || theImage.SizeY() == 0)
6875       {
6876         return Standard_False;
6877       }
6878
6879       const Standard_Size aRowSize = theImage.SizeRowBytes();
6880       if (myTmp.Size() < aRowSize
6881       && !myTmp.Allocate (aRowSize))
6882       {
6883         return Standard_False;
6884       }
6885
6886       // for odd height middle row should be left as is
6887       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
6888       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
6889       {
6890         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
6891         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
6892         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
6893         memcpy (aTop,               aBot,         aRowSize);
6894         memcpy (aBot,               myTmp.Data(), aRowSize);
6895       }
6896       return Standard_True;
6897     }
6898
6899   private:
6900     NCollection_Buffer myTmp;
6901   };
6902
6903 }
6904
6905 //=================================================================================================
6906 //function : VViewParams
6907 //purpose  : Gets or sets AIS View characteristics
6908 //=================================================================================================
6909 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
6910 {
6911   Handle(V3d_View) aView = ViewerTest::CurrentView();
6912   if (aView.IsNull())
6913   {
6914     Message::SendFail ("Error: no active viewer");
6915     return 1;
6916   }
6917
6918   Standard_Boolean toSetProj     = Standard_False;
6919   Standard_Boolean toSetUp       = Standard_False;
6920   Standard_Boolean toSetAt       = Standard_False;
6921   Standard_Boolean toSetEye      = Standard_False;
6922   Standard_Boolean toSetScale    = Standard_False;
6923   Standard_Boolean toSetSize     = Standard_False;
6924   Standard_Boolean toSetCenter2d = Standard_False;
6925   Standard_Real    aViewScale = aView->Scale();
6926   Standard_Real    aViewAspect = aView->Camera()->Aspect();
6927   Standard_Real    aViewSize  = 1.0;
6928   Graphic3d_Vec2i  aCenter2d;
6929   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
6930   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
6931   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
6932   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
6933   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
6934   const Graphic3d_Mat4d& anOrientMat = aView->Camera()->OrientationMatrix();
6935   const Graphic3d_Mat4d& aProjMat = aView->Camera()->ProjectionMatrix();
6936   if (theArgsNb == 1)
6937   {
6938     // print all of the available view parameters
6939     char aText[4096];
6940     Sprintf (aText,
6941              "Scale:  %g\n"
6942              "Aspect: %g\n"
6943              "Proj:   %12g %12g %12g\n"
6944              "Up:     %12g %12g %12g\n"
6945              "At:     %12g %12g %12g\n"
6946              "Eye:    %12g %12g %12g\n"
6947              "OrientMat:    %12g %12g %12g %12g\n"
6948              "              %12g %12g %12g %12g\n"
6949              "              %12g %12g %12g %12g\n"
6950              "              %12g %12g %12g %12g\n"
6951              "ProjMat:      %12g %12g %12g %12g\n"
6952              "              %12g %12g %12g %12g\n"
6953              "              %12g %12g %12g %12g\n"
6954              "              %12g %12g %12g %12g\n",
6955               aViewScale, aViewAspect,
6956               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6957               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6958               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
6959               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z(),
6960               anOrientMat.GetValue (0, 0), anOrientMat.GetValue (0, 1), anOrientMat.GetValue (0, 2), anOrientMat.GetValue (0, 3),
6961               anOrientMat.GetValue (1, 0), anOrientMat.GetValue (1, 1), anOrientMat.GetValue (1, 2), anOrientMat.GetValue (1, 3),
6962               anOrientMat.GetValue (2, 0), anOrientMat.GetValue (2, 1), anOrientMat.GetValue (2, 2), anOrientMat.GetValue (2, 3),
6963               anOrientMat.GetValue (3, 0), anOrientMat.GetValue (3, 1), anOrientMat.GetValue (3, 2), anOrientMat.GetValue (3, 3),
6964               aProjMat.GetValue (0, 0), aProjMat.GetValue (0, 1), aProjMat.GetValue (0, 2), aProjMat.GetValue (0, 3),
6965               aProjMat.GetValue (1, 0), aProjMat.GetValue (1, 1), aProjMat.GetValue (1, 2), aProjMat.GetValue (1, 3),
6966               aProjMat.GetValue (2, 0), aProjMat.GetValue (2, 1), aProjMat.GetValue (2, 2), aProjMat.GetValue (2, 3),
6967               aProjMat.GetValue (3, 0), aProjMat.GetValue (3, 1), aProjMat.GetValue (3, 2), aProjMat.GetValue (3, 3));
6968     theDi << aText;
6969     return 0;
6970   }
6971
6972   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
6973   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
6974   {
6975     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6976     anArg.LowerCase();
6977     if (anUpdateTool.parseRedrawMode (anArg))
6978     {
6979       continue;
6980     }
6981     else if (anArg == "-cmd"
6982           || anArg == "-command"
6983           || anArg == "-args")
6984     {
6985       char aText[4096];
6986       Sprintf (aText,
6987                "-scale %g "
6988                "-proj %g %g %g "
6989                "-up %g %g %g "
6990                "-at %g %g %g\n",
6991                 aViewScale,
6992                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6993                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6994                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
6995       theDi << aText;
6996     }
6997     else if (anArg == "-scale"
6998           || anArg == "-size")
6999     {
7000       if (anArgIter + 1 < theArgsNb
7001        && *theArgVec[anArgIter + 1] != '-')
7002       {
7003         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7004         if (aValueArg.IsRealValue (Standard_True))
7005         {
7006           ++anArgIter;
7007           if (anArg == "-scale")
7008           {
7009             toSetScale = Standard_True;
7010             aViewScale = aValueArg.RealValue();
7011           }
7012           else if (anArg == "-size")
7013           {
7014             toSetSize = Standard_True;
7015             aViewSize = aValueArg.RealValue();
7016           }
7017           continue;
7018         }
7019       }
7020       if (anArg == "-scale")
7021       {
7022         theDi << "Scale: " << aView->Scale() << "\n";
7023       }
7024       else if (anArg == "-size")
7025       {
7026         Graphic3d_Vec2d aSizeXY;
7027         aView->Size (aSizeXY.x(), aSizeXY.y());
7028         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
7029       }
7030     }
7031     else if (anArg == "-eye"
7032           || anArg == "-at"
7033           || anArg == "-up"
7034           || anArg == "-proj")
7035     {
7036       if (anArgIter + 3 < theArgsNb)
7037       {
7038         gp_XYZ anXYZ;
7039         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
7040         {
7041           anArgIter += 3;
7042           if (anArg == "-eye")
7043           {
7044             toSetEye = Standard_True;
7045             aViewEye = anXYZ;
7046           }
7047           else if (anArg == "-at")
7048           {
7049             toSetAt = Standard_True;
7050             aViewAt = anXYZ;
7051           }
7052           else if (anArg == "-up")
7053           {
7054             toSetUp = Standard_True;
7055             aViewUp = anXYZ;
7056           }
7057           else if (anArg == "-proj")
7058           {
7059             toSetProj = Standard_True;
7060             aViewProj = anXYZ;
7061           }
7062           continue;
7063         }
7064       }
7065
7066       if (anArg == "-eye")
7067       {
7068         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
7069       }
7070       else if (anArg == "-at")
7071       {
7072         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
7073       }
7074       else if (anArg == "-up")
7075       {
7076         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
7077       }
7078       else if (anArg == "-proj")
7079       {
7080         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
7081       }
7082     }
7083     else if (anArg == "-center")
7084     {
7085       if (anArgIter + 2 < theArgsNb)
7086       {
7087         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
7088         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
7089         if (anX.IsIntegerValue()
7090          && anY.IsIntegerValue())
7091         {
7092           toSetCenter2d = Standard_True;
7093           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
7094         }
7095       }
7096     }
7097     else
7098     {
7099       Message::SendFail() << "Syntax error at '" << anArg << "'";
7100       return 1;
7101     }
7102   }
7103
7104   // change view parameters in proper order
7105   if (toSetScale)
7106   {
7107     aView->SetScale (aViewScale);
7108   }
7109   if (toSetSize)
7110   {
7111     aView->SetSize (aViewSize);
7112   }
7113   if (toSetEye)
7114   {
7115     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
7116   }
7117   if (toSetAt)
7118   {
7119     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
7120   }
7121   if (toSetProj)
7122   {
7123     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
7124   }
7125   if (toSetUp)
7126   {
7127     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
7128   }
7129   if (toSetCenter2d)
7130   {
7131     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
7132   }
7133
7134   return 0;
7135 }
7136
7137 //==============================================================================
7138 //function : V2DMode
7139 //purpose  :
7140 //==============================================================================
7141 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
7142 {
7143   bool is2dMode = true;
7144   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
7145   if (aV3dView.IsNull())
7146   {
7147     Message::SendFail ("Error: no active viewer");
7148     return 1;
7149   }
7150   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
7151   {
7152     const TCollection_AsciiString anArg = theArgVec[anArgIt];
7153     TCollection_AsciiString anArgCase = anArg;
7154     anArgCase.LowerCase();
7155     if (anArgIt + 1 < theArgsNb
7156      && anArgCase == "-name")
7157     {
7158       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
7159       const TCollection_AsciiString& aViewName = aViewNames.GetViewName();
7160       if (!ViewerTest_myViews.IsBound1 (aViewName))
7161       {
7162         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
7163         return 1;
7164       }
7165       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
7166     }
7167     else if (anArgCase == "-mode")
7168     {
7169       if (anArgIt + 1 < theArgsNb
7170        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
7171       {
7172         ++anArgIt;
7173       }
7174     }
7175     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
7176     {
7177       //
7178     }
7179     else
7180     {
7181       Message::SendFail() << "Syntax error: unknown argument " << anArg;
7182       return 1;
7183     }
7184   }
7185
7186   aV3dView->SetView2DMode (is2dMode);
7187   return 0;
7188 }
7189
7190 //==============================================================================
7191 //function : VAnimation
7192 //purpose  :
7193 //==============================================================================
7194 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
7195                                     Standard_Integer  theArgNb,
7196                                     const char**      theArgVec)
7197 {
7198   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
7199   if (theArgNb < 2)
7200   {
7201     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
7202          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
7203     {
7204       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
7205     }
7206     return 0;
7207   }
7208   if (aCtx.IsNull())
7209   {
7210     Message::SendFail ("Error: no active viewer");
7211     return 1;
7212   }
7213
7214   Standard_Integer anArgIter = 1;
7215   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
7216   if (aNameArg.IsEmpty())
7217   {
7218     Message::SendFail ("Syntax error: animation name is not defined");
7219     return 1;
7220   }
7221
7222   TCollection_AsciiString aNameArgLower = aNameArg;
7223   aNameArgLower.LowerCase();
7224   if (aNameArgLower == "-reset"
7225    || aNameArgLower == "-clear")
7226   {
7227     ViewerTest_AnimationTimelineMap.Clear();
7228     return 0;
7229   }
7230   else if (aNameArg.Value (1) == '-')
7231   {
7232     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
7233     return 1;
7234   }
7235
7236   const char* aNameSplitter = "/";
7237   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
7238   if (aSplitPos == -1)
7239   {
7240     aNameSplitter = ".";
7241     aSplitPos = aNameArg.Search (aNameSplitter);
7242   }
7243
7244   // find existing or create a new animation by specified name within syntax "parent.child".
7245   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
7246   for (; !aNameArg.IsEmpty();)
7247   {
7248     TCollection_AsciiString aNameParent;
7249     if (aSplitPos != -1)
7250     {
7251       if (aSplitPos == aNameArg.Length())
7252       {
7253         Message::SendFail ("Syntax error: animation name is not defined");
7254         return 1;
7255       }
7256
7257       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
7258       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
7259
7260       aSplitPos = aNameArg.Search (aNameSplitter);
7261     }
7262     else
7263     {
7264       aNameParent = aNameArg;
7265       aNameArg.Clear();
7266     }
7267
7268     if (anAnimation.IsNull())
7269     {
7270       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
7271       {
7272         anAnimation = new AIS_Animation (aNameParent);
7273         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
7274       }
7275       aRootAnimation = anAnimation;
7276     }
7277     else
7278     {
7279       aParentAnimation = anAnimation;
7280       anAnimation = aParentAnimation->Find (aNameParent);
7281       if (anAnimation.IsNull())
7282       {
7283         anAnimation = new AIS_Animation (aNameParent);
7284         aParentAnimation->Add (anAnimation);
7285       }
7286     }
7287   }
7288   if (anAnimation.IsNull())
7289   {
7290     Message::SendFail() << "Syntax error: wrong number of arguments";
7291     return 1;
7292   }
7293
7294   if (anArgIter >= theArgNb)
7295   {
7296     // just print the list of children
7297     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
7298     {
7299       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
7300     }
7301     return 0;
7302   }
7303
7304   // animation parameters
7305   Standard_Boolean toPlay = Standard_False;
7306   Standard_Real aPlaySpeed     = 1.0;
7307   Standard_Real aPlayStartTime = anAnimation->StartPts();
7308   Standard_Real aPlayDuration  = anAnimation->Duration();
7309   Standard_Boolean isFreeCamera   = Standard_False;
7310   Standard_Boolean toPauseOnClick = Standard_True;
7311   Standard_Boolean isLockLoop     = Standard_False;
7312   Standard_Boolean toPrintElapsedTime = Standard_False;
7313
7314   // video recording parameters
7315   TCollection_AsciiString aRecFile;
7316   Image_VideoParams aRecParams;
7317
7318   Handle(V3d_View) aView = ViewerTest::CurrentView();
7319   for (; anArgIter < theArgNb; ++anArgIter)
7320   {
7321     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7322     anArg.LowerCase();
7323     // general options
7324     if (anArg == "-reset"
7325      || anArg == "-clear")
7326     {
7327       anAnimation->Clear();
7328     }
7329     else if (anArg == "-remove"
7330           || anArg == "-del"
7331           || anArg == "-delete")
7332     {
7333       if (aParentAnimation.IsNull())
7334       {
7335         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
7336       }
7337       else
7338       {
7339         aParentAnimation->Remove (anAnimation);
7340       }
7341     }
7342     // playback options
7343     else if (anArg == "-play")
7344     {
7345       toPlay = Standard_True;
7346       if (++anArgIter < theArgNb)
7347       {
7348         if (*theArgVec[anArgIter] == '-')
7349         {
7350           --anArgIter;
7351           continue;
7352         }
7353         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
7354
7355         if (++anArgIter < theArgNb)
7356         {
7357           if (*theArgVec[anArgIter] == '-')
7358           {
7359             --anArgIter;
7360             continue;
7361           }
7362           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7363         }
7364       }
7365     }
7366     else if (anArg == "-elapsedtime"
7367           || anArg == "-elapsed")
7368     {
7369       toPrintElapsedTime = Standard_True;
7370     }
7371     else if (anArg == "-resume")
7372     {
7373       toPlay = Standard_True;
7374       aPlayStartTime = anAnimation->ElapsedTime();
7375       if (++anArgIter < theArgNb)
7376       {
7377         if (*theArgVec[anArgIter] == '-')
7378         {
7379           --anArgIter;
7380           continue;
7381         }
7382
7383         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7384       }
7385     }
7386     else if (anArg == "-pause")
7387     {
7388       anAnimation->Pause();
7389     }
7390     else if (anArg == "-stop")
7391     {
7392       anAnimation->Stop();
7393     }
7394     else if (anArg == "-playspeed"
7395           || anArg == "-speed")
7396     {
7397       if (++anArgIter >= theArgNb)
7398       {
7399         Message::SendFail() << "Syntax error at " << anArg << "";
7400         return 1;
7401       }
7402       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
7403     }
7404     else if (anArg == "-lock"
7405           || anArg == "-lockloop"
7406           || anArg == "-playlockloop")
7407     {
7408       isLockLoop = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
7409     }
7410     else if (anArg == "-freecamera"
7411           || anArg == "-nofreecamera"
7412           || anArg == "-playfreecamera"
7413           || anArg == "-noplayfreecamera"
7414           || anArg == "-freelook"
7415           || anArg == "-nofreelook")
7416     {
7417       isFreeCamera = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7418     }
7419     else if (anArg == "-pauseonclick"
7420           || anArg == "-nopauseonclick"
7421           || anArg == "-nopause")
7422     {
7423       toPauseOnClick = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7424     }
7425     // video recodring options
7426     else if (anArg == "-rec"
7427           || anArg == "-record")
7428     {
7429       if (++anArgIter >= theArgNb)
7430       {
7431         Message::SendFail() << "Syntax error at " << anArg;
7432         return 1;
7433       }
7434
7435       aRecFile = theArgVec[anArgIter];
7436       if (aRecParams.FpsNum <= 0)
7437       {
7438         aRecParams.FpsNum = 24;
7439       }
7440
7441       if (anArgIter + 2 < theArgNb
7442       && *theArgVec[anArgIter + 1] != '-'
7443       && *theArgVec[anArgIter + 2] != '-')
7444       {
7445         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
7446         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
7447         if (aWidthArg .IsIntegerValue()
7448          && aHeightArg.IsIntegerValue())
7449         {
7450           aRecParams.Width  = aWidthArg .IntegerValue();
7451           aRecParams.Height = aHeightArg.IntegerValue();
7452           anArgIter += 2;
7453         }
7454       }
7455     }
7456     else if (anArg == "-fps")
7457     {
7458       if (++anArgIter >= theArgNb)
7459       {
7460         Message::SendFail() << "Syntax error at " << anArg;
7461         return 1;
7462       }
7463
7464       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
7465       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
7466       if (aSplitIndex == 0)
7467       {
7468         aRecParams.FpsNum = aFpsArg.IntegerValue();
7469       }
7470       else
7471       {
7472         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
7473         aFpsArg.Split (aFpsArg.Length() - 1);
7474         const TCollection_AsciiString aNumStr = aFpsArg;
7475         aRecParams.FpsNum = aNumStr.IntegerValue();
7476         aRecParams.FpsDen = aDenStr.IntegerValue();
7477         if (aRecParams.FpsDen < 1)
7478         {
7479           Message::SendFail() << "Syntax error at " << anArg;
7480           return 1;
7481         }
7482       }
7483     }
7484     else if (anArg == "-format")
7485     {
7486       if (++anArgIter >= theArgNb)
7487       {
7488         Message::SendFail() << "Syntax error at " << anArg;
7489         return 1;
7490       }
7491       aRecParams.Format = theArgVec[anArgIter];
7492     }
7493     else if (anArg == "-pix_fmt"
7494           || anArg == "-pixfmt"
7495           || anArg == "-pixelformat")
7496     {
7497       if (++anArgIter >= theArgNb)
7498       {
7499         Message::SendFail() << "Syntax error at " << anArg;
7500         return 1;
7501       }
7502       aRecParams.PixelFormat = theArgVec[anArgIter];
7503     }
7504     else if (anArg == "-codec"
7505           || anArg == "-vcodec"
7506           || anArg == "-videocodec")
7507     {
7508       if (++anArgIter >= theArgNb)
7509       {
7510         Message::SendFail() << "Syntax error at " << anArg;
7511         return 1;
7512       }
7513       aRecParams.VideoCodec = theArgVec[anArgIter];
7514     }
7515     else if (anArg == "-crf"
7516           || anArg == "-preset"
7517           || anArg == "-qp")
7518     {
7519       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
7520       if (++anArgIter >= theArgNb)
7521       {
7522         Message::SendFail() << "Syntax error at " << anArg;
7523         return 1;
7524       }
7525
7526       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
7527     }
7528     // animation definition options
7529     else if (anArg == "-start"
7530           || anArg == "-starttime"
7531           || anArg == "-startpts")
7532     {
7533       if (++anArgIter >= theArgNb)
7534       {
7535         Message::SendFail() << "Syntax error at " << anArg;
7536         return 1;
7537       }
7538
7539       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
7540       aRootAnimation->UpdateTotalDuration();
7541     }
7542     else if (anArg == "-end"
7543           || anArg == "-endtime"
7544           || anArg == "-endpts")
7545     {
7546       if (++anArgIter >= theArgNb)
7547       {
7548         Message::SendFail() << "Syntax error at " << anArg;
7549         return 1;
7550       }
7551
7552       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
7553       aRootAnimation->UpdateTotalDuration();
7554     }
7555     else if (anArg == "-dur"
7556           || anArg == "-duration")
7557     {
7558       if (++anArgIter >= theArgNb)
7559       {
7560         Message::SendFail() << "Syntax error at " << anArg;
7561         return 1;
7562       }
7563
7564       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
7565       aRootAnimation->UpdateTotalDuration();
7566     }
7567     else if (anArg == "-command"
7568           || anArg == "-cmd"
7569           || anArg == "-invoke"
7570           || anArg == "-eval"
7571           || anArg == "-proc")
7572     {
7573       if (++anArgIter >= theArgNb)
7574       {
7575         Message::SendFail() << "Syntax error at " << anArg;
7576         return 1;
7577       }
7578
7579       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
7580       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
7581     }
7582     else if (anArg == "-objecttrsf"
7583           || anArg == "-objectransformation"
7584           || anArg == "-objtransformation"
7585           || anArg == "-objtrsf"
7586           || anArg == "-object"
7587           || anArg == "-obj")
7588     {
7589       if (++anArgIter >= theArgNb)
7590       {
7591         Message::SendFail() << "Syntax error at " << anArg;
7592         return 1;
7593       }
7594
7595       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
7596       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
7597       Handle(AIS_InteractiveObject) anObject;
7598       if (!aMapOfAIS.Find2 (anObjName, anObject))
7599       {
7600         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
7601         return 1;
7602       }
7603
7604       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
7605       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
7606       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
7607       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
7608       Standard_Boolean isTrsfSet = Standard_False;
7609
7610       gp_Ax1 anAxis;
7611       Standard_Real anAngles[2] = { 0.0, 0.0 };
7612       Standard_Boolean isAxisRotationSet = Standard_False;
7613
7614       Standard_Integer aTrsfArgIter = anArgIter + 1;
7615       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
7616       {
7617         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
7618         aTrsfArg.LowerCase();
7619         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
7620         if (aTrsfArg.StartsWith ("-rotation")
7621          || aTrsfArg.StartsWith ("-rot"))
7622         {
7623           isTrsfSet = Standard_True;
7624           if (aTrsfArgIter + 4 >= theArgNb
7625           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
7626           {
7627             Message::SendFail() << "Syntax error at " << aTrsfArg;
7628             return 1;
7629           }
7630           aTrsfArgIter += 4;
7631         }
7632         else if (aTrsfArg.StartsWith ("-location")
7633               || aTrsfArg.StartsWith ("-loc"))
7634         {
7635           isTrsfSet = Standard_True;
7636           if (aTrsfArgIter + 3 >= theArgNb
7637           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
7638           {
7639             Message::SendFail() << "Syntax error at " << aTrsfArg;
7640             return 1;
7641           }
7642           aTrsfArgIter += 3;
7643         }
7644         else if (aTrsfArg.StartsWith ("-scale"))
7645         {
7646           isTrsfSet = Standard_True;
7647           if (++aTrsfArgIter >= theArgNb)
7648           {
7649             Message::SendFail() << "Syntax error at " << aTrsfArg;
7650             return 1;
7651           }
7652
7653           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
7654           if (!aScaleStr.IsRealValue (Standard_True))
7655           {
7656             Message::SendFail() << "Syntax error at " << aTrsfArg;
7657             return 1;
7658           }
7659           aScales[anIndex] = aScaleStr.RealValue();
7660         }
7661         else if (aTrsfArg == "-axis")
7662         {
7663           isAxisRotationSet = Standard_True;
7664           gp_XYZ anOrigin, aDirection;
7665           if (aTrsfArgIter + 6 >= theArgNb
7666           || !parseXYZ (theArgVec + aTrsfArgIter + 1, anOrigin)
7667           || !parseXYZ (theArgVec + aTrsfArgIter + 4, aDirection))
7668           {
7669             Message::SendFail() << "Syntax error at " << aTrsfArg;
7670             return 1;
7671           }
7672           anAxis.SetLocation  (anOrigin);
7673           anAxis.SetDirection (aDirection);
7674           aTrsfArgIter += 6;
7675         }
7676         else if (aTrsfArg.StartsWith ("-ang"))
7677         {
7678           isAxisRotationSet = Standard_True;
7679           if (++aTrsfArgIter >= theArgNb)
7680           {
7681             Message::SendFail() << "Syntax error at " << aTrsfArg;
7682             return 1;
7683           }
7684
7685           const TCollection_AsciiString anAngleStr (theArgVec[aTrsfArgIter]);
7686           if (!anAngleStr.IsRealValue (Standard_True))
7687           {
7688             Message::SendFail() << "Syntax error at " << aTrsfArg;
7689             return 1;
7690           }
7691           anAngles[anIndex] = anAngleStr.RealValue();
7692         }
7693         else
7694         {
7695           anArgIter = aTrsfArgIter - 1;
7696           break;
7697         }
7698       }
7699       if (!isTrsfSet && !isAxisRotationSet)
7700       {
7701         Message::SendFail() << "Syntax error at " << anArg;
7702         return 1;
7703       }
7704       else if (aTrsfArgIter >= theArgNb)
7705       {
7706         anArgIter = theArgNb;
7707       }
7708       Handle(AIS_BaseAnimationObject) anObjAnimation;
7709       if (isTrsfSet)
7710       {
7711         aTrsfs[0].SetRotation        (aRotQuats[0]);
7712         aTrsfs[1].SetRotation        (aRotQuats[1]);
7713         aTrsfs[0].SetTranslationPart (aLocPnts[0]);
7714         aTrsfs[1].SetTranslationPart (aLocPnts[1]);
7715         aTrsfs[0].SetScaleFactor     (aScales[0]);
7716         aTrsfs[1].SetScaleFactor     (aScales[1]);
7717
7718         anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
7719       }
7720       else
7721       {
7722         anObjAnimation = new AIS_AnimationAxisRotation (anAnimation->Name(), aCtx, anObject, anAxis,
7723                                                         anAngles[0] * (M_PI / 180.0), anAngles[1] * (M_PI / 180.0));
7724       }
7725       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
7726     }
7727     else if (anArg == "-viewtrsf"
7728           || anArg == "-view")
7729     {
7730       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
7731       if (aCamAnimation.IsNull())
7732       {
7733         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
7734         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
7735       }
7736
7737       Handle(Graphic3d_Camera) aCams[2] =
7738       {
7739         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
7740         new Graphic3d_Camera (aCamAnimation->View()->Camera())
7741       };
7742
7743       Standard_Boolean isTrsfSet = Standard_False;
7744       Standard_Integer aViewArgIter = anArgIter + 1;
7745       for (; aViewArgIter < theArgNb; ++aViewArgIter)
7746       {
7747         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
7748         aViewArg.LowerCase();
7749         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
7750         if (aViewArg.StartsWith ("-scale"))
7751         {
7752           isTrsfSet = Standard_True;
7753           if (++aViewArgIter >= theArgNb)
7754           {
7755             Message::SendFail() << "Syntax error at " << anArg;
7756             return 1;
7757           }
7758
7759           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
7760           if (!aScaleStr.IsRealValue (Standard_True))
7761           {
7762             Message::SendFail() << "Syntax error at " << aViewArg;
7763             return 1;
7764           }
7765           Standard_Real aScale = aScaleStr.RealValue();
7766           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
7767           aCams[anIndex]->SetScale (aScale);
7768         }
7769         else if (aViewArg.StartsWith ("-eye")
7770               || aViewArg.StartsWith ("-center")
7771               || aViewArg.StartsWith ("-at")
7772               || aViewArg.StartsWith ("-up"))
7773         {
7774           isTrsfSet = Standard_True;
7775           gp_XYZ anXYZ;
7776           if (aViewArgIter + 3 >= theArgNb
7777           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
7778           {
7779             Message::SendFail() << "Syntax error at " << aViewArg;
7780             return 1;
7781           }
7782           aViewArgIter += 3;
7783
7784           if (aViewArg.StartsWith ("-eye"))
7785           {
7786             aCams[anIndex]->SetEye (anXYZ);
7787           }
7788           else if (aViewArg.StartsWith ("-center")
7789                 || aViewArg.StartsWith ("-at"))
7790           {
7791             aCams[anIndex]->SetCenter (anXYZ);
7792           }
7793           else if (aViewArg.StartsWith ("-up"))
7794           {
7795             aCams[anIndex]->SetUp (anXYZ);
7796           }
7797         }
7798         else
7799         {
7800           anArgIter = aViewArgIter - 1;
7801           break;
7802         }
7803       }
7804       if (!isTrsfSet)
7805       {
7806         Message::SendFail() << "Syntax error at " << anArg;
7807         return 1;
7808       }
7809       else if (aViewArgIter >= theArgNb)
7810       {
7811         anArgIter = theArgNb;
7812       }
7813
7814       aCamAnimation->SetCameraStart(aCams[0]);
7815       aCamAnimation->SetCameraEnd  (aCams[1]);
7816     }
7817     else
7818     {
7819       Message::SendFail() << "Syntax error at " << anArg;
7820       return 1;
7821     }
7822   }
7823
7824   if (anAnimation.IsNull() || anAnimation->IsStopped())
7825   {
7826     ViewerTest::CurrentEventManager()->AbortViewAnimation();
7827     ViewerTest::CurrentEventManager()->SetObjectsAnimation(Handle(AIS_Animation)());
7828   }
7829
7830   if (toPrintElapsedTime)
7831   {
7832     theDI << "Elapsed Time: " << anAnimation->ElapsedTime() << " s\n";
7833   }
7834
7835   if (!toPlay && aRecFile.IsEmpty())
7836   {
7837     return 0;
7838   }
7839
7840   // Start animation timeline and process frame updating.
7841   if (aRecParams.FpsNum <= 0
7842   && !isLockLoop)
7843   {
7844     Handle(ViewerTest_AnimationHolder) aHolder = new ViewerTest_AnimationHolder (anAnimation, aView, isFreeCamera);
7845     aHolder->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7846     ViewerTest::CurrentEventManager()->SetPauseObjectsAnimation (toPauseOnClick);
7847     ViewerTest::CurrentEventManager()->SetObjectsAnimation (aHolder);
7848     ViewerTest::CurrentEventManager()->ProcessExpose();
7849     return 0;
7850   }
7851
7852   // Perform video recording
7853   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
7854   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
7855   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7856
7857   OSD_Timer aPerfTimer;
7858   aPerfTimer.Start();
7859
7860   Handle(Image_VideoRecorder) aRecorder;
7861   ImageFlipper aFlipper;
7862   Handle(Draw_ProgressIndicator) aProgress;
7863   if (!aRecFile.IsEmpty())
7864   {
7865     if (aRecParams.Width  <= 0
7866      || aRecParams.Height <= 0)
7867     {
7868       aView->Window()->Size (aRecParams.Width, aRecParams.Height);
7869     }
7870
7871     aRecorder = new Image_VideoRecorder();
7872     if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
7873     {
7874       Message::SendFail ("Error: failed to open video file for recording");
7875       return 0;
7876     }
7877
7878     aProgress = new Draw_ProgressIndicator (theDI, 1);
7879   }
7880
7881   // Manage frame-rated animation here
7882   Standard_Real aPts = aPlayStartTime;
7883   int64_t aNbFrames = 0;
7884   Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
7885                             "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
7886   Standard_Integer aSecondsProgress = 0;
7887   for (; aPts <= anUpperPts && aPS.More();)
7888   {
7889     Standard_Real aRecPts = 0.0;
7890     if (aRecParams.FpsNum > 0)
7891     {
7892       aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
7893     }
7894     else
7895     {
7896       aRecPts = aPlaySpeed * aPerfTimer.ElapsedTime();
7897     }
7898
7899     aPts = aPlayStartTime + aRecPts;
7900     ++aNbFrames;
7901     if (!anAnimation->Update (aPts))
7902     {
7903       break;
7904     }
7905
7906     if (!aRecorder.IsNull())
7907     {
7908       V3d_ImageDumpOptions aDumpParams;
7909       aDumpParams.Width          = aRecParams.Width;
7910       aDumpParams.Height         = aRecParams.Height;
7911       aDumpParams.BufferType     = Graphic3d_BT_RGBA;
7912       aDumpParams.StereoOptions  = V3d_SDO_MONO;
7913       aDumpParams.ToAdjustAspect = Standard_True;
7914       if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
7915       {
7916         Message::SendFail ("Error: view dump is failed");
7917         return 0;
7918       }
7919       aFlipper.FlipY (aRecorder->ChangeFrame());
7920       if (!aRecorder->PushFrame())
7921       {
7922         return 0;
7923       }
7924     }
7925     else
7926     {
7927       aView->Redraw();
7928     }
7929
7930     while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
7931     {
7932       aPS.Next();
7933       ++aSecondsProgress;
7934     }
7935   }
7936
7937   aPerfTimer.Stop();
7938   anAnimation->Stop();
7939   const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
7940   theDI << "Average FPS: " << aRecFps << "\n"
7941         << "Nb. Frames: "  << Standard_Real(aNbFrames);
7942
7943   aView->Redraw();
7944   aView->SetImmediateUpdate (wasImmediateUpdate);
7945   return 0;
7946 }
7947
7948
7949 //=======================================================================
7950 //function : VChangeSelected
7951 //purpose  : Adds the shape to selection or remove one from it
7952 //=======================================================================
7953 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
7954                                 Standard_Integer argc,
7955                                 const char ** argv)
7956 {
7957   if(argc != 2)
7958   {
7959     di<<"Usage : " << argv[0] << " shape \n";
7960     return 1;
7961   }
7962   //get AIS_Shape:
7963   TCollection_AsciiString aName(argv[1]);
7964   Handle(AIS_InteractiveObject) anAISObject;
7965   if (!GetMapOfAIS().Find2 (aName, anAISObject)
7966     || anAISObject.IsNull())
7967   {
7968     di<<"Use 'vdisplay' before";
7969     return 1;
7970   }
7971
7972   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
7973   return 0;
7974 }
7975
7976 //=======================================================================
7977 //function : VNbSelected
7978 //purpose  : Returns number of selected objects
7979 //=======================================================================
7980 static Standard_Integer VNbSelected (Draw_Interpretor& di,
7981                                 Standard_Integer argc,
7982                                 const char ** argv)
7983 {
7984   if(argc != 1)
7985   {
7986     di << "Usage : " << argv[0] << "\n";
7987     return 1;
7988   }
7989   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7990   if(aContext.IsNull())
7991   {
7992     di << "use 'vinit' command before " << argv[0] << "\n";
7993     return 1;
7994   }
7995   di << aContext->NbSelected() << "\n";
7996   return 0;
7997 }
7998
7999 //=======================================================================
8000 //function : VSetViewSize
8001 //purpose  :
8002 //=======================================================================
8003 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
8004                                 Standard_Integer argc,
8005                                 const char ** argv)
8006 {
8007   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8008   if(aContext.IsNull())
8009   {
8010     di << "use 'vinit' command before " << argv[0] << "\n";
8011     return 1;
8012   }
8013   if(argc != 2)
8014   {
8015     di<<"Usage : " << argv[0] << " Size\n";
8016     return 1;
8017   }
8018   Standard_Real aSize = Draw::Atof (argv[1]);
8019   if (aSize <= 0.)
8020   {
8021     di<<"Bad Size value  : " << aSize << "\n";
8022     return 1;
8023   }
8024
8025   Handle(V3d_View) aView = ViewerTest::CurrentView();
8026   aView->SetSize(aSize);
8027   return 0;
8028 }
8029
8030 //=======================================================================
8031 //function : VMoveView
8032 //purpose  :
8033 //=======================================================================
8034 static Standard_Integer VMoveView (Draw_Interpretor& di,
8035                                 Standard_Integer argc,
8036                                 const char ** argv)
8037 {
8038   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8039   if(aContext.IsNull())
8040   {
8041     di << "use 'vinit' command before " << argv[0] << "\n";
8042     return 1;
8043   }
8044   if(argc < 4 || argc > 5)
8045   {
8046     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8047     return 1;
8048   }
8049   Standard_Real Dx = Draw::Atof (argv[1]);
8050   Standard_Real Dy = Draw::Atof (argv[2]);
8051   Standard_Real Dz = Draw::Atof (argv[3]);
8052   Standard_Boolean aStart = Standard_True;
8053   if (argc == 5)
8054   {
8055       aStart = (Draw::Atoi (argv[4]) > 0);
8056   }
8057
8058   Handle(V3d_View) aView = ViewerTest::CurrentView();
8059   aView->Move(Dx,Dy,Dz,aStart);
8060   return 0;
8061 }
8062
8063 //=======================================================================
8064 //function : VTranslateView
8065 //purpose  :
8066 //=======================================================================
8067 static Standard_Integer VTranslateView (Draw_Interpretor& di,
8068                                 Standard_Integer argc,
8069                                 const char ** argv)
8070 {
8071   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8072   if(aContext.IsNull())
8073   {
8074     di << "use 'vinit' command before " << argv[0] << "\n";
8075     return 1;
8076   }
8077   if(argc < 4 || argc > 5)
8078   {
8079     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8080     return 1;
8081   }
8082   Standard_Real Dx = Draw::Atof (argv[1]);
8083   Standard_Real Dy = Draw::Atof (argv[2]);
8084   Standard_Real Dz = Draw::Atof (argv[3]);
8085   Standard_Boolean aStart = Standard_True;
8086   if (argc == 5)
8087   {
8088       aStart = (Draw::Atoi (argv[4]) > 0);
8089   }
8090
8091   Handle(V3d_View) aView = ViewerTest::CurrentView();
8092   aView->Translate(Dx,Dy,Dz,aStart);
8093   return 0;
8094 }
8095
8096 //=======================================================================
8097 //function : VTurnView
8098 //purpose  :
8099 //=======================================================================
8100 static Standard_Integer VTurnView (Draw_Interpretor& di,
8101                                 Standard_Integer argc,
8102                                 const char ** argv)
8103 {
8104   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8105   if(aContext.IsNull()) {
8106     di << "use 'vinit' command before " << argv[0] << "\n";
8107     return 1;
8108   }
8109   if(argc < 4 || argc > 5){
8110     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
8111     return 1;
8112   }
8113   Standard_Real Ax = Draw::Atof (argv[1]);
8114   Standard_Real Ay = Draw::Atof (argv[2]);
8115   Standard_Real Az = Draw::Atof (argv[3]);
8116   Standard_Boolean aStart = Standard_True;
8117   if (argc == 5)
8118   {
8119       aStart = (Draw::Atoi (argv[4]) > 0);
8120   }
8121
8122   Handle(V3d_View) aView = ViewerTest::CurrentView();
8123   aView->Turn(Ax,Ay,Az,aStart);
8124   return 0;
8125 }
8126
8127 //==============================================================================
8128 //function : VTextureEnv
8129 //purpose  : ENables or disables environment mapping
8130 //==============================================================================
8131 class OCC_TextureEnv : public Graphic3d_TextureEnv
8132 {
8133 public:
8134   OCC_TextureEnv(const Standard_CString FileName);
8135   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
8136   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
8137                             const Standard_Boolean theModulateFlag,
8138                             const Graphic3d_TypeOfTextureFilter theFilter,
8139                             const Standard_ShortReal theXScale,
8140                             const Standard_ShortReal theYScale,
8141                             const Standard_ShortReal theXShift,
8142                             const Standard_ShortReal theYShift,
8143                             const Standard_ShortReal theAngle);
8144   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
8145 };
8146 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
8147
8148 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
8149   : Graphic3d_TextureEnv(theFileName)
8150 {
8151 }
8152
8153 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
8154   : Graphic3d_TextureEnv(theTexId)
8155 {
8156 }
8157
8158 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
8159                                           const Standard_Boolean theModulateFlag,
8160                                           const Graphic3d_TypeOfTextureFilter theFilter,
8161                                           const Standard_ShortReal theXScale,
8162                                           const Standard_ShortReal theYScale,
8163                                           const Standard_ShortReal theXShift,
8164                                           const Standard_ShortReal theYShift,
8165                                           const Standard_ShortReal theAngle)
8166 {
8167   myParams->SetRepeat     (theRepeatFlag);
8168   myParams->SetModulate   (theModulateFlag);
8169   myParams->SetFilter     (theFilter);
8170   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
8171   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
8172   myParams->SetRotation   (theAngle);
8173 }
8174
8175 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
8176 {
8177   // get the active view
8178   Handle(V3d_View) aView = ViewerTest::CurrentView();
8179   if (aView.IsNull())
8180   {
8181     Message::SendFail ("Error: no active viewer");
8182     return 1;
8183   }
8184
8185   // Checking the input arguments
8186   Standard_Boolean anEnableFlag = Standard_False;
8187   Standard_Boolean isOk         = theArgNb >= 2;
8188   if (isOk)
8189   {
8190     TCollection_AsciiString anEnableOpt(theArgVec[1]);
8191     anEnableFlag = anEnableOpt.IsEqual("on");
8192     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
8193   }
8194   if (anEnableFlag)
8195   {
8196     isOk = (theArgNb == 3 || theArgNb == 11);
8197     if (isOk)
8198     {
8199       TCollection_AsciiString aTextureOpt(theArgVec[2]);
8200       isOk = (!aTextureOpt.IsIntegerValue() ||
8201              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
8202
8203       if (isOk && theArgNb == 11)
8204       {
8205         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
8206                                 aModulateOpt(theArgVec[4]),
8207                                 aFilterOpt  (theArgVec[5]),
8208                                 aSScaleOpt  (theArgVec[6]),
8209                                 aTScaleOpt  (theArgVec[7]),
8210                                 aSTransOpt  (theArgVec[8]),
8211                                 aTTransOpt  (theArgVec[9]),
8212                                 anAngleOpt  (theArgVec[10]);
8213         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
8214                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
8215                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
8216                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
8217                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
8218                 anAngleOpt.IsRealValue (Standard_True));
8219       }
8220     }
8221   }
8222
8223   if (!isOk)
8224   {
8225     Message::SendFail() << "Usage:\n"
8226                         << theArgVec[0] << " off\n"
8227                         << theArgVec[0] << " on {index_of_std_texture(0..7)|texture_file_name} [{clamp|repeat} {decal|modulate} {nearest|bilinear|trilinear} scale_s scale_t translation_s translation_t rotation_degrees]";
8228     return 1;
8229   }
8230
8231   if (anEnableFlag)
8232   {
8233     TCollection_AsciiString aTextureOpt(theArgVec[2]);
8234     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
8235                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
8236                                      new OCC_TextureEnv(theArgVec[2]);
8237
8238     if (theArgNb == 11)
8239     {
8240       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
8241       aTexEnv->SetTextureParameters(
8242         aRepeatOpt.  IsEqual("repeat"),
8243         aModulateOpt.IsEqual("modulate"),
8244         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
8245                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
8246                                                                            Graphic3d_TOTF_TRILINEAR,
8247         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
8248         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
8249         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
8250         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
8251         (Standard_ShortReal)Draw::Atof(theArgVec[10])
8252         );
8253     }
8254     aView->SetTextureEnv(aTexEnv);
8255   }
8256   else // Disabling environment mapping
8257   {
8258     Handle(Graphic3d_TextureEnv) aTexture;
8259     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
8260   }
8261
8262   aView->Redraw();
8263   return 0;
8264 }
8265
8266 namespace
8267 {
8268   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
8269
8270   //! Remove registered clipping plane from all views and objects.
8271   static void removePlane (MapOfPlanes& theRegPlanes,
8272                            const TCollection_AsciiString& theName)
8273   {
8274     Handle(Graphic3d_ClipPlane) aClipPlane;
8275     if (!theRegPlanes.Find (theName, aClipPlane))
8276     {
8277       Message::SendWarning ("Warning: no such plane");
8278       return;
8279     }
8280
8281     theRegPlanes.UnBind (theName);
8282     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
8283          anIObjIt.More(); anIObjIt.Next())
8284     {
8285       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
8286       aPrs->RemoveClipPlane (aClipPlane);
8287     }
8288
8289     for (ViewerTest_ViewerCommandsViewMap::Iterator aViewIt(ViewerTest_myViews);
8290          aViewIt.More(); aViewIt.Next())
8291     {
8292       const Handle(V3d_View)& aView = aViewIt.Key2();
8293       aView->RemoveClipPlane(aClipPlane);
8294     }
8295
8296     ViewerTest::RedrawAllViews();
8297   }
8298 }
8299
8300 //===============================================================================================
8301 //function : VClipPlane
8302 //purpose  :
8303 //===============================================================================================
8304 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8305 {
8306   // use short-cut for created clip planes map of created (or "registered by name") clip planes
8307   static MapOfPlanes aRegPlanes;
8308
8309   if (theArgsNb < 2)
8310   {
8311     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
8312     {
8313       theDi << aPlaneIter.Key() << " ";
8314     }
8315     return 0;
8316   }
8317
8318   TCollection_AsciiString aCommand (theArgVec[1]);
8319   aCommand.LowerCase();
8320   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
8321   if (anActiveView.IsNull())
8322   {
8323     Message::SendFail ("Error: no active viewer");
8324     return 1;
8325   }
8326
8327   // print maximum number of planes for current viewer
8328   if (aCommand == "-maxplanes"
8329    || aCommand == "maxplanes")
8330   {
8331     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
8332           << " plane slots provided by driver.\n";
8333     return 0;
8334   }
8335
8336   // create / delete plane instance
8337   if (aCommand == "-create"
8338    || aCommand == "create"
8339    || aCommand == "-delete"
8340    || aCommand == "delete"
8341    || aCommand == "-clone"
8342    || aCommand == "clone")
8343   {
8344     if (theArgsNb < 3)
8345     {
8346       Message::SendFail ("Syntax error: plane name is required");
8347       return 1;
8348     }
8349
8350     Standard_Boolean toCreate = aCommand == "-create"
8351                              || aCommand == "create";
8352     Standard_Boolean toClone  = aCommand == "-clone"
8353                              || aCommand == "clone";
8354     Standard_Boolean toDelete = aCommand == "-delete"
8355                              || aCommand == "delete";
8356     TCollection_AsciiString aPlane (theArgVec[2]);
8357
8358     if (toCreate)
8359     {
8360       if (aRegPlanes.IsBound (aPlane))
8361       {
8362         std::cout << "Warning: existing plane has been overridden.\n";
8363         toDelete = true;
8364       }
8365       else
8366       {
8367         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8368         return 0;
8369       }
8370     }
8371     else if (toClone) // toClone
8372     {
8373       if (!aRegPlanes.IsBound (aPlane))
8374       {
8375         Message::SendFail ("Error: no such plane");
8376         return 1;
8377       }
8378       else if (theArgsNb < 4)
8379       {
8380         Message::SendFail ("Syntax error: enter name for new plane");
8381         return 1;
8382       }
8383
8384       TCollection_AsciiString aClone (theArgVec[3]);
8385       if (aRegPlanes.IsBound (aClone))
8386       {
8387         Message::SendFail ("Error: plane name is in use");
8388         return 1;
8389       }
8390
8391       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
8392
8393       aRegPlanes.Bind (aClone, aClipPlane->Clone());
8394       return 0;
8395     }
8396
8397     if (toDelete)
8398     {
8399       if (aPlane == "ALL"
8400        || aPlane == "all"
8401        || aPlane == "*")
8402       {
8403         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
8404         {
8405           aPlane = aPlaneIter.Key();
8406           removePlane (aRegPlanes, aPlane);
8407           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
8408         }
8409       }
8410       else
8411       {
8412         removePlane (aRegPlanes, aPlane);
8413       }
8414     }
8415
8416     if (toCreate)
8417     {
8418       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8419     }
8420     return 0;
8421   }
8422
8423   // set / unset plane command
8424   if (aCommand == "set"
8425    || aCommand == "unset")
8426   {
8427     if (theArgsNb < 5)
8428     {
8429       Message::SendFail ("Syntax error: need more arguments");
8430       return 1;
8431     }
8432
8433     // redirect to new syntax
8434     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
8435     anArgVec.SetValue (1, theArgVec[0]);
8436     anArgVec.SetValue (2, theArgVec[2]);
8437     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
8438     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
8439     {
8440       anArgVec.SetValue (anIt, theArgVec[anIt]);
8441     }
8442
8443     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
8444   }
8445
8446   // change plane command
8447   TCollection_AsciiString aPlaneName;
8448   Handle(Graphic3d_ClipPlane) aClipPlane;
8449   Standard_Integer anArgIter = 0;
8450   if (aCommand == "-change"
8451    || aCommand == "change")
8452   {
8453     // old syntax support
8454     if (theArgsNb < 3)
8455     {
8456       Message::SendFail ("Syntax error: need more arguments");
8457       return 1;
8458     }
8459
8460     anArgIter  = 3;
8461     aPlaneName = theArgVec[2];
8462     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
8463     {
8464       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
8465       return 1;
8466     }
8467   }
8468   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
8469   {
8470     anArgIter  = 2;
8471     aPlaneName = theArgVec[1];
8472   }
8473   else
8474   {
8475     anArgIter  = 2;
8476     aPlaneName = theArgVec[1];
8477     aClipPlane = new Graphic3d_ClipPlane();
8478     aRegPlanes.Bind (aPlaneName, aClipPlane);
8479     theDi << "Created new plane " << aPlaneName << ".\n";
8480   }
8481
8482   if (theArgsNb - anArgIter < 1)
8483   {
8484     Message::SendFail ("Syntax error: need more arguments");
8485     return 1;
8486   }
8487
8488   for (; anArgIter < theArgsNb; ++anArgIter)
8489   {
8490     const char**     aChangeArgs   = theArgVec + anArgIter;
8491     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
8492     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
8493     aChangeArg.LowerCase();
8494
8495     Standard_Boolean toEnable = Standard_True;
8496     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
8497     {
8498       aClipPlane->SetOn (toEnable);
8499     }
8500     else if (aChangeArg.StartsWith ("-equation")
8501           || aChangeArg.StartsWith ("equation"))
8502     {
8503       if (aNbChangeArgs < 5)
8504       {
8505         Message::SendFail ("Syntax error: need more arguments");
8506         return 1;
8507       }
8508
8509       Standard_Integer aSubIndex = 1;
8510       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
8511       if (aPrefixLen < aChangeArg.Length())
8512       {
8513         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
8514         if (!aSubStr.IsIntegerValue()
8515           || aSubStr.IntegerValue() <= 0)
8516         {
8517           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8518           return 1;
8519         }
8520         aSubIndex = aSubStr.IntegerValue();
8521       }
8522
8523       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
8524       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
8525       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
8526       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
8527       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8528       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
8529       {
8530         if (aSubPln->ChainNextPlane().IsNull())
8531         {
8532           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8533         }
8534         aSubPln = aSubPln->ChainNextPlane();
8535       }
8536       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8537       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
8538       anArgIter += 4;
8539     }
8540     else if ((aChangeArg == "-boxinterior"
8541            || aChangeArg == "-boxint"
8542            || aChangeArg == "-box")
8543             && aNbChangeArgs >= 7)
8544     {
8545       Graphic3d_BndBox3d aBndBox;
8546       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
8547       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
8548       anArgIter += 6;
8549
8550       Standard_Integer aNbSubPlanes = 6;
8551       const Graphic3d_Vec3d aDirArray[6] =
8552       {
8553         Graphic3d_Vec3d (-1, 0, 0),
8554         Graphic3d_Vec3d ( 1, 0, 0),
8555         Graphic3d_Vec3d ( 0,-1, 0),
8556         Graphic3d_Vec3d ( 0, 1, 0),
8557         Graphic3d_Vec3d ( 0, 0,-1),
8558         Graphic3d_Vec3d ( 0, 0, 1),
8559       };
8560       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8561       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
8562       {
8563         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
8564         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
8565         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
8566         if (aSubPlaneIter + 1 == aNbSubPlanes)
8567         {
8568           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8569         }
8570         else
8571         {
8572           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8573         }
8574         aSubPln = aSubPln->ChainNextPlane();
8575       }
8576     }
8577     else if (aChangeArg == "-capping"
8578           || aChangeArg == "capping")
8579     {
8580       if (aNbChangeArgs < 2)
8581       {
8582         Message::SendFail ("Syntax error: need more arguments");
8583         return 1;
8584       }
8585
8586       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8587       {
8588         aClipPlane->SetCapping (toEnable);
8589         anArgIter += 1;
8590       }
8591       else
8592       {
8593         // just skip otherwise (old syntax)
8594       }
8595     }
8596     else if (aChangeArg == "-useobjectmaterial"
8597           || aChangeArg == "-useobjectmat"
8598           || aChangeArg == "-useobjmat"
8599           || aChangeArg == "-useobjmaterial")
8600     {
8601       if (aNbChangeArgs < 2)
8602       {
8603         Message::SendFail ("Syntax error: need more arguments");
8604         return 1;
8605       }
8606
8607       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8608       {
8609         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
8610         anArgIter += 1;
8611       }
8612     }
8613     else if (aChangeArg == "-useobjecttexture"
8614           || aChangeArg == "-useobjecttex"
8615           || aChangeArg == "-useobjtexture"
8616           || aChangeArg == "-useobjtex")
8617     {
8618       if (aNbChangeArgs < 2)
8619       {
8620         Message::SendFail ("Syntax error: need more arguments");
8621         return 1;
8622       }
8623
8624       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8625       {
8626         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
8627         anArgIter += 1;
8628       }
8629     }
8630     else if (aChangeArg == "-useobjectshader"
8631           || aChangeArg == "-useobjshader")
8632     {
8633       if (aNbChangeArgs < 2)
8634       {
8635         Message::SendFail ("Syntax error: need more arguments");
8636         return 1;
8637       }
8638
8639       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8640       {
8641         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
8642         anArgIter += 1;
8643       }
8644     }
8645     else if (aChangeArg == "-color"
8646           || aChangeArg == "color")
8647     {
8648       Quantity_Color aColor;
8649       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
8650                                                      aChangeArgs + 1,
8651                                                      aColor);
8652       if (aNbParsed == 0)
8653       {
8654         Message::SendFail ("Syntax error: need more arguments");
8655         return 1;
8656       }
8657       aClipPlane->SetCappingColor (aColor);
8658       anArgIter += aNbParsed;
8659     }
8660     else if (aNbChangeArgs >= 1
8661           && (aChangeArg == "-material"
8662            || aChangeArg == "material"))
8663     {
8664       ++anArgIter;
8665       Graphic3d_NameOfMaterial aMatName;
8666       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
8667       {
8668         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
8669         return 1;
8670       }
8671       aClipPlane->SetCappingMaterial (aMatName);
8672     }
8673     else if ((aChangeArg == "-transparency"
8674            || aChangeArg == "-transp")
8675           && aNbChangeArgs >= 2)
8676     {
8677       TCollection_AsciiString aValStr (aChangeArgs[1]);
8678       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
8679       if (aValStr.IsRealValue (Standard_True))
8680       {
8681         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
8682         aMat.SetTransparency ((float )aValStr.RealValue());
8683         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
8684         aClipPlane->SetCappingMaterial (aMat);
8685       }
8686       else
8687       {
8688         aValStr.LowerCase();
8689         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
8690         if (aValStr == "opaque")
8691         {
8692           aMode = Graphic3d_AlphaMode_Opaque;
8693         }
8694         else if (aValStr == "mask")
8695         {
8696           aMode = Graphic3d_AlphaMode_Mask;
8697         }
8698         else if (aValStr == "blend")
8699         {
8700           aMode = Graphic3d_AlphaMode_Blend;
8701         }
8702         else if (aValStr == "maskblend"
8703               || aValStr == "blendmask")
8704         {
8705           aMode = Graphic3d_AlphaMode_MaskBlend;
8706         }
8707         else if (aValStr == "blendauto")
8708         {
8709           aMode = Graphic3d_AlphaMode_BlendAuto;
8710         }
8711         else
8712         {
8713           Message::SendFail() << "Syntax error at '" << aValStr << "'";
8714           return 1;
8715         }
8716         anAspect->SetAlphaMode (aMode);
8717         aClipPlane->SetCappingAspect (anAspect);
8718       }
8719       anArgIter += 1;
8720     }
8721     else if (aChangeArg == "-texname"
8722           || aChangeArg == "texname")
8723     {
8724       if (aNbChangeArgs < 2)
8725       {
8726         Message::SendFail ("Syntax error: need more arguments");
8727         return 1;
8728       }
8729
8730       TCollection_AsciiString aTextureName (aChangeArgs[1]);
8731       Handle(Graphic3d_Texture2D) aTexture = new Graphic3d_Texture2D (aTextureName);
8732       if (!aTexture->IsDone())
8733       {
8734         aClipPlane->SetCappingTexture (NULL);
8735       }
8736       else
8737       {
8738         aTexture->EnableModulate();
8739         aTexture->EnableRepeat();
8740         aClipPlane->SetCappingTexture (aTexture);
8741       }
8742       anArgIter += 1;
8743     }
8744     else if (aChangeArg == "-texscale"
8745           || aChangeArg == "texscale")
8746     {
8747       if (aClipPlane->CappingTexture().IsNull())
8748       {
8749         Message::SendFail ("Error: no texture is set");
8750         return 1;
8751       }
8752
8753       if (aNbChangeArgs < 3)
8754       {
8755         Message::SendFail ("Syntax error: need more arguments");
8756         return 1;
8757       }
8758
8759       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8760       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8761       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
8762       anArgIter += 2;
8763     }
8764     else if (aChangeArg == "-texorigin"
8765           || aChangeArg == "texorigin") // texture origin
8766     {
8767       if (aClipPlane->CappingTexture().IsNull())
8768       {
8769         Message::SendFail ("Error: no texture is set");
8770         return 1;
8771       }
8772
8773       if (aNbChangeArgs < 3)
8774       {
8775         Message::SendFail ("Syntax error: need more arguments");
8776         return 1;
8777       }
8778
8779       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8780       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8781
8782       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
8783       anArgIter += 2;
8784     }
8785     else if (aChangeArg == "-texrotate"
8786           || aChangeArg == "texrotate") // texture rotation
8787     {
8788       if (aClipPlane->CappingTexture().IsNull())
8789       {
8790         Message::SendFail ("Error: no texture is set");
8791         return 1;
8792       }
8793
8794       if (aNbChangeArgs < 2)
8795       {
8796         Message::SendFail ("Syntax error: need more arguments");
8797         return 1;
8798       }
8799
8800       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8801       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
8802       anArgIter += 1;
8803     }
8804     else if (aChangeArg == "-hatch"
8805           || aChangeArg == "hatch")
8806     {
8807       if (aNbChangeArgs < 2)
8808       {
8809         Message::SendFail ("Syntax error: need more arguments");
8810         return 1;
8811       }
8812
8813       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
8814       aHatchStr.LowerCase();
8815       if (aHatchStr == "on")
8816       {
8817         aClipPlane->SetCappingHatchOn();
8818       }
8819       else if (aHatchStr == "off")
8820       {
8821         aClipPlane->SetCappingHatchOff();
8822       }
8823       else
8824       {
8825         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
8826       }
8827       anArgIter += 1;
8828     }
8829     else if (aChangeArg == "-delete"
8830           || aChangeArg == "delete")
8831     {
8832       removePlane (aRegPlanes, aPlaneName);
8833       return 0;
8834     }
8835     else if (aChangeArg == "-set"
8836           || aChangeArg == "-unset"
8837           || aChangeArg == "-setoverrideglobal")
8838     {
8839       // set / unset plane command
8840       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
8841       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
8842       Standard_Integer anIt = 1;
8843       for (; anIt < aNbChangeArgs; ++anIt)
8844       {
8845         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
8846         if (anEntityName.IsEmpty()
8847          || anEntityName.Value (1) == '-')
8848         {
8849           break;
8850         }
8851         else if (!toOverrideGlobal
8852                && ViewerTest_myViews.IsBound1 (anEntityName))
8853         {
8854           const Handle(V3d_View)& aView = ViewerTest_myViews.Find1 (anEntityName);
8855           if (toSet)
8856           {
8857             aView->AddClipPlane (aClipPlane);
8858           }
8859           else
8860           {
8861             aView->RemoveClipPlane (aClipPlane);
8862           }
8863           continue;
8864         }
8865         else if (GetMapOfAIS().IsBound2 (anEntityName))
8866         {
8867           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
8868           if (toSet)
8869           {
8870             aIObj->AddClipPlane (aClipPlane);
8871           }
8872           else
8873           {
8874             aIObj->RemoveClipPlane (aClipPlane);
8875           }
8876           if (!aIObj->ClipPlanes().IsNull())
8877           {
8878             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
8879           }
8880         }
8881         else
8882         {
8883           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
8884           return 1;
8885         }
8886       }
8887
8888       if (anIt == 1)
8889       {
8890         // apply to active view
8891         if (toSet)
8892         {
8893           anActiveView->AddClipPlane (aClipPlane);
8894         }
8895         else
8896         {
8897           anActiveView->RemoveClipPlane (aClipPlane);
8898         }
8899       }
8900       else
8901       {
8902         anArgIter = anArgIter + anIt - 1;
8903       }
8904     }
8905     else
8906     {
8907       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8908       return 1;
8909     }
8910   }
8911
8912   ViewerTest::RedrawAllViews();
8913   return 0;
8914 }
8915
8916 //===============================================================================================
8917 //function : VZRange
8918 //purpose  :
8919 //===============================================================================================
8920 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8921 {
8922   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8923
8924   if (aCurrentView.IsNull())
8925   {
8926     Message::SendFail ("Error: no active viewer");
8927     return 1;
8928   }
8929
8930   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
8931
8932   if (theArgsNb < 2)
8933   {
8934     theDi << "ZNear: " << aCamera->ZNear() << "\n";
8935     theDi << "ZFar: " << aCamera->ZFar() << "\n";
8936     return 0;
8937   }
8938
8939   if (theArgsNb == 3)
8940   {
8941     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
8942     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
8943
8944     if (aNewZNear >= aNewZFar)
8945     {
8946       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
8947       return 1;
8948     }
8949
8950     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
8951     {
8952       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
8953       return 1;
8954     }
8955
8956     aCamera->SetZRange (aNewZNear, aNewZFar);
8957   }
8958   else
8959   {
8960     Message::SendFail ("Syntax error: wrong command arguments");
8961     return 1;
8962   }
8963
8964   aCurrentView->Redraw();
8965
8966   return 0;
8967 }
8968
8969 //===============================================================================================
8970 //function : VAutoZFit
8971 //purpose  :
8972 //===============================================================================================
8973 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8974 {
8975   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8976
8977   if (aCurrentView.IsNull())
8978   {
8979     Message::SendFail ("Error: no active viewer");
8980     return 1;
8981   }
8982
8983   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
8984
8985   if (theArgsNb > 3)
8986   {
8987     Message::SendFail ("Syntax error: wrong command arguments");
8988     return 1;
8989   }
8990
8991   if (theArgsNb < 2)
8992   {
8993     theDi << "Auto z-fit mode: \n"
8994           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
8995           << "Scale: " << aScale << "\n";
8996     return 0;
8997   }
8998
8999   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
9000
9001   if (theArgsNb >= 3)
9002   {
9003     aScale = Draw::Atoi (theArgVec[2]);
9004   }
9005
9006   aCurrentView->SetAutoZFitMode (isOn, aScale);
9007   aCurrentView->Redraw();
9008   return 0;
9009 }
9010
9011 //! Auxiliary function to print projection type
9012 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
9013 {
9014   switch (theProjType)
9015   {
9016     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
9017     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
9018     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
9019     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
9020     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
9021   }
9022   return "UNKNOWN";
9023 }
9024
9025 //===============================================================================================
9026 //function : VCamera
9027 //purpose  :
9028 //===============================================================================================
9029 static int VCamera (Draw_Interpretor& theDI,
9030                     Standard_Integer  theArgsNb,
9031                     const char**      theArgVec)
9032 {
9033   Handle(V3d_View) aView = ViewerTest::CurrentView();
9034   if (aView.IsNull())
9035   {
9036     Message::SendFail ("Error: no active viewer");
9037     return 1;
9038   }
9039
9040   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9041   if (theArgsNb < 2)
9042   {
9043     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
9044     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
9045     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
9046     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
9047     theDI << "Distance:   " << aCamera->Distance() << "\n";
9048     theDI << "IOD:        " << aCamera->IOD() << "\n";
9049     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
9050     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
9051     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
9052     theDI << "ZNear:      " << aCamera->ZNear() << "\n";
9053     theDI << "ZFar:       " << aCamera->ZFar() << "\n";
9054     return 0;
9055   }
9056
9057   TCollection_AsciiString aPrsName;
9058   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9059   {
9060     Standard_CString        anArg = theArgVec[anArgIter];
9061     TCollection_AsciiString anArgCase (anArg);
9062     anArgCase.LowerCase();
9063     if (anArgCase == "-proj"
9064      || anArgCase == "-projection"
9065      || anArgCase == "-projtype"
9066      || anArgCase == "-projectiontype")
9067     {
9068       theDI << projTypeName (aCamera->ProjectionType()) << " ";
9069     }
9070     else if (anArgCase == "-ortho"
9071           || anArgCase == "-orthographic")
9072     {
9073       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
9074     }
9075     else if (anArgCase == "-persp"
9076           || anArgCase == "-perspective"
9077           || anArgCase == "-perspmono"
9078           || anArgCase == "-perspectivemono"
9079           || anArgCase == "-mono")
9080     {
9081       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9082     }
9083     else if (anArgCase == "-stereo"
9084           || anArgCase == "-stereoscopic"
9085           || anArgCase == "-perspstereo"
9086           || anArgCase == "-perspectivestereo")
9087     {
9088       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9089     }
9090     else if (anArgCase == "-left"
9091           || anArgCase == "-lefteye"
9092           || anArgCase == "-monoleft"
9093           || anArgCase == "-monolefteye"
9094           || anArgCase == "-perpsleft"
9095           || anArgCase == "-perpslefteye")
9096     {
9097       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
9098     }
9099     else if (anArgCase == "-right"
9100           || anArgCase == "-righteye"
9101           || anArgCase == "-monoright"
9102           || anArgCase == "-monorighteye"
9103           || anArgCase == "-perpsright")
9104     {
9105       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
9106     }
9107     else if (anArgCase == "-dist"
9108           || anArgCase == "-distance")
9109     {
9110       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9111       if (anArgValue != NULL
9112       && *anArgValue != '-')
9113       {
9114         ++anArgIter;
9115         aCamera->SetDistance (Draw::Atof (anArgValue));
9116         continue;
9117       }
9118       theDI << aCamera->Distance() << " ";
9119     }
9120     else if (anArgCase == "-iod")
9121     {
9122       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9123       if (anArgValue != NULL
9124       && *anArgValue != '-')
9125       {
9126         ++anArgIter;
9127         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
9128         continue;
9129       }
9130       theDI << aCamera->IOD() << " ";
9131     }
9132     else if (anArgCase == "-iodtype")
9133     {
9134       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9135       TCollection_AsciiString anValueCase (anArgValue);
9136       anValueCase.LowerCase();
9137       if (anValueCase == "abs"
9138        || anValueCase == "absolute")
9139       {
9140         ++anArgIter;
9141         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
9142         continue;
9143       }
9144       else if (anValueCase == "rel"
9145             || anValueCase == "relative")
9146       {
9147         ++anArgIter;
9148         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
9149         continue;
9150       }
9151       else if (*anArgValue != '-')
9152       {
9153         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
9154         return 1;
9155       }
9156       switch (aCamera->GetIODType())
9157       {
9158         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
9159         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
9160       }
9161     }
9162     else if (anArgCase == "-zfocus")
9163     {
9164       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9165       if (anArgValue != NULL
9166       && *anArgValue != '-')
9167       {
9168         ++anArgIter;
9169         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
9170         continue;
9171       }
9172       theDI << aCamera->ZFocus() << " ";
9173     }
9174     else if (anArgCase == "-zfocustype")
9175     {
9176       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9177       TCollection_AsciiString anValueCase (anArgValue);
9178       anValueCase.LowerCase();
9179       if (anValueCase == "abs"
9180        || anValueCase == "absolute")
9181       {
9182         ++anArgIter;
9183         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
9184         continue;
9185       }
9186       else if (anValueCase == "rel"
9187             || anValueCase == "relative")
9188       {
9189         ++anArgIter;
9190         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
9191         continue;
9192       }
9193       else if (*anArgValue != '-')
9194       {
9195         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
9196         return 1;
9197       }
9198       switch (aCamera->ZFocusType())
9199       {
9200         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
9201         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
9202       }
9203     }
9204     else if (anArgCase == "-lockzup"
9205           || anArgCase == "-turntable")
9206     {
9207       bool toLockUp = true;
9208       if (++anArgIter < theArgsNb
9209       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
9210       {
9211         --anArgIter;
9212       }
9213       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
9214     }
9215     else if (anArgCase == "-rotationmode"
9216           || anArgCase == "-rotmode")
9217     {
9218       AIS_RotationMode aRotMode = AIS_RotationMode_BndBoxActive;
9219       TCollection_AsciiString aRotStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9220       aRotStr.LowerCase();
9221       if (aRotStr == "bndboxactive"
9222        || aRotStr == "active")
9223       {
9224         aRotMode = AIS_RotationMode_BndBoxActive;
9225       }
9226       else if (aRotStr == "picklast"
9227             || aRotStr == "pick")
9228       {
9229         aRotMode = AIS_RotationMode_PickLast;
9230       }
9231       else if (aRotStr == "pickcenter")
9232       {
9233         aRotMode = AIS_RotationMode_PickCenter;
9234       }
9235       else if (aRotStr == "cameraat"
9236             || aRotStr == "cameracenter")
9237       {
9238         aRotMode = AIS_RotationMode_CameraAt;
9239       }
9240       else if (aRotStr == "bndboxscene"
9241             || aRotStr == "boxscene")
9242       {
9243         aRotMode = AIS_RotationMode_BndBoxScene;
9244       }
9245       else
9246       {
9247         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9248         return 1;
9249       }
9250
9251       ViewerTest::CurrentEventManager()->SetRotationMode (aRotMode);
9252       ++anArgIter;
9253     }
9254     else if (anArgCase == "-navigationmode"
9255           || anArgCase == "-navmode")
9256     {
9257       AIS_NavigationMode aNavMode = AIS_NavigationMode_Orbit;
9258       TCollection_AsciiString aNavStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9259       aNavStr.LowerCase();
9260       if (aNavStr == "orbit")
9261       {
9262         aNavMode = AIS_NavigationMode_Orbit;
9263       }
9264       else if (aNavStr == "flight"
9265             || aNavStr == "fly"
9266             || aNavStr == "copter"
9267             || aNavStr == "helicopter")
9268       {
9269         aNavMode = AIS_NavigationMode_FirstPersonFlight;
9270       }
9271       else if (aNavStr == "walk"
9272             || aNavStr == "shooter")
9273       {
9274         aNavMode = AIS_NavigationMode_FirstPersonWalk;
9275       }
9276       else
9277       {
9278         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9279         return 1;
9280       }
9281
9282       Handle(ViewerTest_EventManager) aViewMgr = ViewerTest::CurrentEventManager();
9283       aViewMgr->SetNavigationMode (aNavMode);
9284       if (aNavMode == AIS_NavigationMode_Orbit)
9285       {
9286         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
9287       }
9288       else
9289       {
9290         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateView);
9291       }
9292       ++anArgIter;
9293     }
9294     else if (anArgCase == "-fov"
9295           || anArgCase == "-fovy"
9296           || anArgCase == "-fovx"
9297           || anArgCase == "-fov2d")
9298     {
9299       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9300       if (anArgValue != NULL
9301       && *anArgValue != '-')
9302       {
9303         ++anArgIter;
9304         if (anArgCase == "-fov2d")
9305         {
9306           aCamera->SetFOV2d (Draw::Atof (anArgValue));
9307         }
9308         else if (anArgCase == "-fovx")
9309         {
9310           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
9311         }
9312         else
9313         {
9314           aCamera->SetFOVy (Draw::Atof (anArgValue));
9315         }
9316         continue;
9317       }
9318       if (anArgCase == "-fov2d")
9319       {
9320         theDI << aCamera->FOV2d() << " ";
9321       }
9322       else if (anArgCase == "-fovx")
9323       {
9324         theDI << aCamera->FOVx() << " ";
9325       }
9326       else
9327       {
9328         theDI << aCamera->FOVy() << " ";
9329       }
9330     }
9331     else if (anArgIter + 1 < theArgsNb
9332           && anArgCase == "-xrpose")
9333     {
9334       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
9335       anXRArg.LowerCase();
9336       if (anXRArg == "base")
9337       {
9338         aCamera = aView->View()->BaseXRCamera();
9339       }
9340       else if (anXRArg == "head")
9341       {
9342         aCamera = aView->View()->PosedXRCamera();
9343       }
9344       else
9345       {
9346         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
9347         return 1;
9348       }
9349       if (aCamera.IsNull())
9350       {
9351         Message::SendFail() << "Error: undefined XR pose";
9352         return 0;
9353       }
9354       if (aView->AutoZFitMode())
9355       {
9356         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
9357         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
9358         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
9359       }
9360     }
9361     else if (aPrsName.IsEmpty()
9362          && !anArgCase.StartsWith ("-"))
9363     {
9364       aPrsName = anArg;
9365     }
9366     else
9367     {
9368       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
9369       return 1;
9370     }
9371   }
9372
9373   if (aPrsName.IsEmpty()
9374    || theArgsNb > 2)
9375   {
9376     aView->Redraw();
9377   }
9378
9379   if (!aPrsName.IsEmpty())
9380   {
9381     Handle(AIS_CameraFrustum) aCameraFrustum;
9382     if (GetMapOfAIS().IsBound2 (aPrsName))
9383     {
9384       // find existing object
9385       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
9386       if (aCameraFrustum.IsNull())
9387       {
9388         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
9389         return 1;
9390       }
9391     }
9392
9393     if (aCameraFrustum.IsNull())
9394     {
9395       aCameraFrustum = new AIS_CameraFrustum();
9396     }
9397     else
9398     {
9399       // not include displayed object of old camera frustum in the new one.
9400       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
9401       aView->ZFitAll();
9402     }
9403     aCameraFrustum->SetCameraFrustum (aCamera);
9404
9405     ViewerTest::Display (aPrsName, aCameraFrustum);
9406   }
9407
9408   return 0;
9409 }
9410
9411 //! Parse stereo output mode
9412 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
9413                                          Graphic3d_StereoMode& theMode)
9414 {
9415   TCollection_AsciiString aFlag (theArg);
9416   aFlag.LowerCase();
9417   if (aFlag == "quadbuffer")
9418   {
9419     theMode = Graphic3d_StereoMode_QuadBuffer;
9420   }
9421   else if (aFlag == "anaglyph")
9422   {
9423     theMode = Graphic3d_StereoMode_Anaglyph;
9424   }
9425   else if (aFlag == "row"
9426         || aFlag == "rowinterlaced")
9427   {
9428     theMode = Graphic3d_StereoMode_RowInterlaced;
9429   }
9430   else if (aFlag == "col"
9431         || aFlag == "colinterlaced"
9432         || aFlag == "columninterlaced")
9433   {
9434     theMode = Graphic3d_StereoMode_ColumnInterlaced;
9435   }
9436   else if (aFlag == "chess"
9437         || aFlag == "chessboard")
9438   {
9439     theMode = Graphic3d_StereoMode_ChessBoard;
9440   }
9441   else if (aFlag == "sbs"
9442         || aFlag == "sidebyside")
9443   {
9444     theMode = Graphic3d_StereoMode_SideBySide;
9445   }
9446   else if (aFlag == "ou"
9447         || aFlag == "overunder")
9448   {
9449     theMode = Graphic3d_StereoMode_OverUnder;
9450   }
9451   else if (aFlag == "pageflip"
9452         || aFlag == "softpageflip")
9453   {
9454     theMode = Graphic3d_StereoMode_SoftPageFlip;
9455   }
9456   else if (aFlag == "openvr"
9457         || aFlag == "vr")
9458   {
9459     theMode = Graphic3d_StereoMode_OpenVR;
9460   }
9461   else
9462   {
9463     return Standard_False;
9464   }
9465   return Standard_True;
9466 }
9467
9468 //! Parse anaglyph filter
9469 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
9470                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
9471 {
9472   TCollection_AsciiString aFlag (theArg);
9473   aFlag.LowerCase();
9474   if (aFlag == "redcyansimple")
9475   {
9476     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9477   }
9478   else if (aFlag == "redcyan"
9479         || aFlag == "redcyanoptimized")
9480   {
9481     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
9482   }
9483   else if (aFlag == "yellowbluesimple")
9484   {
9485     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
9486   }
9487   else if (aFlag == "yellowblue"
9488         || aFlag == "yellowblueoptimized")
9489   {
9490     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
9491   }
9492   else if (aFlag == "greenmagenta"
9493         || aFlag == "greenmagentasimple")
9494   {
9495     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
9496   }
9497   else
9498   {
9499     return Standard_False;
9500   }
9501   return Standard_True;
9502 }
9503
9504 //==============================================================================
9505 //function : VStereo
9506 //purpose  :
9507 //==============================================================================
9508
9509 static int VStereo (Draw_Interpretor& theDI,
9510                     Standard_Integer  theArgNb,
9511                     const char**      theArgVec)
9512 {
9513   Handle(V3d_View) aView = ViewerTest::CurrentView();
9514   if (aView.IsNull())
9515   {
9516     Message::SendFail ("Error: no active viewer");
9517     return 0;
9518   }
9519
9520   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9521   Graphic3d_RenderingParams* aParams = &aView->ChangeRenderingParams();
9522   if (theArgNb < 2)
9523   {
9524     Standard_Boolean isActive = aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo;
9525     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
9526     if (isActive)
9527     {
9528       TCollection_AsciiString aMode;
9529       switch (aView->RenderingParams().StereoMode)
9530       {
9531         case Graphic3d_StereoMode_QuadBuffer:
9532         {
9533           aMode = "quadBuffer";
9534           break;
9535         }
9536         case Graphic3d_StereoMode_RowInterlaced:
9537         {
9538           aMode = "rowInterlaced";
9539           if (aView->RenderingParams().ToSmoothInterlacing)
9540           {
9541             aMode.AssignCat (" (smoothed)");
9542           }
9543           break;
9544         }
9545         case Graphic3d_StereoMode_ColumnInterlaced:
9546         {
9547           aMode = "columnInterlaced";
9548           if (aView->RenderingParams().ToSmoothInterlacing)
9549           {
9550             aMode.AssignCat (" (smoothed)");
9551           }
9552           break;
9553         }
9554         case Graphic3d_StereoMode_ChessBoard:
9555         {
9556           aMode = "chessBoard";
9557           if (aView->RenderingParams().ToSmoothInterlacing)
9558           {
9559             aMode.AssignCat (" (smoothed)");
9560           }
9561           break;
9562         }
9563         case Graphic3d_StereoMode_SideBySide:
9564         {
9565           aMode = "sideBySide";
9566           break;
9567         }
9568         case Graphic3d_StereoMode_OverUnder:
9569         {
9570           aMode = "overUnder";
9571           break;
9572         }
9573         case Graphic3d_StereoMode_SoftPageFlip:
9574         {
9575           aMode = "softPageFlip";
9576           break;
9577         }
9578         case Graphic3d_StereoMode_OpenVR:
9579         {
9580           aMode = "openVR";
9581           break;
9582         }
9583         case Graphic3d_StereoMode_Anaglyph:
9584         {
9585           aMode = "anaglyph";
9586           switch (aView->RenderingParams().AnaglyphFilter)
9587           {
9588             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
9589             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
9590             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
9591             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
9592             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
9593             case Graphic3d_RenderingParams::Anaglyph_UserDefined         : aMode.AssignCat (" (userDefined)");        break;
9594           }
9595         }
9596       }
9597       theDI << "Mode " << aMode << "\n";
9598     }
9599     return 0;
9600   }
9601
9602   Graphic3d_StereoMode aMode = aParams->StereoMode;
9603   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
9604   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
9605   {
9606     Standard_CString        anArg = theArgVec[anArgIter];
9607     TCollection_AsciiString aFlag (anArg);
9608     aFlag.LowerCase();
9609     if (anUpdateTool.parseRedrawMode (aFlag))
9610     {
9611       continue;
9612     }
9613     else if (aFlag == "0"
9614           || aFlag == "off")
9615     {
9616       if (++anArgIter < theArgNb)
9617       {
9618         Message::SendFail ("Error: wrong number of arguments");
9619         return 1;
9620       }
9621
9622       if (aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
9623       {
9624         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9625       }
9626       return 0;
9627     }
9628     else if (aFlag == "1"
9629           || aFlag == "on")
9630     {
9631       if (++anArgIter < theArgNb)
9632       {
9633         Message::SendFail ("Error: wrong number of arguments");
9634         return 1;
9635       }
9636
9637       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9638       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
9639       {
9640         return 0;
9641       }
9642     }
9643     else if (aFlag == "-reverse"
9644           || aFlag == "-noreverse"
9645           || aFlag == "-reversed"
9646           || aFlag == "-swap"
9647           || aFlag == "-noswap")
9648     {
9649       aParams->ToReverseStereo = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
9650     }
9651     else if (aFlag == "-mode"
9652           || aFlag == "-stereomode")
9653     {
9654       if (++anArgIter >= theArgNb
9655       || !parseStereoMode (theArgVec[anArgIter], aMode))
9656       {
9657         Message::SendFail() << "Syntax error at '" << anArg << "'";
9658         return 1;
9659       }
9660
9661       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9662       {
9663         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9664       }
9665     }
9666     else if (aFlag == "-anaglyph"
9667           || aFlag == "-anaglyphfilter")
9668     {
9669       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9670       if (++anArgIter >= theArgNb
9671       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
9672       {
9673         Message::SendFail() << "Syntax error at '" << anArg << "'";
9674         return 1;
9675       }
9676
9677       aMode = Graphic3d_StereoMode_Anaglyph;
9678       aParams->AnaglyphFilter = aFilter;
9679     }
9680     else if (parseStereoMode (anArg, aMode)) // short syntax
9681     {
9682       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9683       {
9684         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9685       }
9686     }
9687     else if (anArgIter + 1 < theArgNb
9688           && aFlag == "-hmdfov2d")
9689     {
9690       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
9691       if (aParams->HmdFov2d < 10.0f
9692        || aParams->HmdFov2d > 180.0f)
9693       {
9694         Message::SendFail() << "Error: FOV is out of range";
9695         return 1;
9696       }
9697     }
9698     else if (aFlag == "-mirror"
9699           || aFlag == "-mirrorcomposer")
9700     {
9701       aParams->ToMirrorComposer = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);;
9702     }
9703     else if (aFlag == "-smooth"
9704           || aFlag == "-nosmooth"
9705           || aFlag == "-smoothinterlacing"
9706           || aFlag == "-nosmoothinterlacing")
9707     {
9708       aParams->ToSmoothInterlacing = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
9709     }
9710     else if (anArgIter + 1 < theArgNb
9711           && (aFlag == "-unitfactor"
9712            || aFlag == "-unitscale"))
9713     {
9714       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
9715     }
9716     else
9717     {
9718       Message::SendFail() << "Syntax error at '" << anArg << "'";
9719       return 1;
9720     }
9721   }
9722
9723   aParams->StereoMode = aMode;
9724   aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9725   if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
9726   {
9727     // initiate implicit continuous rendering
9728     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
9729   }
9730   return 0;
9731 }
9732
9733 //===============================================================================================
9734 //function : VDefaults
9735 //purpose  :
9736 //===============================================================================================
9737 static int VDefaults (Draw_Interpretor& theDi,
9738                       Standard_Integer  theArgsNb,
9739                       const char**      theArgVec)
9740 {
9741   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9742   if (aCtx.IsNull())
9743   {
9744     Message::SendFail ("Error: no active viewer");
9745     return 1;
9746   }
9747
9748   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
9749   if (theArgsNb < 2)
9750   {
9751     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
9752     {
9753       theDi << "DeflType:           relative\n"
9754             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
9755     }
9756     else
9757     {
9758       theDi << "DeflType:           absolute\n"
9759             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
9760     }
9761     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
9762     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
9763     return 0;
9764   }
9765
9766   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9767   {
9768     TCollection_AsciiString anArg (theArgVec[anArgIter]);
9769     anArg.UpperCase();
9770     if (anArg == "-ABSDEFL"
9771      || anArg == "-ABSOLUTEDEFLECTION"
9772      || anArg == "-DEFL"
9773      || anArg == "-DEFLECTION")
9774     {
9775       if (++anArgIter >= theArgsNb)
9776       {
9777         Message::SendFail() << "Syntax error at " << anArg;
9778         return 1;
9779       }
9780       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
9781       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
9782     }
9783     else if (anArg == "-RELDEFL"
9784           || anArg == "-RELATIVEDEFLECTION"
9785           || anArg == "-DEVCOEFF"
9786           || anArg == "-DEVIATIONCOEFF"
9787           || anArg == "-DEVIATIONCOEFFICIENT")
9788     {
9789       if (++anArgIter >= theArgsNb)
9790       {
9791         Message::SendFail() << "Syntax error at " << anArg;
9792         return 1;
9793       }
9794       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
9795       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
9796     }
9797     else if (anArg == "-ANGDEFL"
9798           || anArg == "-ANGULARDEFL"
9799           || anArg == "-ANGULARDEFLECTION")
9800     {
9801       if (++anArgIter >= theArgsNb)
9802       {
9803         Message::SendFail() << "Syntax error at " << anArg;
9804         return 1;
9805       }
9806       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
9807     }
9808     else if (anArg == "-AUTOTR"
9809           || anArg == "-AUTOTRIANG"
9810           || anArg == "-AUTOTRIANGULATION")
9811     {
9812       ++anArgIter;
9813       bool toTurnOn = true;
9814       if (anArgIter >= theArgsNb
9815       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
9816       {
9817         Message::SendFail() << "Syntax error at '" << anArg << "'";
9818         return 1;
9819       }
9820       aDefParams->SetAutoTriangulation (toTurnOn);
9821     }
9822     else
9823     {
9824       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
9825       return 1;
9826     }
9827   }
9828
9829   return 0;
9830 }
9831
9832 //! Parse light source type from string.
9833 static bool parseLightSourceType (const TCollection_AsciiString& theTypeName,
9834                                   Graphic3d_TypeOfLightSource& theType)
9835 {
9836   TCollection_AsciiString aType (theTypeName);
9837   aType.LowerCase();
9838   if (aType == "amb"
9839    || aType == "ambient"
9840    || aType == "amblight")
9841   {
9842     theType = Graphic3d_TypeOfLightSource_Ambient;
9843   }
9844   else if (aType == "directional"
9845         || aType == "dirlight")
9846   {
9847     theType = Graphic3d_TypeOfLightSource_Directional;
9848   }
9849   else if (aType == "spot"
9850         || aType == "spotlight")
9851   {
9852     theType = Graphic3d_TypeOfLightSource_Spot;
9853   }
9854   else if (aType == "poslight"
9855         || aType == "positional"
9856         || aType == "point"
9857         || aType == "pnt")
9858   {
9859     theType = Graphic3d_TypeOfLightSource_Positional;
9860   }
9861   else
9862   {
9863     return false;
9864   }
9865   return true;
9866 }
9867
9868 //! Find existing light by name or index.
9869 static Handle(V3d_Light) findLightSource (const TCollection_AsciiString& theName)
9870 {
9871   Handle(V3d_Light) aLight;
9872   Standard_Integer aLightIndex = -1;
9873   Draw::ParseInteger (theName.ToCString(), aLightIndex);
9874   Standard_Integer aLightIt = 0;
9875   Handle(V3d_View) aView = ViewerTest::CurrentView();
9876   for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
9877   {
9878     if (aLightIndex != -1)
9879     {
9880       if (aLightIt == aLightIndex)
9881       {
9882         return aLightIter.Value();
9883       }
9884     }
9885     else if (aLightIter.Value()->GetId() == theName
9886           || aLightIter.Value()->Name()  == theName)
9887     {
9888       if (!aLight.IsNull())
9889       {
9890         Message::SendWarning() << "Warning: ambiguous light name '" << theName << "'";
9891         break;
9892       }
9893       aLight = aLightIter.Value();
9894     }
9895   }
9896   return aLight;
9897 }
9898
9899 //===============================================================================================
9900 //function : VLight
9901 //purpose  :
9902 //===============================================================================================
9903 static int VLight (Draw_Interpretor& theDi,
9904                    Standard_Integer  theArgsNb,
9905                    const char**      theArgVec)
9906 {
9907   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
9908   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
9909   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9910   if (aView.IsNull()
9911    || aViewer.IsNull())
9912   {
9913     Message::SendFail ("Error: no active viewer");
9914     return 1;
9915   }
9916
9917   if (theArgsNb < 2)
9918   {
9919     // print lights info
9920     Standard_Integer aLightId = 0;
9921     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
9922     {
9923       Handle(V3d_Light) aLight = aLightIter.Value();
9924       const Quantity_Color aColor = aLight->Color();
9925       theDi << "Light #" << aLightId
9926             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
9927             << " [" << aLight->GetId() << "] "
9928             << (aLight->IsEnabled() ? "ON" : "OFF") << "\n";
9929       switch (aLight->Type())
9930       {
9931         case Graphic3d_TypeOfLightSource_Ambient:
9932         {
9933           theDi << "  Type:       Ambient\n"
9934                 << "  Intensity:  " << aLight->Intensity() << "\n";
9935           break;
9936         }
9937         case Graphic3d_TypeOfLightSource_Directional:
9938         {
9939           theDi << "  Type:       Directional\n"
9940                 << "  Intensity:  " << aLight->Intensity() << "\n"
9941                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9942                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9943                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9944                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n";
9945           break;
9946         }
9947         case Graphic3d_TypeOfLightSource_Positional:
9948         {
9949           theDi << "  Type:       Positional\n"
9950                 << "  Intensity:  " << aLight->Intensity() << "\n"
9951                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9952                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9953                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9954                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9955                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9956                 << "  Range:      " << aLight->Range() << "\n";
9957           break;
9958         }
9959         case Graphic3d_TypeOfLightSource_Spot:
9960         {
9961           theDi << "  Type:       Spot\n"
9962                 << "  Intensity:  " << aLight->Intensity() << "\n"
9963                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9964                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9965                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9966                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n"
9967                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9968                 << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n"
9969                 << "  Exponent:   " << aLight->Concentration() << "\n"
9970                 << "  Range:      " << aLight->Range() << "\n";
9971           break;
9972         }
9973         default:
9974         {
9975           theDi << "  Type:       UNKNOWN\n";
9976           break;
9977         }
9978       }
9979       theDi << "  Color:      " << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
9980     }
9981   }
9982
9983   Handle(V3d_Light) aLightOld, aLightNew;
9984   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
9985   bool isGlobal = true;
9986   ViewerTest_AutoUpdater anUpdateTool (aCtx, aView);
9987   Handle(AIS_LightSource) aLightPrs;
9988   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
9989   {
9990     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
9991     TCollection_AsciiString anArgCase (anArg);
9992     anArgCase.LowerCase();
9993     if (anUpdateTool.parseRedrawMode (anArg))
9994     {
9995       continue;
9996     }
9997     else if (anArgCase == "-new"
9998           || anArgCase == "-add"
9999           || anArgCase == "-create"
10000           || anArgCase == "-type"
10001           || (anArgCase == "-reset"
10002           && !aLightNew.IsNull())
10003           || (anArgCase == "-defaults"
10004           && !aLightNew.IsNull())
10005           || anArgCase == "add"
10006           || anArgCase == "new"
10007           || anArgCase == "create")
10008     {
10009       Graphic3d_TypeOfLightSource aType = Graphic3d_TypeOfLightSource_Ambient;
10010       if (anArgCase == "-reset")
10011       {
10012         aType = aLightNew->Type();
10013       }
10014       else if (anArgIt + 1 >= theArgsNb
10015            || !parseLightSourceType (theArgVec[++anArgIt], aType))
10016       {
10017         theDi << "Syntax error at '" << theArgVec[anArgIt] << "'\n";
10018         return 1;
10019       }
10020
10021       TCollection_AsciiString aName;
10022       if (!aLightNew.IsNull())
10023       {
10024         aName = aLightNew->Name();
10025       }
10026       switch (aType)
10027       {
10028         case Graphic3d_TypeOfLightSource_Ambient:
10029         {
10030           aLightNew = new V3d_AmbientLight();
10031           break;
10032         }
10033         case Graphic3d_TypeOfLightSource_Directional:
10034         {
10035           aLightNew = new V3d_DirectionalLight();
10036           break;
10037         }
10038         case Graphic3d_TypeOfLightSource_Spot:
10039         {
10040           aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
10041           break;
10042         }
10043         case Graphic3d_TypeOfLightSource_Positional:
10044         {
10045           aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
10046           break;
10047         }
10048       }
10049
10050       if (anArgCase == "-type"
10051       && !aLightOld.IsNull())
10052       {
10053         aLightNew->CopyFrom (aLightOld);
10054       }
10055       aLightNew->SetName (aName);
10056     }
10057     else if ((anArgCase == "-layer"
10058            || anArgCase == "-zlayer")
10059           && anArgIt + 1 < theArgsNb)
10060     {
10061       if (!ViewerTest::ParseZLayer (theArgVec[++anArgIt], aLayer)
10062       ||  aLayer == Graphic3d_ZLayerId_UNKNOWN)
10063       {
10064         Message::SendFail() << "Error: wrong syntax at '" << theArgVec[anArgIt] << "'";
10065         return 1;
10066       }
10067     }
10068     else if (anArgCase == "-glob"
10069           || anArgCase == "-global"
10070           || anArgCase == "-loc"
10071           || anArgCase == "-local")
10072     {
10073       isGlobal = anArgCase.StartsWith ("-glob");
10074     }
10075     else if (anArgCase == "-def"
10076           || anArgCase == "-defaults"
10077           || anArgCase == "-reset")
10078     {
10079       aViewer->SetDefaultLights();
10080       aLightOld.Nullify();
10081       aLightNew.Nullify();
10082       aLightPrs.Nullify();
10083     }
10084     else if (anArgCase == "-clr"
10085           || anArgCase == "-clear"
10086           || anArgCase == "clear")
10087     {
10088       TColStd_SequenceOfInteger aLayers;
10089       aViewer->GetAllZLayers (aLayers);
10090       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10091       {
10092         if (aLayeriter.Value() == aLayer
10093          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10094         {
10095           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10096           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10097           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10098           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10099           {
10100             break;
10101           }
10102         }
10103       }
10104
10105       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10106       {
10107         ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
10108         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10109         {
10110           Handle(V3d_Light) aLight = aLightIter.Value();
10111           Handle(AIS_InteractiveObject) aPrsObject;
10112           GetMapOfAIS().Find2 (aLight->Name(), aPrsObject);
10113           if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10114           {
10115             aCtx->Remove (aLightSourceDel, false);
10116             aMap.UnBind1 (aLightSourceDel);
10117           }
10118           aViewer->DelLight (aLight);
10119           aLightIter = aView->ActiveLightIterator();
10120         }
10121       }
10122
10123       aLightOld.Nullify();
10124       aLightNew.Nullify();
10125       aLightPrs.Nullify();
10126     }
10127     else if (!aLightNew.IsNull()
10128           && (anArgCase == "-display"
10129            || anArgCase == "-disp"
10130            || anArgCase == "-presentation"
10131            || anArgCase == "-prs"))
10132     {
10133       TCollection_AsciiString aLightName = aLightNew->Name();
10134       if (anArgIt + 1 < theArgsNb
10135        && theArgVec[anArgIt + 1][0] != '-')
10136       {
10137         // old syntax
10138         aLightName = theArgVec[++anArgIt];
10139         if (aLightNew->Name() != aLightName)
10140         {
10141           if (Handle(V3d_Light) anOtherLight = findLightSource (aLightName))
10142           {
10143             theDi << "Syntax error: light with name '" << aLightName << "' is already defined";
10144             return 1;
10145           }
10146           aLightNew->SetName (aLightName);
10147         }
10148       }
10149       if (aLightName.IsEmpty())
10150       {
10151         Message::SendFail() << "Error: nameless light source cannot be displayed";
10152         return 1;
10153       }
10154       if (aLightPrs.IsNull())
10155       {
10156         aLightPrs = new AIS_LightSource (aLightNew);
10157       }
10158       theDi << aLightName << " ";
10159     }
10160     else if (!aLightNew.IsNull()
10161           && (anArgCase == "-disable"
10162            || anArgCase == "-disabled"
10163            || anArgCase == "-enable"
10164            || anArgCase == "-enabled"))
10165     {
10166       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10167       if (anArgCase == "-disable"
10168        || anArgCase == "-disabled")
10169       {
10170         toEnable = !toEnable;
10171       }
10172       aLightNew->SetEnabled (toEnable);
10173     }
10174     else if (!aLightNew.IsNull()
10175           && (anArgCase == "-color"
10176            || anArgCase == "-colour"
10177            || anArgCase == "color"))
10178     {
10179       Quantity_Color aColor;
10180       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
10181                                                      theArgVec + anArgIt + 1,
10182                                                      aColor);
10183       anArgIt += aNbParsed;
10184       if (aNbParsed == 0)
10185       {
10186         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10187         return 1;
10188       }
10189       aLightNew->SetColor (aColor);
10190     }
10191     else if (!aLightNew.IsNull()
10192           && (anArgCase == "-pos"
10193            || anArgCase == "-position"
10194            || anArgCase == "-prsposition"
10195            || anArgCase == "-prspos"
10196            || anArgCase == "pos"
10197            || anArgCase == "position")
10198           && (anArgIt + 3) < theArgsNb)
10199     {
10200       gp_XYZ aPosXYZ;
10201       if (!parseXYZ (theArgVec + anArgIt + 1, aPosXYZ))
10202       {
10203         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10204         return 1;
10205       }
10206
10207       anArgIt += 3;
10208       if (anArgCase == "-prsposition"
10209        || anArgCase == "-prspos")
10210       {
10211         aLightNew->SetDisplayPosition (aPosXYZ);
10212       }
10213       else
10214       {
10215         if (aLightNew->Type() != Graphic3d_TypeOfLightSource_Positional
10216          && aLightNew->Type() != Graphic3d_TypeOfLightSource_Spot)
10217         {
10218           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10219           return 1;
10220         }
10221
10222         aLightNew->SetPosition (aPosXYZ);
10223       }
10224     }
10225     else if (!aLightNew.IsNull()
10226           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional
10227            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10228           && (anArgCase == "-dir"
10229            || anArgCase == "-direction")
10230           && (anArgIt + 3) < theArgsNb)
10231     {
10232       gp_XYZ aDirXYZ;
10233       if (!parseXYZ (theArgVec + anArgIt + 1, aDirXYZ))
10234       {
10235         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10236         return 1;
10237       }
10238
10239       anArgIt += 3;
10240       aLightNew->SetDirection (gp_Dir (aDirXYZ));
10241     }
10242     else if (!aLightNew.IsNull()
10243           && (anArgCase == "-smoothangle"
10244            || anArgCase == "-smoothradius"
10245            || anArgCase == "-sm"
10246            || anArgCase == "-smoothness")
10247           && anArgIt + 1 < theArgsNb)
10248     {
10249       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10250       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10251       {
10252         aSmoothness = Standard_ShortReal(aSmoothness * M_PI / 180.0);
10253       }
10254       if (Abs (aSmoothness) <= ShortRealEpsilon())
10255       {
10256         aLightNew->SetIntensity (1.f);
10257       }
10258       else if (Abs (aLightNew->Smoothness()) <= ShortRealEpsilon())
10259       {
10260         aLightNew->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
10261       }
10262       else
10263       {
10264         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightNew->Smoothness());
10265         aLightNew->SetIntensity (aLightNew->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
10266       }
10267
10268       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10269       {
10270         aLightNew->SetSmoothRadius (aSmoothness);
10271       }
10272       else if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10273       {
10274         aLightNew->SetSmoothAngle (aSmoothness);
10275       }
10276     }
10277     else if (!aLightNew.IsNull()
10278           && (anArgCase == "-int"
10279            || anArgCase == "-intensity")
10280           && anArgIt + 1 < theArgsNb)
10281     {
10282       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10283       aLightNew->SetIntensity (aIntensity);
10284     }
10285     else if (!aLightNew.IsNull()
10286           &&  aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10287           && (anArgCase == "-spotangle"
10288            || anArgCase == "-ang"
10289            || anArgCase == "-angle")
10290           && anArgIt + 1 < theArgsNb)
10291     {
10292       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10293       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
10294       aLightNew->SetAngle (anAngle);
10295     }
10296     else if (!aLightNew.IsNull()
10297           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10298            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10299           && (anArgCase == "-constatten"
10300            || anArgCase == "-constattenuation")
10301           && anArgIt + 1 < theArgsNb)
10302     {
10303       const Standard_ShortReal aConstAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10304       aLightNew->SetAttenuation (aConstAtten, aLightNew->LinearAttenuation());
10305     }
10306     else if (!aLightNew.IsNull()
10307           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10308            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10309           && (anArgCase == "-linatten"
10310            || anArgCase == "-linearatten"
10311            || anArgCase == "-linearattenuation")
10312           && anArgIt + 1 < theArgsNb)
10313     {
10314       const Standard_ShortReal aLinAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10315       aLightNew->SetAttenuation (aLightNew->ConstAttenuation(), aLinAtten);
10316     }
10317     else if (!aLightNew.IsNull()
10318           && aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10319           && (anArgCase == "-spotexp"
10320            || anArgCase == "-spotexponent"
10321            || anArgCase == "-exp"
10322            || anArgCase == "-exponent")
10323           && anArgIt + 1 < theArgsNb)
10324     {
10325       aLightNew->SetConcentration ((Standard_ShortReal )Atof (theArgVec[++anArgIt]));
10326     }
10327     else if (!aLightNew.IsNull()
10328            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10329            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Directional
10330            && anArgCase == "-range"
10331            && anArgIt + 1 < theArgsNb)
10332     {
10333       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[++anArgIt]));
10334       aLightNew->SetRange (aRange);
10335     }
10336     else if (!aLightNew.IsNull()
10337           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10338           && (anArgCase == "-head"
10339            || anArgCase == "-headlight"))
10340     {
10341       Standard_Boolean isHeadLight = Standard_True;
10342       if (anArgIt + 1 < theArgsNb
10343        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
10344       {
10345         ++anArgIt;
10346       }
10347       aLightNew->SetHeadlight (isHeadLight);
10348     }
10349     else if (!aLightNew.IsNull()
10350            && anArgCase == "-name"
10351            && anArgIt + 1 < theArgsNb)
10352     {
10353       const TCollection_AsciiString aName = theArgVec[++anArgIt];
10354       if (aLightNew->Name() == aName)
10355       {
10356         continue;
10357       }
10358
10359       if (Handle(V3d_Light) anOtherLight = findLightSource (aName))
10360       {
10361         theDi << "Syntax error: light with name '" << aName << "' is already defined";
10362         return 1;
10363       }
10364       aLightNew->SetName (aName);
10365     }
10366     else if (!aLightPrs.IsNull()
10367           && (anArgCase == "-showzoomable"
10368            || anArgCase == "-prszoomable"
10369            || anArgCase == "-zoomable"))
10370     {
10371       const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10372       aLightPrs->SetZoomable (isZoomable);
10373     }
10374     else if (!aLightPrs.IsNull()
10375          && (anArgCase == "-showdraggable"
10376           || anArgCase == "-prsdraggable"
10377           || anArgCase == "-draggable"))
10378     {
10379       const bool isDraggable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10380       aLightPrs->SetDraggable (isDraggable);
10381     }
10382     else if (!aLightPrs.IsNull()
10383           && (anArgCase == "-showname"
10384            || anArgCase == "-prsname"))
10385     {
10386       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10387       aLightPrs->SetDisplayName (toDisplay);
10388     }
10389     else if (!aLightPrs.IsNull()
10390           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10391            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10392           && (anArgCase == "-showrange"
10393            || anArgCase == "-prsrange"))
10394     {
10395       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10396       aLightPrs->SetDisplayRange (toDisplay);
10397     }
10398     else if (!aLightPrs.IsNull()
10399           && (anArgCase == "-showsize"
10400            || anArgCase == "-prssize")
10401           && anArgIt + 1 < theArgsNb)
10402     {
10403       Standard_Real aSize = 0.0;
10404       if (!Draw::ParseReal (theArgVec[++anArgIt], aSize)
10405        || aSize <= 0.0
10406        || aLightPrs.IsNull())
10407       {
10408         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10409         return 1;
10410       }
10411
10412       aLightPrs->SetSize (aSize);
10413     }
10414     else if (!aLightPrs.IsNull()
10415           && (anArgCase == "-dirarcsize"
10416            || anArgCase == "-arcsize"
10417            || anArgCase == "-arc")
10418           && anArgIt + 1 < theArgsNb)
10419     {
10420       Standard_Integer aSize = 0;
10421       if (!Draw::ParseInteger (theArgVec[anArgIt + 1], aSize)
10422        || aSize <= 0
10423        || aLightPrs->Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
10424       {
10425         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10426         return 1;
10427       }
10428       ++anArgIt;
10429       aLightPrs->SetArcSize (aSize);
10430     }
10431     else if (!aLightNew.IsNull()
10432           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10433           && (anArgCase == "-castshadow"
10434            || anArgCase == "-castshadows"
10435            || anArgCase == "-shadows"))
10436     {
10437       bool toCastShadows = true;
10438       if (anArgIt + 1 < theArgsNb
10439        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
10440       {
10441         ++anArgIt;
10442       }
10443       aLightNew->SetCastShadows (toCastShadows);
10444     }
10445     else if (anArgCase == "-del"
10446           || anArgCase == "-delete"
10447           || anArgCase == "-remove"
10448           || anArgCase == "del"
10449           || anArgCase == "delete"
10450           || anArgCase == "remove")
10451     {
10452       if (aLightOld.IsNull())
10453       {
10454         if (!aLightNew.IsNull())
10455         {
10456           aLightNew.Nullify();
10457           continue;
10458         }
10459
10460         if (++anArgIt >= theArgsNb)
10461         {
10462           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10463           return 1;
10464         }
10465
10466         const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10467         aLightOld = findLightSource (anOldName);
10468         if (aLightOld.IsNull())
10469         {
10470           Message::SendWarning() << "Warning: light '" << anOldName << "' not found";
10471           continue;
10472         }
10473       }
10474
10475       aLightNew.Nullify();
10476       aLightPrs.Nullify();
10477     }
10478     else if (anArgCase == "-change"
10479           || anArgCase == "change")
10480     {
10481       // just skip old syntax
10482     }
10483     else if (aLightNew.IsNull()
10484          && !anArgCase.StartsWith ("-"))
10485     {
10486       if (!aLightNew.IsNull())
10487       {
10488         continue;
10489       }
10490
10491       const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10492       aLightOld = findLightSource (anOldName);
10493       if (!aLightOld.IsNull())
10494       {
10495         aLightNew = aLightOld;
10496
10497         Handle(AIS_InteractiveObject) aPrsObject;
10498         GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10499         aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsObject);
10500       }
10501       else
10502       {
10503         Standard_Integer aLightIndex = -1;
10504         Draw::ParseInteger (anOldName.ToCString(), aLightIndex);
10505         if (aLightIndex != -1)
10506         {
10507           Message::SendFail() << "Syntax error: light source with index '" << aLightIndex << "' is not found";
10508           return 1;
10509         }
10510
10511         aLightNew = new V3d_AmbientLight();
10512         aLightNew->SetName (anOldName);
10513       }
10514     }
10515     else
10516     {
10517       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
10518       return 1;
10519     }
10520   }
10521
10522   // delete old light source
10523   if (!aLightOld.IsNull()
10524     && aLightOld != aLightNew)
10525   {
10526     TColStd_SequenceOfInteger aLayers;
10527     aViewer->GetAllZLayers (aLayers);
10528     for (TColStd_SequenceOfInteger::Iterator aLayerIter (aLayers); aLayerIter.More(); aLayerIter.Next())
10529     {
10530       if (aLayerIter.Value() == aLayer
10531        || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10532       {
10533         Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerIter.Value());
10534         if (!aSettings.Lights().IsNull())
10535         {
10536           aSettings.Lights()->Remove (aLightOld);
10537           if (aSettings.Lights()->IsEmpty())
10538           {
10539             aSettings.SetLights (Handle(Graphic3d_LightSet)());
10540           }
10541         }
10542         aViewer->SetZLayerSettings (aLayerIter.Value(), aSettings);
10543         if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10544         {
10545           break;
10546         }
10547       }
10548     }
10549
10550     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10551     {
10552       Handle(AIS_InteractiveObject) aPrsObject;
10553       GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10554       if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10555       {
10556         aCtx->Remove (aLightSourceDel, false);
10557         GetMapOfAIS().UnBind1 (aLightSourceDel);
10558       }
10559       aViewer->DelLight (aLightOld);
10560     }
10561     aLightOld.Nullify();
10562   }
10563
10564   // add new light source
10565   if (!aLightNew.IsNull())
10566   {
10567     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10568     {
10569       aViewer->AddLight (aLightNew);
10570       if (isGlobal)
10571       {
10572         aViewer->SetLightOn (aLightNew);
10573       }
10574       else
10575       {
10576         aView->SetLightOn (aLightNew);
10577       }
10578     }
10579     else
10580     {
10581       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayer);
10582       if (aSettings.Lights().IsNull())
10583       {
10584         aSettings.SetLights (new Graphic3d_LightSet());
10585       }
10586       aSettings.Lights()->Add (aLightNew);
10587       aViewer->SetZLayerSettings (aLayer, aSettings);
10588     }
10589
10590     if (!aLightPrs.IsNull())
10591     {
10592       aLightPrs->SetLight (aLightNew);
10593       ViewerTest::Display (aLightNew->Name(), aLightPrs, false);
10594     }
10595   }
10596
10597   // manage presentations
10598   struct LightPrsSort
10599   {
10600     bool operator() (const Handle(AIS_LightSource)& theLeft,
10601                      const Handle(AIS_LightSource)& theRight)
10602     {
10603       return theLeft->Light()->GetId() < theRight->Light()->GetId();
10604     }
10605   };
10606
10607   AIS_ListOfInteractive aPrsList;
10608   aCtx->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
10609   if (!aPrsList.IsEmpty())
10610   {
10611     // update light source presentations
10612     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
10613     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
10614     {
10615       if (Handle(AIS_LightSource) aLightPrs2 = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
10616       {
10617         aLightPrsVec.push_back (aLightPrs2);
10618       }
10619     }
10620
10621     // sort objects by id as AIS_InteractiveContext stores them in unordered map
10622     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
10623
10624     Standard_Integer aTopStack = 0;
10625     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
10626     {
10627       Handle(AIS_LightSource) aLightPrs2 = *aPrsIter;
10628       if (!aLightPrs2->TransformPersistence().IsNull()
10629         && aLightPrs2->TransformPersistence()->IsTrihedronOr2d())
10630       {
10631         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs2->Size();
10632         aLightPrs2->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
10633         aTopStack += aPrsSize + aPrsSize / 2;
10634       }
10635       aCtx->Redisplay (aLightPrs2, false);
10636       aCtx->SetTransformPersistence (aLightPrs2, aLightPrs2->TransformPersistence());
10637     }
10638   }
10639   return 0;
10640 }
10641
10642 //===============================================================================================
10643 //function : VPBREnvironment
10644 //purpose  :
10645 //===============================================================================================
10646 static int VPBREnvironment (Draw_Interpretor&,
10647                             Standard_Integer theArgsNb,
10648                             const char**     theArgVec)
10649 {
10650   if (theArgsNb > 2)
10651   {
10652     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
10653     return 1;
10654   }
10655
10656   Handle(V3d_View) aView = ViewerTest::CurrentView();
10657   if (aView.IsNull())
10658   {
10659     Message::SendFail ("Error: no active viewer");
10660     return 1;
10661   }
10662
10663   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
10664   anArg.LowerCase();
10665
10666   if (anArg == "-generate"
10667    || anArg == "-gen")
10668   {
10669     aView->GeneratePBREnvironment (Standard_True);
10670   }
10671   else if (anArg == "-clear")
10672   {
10673     aView->ClearPBREnvironment (Standard_True);
10674   }
10675   else
10676   {
10677     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
10678     return 1;
10679   }
10680
10681   return 0;
10682 }
10683
10684 //! Read Graphic3d_RenderingParams::PerfCounters flag.
10685 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
10686                                             Standard_Boolean& theToReset,
10687                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
10688                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
10689 {
10690   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
10691   TCollection_AsciiString aVal = theValue;
10692   Standard_Boolean toReverse = Standard_False;
10693   if (aVal == "none")
10694   {
10695     theToReset = Standard_True;
10696     return Standard_True;
10697   }
10698   else if (aVal.StartsWith ("-"))
10699   {
10700     toReverse = Standard_True;
10701     aVal = aVal.SubString (2, aVal.Length());
10702   }
10703   else if (aVal.StartsWith ("no"))
10704   {
10705     toReverse = Standard_True;
10706     aVal = aVal.SubString (3, aVal.Length());
10707   }
10708   else if (aVal.StartsWith ("+"))
10709   {
10710     aVal = aVal.SubString (2, aVal.Length());
10711   }
10712   else
10713   {
10714     theToReset = Standard_True;
10715   }
10716
10717   if (     aVal == "fps"
10718         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
10719   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
10720   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
10721   else if (aVal == "structs"
10722         || aVal == "structures"
10723         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
10724   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
10725   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
10726   else if (aVal == "tris"
10727         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
10728   else if (aVal == "pnts"
10729         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
10730   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
10731   else if (aVal == "mem"
10732         || aVal == "gpumem"
10733         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
10734   else if (aVal == "skipimmediate"
10735         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
10736   else if (aVal == "frametime"
10737         || aVal == "frametimers"
10738         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
10739   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
10740   else if (aVal == "extended"
10741         || aVal == "verbose"
10742         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
10743   else if (aVal == "full"
10744         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
10745   else
10746   {
10747     return Standard_False;
10748   }
10749
10750   if (toReverse)
10751   {
10752     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
10753   }
10754   else
10755   {
10756     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
10757   }
10758   return Standard_True;
10759 }
10760
10761 //! Read Graphic3d_RenderingParams::PerfCounters flags.
10762 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
10763                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
10764 {
10765   TCollection_AsciiString aValue = theValue;
10766   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
10767   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
10768   Standard_Boolean toReset = Standard_False;
10769   for (;;)
10770   {
10771     Standard_Integer aSplitPos = aValue.Search ("|");
10772     if (aSplitPos <= 0)
10773     {
10774       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
10775       {
10776         return Standard_False;
10777       }
10778       if (toReset)
10779       {
10780         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
10781       }
10782       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
10783       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
10784       return Standard_True;
10785     }
10786
10787     if (aSplitPos > 1)
10788     {
10789       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
10790       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
10791       {
10792         return Standard_False;
10793       }
10794     }
10795     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
10796   }
10797 }
10798
10799 //=======================================================================
10800 //function : VRenderParams
10801 //purpose  : Enables/disables rendering features
10802 //=======================================================================
10803
10804 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
10805                                        Standard_Integer  theArgNb,
10806                                        const char**      theArgVec)
10807 {
10808   Handle(V3d_View) aView = ViewerTest::CurrentView();
10809   if (aView.IsNull())
10810   {
10811     Message::SendFail ("Error: no active viewer");
10812     return 1;
10813   }
10814
10815   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
10816   TCollection_AsciiString aCmdName (theArgVec[0]);
10817   aCmdName.LowerCase();
10818   if (aCmdName == "vraytrace")
10819   {
10820     if (theArgNb == 1)
10821     {
10822       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
10823       return 0;
10824     }
10825     else if (theArgNb == 2)
10826     {
10827       TCollection_AsciiString aValue (theArgVec[1]);
10828       aValue.LowerCase();
10829       if (aValue == "on"
10830        || aValue == "1")
10831       {
10832         aParams.Method = Graphic3d_RM_RAYTRACING;
10833         aView->Redraw();
10834         return 0;
10835       }
10836       else if (aValue == "off"
10837             || aValue == "0")
10838       {
10839         aParams.Method = Graphic3d_RM_RASTERIZATION;
10840         aView->Redraw();
10841         return 0;
10842       }
10843       else
10844       {
10845         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
10846         return 1;
10847       }
10848     }
10849     else
10850     {
10851       Message::SendFail ("Syntax error: wrong number of arguments");
10852       return 1;
10853     }
10854   }
10855
10856   if (theArgNb < 2)
10857   {
10858     theDI << "renderMode:  ";
10859     switch (aParams.Method)
10860     {
10861       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10862       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
10863     }
10864     theDI << "\n";
10865     theDI << "transparency:  ";
10866     switch (aParams.TransparencyMethod)
10867     {
10868       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
10869       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
10870                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
10871       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
10872                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
10873     }
10874     theDI << "\n";
10875     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
10876     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
10877     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
10878     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
10879     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
10880     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
10881     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
10882     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
10883     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
10884     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
10885     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
10886     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
10887     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
10888     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
10889     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
10890     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
10891     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
10892     theDI << "shadingModel: ";
10893     switch (aView->ShadingModel())
10894     {
10895       case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
10896       case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit";     break;
10897       case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat";      break;
10898       case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud";   break;
10899       case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong";     break;
10900       case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
10901       case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
10902     }
10903     theDI << "\n";
10904     {
10905       theDI << "perfCounters:";
10906       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
10907       {
10908         theDI << " fps";
10909       }
10910       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
10911       {
10912         theDI << " cpu";
10913       }
10914       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
10915       {
10916         theDI << " structs";
10917       }
10918       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
10919       {
10920         theDI << " groups";
10921       }
10922       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
10923       {
10924         theDI << " arrays";
10925       }
10926       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
10927       {
10928         theDI << " tris";
10929       }
10930       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
10931       {
10932         theDI << " lines";
10933       }
10934       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
10935       {
10936         theDI << " pnts";
10937       }
10938       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
10939       {
10940         theDI << " gpumem";
10941       }
10942       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
10943       {
10944         theDI << " frameTime";
10945       }
10946       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
10947       {
10948         theDI << " skipimmediate";
10949       }
10950       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
10951       {
10952         theDI << " none";
10953       }
10954       theDI << "\n";
10955     }
10956     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
10957     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
10958     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
10959                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
10960                                                                                                                     "noUpdate") << "\n";
10961     theDI << "\n";
10962     return 0;
10963   }
10964
10965   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
10966   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10967   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10968   {
10969     Standard_CString        anArg (theArgVec[anArgIter]);
10970     TCollection_AsciiString aFlag (anArg);
10971     aFlag.LowerCase();
10972     if (anUpdateTool.parseRedrawMode (aFlag))
10973     {
10974       continue;
10975     }
10976     else if (aFlag == "-echo"
10977           || aFlag == "-print")
10978     {
10979       toPrint = Standard_True;
10980       anUpdateTool.Invalidate();
10981     }
10982     else if (aFlag == "-reset")
10983     {
10984       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
10985     }
10986     else if (aFlag == "-sync"
10987           && (anArgIter + 1 < theArgNb))
10988     {
10989       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
10990       aSyncFlag.LowerCase();
10991       if (aSyncFlag == "default"
10992        || aSyncFlag == "defaults"
10993        || aSyncFlag == "viewer")
10994       {
10995         toSyncDefaults = true;
10996       }
10997       else if (aSyncFlag == "allviews"
10998             || aSyncFlag == "views")
10999       {
11000         toSyncAllViews = true;
11001       }
11002       else
11003       {
11004         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
11005         return 1;
11006       }
11007     }
11008     else if (aFlag == "-mode"
11009           || aFlag == "-rendermode"
11010           || aFlag == "-render_mode")
11011     {
11012       if (toPrint)
11013       {
11014         switch (aParams.Method)
11015         {
11016           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11017           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
11018         }
11019         continue;
11020       }
11021       else
11022       {
11023         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11024         return 1;
11025       }
11026     }
11027     else if (aFlag == "-ray"
11028           || aFlag == "-raytrace")
11029     {
11030       if (toPrint)
11031       {
11032         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
11033         continue;
11034       }
11035
11036       bool isRayTrace = true;
11037       if (anArgIter + 1 < theArgNb
11038        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
11039       {
11040         ++anArgIter;
11041       }
11042       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
11043     }
11044     else if (aFlag == "-rast"
11045           || aFlag == "-raster"
11046           || aFlag == "-rasterization")
11047     {
11048       if (toPrint)
11049       {
11050         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
11051         continue;
11052       }
11053
11054       bool isRaster = true;
11055       if (anArgIter + 1 < theArgNb
11056        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
11057       {
11058         ++anArgIter;
11059       }
11060       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
11061     }
11062     else if (aFlag == "-msaa")
11063     {
11064       if (toPrint)
11065       {
11066         theDI << aParams.NbMsaaSamples << " ";
11067         continue;
11068       }
11069       else if (++anArgIter >= theArgNb)
11070       {
11071         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11072         return 1;
11073       }
11074
11075       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11076       if (aNbSamples < 0)
11077       {
11078         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11079         return 1;
11080       }
11081       else
11082       {
11083         aParams.NbMsaaSamples = aNbSamples;
11084       }
11085     }
11086     else if (aFlag == "-linefeather"
11087           || aFlag == "-edgefeather"
11088           || aFlag == "-feather")
11089     {
11090       if (toPrint)
11091       {
11092         theDI << " " << aParams.LineFeather << " ";
11093         continue;
11094       }
11095       else if (++anArgIter >= theArgNb)
11096       {
11097         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11098         return 1;
11099       }
11100
11101       TCollection_AsciiString aParam = theArgVec[anArgIter];
11102       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11103       if (aFeather <= 0.0f)
11104       {
11105         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
11106         return 1;
11107       }
11108       aParams.LineFeather = aFeather;
11109     }
11110     else if (aFlag == "-oit")
11111     {
11112       if (toPrint)
11113       {
11114         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
11115         {
11116           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
11117         }
11118         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
11119         {
11120           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
11121         }
11122         else
11123         {
11124           theDI << "off" << " ";
11125         }
11126         continue;
11127       }
11128       else if (++anArgIter >= theArgNb)
11129       {
11130         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11131         return 1;
11132       }
11133
11134       TCollection_AsciiString aParam = theArgVec[anArgIter];
11135       aParam.LowerCase();
11136       if (aParam == "peeling"
11137        || aParam == "peel")
11138       {
11139         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
11140         if (anArgIter + 1 < theArgNb
11141          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
11142         {
11143           ++anArgIter;
11144           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11145           if (aNbLayers < 2)
11146           {
11147             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
11148             return 1;
11149           }
11150           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11151         }
11152       }
11153       else if (aParam == "weighted"
11154             || aParam == "weight")
11155       {
11156         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11157         if (anArgIter + 1 < theArgNb
11158          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
11159         {
11160           ++anArgIter;
11161           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
11162           if (aWeight < 0.f || aWeight > 1.f)
11163           {
11164             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11165             return 1;
11166           }
11167           aParams.OitDepthFactor = aWeight;
11168         }
11169       }
11170       else if (aParam.IsRealValue())
11171       {
11172         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11173         if (aWeight < 0.f || aWeight > 1.f)
11174         {
11175           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11176           return 1;
11177         }
11178
11179         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11180         aParams.OitDepthFactor     = aWeight;
11181       }
11182       else if (aParam == "off")
11183       {
11184         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
11185       }
11186       else
11187       {
11188         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11189         return 1;
11190       }
11191     }
11192     else if (aFlag == "-fonthinting"
11193           || aFlag == "-fonthint")
11194     {
11195       if (toPrint)
11196       {
11197         if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11198         {
11199           theDI << "normal" << " ";
11200         }
11201         else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11202         {
11203           theDI << "light" << " ";
11204         }
11205         else
11206         {
11207           theDI << "off" << " ";
11208         }
11209         continue;
11210       }
11211       else if (anArgIter + 1 >= theArgNb)
11212       {
11213         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11214         return 1;
11215       }
11216
11217       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11218       aHintStyle.LowerCase();
11219       if (aHintStyle == "normal"
11220        || aHintStyle == "on"
11221        || aHintStyle == "1")
11222       {
11223         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11224         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Normal);
11225       }
11226       else if (aHintStyle == "light")
11227       {
11228         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11229         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Light);
11230       }
11231       else if (aHintStyle == "no"
11232             || aHintStyle == "off"
11233             || aHintStyle == "0")
11234       {
11235         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11236         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11237       }
11238       else
11239       {
11240         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11241         return 1;
11242       }
11243     }
11244     else if (aFlag == "-fontautohinting"
11245           || aFlag == "-fontautohint")
11246     {
11247       if (toPrint)
11248       {
11249         if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
11250         {
11251           theDI << "force" << " ";
11252         }
11253         else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
11254         {
11255           theDI << "disallow" << " ";
11256         }
11257         else
11258         {
11259           theDI << "auto" << " ";
11260         }
11261         continue;
11262       }
11263       else if (anArgIter + 1 >= theArgNb)
11264       {
11265         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11266         return 1;
11267       }
11268
11269       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11270       aHintStyle.LowerCase();
11271       if (aHintStyle == "force")
11272       {
11273         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11274         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_ForceAutohint);
11275       }
11276       else if (aHintStyle == "disallow"
11277             || aHintStyle == "no")
11278       {
11279         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11280         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_NoAutohint);
11281       }
11282       else if (aHintStyle == "auto")
11283       {
11284         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11285         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11286       }
11287       else
11288       {
11289         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11290         return 1;
11291       }
11292     }
11293     else if (aFlag == "-depthprepass")
11294     {
11295       if (toPrint)
11296       {
11297         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11298         continue;
11299       }
11300       aParams.ToEnableDepthPrepass = Standard_True;
11301       if (anArgIter + 1 < theArgNb
11302        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11303       {
11304         ++anArgIter;
11305       }
11306     }
11307     else if (aFlag == "-samplealphatocoverage"
11308           || aFlag == "-alphatocoverage")
11309     {
11310       if (toPrint)
11311       {
11312         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11313         continue;
11314       }
11315       aParams.ToEnableAlphaToCoverage = Standard_True;
11316       if (anArgIter + 1 < theArgNb
11317        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11318       {
11319         ++anArgIter;
11320       }
11321     }
11322     else if (aFlag == "-rendscale"
11323           || aFlag == "-renderscale"
11324           || aFlag == "-renderresolutionscale")
11325     {
11326       if (toPrint)
11327       {
11328         theDI << aParams.RenderResolutionScale << " ";
11329         continue;
11330       }
11331       else if (++anArgIter >= theArgNb)
11332       {
11333         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11334         return 1;
11335       }
11336
11337       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11338       if (aScale < 0.01)
11339       {
11340         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11341         return 1;
11342       }
11343       else
11344       {
11345         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11346       }
11347     }
11348     else if (aFlag == "-raydepth"
11349           || aFlag == "-ray_depth")
11350     {
11351       if (toPrint)
11352       {
11353         theDI << aParams.RaytracingDepth << " ";
11354         continue;
11355       }
11356       else if (++anArgIter >= theArgNb)
11357       {
11358         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11359         return 1;
11360       }
11361
11362       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11363
11364       // We allow RaytracingDepth be more than 10 in case of GI enabled
11365       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11366       {
11367         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11368         return 1;
11369       }
11370       else
11371       {
11372         aParams.RaytracingDepth = aDepth;
11373       }
11374     }
11375     else if (aFlag == "-shad"
11376           || aFlag == "-shadows")
11377     {
11378       if (toPrint)
11379       {
11380         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11381         continue;
11382       }
11383
11384       Standard_Boolean toEnable = Standard_True;
11385       if (++anArgIter < theArgNb
11386       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11387       {
11388         --anArgIter;
11389       }
11390       aParams.IsShadowEnabled = toEnable;
11391     }
11392     else if (aFlag == "-shadowmapresolution"
11393           || aFlag == "-shadowmap")
11394     {
11395       if (toPrint)
11396       {
11397         theDI << aParams.ShadowMapResolution << " ";
11398         continue;
11399       }
11400       else if (++anArgIter >= theArgNb)
11401       {
11402         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11403         return 1;
11404       }
11405
11406       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
11407     }
11408     else if (aFlag == "-shadowmapbias")
11409     {
11410       if (toPrint)
11411       {
11412         theDI << aParams.ShadowMapBias << " ";
11413         continue;
11414       }
11415       else if (++anArgIter >= theArgNb)
11416       {
11417         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11418         return 1;
11419       }
11420
11421       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
11422     }
11423     else if (aFlag == "-refl"
11424           || aFlag == "-reflections")
11425     {
11426       if (toPrint)
11427       {
11428         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11429         continue;
11430       }
11431
11432       Standard_Boolean toEnable = Standard_True;
11433       if (++anArgIter < theArgNb
11434       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11435       {
11436         --anArgIter;
11437       }
11438       aParams.IsReflectionEnabled = toEnable;
11439     }
11440     else if (aFlag == "-fsaa")
11441     {
11442       if (toPrint)
11443       {
11444         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11445         continue;
11446       }
11447
11448       Standard_Boolean toEnable = Standard_True;
11449       if (++anArgIter < theArgNb
11450       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11451       {
11452         --anArgIter;
11453       }
11454       aParams.IsAntialiasingEnabled = toEnable;
11455     }
11456     else if (aFlag == "-gleam")
11457     {
11458       if (toPrint)
11459       {
11460         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11461         continue;
11462       }
11463
11464       Standard_Boolean toEnable = Standard_True;
11465       if (++anArgIter < theArgNb
11466       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11467       {
11468         --anArgIter;
11469       }
11470       aParams.IsTransparentShadowEnabled = toEnable;
11471     }
11472     else if (aFlag == "-gi")
11473     {
11474       if (toPrint)
11475       {
11476         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11477         continue;
11478       }
11479
11480       Standard_Boolean toEnable = Standard_True;
11481       if (++anArgIter < theArgNb
11482       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11483       {
11484         --anArgIter;
11485       }
11486       aParams.IsGlobalIlluminationEnabled = toEnable;
11487       if (!toEnable)
11488       {
11489         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11490       }
11491     }
11492     else if (aFlag == "-blockedrng"
11493           || aFlag == "-brng")
11494     {
11495       if (toPrint)
11496       {
11497         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
11498         continue;
11499       }
11500
11501       Standard_Boolean toEnable = Standard_True;
11502       if (++anArgIter < theArgNb
11503         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11504       {
11505         --anArgIter;
11506       }
11507       aParams.CoherentPathTracingMode = toEnable;
11508     }
11509     else if (aFlag == "-maxrad")
11510     {
11511       if (toPrint)
11512       {
11513         theDI << aParams.RadianceClampingValue << " ";
11514         continue;
11515       }
11516       else if (++anArgIter >= theArgNb)
11517       {
11518         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11519         return 1;
11520       }
11521
11522       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11523       if (!aMaxRadStr.IsRealValue (Standard_True))
11524       {
11525         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11526         return 1;
11527       }
11528
11529       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11530       if (aMaxRadiance <= 0.0)
11531       {
11532         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
11533         return 1;
11534       }
11535       else
11536       {
11537         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
11538       }
11539     }
11540     else if (aFlag == "-iss")
11541     {
11542       if (toPrint)
11543       {
11544         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
11545         continue;
11546       }
11547
11548       Standard_Boolean toEnable = Standard_True;
11549       if (++anArgIter < theArgNb
11550         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11551       {
11552         --anArgIter;
11553       }
11554       aParams.AdaptiveScreenSampling = toEnable;
11555     }
11556     else if (aFlag == "-issatomic")
11557     {
11558       if (toPrint)
11559       {
11560         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
11561         continue;
11562       }
11563
11564       Standard_Boolean toEnable = Standard_True;
11565       if (++anArgIter < theArgNb
11566       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11567       {
11568         --anArgIter;
11569       }
11570       aParams.AdaptiveScreenSamplingAtomic = toEnable;
11571     }
11572     else if (aFlag == "-issd")
11573     {
11574       if (toPrint)
11575       {
11576         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
11577         continue;
11578       }
11579
11580       Standard_Boolean toEnable = Standard_True;
11581       if (++anArgIter < theArgNb
11582         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11583       {
11584         --anArgIter;
11585       }
11586       aParams.ShowSamplingTiles = toEnable;
11587     }
11588     else if (aFlag == "-tilesize")
11589     {
11590       if (toPrint)
11591       {
11592         theDI << aParams.RayTracingTileSize << " ";
11593         continue;
11594       }
11595       else if (++anArgIter >= theArgNb)
11596       {
11597         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11598         return 1;
11599       }
11600
11601       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
11602       if (aTileSize < 1)
11603       {
11604         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
11605         return 1;
11606       }
11607       aParams.RayTracingTileSize = aTileSize;
11608     }
11609     else if (aFlag == "-nbtiles")
11610     {
11611       if (toPrint)
11612       {
11613         theDI << aParams.NbRayTracingTiles << " ";
11614         continue;
11615       }
11616       else if (++anArgIter >= theArgNb)
11617       {
11618         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11619         return 1;
11620       }
11621
11622       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
11623       if (aNbTiles < -1)
11624       {
11625         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
11626         return 1;
11627       }
11628       else if (aNbTiles > 0
11629             && (aNbTiles < 64
11630              || aNbTiles > 1024))
11631       {
11632         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
11633       }
11634       aParams.NbRayTracingTiles = aNbTiles;
11635     }
11636     else if (aFlag == "-env")
11637     {
11638       if (toPrint)
11639       {
11640         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
11641         continue;
11642       }
11643
11644       Standard_Boolean toEnable = Standard_True;
11645       if (++anArgIter < theArgNb
11646         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11647       {
11648         --anArgIter;
11649       }
11650       aParams.UseEnvironmentMapBackground = toEnable;
11651     }
11652     else if (aFlag == "-ignorenormalmap")
11653     {
11654       if (toPrint)
11655       {
11656         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
11657         continue;
11658       }
11659
11660       Standard_Boolean toEnable = Standard_True;
11661       if (++anArgIter < theArgNb
11662         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11663       {
11664         --anArgIter;
11665       }
11666       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
11667     }
11668     else if (aFlag == "-twoside")
11669     {
11670       if (toPrint)
11671       {
11672         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
11673         continue;
11674       }
11675
11676       Standard_Boolean toEnable = Standard_True;
11677       if (++anArgIter < theArgNb
11678         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11679       {
11680         --anArgIter;
11681       }
11682       aParams.TwoSidedBsdfModels = toEnable;
11683     }
11684     else if (aFlag == "-shademodel"
11685           || aFlag == "-shadingmodel"
11686           || aFlag == "-shading")
11687     {
11688       if (toPrint)
11689       {
11690         switch (aView->ShadingModel())
11691         {
11692           case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
11693           case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit ";    break;
11694           case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat ";     break;
11695           case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud ";  break;
11696           case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong ";    break;
11697           case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
11698           case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
11699         }
11700         continue;
11701       }
11702
11703       if (++anArgIter >= theArgNb)
11704       {
11705         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11706       }
11707
11708       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TypeOfShadingModel_DEFAULT;
11709       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
11710        && aModel != Graphic3d_TypeOfShadingModel_DEFAULT)
11711       {
11712         aView->SetShadingModel (aModel);
11713       }
11714       else
11715       {
11716         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
11717         return 1;
11718       }
11719     }
11720     else if (aFlag == "-pbrenvpow2size"
11721           || aFlag == "-pbrenvp2s"
11722           || aFlag == "-pep2s")
11723     {
11724       if (++anArgIter >= theArgNb)
11725       {
11726         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11727         return 1;
11728       }
11729
11730       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
11731       if (aPbrEnvPow2Size < 1)
11732       {
11733         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
11734         return 1;
11735       }
11736       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
11737     }
11738     else if (aFlag == "-pbrenvspecmaplevelsnumber"
11739           || aFlag == "-pbrenvspecmapnblevels"
11740           || aFlag == "-pbrenvspecmaplevels"
11741           || aFlag == "-pbrenvsmln"
11742           || aFlag == "-pesmln")
11743     {
11744       if (++anArgIter >= theArgNb)
11745       {
11746         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11747         return 1;
11748       }
11749
11750       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
11751       if (aPbrEnvSpecMapNbLevels < 2)
11752       {
11753         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
11754         return 1;
11755       }
11756       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
11757     }
11758     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
11759           || aFlag == "-pbrenvbakingdiffsamples"
11760           || aFlag == "-pbrenvbdsn")
11761     {
11762       if (++anArgIter >= theArgNb)
11763       {
11764         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11765         return 1;
11766       }
11767
11768       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11769       if (aPbrEnvBakingDiffNbSamples < 1)
11770       {
11771         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
11772         return 1;
11773       }
11774       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
11775     }
11776     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
11777           || aFlag == "-pbrenvbakingspecsamples"
11778           || aFlag == "-pbrenvbssn")
11779     {
11780     if (++anArgIter >= theArgNb)
11781     {
11782       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11783       return 1;
11784     }
11785
11786     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
11787     if (aPbrEnvBakingSpecNbSamples < 1)
11788     {
11789       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
11790       return 1;
11791     }
11792     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
11793     }
11794     else if (aFlag == "-pbrenvbakingprobability"
11795           || aFlag == "-pbrenvbp")
11796     {
11797       if (++anArgIter >= theArgNb)
11798       {
11799         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11800         return 1;
11801       }
11802       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
11803       if (aPbrEnvBakingProbability < 0.f
11804        || aPbrEnvBakingProbability > 1.f)
11805       {
11806         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
11807         return 1;
11808       }
11809       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
11810     }
11811     else if (aFlag == "-resolution")
11812     {
11813       if (++anArgIter >= theArgNb)
11814       {
11815         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11816         return 1;
11817       }
11818
11819       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
11820       if (aResolution.IsIntegerValue())
11821       {
11822         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
11823       }
11824       else
11825       {
11826         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
11827         return 1;
11828       }
11829     }
11830     else if (aFlag == "-rebuildglsl"
11831           || aFlag == "-rebuild")
11832     {
11833       if (toPrint)
11834       {
11835         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
11836         continue;
11837       }
11838
11839       Standard_Boolean toEnable = Standard_True;
11840       if (++anArgIter < theArgNb
11841           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11842       {
11843         --anArgIter;
11844       }
11845       aParams.RebuildRayTracingShaders = toEnable;
11846     }
11847     else if (aFlag == "-focal")
11848     {
11849       if (++anArgIter >= theArgNb)
11850       {
11851         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11852         return 1;
11853       }
11854
11855       TCollection_AsciiString aParam (theArgVec[anArgIter]);
11856       if (aParam.IsRealValue (Standard_True))
11857       {
11858         float aFocalDist = static_cast<float> (aParam.RealValue());
11859         if (aFocalDist < 0)
11860         {
11861           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11862           return 1;
11863         }
11864         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
11865       }
11866       else
11867       {
11868         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11869         return 1;
11870       }
11871     }
11872     else if (aFlag == "-aperture")
11873     {
11874       if (++anArgIter >= theArgNb)
11875       {
11876         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11877         return 1;
11878       }
11879
11880       TCollection_AsciiString aParam(theArgVec[anArgIter]);
11881       if (aParam.IsRealValue (Standard_True))
11882       {
11883         float aApertureSize = static_cast<float> (aParam.RealValue());
11884         if (aApertureSize < 0)
11885         {
11886           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11887           return 1;
11888         }
11889         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
11890       }
11891       else
11892       {
11893         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11894         return 1;
11895       }
11896     }
11897     else if (aFlag == "-exposure")
11898     {
11899       if (++anArgIter >= theArgNb)
11900       {
11901         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11902         return 1;
11903       }
11904
11905       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
11906       if (anExposure.IsRealValue (Standard_True))
11907       {
11908         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
11909       }
11910       else
11911       {
11912         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11913         return 1;
11914       }
11915     }
11916     else if (aFlag == "-whitepoint")
11917     {
11918       if (++anArgIter >= theArgNb)
11919       {
11920         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11921         return 1;
11922       }
11923
11924       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
11925       if (aWhitePoint.IsRealValue (Standard_True))
11926       {
11927         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
11928       }
11929       else
11930       {
11931         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11932         return 1;
11933       }
11934     }
11935     else if (aFlag == "-tonemapping")
11936     {
11937       if (++anArgIter >= theArgNb)
11938       {
11939         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11940         return 1;
11941       }
11942
11943       TCollection_AsciiString aMode (theArgVec[anArgIter]);
11944       aMode.LowerCase();
11945
11946       if (aMode == "disabled")
11947       {
11948         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
11949       }
11950       else if (aMode == "filmic")
11951       {
11952         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
11953       }
11954       else
11955       {
11956         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11957         return 1;
11958       }
11959     }
11960     else if (aFlag == "-performancestats"
11961           || aFlag == "-performancecounters"
11962           || aFlag == "-perfstats"
11963           || aFlag == "-perfcounters"
11964           || aFlag == "-stats")
11965     {
11966       if (++anArgIter >= theArgNb)
11967       {
11968         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11969         return 1;
11970       }
11971
11972       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
11973       aFlagsStr.LowerCase();
11974       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
11975       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
11976       {
11977         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11978         return 1;
11979       }
11980       aView->ChangeRenderingParams().CollectedStats = aFlags;
11981       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
11982     }
11983     else if (aFlag == "-perfupdateinterval"
11984           || aFlag == "-statsupdateinterval")
11985     {
11986       if (++anArgIter >= theArgNb)
11987       {
11988         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11989         return 1;
11990       }
11991       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11992     }
11993     else if (aFlag == "-perfchart"
11994           || aFlag == "-statschart")
11995     {
11996       if (++anArgIter >= theArgNb)
11997       {
11998         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11999         return 1;
12000       }
12001       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
12002     }
12003     else if (aFlag == "-perfchartmax"
12004           || aFlag == "-statschartmax")
12005     {
12006       if (++anArgIter >= theArgNb)
12007       {
12008         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12009         return 1;
12010       }
12011       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12012     }
12013     else if (aFlag == "-frustumculling"
12014           || aFlag == "-culling")
12015     {
12016       if (toPrint)
12017       {
12018         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
12019                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
12020                                                                                                    "noUpdate") << " ";
12021         continue;
12022       }
12023
12024       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
12025       if (++anArgIter < theArgNb)
12026       {
12027         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
12028         aStateStr.LowerCase();
12029         bool toEnable = true;
12030         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
12031         {
12032           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
12033         }
12034         else if (aStateStr == "noupdate"
12035               || aStateStr == "freeze")
12036         {
12037           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
12038         }
12039         else
12040         {
12041           --anArgIter;
12042         }
12043       }
12044       aParams.FrustumCullingState = aState;
12045     }
12046     else
12047     {
12048       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
12049       return 1;
12050     }
12051   }
12052
12053   // set current view parameters as defaults
12054   if (toSyncDefaults)
12055   {
12056     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
12057   }
12058   if (toSyncAllViews)
12059   {
12060     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
12061     {
12062       aViewIter.Value()->ChangeRenderingParams() = aParams;
12063     }
12064   }
12065   return 0;
12066 }
12067
12068 //=======================================================================
12069 //function : searchInfo
12070 //purpose  :
12071 //=======================================================================
12072 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12073                                            const TCollection_AsciiString&              theKey)
12074 {
12075   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12076   {
12077     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12078     {
12079       return anIter.Value();
12080     }
12081   }
12082   return TCollection_AsciiString();
12083 }
12084
12085 //=======================================================================
12086 //function : VStatProfiler
12087 //purpose  :
12088 //=======================================================================
12089 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12090                                        Standard_Integer  theArgNb,
12091                                        const char**      theArgVec)
12092 {
12093   Handle(V3d_View) aView = ViewerTest::CurrentView();
12094   if (aView.IsNull())
12095   {
12096     Message::SendFail ("Error: no active viewer");
12097     return 1;
12098   }
12099
12100   Standard_Boolean toRedraw = Standard_True;
12101   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12102   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12103   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12104   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12105   {
12106     Standard_CString        anArg (theArgVec[anArgIter]);
12107     TCollection_AsciiString aFlag (anArg);
12108     aFlag.LowerCase();
12109     if (aFlag == "-noredraw")
12110     {
12111       toRedraw = Standard_False;
12112     }
12113     else
12114     {
12115       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12116       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12117       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12118       else if (aFlag == "alllayers"
12119             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12120       else if (aFlag == "allstructs"
12121             || aFlag == "allstructures"
12122             || aFlag == "structs"
12123             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12124       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12125       else if (aFlag == "allarrays"
12126             || aFlag == "fillarrays"
12127             || aFlag == "linearrays"
12128             || aFlag == "pointarrays"
12129             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12130       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12131       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12132       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12133       else if (aFlag == "geommem"
12134             || aFlag == "texturemem"
12135             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12136       else if (aFlag == "elapsedframe"
12137             || aFlag == "cpuframeaverage"
12138             || aFlag == "cpupickingaverage"
12139             || aFlag == "cpucullingaverage"
12140             || aFlag == "cpudynaverage"
12141             || aFlag == "cpuframemax"
12142             || aFlag == "cpupickingmax"
12143             || aFlag == "cpucullingmax"
12144             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12145       else
12146       {
12147         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12148         continue;
12149       }
12150
12151       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12152     }
12153   }
12154
12155   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12156   {
12157     aView->ChangeRenderingParams().CollectedStats =
12158       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12159
12160     if (toRedraw)
12161     {
12162       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12163       aView->Redraw();
12164       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12165     }
12166
12167     TColStd_IndexedDataMapOfStringString aDict;
12168     aView->StatisticInformation (aDict);
12169
12170     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12171
12172     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12173     {
12174       Standard_CString        anArg(theArgVec[anArgIter]);
12175       TCollection_AsciiString aFlag(anArg);
12176       aFlag.LowerCase();
12177       if (aFlag == "fps")
12178       {
12179         theDI << searchInfo (aDict, "FPS") << " ";
12180       }
12181       else if (aFlag == "cpu")
12182       {
12183         theDI << searchInfo (aDict, "CPU FPS") << " ";
12184       }
12185       else if (aFlag == "alllayers")
12186       {
12187         theDI << searchInfo (aDict, "Layers") << " ";
12188       }
12189       else if (aFlag == "layers")
12190       {
12191         theDI << searchInfo (aDict, "Rendered layers") << " ";
12192       }
12193       else if (aFlag == "allstructs"
12194             || aFlag == "allstructures")
12195       {
12196         theDI << searchInfo (aDict, "Structs") << " ";
12197       }
12198       else if (aFlag == "structs"
12199             || aFlag == "structures")
12200       {
12201         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
12202         if (aRend.IsEmpty()) // all structures rendered
12203         {
12204           aRend = searchInfo (aDict, "Structs");
12205         }
12206         theDI << aRend << " ";
12207       }
12208       else if (aFlag == "groups")
12209       {
12210         theDI << searchInfo (aDict, "Rendered groups") << " ";
12211       }
12212       else if (aFlag == "allarrays")
12213       {
12214         theDI << searchInfo (aDict, "Rendered arrays") << " ";
12215       }
12216       else if (aFlag == "fillarrays")
12217       {
12218         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
12219       }
12220       else if (aFlag == "linearrays")
12221       {
12222         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
12223       }
12224       else if (aFlag == "pointarrays")
12225       {
12226         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
12227       }
12228       else if (aFlag == "textarrays")
12229       {
12230         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
12231       }
12232       else if (aFlag == "triangles")
12233       {
12234         theDI << searchInfo (aDict, "Rendered triangles") << " ";
12235       }
12236       else if (aFlag == "points")
12237       {
12238         theDI << searchInfo (aDict, "Rendered points") << " ";
12239       }
12240       else if (aFlag == "geommem")
12241       {
12242         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12243       }
12244       else if (aFlag == "texturemem")
12245       {
12246         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12247       }
12248       else if (aFlag == "framemem")
12249       {
12250         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12251       }
12252       else if (aFlag == "elapsedframe")
12253       {
12254         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12255       }
12256       else if (aFlag == "cpuframe_average")
12257       {
12258         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12259       }
12260       else if (aFlag == "cpupicking_average")
12261       {
12262         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12263       }
12264       else if (aFlag == "cpuculling_average")
12265       {
12266         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12267       }
12268       else if (aFlag == "cpudyn_average")
12269       {
12270         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12271       }
12272       else if (aFlag == "cpuframe_max")
12273       {
12274         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12275       }
12276       else if (aFlag == "cpupicking_max")
12277       {
12278         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12279       }
12280       else if (aFlag == "cpuculling_max")
12281       {
12282         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12283       }
12284       else if (aFlag == "cpudyn_max")
12285       {
12286         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12287       }
12288     }
12289   }
12290   else
12291   {
12292     if (toRedraw)
12293     {
12294       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12295       aView->Redraw();
12296       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12297     }
12298     theDI << "Statistic info:\n" << aView->StatisticInformation();
12299   }
12300   return 0;
12301 }
12302
12303 //=======================================================================
12304 //function : VXRotate
12305 //purpose  :
12306 //=======================================================================
12307 static Standard_Integer VXRotate (Draw_Interpretor& di,
12308                                    Standard_Integer argc,
12309                                    const char ** argv)
12310 {
12311   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12312   if (aContext.IsNull())
12313   {
12314     di << argv[0] << "ERROR : use 'vinit' command before \n";
12315     return 1;
12316   }
12317
12318   if (argc != 3)
12319   {
12320     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12321     return 1;
12322   }
12323
12324   TCollection_AsciiString aName (argv[1]);
12325   Standard_Real anAngle = Draw::Atof (argv[2]);
12326
12327   // find object
12328   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12329   Handle(AIS_InteractiveObject) anIObj;
12330   if (!aMap.Find2 (aName, anIObj))
12331   {
12332     di << "Use 'vdisplay' before\n";
12333     return 1;
12334   }
12335
12336   gp_Trsf aTransform;
12337   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12338   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12339
12340   aContext->SetLocation (anIObj, aTransform);
12341   aContext->UpdateCurrentViewer();
12342   return 0;
12343 }
12344
12345 namespace
12346 {
12347   //! Structure for setting AIS_Manipulator::SetPart() property.
12348   struct ManipAxisModeOnOff
12349   {
12350     Standard_Integer    Axis;
12351     AIS_ManipulatorMode Mode;
12352     Standard_Boolean    ToEnable;
12353
12354     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
12355   };
12356
12357   enum ManipAjustPosition
12358   {
12359     ManipAjustPosition_Off,
12360     ManipAjustPosition_Center,
12361     ManipAjustPosition_Location,
12362     ManipAjustPosition_ShapeLocation,
12363   };
12364 }
12365
12366 //===============================================================================================
12367 //function : VManipulator
12368 //purpose  :
12369 //===============================================================================================
12370 static int VManipulator (Draw_Interpretor& theDi,
12371                          Standard_Integer  theArgsNb,
12372                          const char**      theArgVec)
12373 {
12374   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12375   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12376   if (aCurrentView.IsNull()
12377    || aViewer.IsNull())
12378   {
12379     Message::SendFail ("Error: no active viewer");
12380     return 1;
12381   }
12382
12383   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12384   Standard_Integer anArgIter = 1;
12385   Handle(AIS_Manipulator) aManipulator;
12386   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12387   TCollection_AsciiString aName;
12388   // parameters
12389   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
12390   Standard_Real aGap = -1.0, aSize = -1.0;
12391   NCollection_Sequence<ManipAxisModeOnOff> aParts;
12392   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
12393   //
12394   bool toDetach = false;
12395   AIS_Manipulator::OptionsForAttach anAttachOptions;
12396   Handle(AIS_InteractiveObject) anAttachObject;
12397   Handle(V3d_View) aViewAffinity;
12398   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
12399   //
12400   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
12401   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
12402   Standard_Integer toStopMouseTransform = -1;
12403   // explicit transformation
12404   gp_Trsf aTrsf;
12405   gp_XYZ aTmpXYZ;
12406   Standard_Real aTmpReal = 0.0;
12407   gp_XYZ aRotPnt, aRotAxis;
12408   for (; anArgIter < theArgsNb; ++anArgIter)
12409   {
12410     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12411     anArg.LowerCase();
12412     if (anUpdateTool.parseRedrawMode (anArg))
12413     {
12414       continue;
12415     }
12416     else if (anArg == "-help")
12417     {
12418       theDi.PrintHelp (theArgVec[0]);
12419       return 0;
12420     }
12421     //
12422     else if (anArg == "-autoactivate"
12423           || anArg == "-noautoactivate")
12424     {
12425       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12426     }
12427     else if (anArg == "-followtranslation"
12428           || anArg == "-nofollowtranslation")
12429     {
12430       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12431     }
12432     else if (anArg == "-followrotation"
12433           || anArg == "-nofollowrotation")
12434     {
12435       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12436     }
12437     else if (anArg == "-followdragging"
12438           || anArg == "-nofollowdragging")
12439     {
12440       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12441     }
12442     else if (anArg == "-gap"
12443           && anArgIter + 1 < theArgsNb
12444           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
12445           && aGap >= 0.0)
12446     {
12447       ++anArgIter;
12448     }
12449     else if (anArg == "-size"
12450           && anArgIter + 1 < theArgsNb
12451           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
12452           && aSize > 0.0)
12453     {
12454       ++anArgIter;
12455     }
12456     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
12457           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
12458     {
12459       ManipAxisModeOnOff aPart;
12460       Standard_Integer aMode = 0;
12461       if (anArg == "-part")
12462       {
12463         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
12464           || aPart.Axis < 0 || aPart.Axis > 3)
12465         {
12466           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
12467           return 1;
12468         }
12469       }
12470       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
12471         || aMode < 1 || aMode > 4)
12472       {
12473         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
12474         return 1;
12475       }
12476       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
12477       {
12478         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
12479         return 1;
12480       }
12481       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
12482       aParts.Append (aPart);
12483     }
12484     else if (anArg == "-pos"
12485           && anArgIter + 3 < theArgsNb
12486           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
12487     {
12488       anArgIter += 3;
12489       if (anArgIter + 3 < theArgsNb
12490        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
12491        && aVDir.Modulus() > Precision::Confusion())
12492       {
12493         anArgIter += 3;
12494       }
12495       if (anArgIter + 3 < theArgsNb
12496        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
12497        && anXDir.Modulus() > Precision::Confusion())
12498       {
12499         anArgIter += 3;
12500       }
12501     }
12502     else if (anArg == "-zoomable"
12503           || anArg == "-notzoomable")
12504     {
12505       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12506     }
12507     //
12508     else if (anArg == "-adjustposition"
12509           || anArg == "-noadjustposition")
12510     {
12511       anAttachPos = ManipAjustPosition_Center;
12512       if (anArgIter + 1 < theArgsNb)
12513       {
12514         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
12515         aPosName.LowerCase();
12516         if (aPosName == "0")
12517         {
12518           anAttachPos = ManipAjustPosition_Off;
12519         }
12520         else if (aPosName == "1"
12521               || aPosName == "center")
12522         {
12523           anAttachPos = ManipAjustPosition_Center;
12524         }
12525         else if (aPosName == "transformation"
12526               || aPosName == "trsf"
12527               || aPosName == "location"
12528               || aPosName == "loc")
12529         {
12530           anAttachPos = ManipAjustPosition_Location;
12531         }
12532         else if (aPosName == "shapelocation"
12533               || aPosName == "shapeloc")
12534         {
12535           anAttachPos = ManipAjustPosition_ShapeLocation;
12536         }
12537         else
12538         {
12539           --anArgIter;
12540         }
12541       }
12542       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
12543     }
12544     else if (anArg == "-adjustsize"
12545           || anArg == "-noadjustsize")
12546     {
12547       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12548     }
12549     else if (anArg == "-enablemodes"
12550           || anArg == "-enablemodes")
12551     {
12552       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12553     }
12554     //
12555     else if (anArg == "-starttransform"
12556           && anArgIter + 2 < theArgsNb
12557           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
12558           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
12559     {
12560       anArgIter += 2;
12561     }
12562     else if (anArg == "-transform"
12563           && anArgIter + 2 < theArgsNb
12564           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
12565           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
12566     {
12567       anArgIter += 2;
12568     }
12569     else if (anArg == "-stoptransform")
12570     {
12571       toStopMouseTransform = 1;
12572       if (anArgIter + 1 < theArgsNb
12573        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
12574       {
12575         ++anArgIter;
12576         toStopMouseTransform = 0;
12577       }
12578     }
12579     //
12580     else if (anArg == "-move"
12581           && anArgIter + 3 < theArgsNb
12582           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
12583     {
12584       anArgIter += 3;
12585       aTrsf.SetTranslationPart (aTmpXYZ);
12586     }
12587     else if (anArg == "-scale"
12588           && anArgIter + 1 < theArgsNb
12589           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
12590     {
12591       ++anArgIter;
12592       aTrsf.SetScale (gp_Pnt(), aTmpReal);
12593     }
12594     else if (anArg == "-rotate"
12595           && anArgIter + 7 < theArgsNb
12596           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
12597           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
12598           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
12599     {
12600       anArgIter += 7;
12601       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
12602     }
12603     //
12604     else if (anArg == "-detach")
12605     {
12606       toDetach = true;
12607     }
12608     else if (anArg == "-attach"
12609           && anArgIter + 1 < theArgsNb)
12610     {
12611       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
12612       if (!aMapAIS.Find2 (anObjName, anAttachObject))
12613       {
12614         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
12615         return 1;
12616       }
12617
12618       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
12619       {
12620         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
12621         if (!aManip.IsNull()
12622           && aManip->IsAttached()
12623           && aManip->Object() == anAttachObject)
12624         {
12625           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
12626           return 1;
12627         }
12628       }
12629     }
12630     else if (anArg == "-view"
12631           && anArgIter + 1 < theArgsNb
12632           && aViewAffinity.IsNull())
12633     {
12634       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
12635       if (aViewString == "active")
12636       {
12637         aViewAffinity = ViewerTest::CurrentView();
12638       }
12639       else // Check view name
12640       {
12641         ViewerTest_Names aViewNames (aViewString);
12642         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
12643         {
12644           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
12645           return 1;
12646         }
12647         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
12648         if (aViewAffinity.IsNull())
12649         {
12650           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
12651           return 1;
12652         }
12653       }
12654     }
12655     else if (aName.IsEmpty())
12656     {
12657       aName = theArgVec[anArgIter];
12658       if (!aMapAIS.IsBound2 (aName))
12659       {
12660         aManipulator = new AIS_Manipulator();
12661         aManipulator->SetModeActivationOnDetection (true);
12662         aMapAIS.Bind (aManipulator, aName);
12663       }
12664       else
12665       {
12666         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12667         if (aManipulator.IsNull())
12668         {
12669           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12670           return 1;
12671         }
12672       }
12673     }
12674     else
12675     {
12676       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
12677     }
12678   }
12679
12680   if (aName.IsEmpty())
12681   {
12682     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
12683     return 1;
12684   }
12685   if (!toDetach
12686     && aManipulator.IsNull())
12687   {
12688     aManipulator = new AIS_Manipulator();
12689     aManipulator->SetModeActivationOnDetection (true);
12690     aMapAIS.Bind (aManipulator, aName);
12691   }
12692
12693   // -----------------------------------------
12694   // change properties of manipulator instance
12695   // -----------------------------------------
12696
12697   if (toAutoActivate != -1)
12698   {
12699     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
12700   }
12701   if (toFollowTranslation != -1)
12702   {
12703     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
12704   }
12705   if (toFollowRotation != -1)
12706   {
12707     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
12708   }
12709   if (toFollowDragging != -1)
12710   {
12711     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
12712   }
12713   if (aGap >= 0.0f)
12714   {
12715     aManipulator->SetGap ((float )aGap);
12716   }
12717
12718   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
12719   {
12720     const ManipAxisModeOnOff& aPart = aPartIter.Value();
12721     if (aPart.Axis == -1)
12722     {
12723       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
12724     }
12725     else
12726     {
12727       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
12728     }
12729   }
12730
12731   if (aSize > 0.0)
12732   {
12733     aManipulator->SetSize ((float )aSize);
12734   }
12735   if (isZoomable != -1)
12736   {
12737     aManipulator->SetZoomPersistence (isZoomable == 0);
12738
12739     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12740     {
12741       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
12742       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
12743     }
12744   }
12745
12746   // ----------------------------------
12747   // detach existing manipulator object
12748   // ----------------------------------
12749
12750   if (toDetach)
12751   {
12752     aManipulator->Detach();
12753     aMapAIS.UnBind2 (aName);
12754     ViewerTest::GetAISContext()->Remove (aManipulator, false);
12755   }
12756
12757   // ---------------------------------------------------
12758   // attach, detach or access manipulator from an object
12759   // ---------------------------------------------------
12760
12761   if (!anAttachObject.IsNull())
12762   {
12763     aManipulator->Attach (anAttachObject, anAttachOptions);
12764   }
12765   if (!aViewAffinity.IsNull())
12766   {
12767     for (ViewerTest_ViewerCommandsViewMap::Iterator anIter (ViewerTest_myViews);
12768          anIter.More(); anIter.Next())
12769     {
12770       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Key2(), false);
12771     }
12772     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
12773   }
12774
12775   if (anAttachPos != ManipAjustPosition_Off
12776    && aManipulator->IsAttached()
12777    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
12778   {
12779     gp_Ax2 aPosition = gp::XOY();
12780     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
12781     switch (anAttachPos)
12782     {
12783       case ManipAjustPosition_Off:
12784       {
12785         break;
12786       }
12787       case ManipAjustPosition_Location:
12788       {
12789         aPosition = gp::XOY().Transformed (aBaseTrsf);
12790         break;
12791       }
12792       case ManipAjustPosition_ShapeLocation:
12793       {
12794         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
12795         {
12796           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
12797         }
12798         else
12799         {
12800           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
12801           return 1;
12802         }
12803         break;
12804       }
12805       case ManipAjustPosition_Center:
12806       {
12807         Bnd_Box aBox;
12808         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
12809         {
12810           Bnd_Box anObjBox;
12811           anObjIter.Value()->BoundingBox (anObjBox);
12812           aBox.Add (anObjBox);
12813         }
12814         aBox = aBox.FinitePart();
12815         if (!aBox.IsVoid())
12816         {
12817           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
12818           aPosition.SetLocation (aCenter);
12819         }
12820         break;
12821       }
12822     }
12823     aManipulator->SetPosition (aPosition);
12824   }
12825   if (!Precision::IsInfinite (aLocation.X()))
12826   {
12827     if (aVDir.Modulus() <= Precision::Confusion())
12828     {
12829       aVDir = aManipulator->Position().Direction().XYZ();
12830     }
12831     if (anXDir.Modulus() <= Precision::Confusion())
12832     {
12833       anXDir = aManipulator->Position().XDirection().XYZ();
12834     }
12835     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
12836   }
12837
12838   // --------------------------------------
12839   // apply transformation using manipulator
12840   // --------------------------------------
12841
12842   if (aMousePosFrom.x() != IntegerLast())
12843   {
12844     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
12845   }
12846   if (aMousePosTo.x() != IntegerLast())
12847   {
12848     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
12849   }
12850   if (toStopMouseTransform != -1)
12851   {
12852     aManipulator->StopTransform (toStopMouseTransform == 1);
12853   }
12854
12855   if (aTrsf.Form() != gp_Identity)
12856   {
12857     aManipulator->Transform (aTrsf);
12858   }
12859
12860   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12861   {
12862     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
12863   }
12864   return 0;
12865 }
12866
12867 //===============================================================================================
12868 //function : VSelectionProperties
12869 //purpose  :
12870 //===============================================================================================
12871 static int VSelectionProperties (Draw_Interpretor& theDi,
12872                                  Standard_Integer  theArgsNb,
12873                                  const char**      theArgVec)
12874 {
12875   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
12876   if (aCtx.IsNull())
12877   {
12878     Message::SendFail ("Error: no active viewer");
12879     return 1;
12880   }
12881
12882   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
12883   {
12884     // handle obsolete alias
12885     bool toEnable = true;
12886     if (theArgsNb < 2)
12887     {
12888       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
12889       return 0;
12890     }
12891     else if (theArgsNb != 2
12892          || !Draw::ParseOnOff (theArgVec[1], toEnable))
12893     {
12894       Message::SendFail ("Syntax error: wrong number of parameters");
12895       return 1;
12896     }
12897     if (toEnable != aCtx->ToHilightSelected())
12898     {
12899       aCtx->ClearDetected();
12900       aCtx->SetToHilightSelected (toEnable);
12901     }
12902     return 0;
12903   }
12904
12905   Standard_Boolean toPrint  = theArgsNb == 1;
12906   Standard_Boolean toRedraw = Standard_False;
12907   Standard_Integer anArgIter = 1;
12908   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
12909   if (anArgIter < theArgsNb)
12910   {
12911     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
12912     anArgFirst.LowerCase();
12913     ++anArgIter;
12914     if (anArgFirst == "dynhighlight"
12915      || anArgFirst == "dynhilight"
12916      || anArgFirst == "dynamichighlight"
12917      || anArgFirst == "dynamichilight")
12918     {
12919       aType = Prs3d_TypeOfHighlight_Dynamic;
12920     }
12921     else if (anArgFirst == "localdynhighlight"
12922           || anArgFirst == "localdynhilight"
12923           || anArgFirst == "localdynamichighlight"
12924           || anArgFirst == "localdynamichilight")
12925     {
12926       aType = Prs3d_TypeOfHighlight_LocalDynamic;
12927     }
12928     else if (anArgFirst == "selhighlight"
12929           || anArgFirst == "selhilight"
12930           || anArgFirst == "selectedhighlight"
12931           || anArgFirst == "selectedhilight")
12932     {
12933       aType = Prs3d_TypeOfHighlight_Selected;
12934     }
12935     else if (anArgFirst == "localselhighlight"
12936           || anArgFirst == "localselhilight"
12937           || anArgFirst == "localselectedhighlight"
12938           || anArgFirst == "localselectedhilight")
12939     {
12940       aType = Prs3d_TypeOfHighlight_LocalSelected;
12941     }
12942     else
12943     {
12944       --anArgIter;
12945     }
12946   }
12947   for (; anArgIter < theArgsNb; ++anArgIter)
12948   {
12949     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12950     anArg.LowerCase();
12951     if (anArg == "-help")
12952     {
12953       theDi.PrintHelp (theArgVec[0]);
12954       return 0;
12955     }
12956     else if (anArg == "-print")
12957     {
12958       toPrint = Standard_True;
12959     }
12960     else if (anArg == "-autoactivate")
12961     {
12962       Standard_Boolean toEnable = Standard_True;
12963       if (anArgIter + 1 < theArgsNb
12964        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12965       {
12966         ++anArgIter;
12967       }
12968       aCtx->SetAutoActivateSelection (toEnable);
12969     }
12970     else if (anArg == "-automatichighlight"
12971           || anArg == "-automatichilight"
12972           || anArg == "-autohighlight"
12973           || anArg == "-autohilight")
12974     {
12975       Standard_Boolean toEnable = Standard_True;
12976       if (anArgIter + 1 < theArgsNb
12977        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12978       {
12979         ++anArgIter;
12980       }
12981       aCtx->ClearSelected (false);
12982       aCtx->ClearDetected();
12983       aCtx->SetAutomaticHilight (toEnable);
12984       toRedraw = true;
12985     }
12986     else if (anArg == "-highlightselected"
12987           || anArg == "-hilightselected")
12988     {
12989       Standard_Boolean toEnable = Standard_True;
12990       if (anArgIter + 1 < theArgsNb
12991        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12992       {
12993         ++anArgIter;
12994       }
12995       aCtx->ClearDetected();
12996       aCtx->SetToHilightSelected (toEnable);
12997       toRedraw = true;
12998     }
12999     else if (anArg == "-pickstrategy"
13000           || anArg == "-pickingstrategy")
13001     {
13002       if (++anArgIter >= theArgsNb)
13003       {
13004         Message::SendFail ("Syntax error: type of highlighting is undefined");
13005         return 1;
13006       }
13007
13008       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13009       TCollection_AsciiString aVal (theArgVec[anArgIter]);
13010       aVal.LowerCase();
13011       if (aVal == "first"
13012        || aVal == "firstaccepted"
13013        || aVal == "firstacceptable")
13014       {
13015         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13016       }
13017       else if (aVal == "topmost"
13018             || aVal == "onlyTopmost")
13019       {
13020         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
13021       }
13022       else
13023       {
13024         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
13025         return 1;
13026       }
13027
13028       aCtx->SetPickingStrategy (aStrategy);
13029     }
13030     else if (anArg == "-pixtol"
13031           && anArgIter + 1 < theArgsNb)
13032     {
13033       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
13034     }
13035     else if (anArg == "-preferclosest")
13036     {
13037       bool toPreferClosest = true;
13038       if (anArgIter + 1 < theArgsNb
13039        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
13040       {
13041         ++anArgIter;
13042       }
13043       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
13044     }
13045     else if ((anArg == "-depthtol"
13046            || anArg == "-depthtolerance")
13047           && anArgIter + 1 < theArgsNb)
13048     {
13049       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
13050       aTolType.LowerCase();
13051       if (aTolType == "uniform")
13052       {
13053         if (anArgIter + 1 >= theArgsNb)
13054         {
13055           Message::SendFail() << "Syntax error: wrong number of arguments";
13056           return 1;
13057         }
13058         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
13059                                                  Draw::Atof (theArgVec[++anArgIter]));
13060       }
13061       else if (aTolType == "uniformpx")
13062       {
13063         if (anArgIter + 1 >= theArgsNb)
13064         {
13065           Message::SendFail() << "Syntax error: wrong number of arguments";
13066           return 1;
13067         }
13068         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
13069                                                  Draw::Atof (theArgVec[++anArgIter]));
13070       }
13071       else if (aTolType == "sensfactor")
13072       {
13073         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
13074       }
13075       else
13076       {
13077         Message::SendFail() << "Syntax error at '" << aTolType << "'";
13078         return 1;
13079       }
13080     }
13081     else if ((anArg == "-mode"
13082            || anArg == "-dispmode")
13083           && anArgIter + 1 < theArgsNb)
13084     {
13085       if (aType == Prs3d_TypeOfHighlight_None)
13086       {
13087         Message::SendFail ("Syntax error: type of highlighting is undefined");
13088         return 1;
13089       }
13090
13091       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13092       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13093       aStyle->SetDisplayMode (aDispMode);
13094       toRedraw = Standard_True;
13095     }
13096     else if (anArg == "-layer"
13097           && anArgIter + 1 < theArgsNb)
13098     {
13099       if (aType == Prs3d_TypeOfHighlight_None)
13100       {
13101         Message::SendFail ("Syntax error: type of highlighting is undefined");
13102         return 1;
13103       }
13104
13105       ++anArgIter;
13106       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13107       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13108       {
13109         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13110         return 1;
13111       }
13112
13113       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13114       aStyle->SetZLayer (aNewLayer);
13115       toRedraw = Standard_True;
13116     }
13117     else if (anArg == "-hicolor"
13118           || anArg == "-selcolor"
13119           || anArg == "-color")
13120     {
13121       if (anArg.StartsWith ("-hi"))
13122       {
13123         aType = Prs3d_TypeOfHighlight_Dynamic;
13124       }
13125       else if (anArg.StartsWith ("-sel"))
13126       {
13127         aType = Prs3d_TypeOfHighlight_Selected;
13128       }
13129       else if (aType == Prs3d_TypeOfHighlight_None)
13130       {
13131         Message::SendFail ("Syntax error: type of highlighting is undefined");
13132         return 1;
13133       }
13134
13135       Quantity_Color aColor;
13136       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13137                                                      theArgVec + anArgIter + 1,
13138                                                      aColor);
13139       if (aNbParsed == 0)
13140       {
13141         Message::SendFail ("Syntax error: need more arguments");
13142         return 1;
13143       }
13144       anArgIter += aNbParsed;
13145
13146       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13147       aStyle->SetColor (aColor);
13148       toRedraw = Standard_True;
13149     }
13150     else if ((anArg == "-transp"
13151            || anArg == "-transparency"
13152            || anArg == "-hitransp"
13153            || anArg == "-seltransp"
13154            || anArg == "-hitransplocal"
13155            || anArg == "-seltransplocal")
13156           && anArgIter + 1 < theArgsNb)
13157     {
13158       if (anArg.StartsWith ("-hi"))
13159       {
13160         aType = Prs3d_TypeOfHighlight_Dynamic;
13161       }
13162       else if (anArg.StartsWith ("-sel"))
13163       {
13164         aType = Prs3d_TypeOfHighlight_Selected;
13165       }
13166       else if (aType == Prs3d_TypeOfHighlight_None)
13167       {
13168         Message::SendFail ("Syntax error: type of highlighting is undefined");
13169         return 1;
13170       }
13171
13172       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13173       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13174       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13175       toRedraw = Standard_True;
13176     }
13177     else if ((anArg == "-mat"
13178            || anArg == "-material")
13179           && anArgIter + 1 < theArgsNb)
13180     {
13181       if (aType == Prs3d_TypeOfHighlight_None)
13182       {
13183         Message::SendFail ("Syntax error: type of highlighting is undefined");
13184         return 1;
13185       }
13186
13187       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13188       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13189       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
13190       {
13191         ++anArgIter;
13192         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13193         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13194         Graphic3d_MaterialAspect aMat (aMatName);
13195         aMat.SetColor (aStyle->Color());
13196         aMat.SetTransparency (aStyle->Transparency());
13197         anAspect->SetFrontMaterial (aMat);
13198         anAspect->SetInteriorColor (aStyle->Color());
13199         aStyle->SetBasicFillAreaAspect (anAspect);
13200       }
13201       else
13202       {
13203         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
13204       }
13205       toRedraw = Standard_True;
13206     }
13207     else
13208     {
13209       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
13210       return 1;
13211     }
13212   }
13213
13214   if (toPrint)
13215   {
13216     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
13217     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
13218     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
13219     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
13220     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
13221     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
13222     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
13223     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
13224     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
13225     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
13226     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
13227     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
13228     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
13229     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
13230   }
13231
13232   if (aCtx->NbSelected() != 0 && toRedraw)
13233   {
13234     aCtx->HilightSelected (Standard_True);
13235   }
13236
13237   return 0;
13238 }
13239
13240 //===============================================================================================
13241 //function : VDumpSelectionImage
13242 //purpose  :
13243 //===============================================================================================
13244 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13245                                 Standard_Integer  theArgsNb,
13246                                 const char**      theArgVec)
13247 {
13248   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13249   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13250   if (aContext.IsNull())
13251   {
13252     Message::SendFail ("Error: no active viewer");
13253     return 1;
13254   }
13255
13256   TCollection_AsciiString aFile;
13257   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13258   Handle(Graphic3d_Camera) aCustomCam;
13259   Image_Format anImgFormat = Image_Format_BGR;
13260   Standard_Integer aPickedIndex = 1;
13261   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13262   {
13263     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13264     aParam.LowerCase();
13265     if (aParam == "-type")
13266     {
13267       if (++anArgIter >= theArgsNb)
13268       {
13269         Message::SendFail ("Syntax error: wrong number parameters of flag '-type'");
13270         return 1;
13271       }
13272
13273       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13274       aValue.LowerCase();
13275       if (aValue == "depth"
13276        || aValue == "normdepth"
13277        || aValue == "normalizeddepth")
13278       {
13279         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13280         anImgFormat = Image_Format_GrayF;
13281       }
13282       else if (aValue == "depthinverted"
13283             || aValue == "normdepthinverted"
13284             || aValue == "normalizeddepthinverted"
13285             || aValue == "inverted")
13286       {
13287         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13288         anImgFormat = Image_Format_GrayF;
13289       }
13290       else if (aValue == "unnormdepth"
13291             || aValue == "unnormalizeddepth")
13292       {
13293         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13294         anImgFormat = Image_Format_GrayF;
13295       }
13296       else if (aValue == "objectcolor"
13297             || aValue == "object"
13298             || aValue == "color")
13299       {
13300         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13301       }
13302       else if (aValue == "entitycolor"
13303             || aValue == "entity")
13304       {
13305         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13306       }
13307       else if (aValue == "entitytypecolor"
13308             || aValue == "entitytype")
13309       {
13310         aType = StdSelect_TypeOfSelectionImage_ColoredEntityType;
13311       }
13312       else if (aValue == "ownercolor"
13313             || aValue == "owner")
13314       {
13315         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13316       }
13317       else if (aValue == "selectionmodecolor"
13318             || aValue == "selectionmode"
13319             || aValue == "selmodecolor"
13320             || aValue == "selmode")
13321       {
13322         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13323       }
13324       else if (aValue == "surfnormal"
13325             || aValue == "surfacenormal"
13326             || aValue == "normal")
13327       {
13328         aType = StdSelect_TypeOfSelectionImage_SurfaceNormal;
13329       }
13330       else
13331       {
13332         Message::SendFail() << "Syntax error: unknown type '" << aValue << "'";
13333         return 1;
13334       }
13335     }
13336     else if (aParam == "-picked"
13337           || aParam == "-pickeddepth"
13338           || aParam == "-pickedindex")
13339     {
13340       if (++anArgIter >= theArgsNb)
13341       {
13342         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13343         return 1;
13344       }
13345
13346       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13347     }
13348     else if (anArgIter + 1 < theArgsNb
13349           && aParam == "-xrpose")
13350     {
13351       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13352       anXRArg.LowerCase();
13353       if (anXRArg == "base")
13354       {
13355         aCustomCam = aView->View()->BaseXRCamera();
13356       }
13357       else if (anXRArg == "head")
13358       {
13359         aCustomCam = aView->View()->PosedXRCamera();
13360       }
13361       else
13362       {
13363         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13364         return 1;
13365       }
13366       if (aCustomCam.IsNull())
13367       {
13368         Message::SendFail() << "Error: undefined XR pose";
13369         return 0;
13370       }
13371     }
13372     else if (aFile.IsEmpty())
13373     {
13374       aFile = theArgVec[anArgIter];
13375     }
13376     else
13377     {
13378       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13379       return 1;
13380     }
13381   }
13382   if (aFile.IsEmpty())
13383   {
13384     Message::SendFail ("Syntax error: image file name is missing");
13385     return 1;
13386   }
13387
13388   Standard_Integer aWidth = 0, aHeight = 0;
13389   aView->Window()->Size (aWidth, aHeight);
13390
13391   Image_AlienPixMap aPixMap;
13392   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13393   {
13394     Message::SendFail ("Error: can't allocate image");
13395     return 1;
13396   }
13397
13398   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13399   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13400   if (!aCustomCam.IsNull())
13401   {
13402     aView->SetCamera (aCustomCam);
13403   }
13404   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13405   {
13406     Message::SendFail ("Error: can't generate selection image");
13407     return 1;
13408   }
13409   if (!aCustomCam.IsNull())
13410   {
13411     aView->SetCamera (aCamBack);
13412   }
13413   aView->SetImmediateUpdate (wasImmUpdate);
13414
13415   if (!aPixMap.Save (aFile))
13416   {
13417     Message::SendFail ("Error: can't save selection image");
13418     return 0;
13419   }
13420   return 0;
13421 }
13422
13423 //===============================================================================================
13424 //function : VViewCube
13425 //purpose  :
13426 //===============================================================================================
13427 static int VViewCube (Draw_Interpretor& ,
13428                       Standard_Integer  theNbArgs,
13429                       const char**      theArgVec)
13430 {
13431   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13432   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13433   if (aContext.IsNull() || aView.IsNull())
13434   {
13435     Message::SendFail ("Error: no active viewer");
13436     return 1;
13437   }
13438   else if (theNbArgs < 2)
13439   {
13440     Message::SendFail ("Syntax error: wrong number arguments");
13441     return 1;
13442   }
13443
13444   Handle(AIS_ViewCube) aViewCube;
13445   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13446   Quantity_Color aColorRgb;
13447   TCollection_AsciiString aName;
13448   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13449   {
13450     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13451     anArg.LowerCase();
13452     if (anUpdateTool.parseRedrawMode (anArg))
13453     {
13454       //
13455     }
13456     else if (aViewCube.IsNull())
13457     {
13458       aName = theArgVec[anArgIter];
13459       if (aName.StartsWith ("-"))
13460       {
13461         Message::SendFail ("Syntax error: object name should be specified");
13462         return 1;
13463       }
13464       Handle(AIS_InteractiveObject) aPrs;
13465       GetMapOfAIS().Find2 (aName, aPrs);
13466       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13467       if (aViewCube.IsNull())
13468       {
13469         aViewCube = new AIS_ViewCube();
13470         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13471         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13472         aViewCube->SetFixedAnimationLoop (false);
13473       }
13474     }
13475     else if (anArg == "-reset")
13476     {
13477       aViewCube->ResetStyles();
13478     }
13479     else if (anArg == "-color"
13480           || anArg == "-boxcolor"
13481           || anArg == "-boxsidecolor"
13482           || anArg == "-sidecolor"
13483           || anArg == "-boxedgecolor"
13484           || anArg == "-edgecolor"
13485           || anArg == "-boxcornercolor"
13486           || anArg == "-cornercolor"
13487           || anArg == "-innercolor"
13488           || anArg == "-textcolor"
13489           || anArg == "-xaxistextcolor"
13490           || anArg == "-yaxistextcolor"
13491           || anArg == "-zaxistextcolor")
13492     {
13493       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
13494                                                      theArgVec + anArgIter + 1,
13495                                                      aColorRgb);
13496       if (aNbParsed == 0)
13497       {
13498         Message::SendFail() << "Syntax error at '" << anArg << "'";
13499         return 1;
13500       }
13501       anArgIter += aNbParsed;
13502       if (anArg == "-boxcolor")
13503       {
13504         aViewCube->SetBoxColor (aColorRgb);
13505       }
13506       else if (anArg == "-boxsidecolor"
13507             || anArg == "-sidecolor")
13508       {
13509         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13510         aViewCube->SynchronizeAspects();
13511       }
13512       else if (anArg == "-boxedgecolor"
13513             || anArg == "-edgecolor")
13514       {
13515         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13516         aViewCube->SynchronizeAspects();
13517       }
13518       else if (anArg == "-boxcornercolor"
13519             || anArg == "-cornercolor")
13520       {
13521         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13522         aViewCube->SynchronizeAspects();
13523       }
13524       else if (anArg == "-innercolor")
13525       {
13526         aViewCube->SetInnerColor (aColorRgb);
13527       }
13528       else if (anArg == "-textcolor")
13529       {
13530         aViewCube->SetTextColor (aColorRgb);
13531       }
13532       else if (anArg == "-xaxistextcolor"
13533             || anArg == "-yaxistextcolor"
13534             || anArg == "-zaxistextcolor")
13535       {
13536         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
13537                                 ? Prs3d_DatumParts_XAxis
13538                                 : (anArg.Value (2) == 'y'
13539                                  ? Prs3d_DatumParts_YAxis
13540                                  : Prs3d_DatumParts_ZAxis);
13541         aViewCube->Attributes()->SetOwnDatumAspects();
13542         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
13543       }
13544       else
13545       {
13546         aViewCube->SetColor (aColorRgb);
13547       }
13548     }
13549     else if (anArgIter + 1 < theNbArgs
13550           && (anArg == "-transparency"
13551            || anArg == "-boxtransparency"))
13552     {
13553       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13554       if (aValue < 0.0 || aValue > 1.0)
13555       {
13556         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13557         return 1;
13558       }
13559
13560       if (anArg == "-boxtransparency")
13561       {
13562         aViewCube->SetBoxTransparency (aValue);
13563       }
13564       else
13565       {
13566         aViewCube->SetTransparency (aValue);
13567       }
13568     }
13569     else if (anArg == "-axes"
13570           || anArg == "-edges"
13571           || anArg == "-vertices"
13572           || anArg == "-vertexes"
13573           || anArg == "-fixedanimation")
13574     {
13575       bool toShow = true;
13576       if (anArgIter + 1 < theNbArgs
13577        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
13578       {
13579         ++anArgIter;
13580       }
13581       if (anArg == "-fixedanimation")
13582       {
13583         aViewCube->SetFixedAnimationLoop (toShow);
13584       }
13585       else if (anArg == "-axes")
13586       {
13587         aViewCube->SetDrawAxes (toShow);
13588       }
13589       else if (anArg == "-edges")
13590       {
13591         aViewCube->SetDrawEdges (toShow);
13592       }
13593       else
13594       {
13595         aViewCube->SetDrawVertices (toShow);
13596       }
13597     }
13598     else if (anArg == "-yup"
13599           || anArg == "-zup")
13600     {
13601       bool isOn = true;
13602       if (anArgIter + 1 < theNbArgs
13603        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
13604       {
13605         ++anArgIter;
13606       }
13607       if (anArg == "-yup")
13608       {
13609         aViewCube->SetYup (isOn);
13610       }
13611       else
13612       {
13613         aViewCube->SetYup (!isOn);
13614       }
13615     }
13616     else if (anArgIter + 1 < theNbArgs
13617           && anArg == "-font")
13618     {
13619       aViewCube->SetFont (theArgVec[++anArgIter]);
13620     }
13621     else if (anArgIter + 1 < theNbArgs
13622           && anArg == "-fontheight")
13623     {
13624       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
13625     }
13626     else if (anArgIter + 1 < theNbArgs
13627           && (anArg == "-size"
13628            || anArg == "-boxsize"))
13629     {
13630       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
13631                           anArg != "-boxsize");
13632     }
13633     else if (anArgIter + 1 < theNbArgs
13634           && (anArg == "-boxfacet"
13635            || anArg == "-boxfacetextension"
13636            || anArg == "-facetextension"
13637            || anArg == "-extension"))
13638     {
13639       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
13640     }
13641     else if (anArgIter + 1 < theNbArgs
13642           && (anArg == "-boxedgegap"
13643            || anArg == "-edgegap"))
13644     {
13645       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
13646     }
13647     else if (anArgIter + 1 < theNbArgs
13648           && (anArg == "-boxedgeminsize"
13649            || anArg == "-edgeminsize"))
13650     {
13651       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
13652     }
13653     else if (anArgIter + 1 < theNbArgs
13654           && (anArg == "-boxcornerminsize"
13655            || anArg == "-cornerminsize"))
13656     {
13657       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
13658     }
13659     else if (anArgIter + 1 < theNbArgs
13660           && anArg == "-axespadding")
13661     {
13662       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
13663     }
13664     else if (anArgIter + 1 < theNbArgs
13665           && anArg == "-roundradius")
13666     {
13667       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
13668     }
13669     else if (anArgIter + 1 < theNbArgs
13670           && anArg == "-duration")
13671     {
13672       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
13673     }
13674     else if (anArgIter + 1 < theNbArgs
13675           && anArg == "-axesradius")
13676     {
13677       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
13678     }
13679     else if (anArgIter + 1 < theNbArgs
13680           && anArg == "-axesconeradius")
13681     {
13682       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
13683     }
13684     else if (anArgIter + 1 < theNbArgs
13685           && anArg == "-axessphereradius")
13686     {
13687       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
13688     }
13689     else if (anArg == "-orthopers")
13690     {
13691       const Handle(Graphic3d_TransformPers)& aTrsfPers = aViewCube->TransformPersistence();
13692       Handle(Graphic3d_TransformPers) anOrthoPers = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_OrthoPers, aTrsfPers->Corner2d(), aTrsfPers->Offset2d());
13693       aViewCube->SetTransformPersistence (anOrthoPers);
13694     }
13695     else
13696     {
13697       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13698       return 1;
13699     }
13700   }
13701   if (aViewCube.IsNull())
13702   {
13703     Message::SendFail ("Syntax error: wrong number of arguments");
13704     return 1;
13705   }
13706
13707   ViewerTest::Display (aName, aViewCube, false);
13708   return 0;
13709 }
13710
13711 //! Parse color type argument.
13712 static bool parseColorType (const char* theString,
13713                             Quantity_TypeOfColor& theType)
13714 {
13715   TCollection_AsciiString aType (theString);
13716   aType.LowerCase();
13717   if      (aType == "rgb")  { theType = Quantity_TOC_RGB; }
13718   else if (aType == "srgb") { theType = Quantity_TOC_sRGB; }
13719   else if (aType == "hex")  { theType = Quantity_TOC_sRGB; }
13720   else if (aType == "name") { theType = Quantity_TOC_sRGB; }
13721   else if (aType == "hls")  { theType = Quantity_TOC_HLS; }
13722   else if (aType == "lab")  { theType = Quantity_TOC_CIELab; }
13723   else if (aType == "lch")  { theType = Quantity_TOC_CIELch; }
13724   else { return false; }
13725   return true;
13726 }
13727
13728 //===============================================================================================
13729 //function : VColorConvert
13730 //purpose  :
13731 //===============================================================================================
13732 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
13733 {
13734   Quantity_TypeOfColor aTypeFrom = Quantity_TOC_RGB, aTypeTo = Quantity_TOC_RGB;
13735   double anInput[4] = {};
13736   Quantity_ColorRGBA aColor (0.0f, 0.0f, 0.0f, 1.0f);
13737   bool toPrintHex = false, toPrintName = false, hasAlpha = false;
13738   for (int anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13739   {
13740     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
13741     anArgCase.LowerCase();
13742     if ((anArgCase == "-from"
13743       || anArgCase == "from")
13744      && anArgIter + 1 < theNbArgs
13745      && parseColorType (theArgVec[anArgIter + 1], aTypeFrom))
13746     {
13747       ++anArgIter;
13748     }
13749     else if ((anArgCase == "-to"
13750            || anArgCase == "to")
13751           && anArgIter + 1 < theNbArgs
13752           && parseColorType (theArgVec[anArgIter + 1], aTypeTo))
13753     {
13754       TCollection_AsciiString aToStr (theArgVec[++anArgIter]);
13755       aToStr.LowerCase();
13756       toPrintHex  = (aToStr == "hex");
13757       toPrintName = (aToStr == "name");
13758     }
13759     else if (Quantity_ColorRGBA::ColorFromHex (theArgVec[anArgIter], aColor))
13760     {
13761       hasAlpha = anArgCase.Length() >= 8;
13762     }
13763     else if (Quantity_Color::ColorFromName (theArgVec[anArgIter], aColor.ChangeRGB()))
13764     {
13765       //
13766     }
13767     else if (anArgIter + 2 < theNbArgs
13768           && Draw::ParseReal (theArgVec[anArgIter + 0], anInput[0])
13769           && Draw::ParseReal (theArgVec[anArgIter + 1], anInput[1])
13770           && Draw::ParseReal (theArgVec[anArgIter + 2], anInput[2]))
13771     {
13772       if (anArgIter + 3 < theNbArgs
13773        && Draw::ParseReal (theArgVec[anArgIter + 3], anInput[3]))
13774       {
13775         anArgIter += 1;
13776         aColor.SetAlpha ((float )anInput[3]);
13777         hasAlpha = true;
13778       }
13779       anArgIter += 2;
13780       aColor.ChangeRGB().SetValues (anInput[0], anInput[1], anInput[2], aTypeFrom);
13781     }
13782     else
13783     {
13784       theDI << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13785       return 1;
13786     }
13787   }
13788
13789   if (toPrintHex)
13790   {
13791     if (hasAlpha || aColor.Alpha() < 1.0f)
13792     {
13793       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
13794     }
13795     else
13796     {
13797       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
13798     }
13799   }
13800   else if (toPrintName)
13801   {
13802     theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
13803   }
13804   else
13805   {
13806     double anOutput[3] = {};
13807     aColor.GetRGB().Values (anOutput[0], anOutput[1], anOutput[2], aTypeTo);
13808
13809     // print values with 6 decimal digits
13810     char aBuffer[1024];
13811     if (hasAlpha || aColor.Alpha() < 1.0f)
13812     {
13813       Sprintf (aBuffer, "%.6f %.6f %.6f %.6f", anOutput[0], anOutput[1], anOutput[2], aColor.Alpha());
13814     }
13815     else
13816     {
13817       Sprintf (aBuffer, "%.6f %.6f %.6f", anOutput[0], anOutput[1], anOutput[2]);
13818     }
13819     theDI << aBuffer;
13820   }
13821   return 0;
13822 }
13823  
13824 //===============================================================================================
13825 //function : VColorDiff
13826 //purpose  :
13827 //===============================================================================================
13828 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13829 {
13830   if (theNbArgs != 7)
13831   {
13832     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13833     return 1;
13834   }
13835
13836   double aR1 = Draw::Atof (theArgVec[1]);
13837   double aG1 = Draw::Atof (theArgVec[2]);
13838   double aB1 = Draw::Atof (theArgVec[3]);
13839   double aR2 = Draw::Atof (theArgVec[4]);
13840   double aG2 = Draw::Atof (theArgVec[5]);
13841   double aB2 = Draw::Atof (theArgVec[6]);
13842
13843   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
13844   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
13845
13846   theDI << aColor1.DeltaE2000 (aColor2);
13847
13848   return 0;
13849 }
13850  
13851 //===============================================================================================
13852 //function : VSelBvhBuild
13853 //purpose  :
13854 //===============================================================================================
13855 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
13856 {
13857   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
13858   if (aCtx.IsNull())
13859   {
13860     Message::SendFail ("Error: no active viewer");
13861     return 1;
13862   }
13863
13864   if (theNbArgs < 2)
13865   {
13866     Message::SendFail ("Error: command syntax is incorrect, see help");
13867     return 1;
13868   }
13869
13870   Standard_Integer toEnable = -1;
13871   Standard_Integer aThreadsNb = -1;
13872   Standard_Boolean toWait = Standard_False;
13873
13874   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13875   {
13876     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13877     anArg.LowerCase();
13878
13879     if (anArg == "-nbthreads"
13880         && anArgIter + 1 < theNbArgs)
13881     {
13882       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
13883       if (aThreadsNb < 1)
13884       {
13885         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
13886       }
13887     }
13888     else if (anArg == "-wait")
13889     {
13890       toWait = Standard_True;
13891     }
13892     else if (toEnable == -1)
13893     {
13894       Standard_Boolean toEnableValue = Standard_True;
13895       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
13896       {
13897         toEnable = toEnableValue ? 1 : 0;
13898       }
13899       else
13900       {
13901         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13902         return 1;
13903       }
13904     }
13905     else
13906     {
13907       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13908       return 1;
13909     }
13910   }
13911
13912   if (aThreadsNb == -1)
13913   {
13914     aThreadsNb = 1;
13915   }
13916   if (toEnable != -1)
13917   {
13918     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
13919   }
13920   if (toWait)
13921   {
13922     aCtx->MainSelector()->WaitForBVHBuild();
13923   }
13924
13925   return 0;
13926 }
13927
13928 //=======================================================================
13929 //function : VChangeMouseGesture
13930 //purpose  :
13931 //=======================================================================
13932 static int VChangeMouseGesture (Draw_Interpretor&,
13933                                 Standard_Integer  theArgsNb,
13934                                 const char**      theArgVec)
13935 {
13936   Handle(V3d_View) aView = ViewerTest::CurrentView();
13937   if (aView.IsNull())
13938   {
13939     Message::SendFail ("Error: no active viewer");
13940     return 1;
13941   }
13942
13943   NCollection_DoubleMap<TCollection_AsciiString, AIS_MouseGesture> aGestureMap;
13944   {
13945     aGestureMap.Bind ("none",            AIS_MouseGesture_NONE);
13946     aGestureMap.Bind ("selectrectangle", AIS_MouseGesture_SelectRectangle);
13947     aGestureMap.Bind ("selectlasso",     AIS_MouseGesture_SelectLasso);
13948     aGestureMap.Bind ("zoom",            AIS_MouseGesture_Zoom);
13949     aGestureMap.Bind ("zoomwindow",      AIS_MouseGesture_ZoomWindow);
13950     aGestureMap.Bind ("pan",             AIS_MouseGesture_Pan);
13951     aGestureMap.Bind ("rotateorbit",     AIS_MouseGesture_RotateOrbit);
13952     aGestureMap.Bind ("rotateview",      AIS_MouseGesture_RotateView);
13953     aGestureMap.Bind ("drag",            AIS_MouseGesture_Drag);
13954   }
13955   NCollection_DoubleMap<TCollection_AsciiString, Standard_UInteger> aMouseButtonMap;
13956   {
13957     aMouseButtonMap.Bind ("none",   (Standard_UInteger )Aspect_VKeyMouse_NONE);
13958     aMouseButtonMap.Bind ("left",   (Standard_UInteger )Aspect_VKeyMouse_LeftButton);
13959     aMouseButtonMap.Bind ("middle", (Standard_UInteger )Aspect_VKeyMouse_MiddleButton);
13960     aMouseButtonMap.Bind ("right",  (Standard_UInteger )Aspect_VKeyMouse_RightButton);
13961   }
13962
13963   Standard_UInteger aButton = (Standard_UInteger )Aspect_VKeyMouse_LeftButton;
13964   AIS_MouseGesture aGesture = AIS_MouseGesture_RotateOrbit;
13965   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13966   {
13967     Standard_CString        anArg = theArgVec[anArgIter];
13968     TCollection_AsciiString anArgCase (anArg);
13969     anArgCase.LowerCase();
13970     if (anArgCase == "-button")
13971     {
13972       TCollection_AsciiString aButtonStr = theArgVec[++anArgIter];
13973       aButtonStr.LowerCase();
13974       aButton = aMouseButtonMap.Find1 (aButtonStr);
13975     }
13976     else if (anArgCase == "-gesture")
13977     {
13978       TCollection_AsciiString aGestureStr = theArgVec[++anArgIter];
13979       aGestureStr.LowerCase();
13980       aGesture = aGestureMap.Find1 (aGestureStr);
13981     }
13982     else
13983     {
13984       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
13985       return 1;
13986     }
13987   }
13988
13989   Handle(ViewerTest_EventManager) aViewMgr = ViewerTest::CurrentEventManager();
13990   aViewMgr->ChangeMouseGestureMap().Bind (aButton, aGesture);
13991
13992   return 0;
13993 }
13994
13995 //=======================================================================
13996 //function : ViewerTest_ExitProc
13997 //purpose  :
13998 //=======================================================================
13999 static void ViewerTest_ExitProc (ClientData )
14000 {
14001   NCollection_List<TCollection_AsciiString> aViewList;
14002   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
14003        anIter.More(); anIter.Next())
14004   {
14005     aViewList.Append (anIter.Key1());
14006   }
14007
14008   for (NCollection_List<TCollection_AsciiString>::Iterator anIter (aViewList);
14009        anIter.More(); anIter.Next())
14010   {
14011     ViewerTest::RemoveView (anIter.Value(), true);
14012   }
14013 }
14014
14015 //=======================================================================
14016 //function : ViewerCommands
14017 //purpose  :
14018 //=======================================================================
14019
14020 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
14021 {
14022   static bool TheIsInitialized = false;
14023   if (TheIsInitialized)
14024   {
14025     return;
14026   }
14027
14028   TheIsInitialized = true;
14029   // define destruction callback to destroy views in a well-defined order
14030   Tcl_CreateExitHandler (ViewerTest_ExitProc, 0);
14031
14032   const char* aGroup = "AIS Viewer";
14033   const char* aFileName = __FILE__;
14034   auto addCmd = [&](const char* theName, Draw_Interpretor::CommandFunction theFunc, const char* theHelp)
14035   {
14036     theCommands.Add (theName, theHelp, aFileName, theFunc, aGroup);
14037   };
14038
14039   addCmd ("vdriver", VDriver, /* [vdriver] */ R"(
14040 vdriver [-list] [-default DriverName] [-load DriverName]
14041 Manages active graphic driver factory.
14042 Prints current active driver when called without arguments.
14043 Makes specified driver active when ActiveName argument is specified.
14044  -list    print registered factories
14045  -default define which factory should be used by default (to be used by next vinit call)
14046  -load    try loading factory plugin and set it as default one
14047 )" /* [vdriver] */);
14048
14049   addCmd ("vinit", VInit, /* [vinit] */ R"(
14050 vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]
14051       [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {0|1}]=0 [-2d_mode {0|1}]=0
14052       [-display displayName] [-dpiAware {0|1}]=0
14053       [-subview] [-parent OtherView] [-composer {0|1}]=0 [-margins DX DY]=0
14054 Creates new View window with specified name viewName.
14055 By default the new view is created in the viewer and in graphic driver shared with active view.
14056  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}
14057        if driverName isn't specified the driver will be shared with active view;
14058        if viewerName isn't specified the viewer will be shared with active view.
14059  -display HostName.DisplayNumber[:ScreenNumber]
14060
14061 Display name will be used within creation of graphic driver, when specified.
14062  -left,  -top    pixel position of left top corner of the window.
14063  -width, -height width and height of window respectively.
14064  -cloneActive flag to copy camera and dimensions of active view.
14065  -exitOnClose when specified, closing the view will exit application.
14066  -closeOnEscape when specified, view will be closed on pressing Escape.
14067  -virtual create an offscreen window within interactive session
14068  -subview create a subview within another view
14069  -2d_mode when on, view will not react on rotate scene events
14070  -dpiAware override dpi aware hint (Windows platform)
14071 Additional commands for operations with views: vclose, vactivate, vviewlist.
14072 )" /* [vinit] */);
14073
14074   addCmd ("vclose", VClose, /* [vclose] */ R"(
14075 vclose [view_id [keep_context=0|1]]
14076 or vclose ALL - to remove all created views
14077  - removes view(viewer window) defined by its view_id.
14078  - keep_context: by default 0; if 1 and the last view is deleted the current context is not removed.
14079 )" /* [vclose] */);
14080
14081   addCmd ("vactivate", VActivate, /* [vactivate] */ R"(
14082 vactivate view_id [-noUpdate]
14083 Activates view(viewer window) defined by its view_id.
14084 )" /* [vactivate] */);
14085
14086   addCmd ("vviewlist", VViewList, /* [vviewlist] */ R"(
14087 vviewlist [format={tree, long}]=tree
14088 Prints current list of views per viewer and graphic_driver ID shared between viewers
14089  - format: format of result output, if tree the output is a tree view;
14090            otherwise it's a list of full view names.
14091 )" /* [vviewlist] */);
14092
14093   addCmd ("vhelp", VHelp, /* [vhelp] */ R"(
14094 vhelp : display help on the viewer commands and list of hotkeys.
14095 )" /* [vhelp] */);
14096
14097   addCmd ("vviewproj", VViewProj, /* [vviewproj] */ R"(
14098 vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]
14099           [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]
14100 Setup view direction
14101  -Yup      use Y-up convention instead of Zup (which is default).
14102  +-X+-Y+-Z define direction as combination of DX, DY and DZ;
14103            for example '+Z' will show front of the model,
14104            '-X-Y+Z' will define left axonometric view.
14105  -frame    define camera Up and Right directions (regardless Up convention);
14106            for example '+X+Z' will show front of the model with Z-up.
14107 )" /* [vviewproj] */);
14108
14109   addCmd ("vtop", VViewProj, /* [vtop] */ R"(
14110 vtop or <T> : Display top view (+X+Y) in the 3D viewer window.
14111 )" /* [vtop] */);
14112
14113   addCmd ("vbottom", VViewProj, /* [vbottom] */ R"(
14114 vbottom : Display bottom view (+X-Y) in the 3D viewer window.
14115 )" /* [vbottom] */);
14116
14117   addCmd ("vleft", VViewProj, /* [vleft] */ R"(
14118 vleft : Display left view (-Y+Z) in the 3D viewer window.
14119 )" /* [vleft] */);
14120
14121   addCmd ("vright", VViewProj, /* [vright] */ R"(
14122 vright : Display right view (+Y+Z) in the 3D viewer window.
14123 )" /* [vright] */);
14124
14125   addCmd ("vaxo", VViewProj, /* [vaxo] */ R"(
14126 vaxo or <A> : Display axonometric view (+X-Y+Z) in the 3D viewer window.
14127 )" /* [vaxo] */);
14128
14129   addCmd ("vfront", VViewProj, /* [vfront] */ R"(
14130 vfront : Display front view (+X+Z) in the 3D viewer window.
14131 )" /* [vfront] */);
14132
14133   addCmd ("vback", VViewProj, /* [vfront] */ R"(
14134 vback : Display back view (-X+Z) in the 3D viewer window.
14135 )" /* [vback] */);
14136
14137   addCmd ("vpick", VPick, /* [vpick] */ R"(
14138 vpick X Y Z [shape subshape]
14139 )" /* [vpick] */);
14140
14141   addCmd ("vfit", VFit, /* [vfit] */ R"(
14142 vfit or <F> [-selected] [-noupdate]
14143 Fit all / selected. Objects in the view are visualized to occupy the maximum surface.
14144 )" /* [vfit] */);
14145
14146   addCmd ("vfitarea", VFitArea, /* [vfitarea] */ R"(
14147 vfitarea [x1 y1 x2 y2] [x1 y1 z1 x2 y2 z2]
14148 Fit view to show area located between two points
14149 given in world 2D or 3D coordinates.
14150 )" /* [vfitarea] */);
14151
14152   addCmd ("vzfit", VZFit, /* [vzfit] */ R"(
14153 vzfit [scale]
14154 Automatic depth panning.
14155 Matches Z near, Z far view volume planes to the displayed objects.
14156  - "scale" specifies factor to scale computed z range.
14157 )" /* [vzfit] */);
14158
14159   addCmd ("vrepaint", VRepaint, /* [vrepaint] */ R"(
14160 vrepaint [-immediate] [-continuous FPS]
14161 Force redraw of active View.
14162  -immediate  flag performs redraw of immediate layers only;
14163  -continuous activates/deactivates continuous redraw of active View,
14164              0 means no continuous rendering,
14165             -1 means non-stop redraws,
14166             >0 specifies target framerate.
14167 )" /* [vrepaint] */);
14168
14169   addCmd ("vclear", VClear, /* [vclear] */ R"(
14170 vclear : Remove all the object from the viewer
14171 )" /* [vclear] */);
14172
14173   addCmd ("vbackground", VBackground, /* [vbackground] */ R"(
14174 vbackground [-color Color [-default]]
14175     [-gradient Color1 Color2 [-default]
14176     [-gradientMode {NONE|HORIZONTAL|VERTICAL|DIAG1|DIAG2|CORNER1|CORNER2|CORNER3|ELLIPTICAL}]=VERT]
14177     [-imageFile ImageFile [-imageMode {CENTERED|TILED|STRETCH|NONE}]=CENTERED [-srgb {0|1}]=1]
14178     [-cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]=0]
14179     [-skydome [-sunDir X Y Z=0 1 0] [-cloud Cloudy=0.2] [-time Time=0.0]
14180               [-fog Haze=0.0] [-size SizePx=512]]
14181     [-pbrEnv {ibl|noibl|keep}]
14182 Changes background or some background settings.
14183  -color        sets background color
14184  -gradient     sets background gradient starting and ending colors
14185  -gradientMode sets gradient fill method
14186  -default      sets background default gradient or color
14187  -imageFile    sets filename of image used as background
14188  -imageMode    sets image fill type
14189  -cubemap      sets environment cubemap as background
14190  -invertedz    sets inversion of Z axis for background cubemap rendering; FALSE when unspecified
14191  -pbrEnv       sets on/off Image Based Lighting (IBL) from background cubemap for PBR
14192  -srgb         prefer sRGB texture format when applicable; TRUE when unspecified"
14193  -order        defines order of tiles in one image cubemap
14194                TileIndexi defubes an index in range [0, 5] for i tile of one image packed cubemap
14195                (has no effect in case of multi-image cubemaps).
14196 Skydome background parameters (generated cubemap):
14197  -skydome      sets procedurally generated skydome as background
14198  -sunDir       sets direction to the sun, direction with negative y component represents moon direction (-x, -y, -z)
14199  -cloud        sets cloud intensity (0.0 - clear sky, 1.0 - very high cloudy)
14200  -time         might be tweaked to slightly change appearance of clouds
14201  -fog          sets mist intensity (0.0 - no mist at all, 1.0 - high mist)
14202  -size         sets size in pixels of cubemap side
14203 )" /* [vbackground] */);
14204
14205   addCmd ("vsetbg", VBackground, /* [vsetbg] */ R"(
14206 Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.
14207 )" /* [vsetbg] */);
14208
14209   addCmd ("vsetbgmode", VBackground, /* [vsetbgmode] */ R"(
14210 Alias for 'vbackground -imageMode FillType'.
14211 )" /* [vsetbgmode] */);
14212
14213   addCmd ("vsetgradientbg", VBackground, /* [vsetgradientbg] */ R"(
14214 Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.
14215 )" /* [vsetgradientbg] */);
14216
14217   addCmd ("vsetgrbgmode", VBackground, /* [vsetgrbgmode] */ R"(
14218 Alias for 'vbackground -gradientMode FillMethod'.
14219 )" /* [vsetgrbgmode] */);
14220
14221   addCmd ("vsetcolorbg", VBackground, /* [vsetcolorbg] */ R"(
14222 Alias for 'vbackground -color Color'.
14223 )" /* [vsetcolorbg] */);
14224
14225   addCmd ("vsetdefaultbg", VBackground, /* [vsetdefaultbg] */ R"(
14226 Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'
14227   and for 'vbackground -default -color Color'.
14228 )" /* [vsetdefaultbg] */);
14229
14230   addCmd ("vscale", VScale, /* [vscale] */ R"(
14231 vscale X Y Z
14232 )" /* [vscale] */);
14233
14234   addCmd ("vzbufftrihedron", VZBuffTrihedron, /* [vzbufftrihedron] */ R"(
14235 vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]
14236        [-position center|left_lower|left_upper|right_lower|right_upper]
14237        [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]
14238        [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]
14239        [-nbfacets value=12] [-colorLabels color=WHITE]
14240        [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]
14241 Displays a trihedron.
14242 )" /* [vzbufftrihedron] */);
14243
14244   addCmd ("vrotate", VRotate, /* [vrotate] */ R"(
14245 vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]
14246  -mouseStart start rotation according to the mouse position;
14247  -mouseMove  continue rotation with angle computed
14248              from last and new mouse position.
14249 )" /* [vrotate] */);
14250
14251   addCmd ("vzoom", VZoom, /* [vzoom] */ R"(
14252 vzoom coef
14253 )" /* [vzoom] */);
14254
14255   addCmd ("vpan", VPan, /* [vpan] */ R"(
14256 vpan dx dy
14257 )" /* [vpan] */);
14258
14259   addCmd ("vcolorscale", VColorScale, /* [vcolorscale] */ R"(
14260 vcolorscale name [-noupdate|-update] [-demo]
14261       [-range RangeMin=0 RangeMax=1 NbIntervals=10]
14262       [-font HeightFont=20]
14263       [-logarithmic {on|off}=off] [-reversed {on|off}=off]
14264       [-smoothTransition {on|off}=off]
14265       [-hueRange MinAngle=230 MaxAngle=0]
14266       [-colorRange MinColor=BLUE1 MaxColor=RED]
14267       [-textPos {left|right|center|none}=right]
14268       [-labelAtBorder {on|off}=on]
14269       [-colors Color1 Color2 ...] [-color Index Color]
14270       [-labels Label1 Label2 ...] [-label Index Label]
14271       [-freeLabels NbOfLabels Label1 Label2 ...]
14272       [-xy Left=0 Bottom=0]
14273       [-uniform lightness hue_from hue_to]
14274  -demo       display a color scale with demonstration values
14275  -colors     set colors for all intervals
14276  -color      set color for specific interval
14277  -uniform    generate colors with the same lightness
14278  -textpos    horizontal label position relative to color scale bar
14279  -labelAtBorder vertical label position relative to color interval;
14280              at border means the value inbetween neighbor intervals,
14281              at center means the center value within current interval
14282  -labels     set labels for all intervals
14283  -freeLabels same as -labels but does not require
14284              matching the number of intervals
14285  -label      set label for specific interval
14286  -title      set title
14287  -reversed   setup smooth color transition between intervals
14288  -smoothTransition swap colorscale direction
14289  -hueRange   set hue angles corresponding to minimum and maximum values
14290 )" /* [vcolorscale] */);
14291
14292   addCmd ("vgraduatedtrihedron", VGraduatedTrihedron, /* [vgraduatedtrihedron] */ R"(
14293 vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]
14294     [-namefont Name] [-valuesfont Name]
14295     [-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]
14296     [-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]
14297     [-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]
14298     [-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]
14299     [-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]
14300     [-xcolor Color] [-ycolor Color] [-zcolor Color]
14301     [-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]
14302     [-xticks Number] [-yticks Number] [-zticks Number]
14303     [-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]
14304     [-drawgrid on/off] [-drawaxes on/off]
14305 Display or erase graduated trihedron
14306  - xname, yname, zname - names of axes, default: X, Y, Z
14307  - namefont - font of axes names. Default: Arial
14308  - xnameoffset, ynameoffset, znameoffset - offset of name
14309    from values or tickmarks or axis. Default: 30
14310  - xnamecolor, ynamecolor, znamecolor - colors of axes names
14311  - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values
14312    from tickmarks or axis. Default: 10
14313  - valuesfont - font of axes values. Default: Arial
14314  - xcolor, ycolor, zcolor - color of axis and values
14315  - xticks, yticks, xzicks - number of tickmark on axes. Default: 5
14316  - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10
14317 )" /* [vgraduatedtrihedron] */);
14318
14319   addCmd ("vtile", VTile, /* [vtile] */ R"(
14320 vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]
14321 Setup view to draw a tile (a part of virtual bigger viewport).
14322  -totalSize the size of virtual bigger viewport
14323  -tileSize  tile size (the view size will be used if omitted)
14324  -lowerLeft tile offset as lower left corner
14325  -upperLeft tile offset as upper left corner
14326 )" /* [vtile] */);
14327
14328   addCmd ("vzlayer", VZLayer, /* [vzlayer] */ R"(
14329 vzlayer [layerId]
14330         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]
14331         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]
14332         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]
14333         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]
14334 ZLayer list management
14335  -add      add new z layer to viewer and print its id
14336  -insertBefore add new z layer and insert it before existing one
14337  -insertAfter  add new z layer and insert it after  existing one
14338  -delete   delete z layer
14339  -get      print sequence of z layers
14340  -settings print status of z layer settings
14341  -disable  disables given setting
14342  -enable   enables  given setting
14343 )" /* [vzlayer] */);
14344
14345   addCmd ("vlayerline", VLayerLine, /* [vlayerline] */ R"(
14346 vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]
14347 )" /* [vlayerline] */);
14348
14349   addCmd ("vgrid", VGrid, /* [vgrid] */ R"(
14350 vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]
14351       [-step X Y] [-size DX DY]
14352       [-step StepRadius NbDivisions] [-radius Radius]
14353 )" /* [vgrid] */);
14354
14355   addCmd ("vpriviledgedplane", VPriviledgedPlane, /* [vpriviledgedplane] */ R"(
14356 vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]
14357 Sets or prints viewer's priviledged plane geometry:
14358   Ox, Oy, Oz - plane origin;
14359   Nx, Ny, Nz - plane normal direction;
14360   Xx, Xy, Xz - plane x-reference axis direction.
14361 )" /* [vpriviledgedplane] */);
14362
14363   addCmd ("vconvert", VConvert, /* [vconvert] */ R"(
14364 vconvert v [Mode={window|view}]
14365 vconvert x y [Mode={window|view|grid|ray}]
14366 vconvert x y z [Mode={window|grid}]
14367 Convert the given coordinates to window/view/model space:
14368  - window - convert to window coordinates, pixels;
14369  - view   - convert to view projection plane;
14370  - grid   - convert to model coordinates, given on grid;
14371  - ray    - convert projection ray to model coordinates.
14372 )" /* [vconvert] */);
14373
14374   addCmd ("vfps", VFps, /* [vfps] */ R"(
14375 vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view.
14376 )" /* [vfps] */);
14377
14378   addCmd ("vstereo", VStereo, /* [vstereo] */ R"(
14379 vstereo [0|1] [-mode Mode] [-reverse {0|1}]
14380         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]
14381         [-anaglyph Filter] [-smoothInterlacing]
14382 Control stereo output mode. Available modes for -mode:
14383   quadBuffer       OpenGL QuadBuffer stereo;
14384     requires driver support;
14385     should be called BEFORE vinit!
14386   anaglyph         Anaglyph glasses, filters for -anaglyph:
14387     redCyan, redCyanSimple, yellowBlue, yellowBlueSimple, greenMagentaSimple.
14388   rowInterlaced    row-interlaced display
14389     smooth         smooth interlaced output for better text readability
14390   columnInterlaced column-interlaced display
14391   chessBoard       chess-board output
14392   sideBySide       horizontal pair
14393   overUnder        vertical   pair
14394   openVR           OpenVR (HMD), extra options:
14395     -mirrorComposer flag to mirror VR frame in the window (debug);
14396     -unitFactor     specifies meters scale factor for mapping VR input.
14397 )" /* [vstereo] */);
14398
14399   addCmd ("vmemgpu", VMemGpu, /* [vmemgpu] */ R"(
14400 vmemgpu [f]: print system-dependent GPU memory information if available;
14401 with f option returns free memory in bytes.
14402 )" /* [vmemgpu] */);
14403
14404   addCmd ("vreadpixel", VReadPixel, /* [vreadpixel] */ R"(
14405 vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]
14406 Read pixel value for active view.
14407 )" /* [vreadpixel] */);
14408
14409   addCmd ("diffimage", VDiffImage, /* [diffimage] */ R"(
14410 diffimage imageFile1 imageFile2 [diffImageFile]
14411           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]
14412           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]
14413 Compare two images by content and generate difference image.
14414 When -exitOnClose is specified, closing the view will exit application.
14415 When -closeOnEscape is specified, view will be closed on pressing Escape.
14416 )" /* [diffimage] */);
14417
14418   addCmd ("vselect", VSelect, /* [vselect] */ R"(
14419 vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1]
14420         [-replace|-replaceextra|-xor|-add|-remove]
14421 Emulate different types of selection:
14422  1) Single click selection.
14423  2) Selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2).
14424  3) Selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn).
14425  4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.
14426     If the flag is set to 1, both sensitives that were included completely
14427     and overlapped partially by defined rectangle or polygon will be detected,
14428     otherwise algorithm will chose only fully included sensitives.
14429     Default behavior is to detect only full inclusion
14430     (partial inclusion - overlap - is not allowed by default).
14431  5) Selection scheme replace, replaceextra, xor, add or remove (replace by default).
14432 )" /* [vselect] */);
14433
14434   addCmd ("vmoveto", VMoveTo, /* [vmoveto] */ R"(
14435 vmoveto [x y] [-reset]
14436 Emulate cursor movement to pixel position (x,y).
14437  -reset resets current highlighting.
14438 )" /* [vmoveto] */);
14439
14440   addCmd ("vselaxis", VSelectByAxis, /* [vselaxis] */ R"(
14441 vselaxis x y z dx dy dz [-onlyTop 0|1] [-display Name] [-showNormal 0|1]"
14442 Provides intersection by given axis and print result intersection points.
14443  -onlyTop       switches On/Off mode to find only top point or all;
14444  -display Name  displays intersecting axis and result intersection points for debug goals;
14445  -showNormal    adds displaying of normal in intersection point or not.
14446 )" /* [vselaxis] */);
14447
14448   addCmd ("vviewparams", VViewParams, /* [vviewparams] */ R"(
14449 vviewparams [-args] [-scale [s]]
14450             [-eye [x y z]] [-at [x y z]] [-up [x y z]]
14451             [-proj [x y z]] [-center x y] [-size sx]
14452 Manage current view parameters (camera orientation) or prints all
14453 current values when called without argument.
14454  -scale [s]    prints or sets viewport relative scale
14455  -eye  [x y z] prints or sets eye location
14456  -at   [x y z] prints or sets center of look
14457  -up   [x y z] prints or sets direction of up vector
14458  -proj [x y z] prints or sets direction of look
14459  -center x y   sets location of center of the screen in pixels
14460  -size [sx]    prints viewport projection width and height sizes
14461                or changes the size of its maximum dimension
14462  -args         prints vviewparams arguments for restoring current view
14463 )" /* [vviewparams] */);
14464
14465   addCmd ("v2dmode", V2DMode, /* [v2dmode] */ R"(
14466 v2dmode [-name viewName] [-mode {-on|-off}=-on]
14467   name - name of existing view, if not defined, the active view is changed;
14468   mode - switches On/Off rotation mode.
14469 Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:
14470  - rotation of the view by 3rd mouse button with Ctrl active
14471  - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right
14472 View camera position might be changed only by commands.
14473 )" /* [v2dmode] */);
14474
14475   addCmd ("vanimation", VAnimation, /* [vanimation] */ R"(
14476 Alias for vanim
14477 )" /* [vanimation] */);
14478
14479   addCmd ("vanim", VAnimation, /* [vanim] */ R"(
14480 List existing animations:
14481   vanim
14482
14483 Animation playback:
14484   vanim name {-play|-resume|-pause|-stop} [playFrom [playDuration]] [-speed Coeff]
14485              [-freeLook] [-noPauseOnClick] [-lockLoop] [-elapsedTime]
14486
14487   -speed          playback speed (1.0 is normal speed)
14488   -freeLook       skip camera animations
14489   -noPauseOnClick do not pause animation on mouse click
14490   -lockLoop       disable any interactions
14491   -elapsedTime    prints elapsed time in seconds"
14492
14493 Animation definition:
14494   vanim Name/sub/name [-clear] [-delete]
14495         [-start TimeSec] [-duration TimeSec] [-end TimeSec]
14496
14497 Animation name defined in path-style (anim/name or anim.name)
14498 specifies nested animations.
14499 There is no syntax to explicitly add new animation,
14500 and all non-existing animations within the name will be
14501 implicitly created on first use (including parents).
14502
14503 Each animation might define the SINGLE action (see below),
14504 like camera transition, object transformation or custom callback.
14505 Child animations can be used for defining concurrent actions.
14506
14507 Camera animation:
14508   vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]
14509                    [-at1  X Y Z] [-at2  X Y Z]
14510                    [-up1  X Y Z] [-up2  X Y Z]
14511                    [-scale1 Scale] [-scale2 Scale]
14512   -eyeX   camera Eye positions pair (start and end)
14513   -atX    camera Center positions pair
14514   -upX    camera Up directions pair
14515   -scaleX camera Scale factors pair
14516
14517 Object animation:
14518   vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]
14519                      [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]
14520                      [-scale1 Scale] [-scale2 Scale]
14521  -locX   object Location points pair (translation)
14522  -rotX   object Orientations pair (quaternions)
14523  -scaleX object Scale factors pair (quaternions)
14524
14525   vanim name -object [-axis OX OY OZ DX DY DZ] [-ang1 A] [-ang2 A]
14526  -axis   rotation axis
14527  -ang1   start rotation angle in degrees
14528  -ang2   end   rotation angle in degrees
14529
14530 Custom callback:
14531   vanim name -invoke "Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN"
14532
14533   %Pts        overall animation presentation timestamp
14534   %LocalPts   local animation timestamp
14535   %Normalized local animation normalized value in range 0..1
14536
14537 Video recording:
14538   vanim name -record FileName [Width Height] [-fps FrameRate=24]
14539         [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]
14540         [-crf Value] [-preset Preset]
14541   -fps     video framerate
14542   -format  file format, container (matroska, etc.)
14543   -vcodec  video codec identifier (ffv1, mjpeg, etc.)
14544   -pix_fmt image pixel format (yuv420p, rgb24, etc.)
14545   -crf     constant rate factor (specific to codec)
14546   -preset  codec parameters preset (specific to codec)
14547 )" /* [vanim] */);
14548
14549   addCmd ("vchangeselected", VChangeSelected, /* [vchangeselected] */ R"(
14550 vchangeselected shape : Add shape to selection or remove one from it.
14551 )" /* [vchangeselected] */);
14552
14553   addCmd ("vnbselected", VNbSelected, /* [vnbselected] */ R"(
14554 vnbselected : Returns number of selected objects in the interactive context.
14555 )" /* [vnbselected] */);
14556
14557   addCmd ("vcamera", VCamera, /* [vcamera] */ R"(
14558 vcamera [PrsName] [-ortho] [-projtype]
14559         [-persp]
14560         [-fovy   [Angle]] [-distance [Distance]]
14561         [-stereo] [-leftEye] [-rightEye]
14562         [-iod [Distance]] [-iodType    [absolute|relative]]
14563         [-zfocus [Value]] [-zfocusType [absolute|relative]]
14564         [-fov2d  [Angle]] [-lockZup {0|1}]
14565         [-rotationMode {active|pick|pickCenter|cameraAt|scene}]
14566         [-navigationMode {orbit|walk|flight}]
14567         [-xrPose base|head=base]
14568 Manages camera parameters.
14569 Displays frustum when presentation name PrsName is specified.
14570 Prints current value when option called without argument.
14571
14572 Orthographic camera:
14573  -ortho      activate orthographic projection.
14574
14575 Perspective camera:
14576  -persp      activate perspective  projection (mono);
14577  -fovy       field of view in y axis, in degrees;
14578  -fov2d      field of view limit for 2d on-screen elements;
14579  -distance   distance of eye from camera center;
14580  -lockZup    lock Z up (turntable mode);
14581  -rotationMode rotation mode (gravity point);
14582  -navigationMode navigation mode.
14583
14584 Stereoscopic camera:
14585  -stereo     perspective  projection (stereo);
14586  -leftEye    perspective  projection (left  eye);
14587  -rightEye   perspective  projection (right eye);
14588  -iod        intraocular distance value;
14589  -iodType    distance type, absolute or relative;
14590  -zfocus     stereographic focus value;
14591  -zfocusType focus type, absolute or relative.
14592 )" /* [vcamera] */);
14593
14594   addCmd ("vautozfit", VAutoZFit, /* [vautozfit] */ R"(
14595 vautozfit [on={1|0}] [scale]
14596 Prints or changes parameters of automatic z-fit mode:
14597  "on" - turns automatic z-fit on or off;
14598  "scale" - specifies factor to scale computed z range.
14599 )" /* [vautozfit] */);
14600
14601   addCmd ("vzrange", VZRange, /* [vzrange] */ R"(
14602 vzrange [znear] [zfar]
14603 Applies provided znear/zfar to view or prints current values.
14604 )" /* [vzrange] */);
14605
14606   addCmd ("vsetviewsize", VSetViewSize, /* [vsetviewsize] */ R"(
14607 vsetviewsize size
14608 )" /* [vsetviewsize] */);
14609
14610   addCmd ("vmoveview", VMoveView, /* [vmoveview] */ R"(
14611 vmoveview Dx Dy Dz [Start = 1|0]
14612 )" /* [vmoveview] */);
14613
14614   addCmd ("vtranslateview", VTranslateView, /* [vtranslateview] */ R"(
14615 vtranslateview Dx Dy Dz [Start = 1|0)]
14616 )" /* [vtranslateview] */);
14617
14618   addCmd ("vturnview", VTurnView, /* [vturnview] */ R"(
14619 vturnview Ax Ay Az [Start = 1|0]
14620 )" /* [vturnview] */);
14621
14622   addCmd ("vtextureenv", VTextureEnv, /* [vtextureenv] */ R"(
14623 vtextureenv {on|off} {image_file}
14624             [{clamp|repeat} {decal|modulate} {nearest|bilinear|trilinear} ss st ts tt rot]
14625 Enables or disables environment mapping in the 3D view, loading the texture from the given standard
14626 or user-defined file and optionally applying texture mapping parameters.
14627  ss, st - scale factors for s and t texture coordinates;
14628  ts, tt - translation for s and t texture coordinates;
14629  rot    - texture rotation angle in degrees.
14630 )" /* [vtextureenv] */);
14631
14632   addCmd ("vhlr", VHLR, /* [vhlr] */ R"(
14633 vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]
14634 Hidden Line Removal algorithm.
14635  -showHidden if set ON, hidden lines are drawn as dotted ones;
14636  -algoType   type of HLR algorithm:
14637             'algo' - exact HLR algorithm is applied;
14638             'polyAlgo' - polygonal HLR algorithm is applied.
14639 )" /* [vhlr] */);
14640
14641   addCmd ("vhlrtype", VHLRType, /* [vhlrtype] */ R"(
14642 vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]
14643 Changes the type of HLR algorithm using for shapes:
14644  'algo' - exact HLR algorithm is applied;
14645  'polyAlgo' - polygonal HLR algorithm is applied.
14646 If shapes are not given - option is applied to all shapes in the view.
14647 )" /* [vhlrtype] */);
14648
14649   addCmd ("vclipplane", VClipPlane, /* [vclipplane] */ R"(
14650 vclipplane planeName [{0|1}]
14651     [-equation1 A B C D]
14652     [-equation2 A B C D]
14653     [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]
14654     [-set|-unset|-setOverrideGlobal [objects|views]]
14655     [-maxPlanes]
14656     [-capping {0|1}]
14657       [-color R G B] [-transparency Value] [-hatch {on|off|ID}]
14658       [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]
14659         [-texRotate Angle]
14660       [-useObjMaterial {0|1}] [-useObjTexture {0|1}]
14661         [-useObjShader {0|1}]
14662
14663 Clipping planes management:
14664  -maxPlanes   print plane limit for view;
14665  -delete      delete plane with given name;
14666  {off|on|0|1} turn clipping on/off;
14667  -set|-unset  set/unset plane for Object or View list;
14668               applied to active View when list is omitted;
14669  -equation A B C D change plane equation;
14670  -clone SourcePlane NewPlane clone the plane definition.
14671
14672 Capping options:
14673  -capping {off|on|0|1} turn capping on/off;
14674  -color R G B          set capping color;
14675  -transparency Value   set capping transparency 0..1;
14676  -texName Texture      set capping texture;
14677  -texScale SX SY       set capping tex scale;
14678  -texOrigin TX TY      set capping tex origin;
14679  -texRotate Angle      set capping tex rotation;
14680  -hatch {on|off|ID}    set capping hatching mask;
14681  -useObjMaterial {off|on|0|1} use material of clipped object;
14682  -useObjTexture  {off|on|0|1} use texture of clipped object;
14683  -useObjShader   {off|on|0|1} use shader program of object.
14684 )" /* [vclipplane] */);
14685
14686   addCmd ("vdefaults", VDefaults, /* [vdefaults] */ R"(
14687 vdefaults [-absDefl value] [-devCoeff value] [-angDefl value]
14688           [-autoTriang {off/on | 0/1}]
14689 )" /* [vdefaults] */);
14690
14691   addCmd ("vlight", VLight, /* [vlight] */ R"(
14692 vlight [lightName] [-noupdate]
14693        [-clear|-defaults] [-layer Id] [-local|-global] [-disable|-enable]
14694        [-type {ambient|directional|spotlight|positional}] [-name value]
14695        [-position X Y Z] [-direction X Y Z] [-color colorName] [-intensity value]
14696        [-headlight 0|1] [-castShadows 0|1]
14697        [-range value] [-constAttenuation value] [-linearAttenuation value]
14698        [-spotExponent value] [-spotAngle angleDeg]
14699        [-smoothAngle value] [-smoothRadius value]
14700        [-display] [-showName 1|0] [-showRange 1|0] [-prsZoomable 1|0] [-prsSize Value]
14701        [-arcSize Value]
14702
14703 Command manages light sources. Without arguments shows list of lights.
14704 Arguments affecting the list of defined/active lights:
14705  -clear       remove all light sources;
14706  -defaults    defines two standard light sources;
14707  -reset       resets light source parameters to default values;
14708  -type        sets type of light source;
14709  -name        sets new name to light source;
14710  -global      assigns light source to all views (default state);
14711  -local       assigns light source to active view;
14712  -zlayer      assigns light source to specified Z-Layer.
14713
14714 Ambient light parameters:
14715  -color       sets (normalized) light color;
14716  -intensity   sets intensity of light source, 1.0 by default;
14717               affects also environment cubemap intensity.
14718
14719 Point light parameters:
14720  -color       sets (normalized) light color;
14721  -intensity   sets PBR intensity;
14722  -range       sets clamping distance;
14723  -constAtten  (obsolete) sets constant attenuation factor;
14724  -linearAtten (obsolete) sets linear   attenuation factor;
14725  -smoothRadius sets PBR smoothing radius.
14726
14727 Directional light parameters:
14728  -color       sets (normalized) light color;
14729  -intensity   sets PBR intensity;
14730  -direction   sets direction;
14731  -headlight   sets headlight flag;
14732  -castShadows enables/disables shadow casting;
14733  -smoothAngle sets PBR smoothing angle (in degrees) within 0..90 range.
14734
14735 Spot light parameters:
14736  -color       sets (normalized) light color;
14737  -intensity   sets PBR intensity;
14738  -range       sets clamping distance;
14739  -position    sets position;
14740  -direction   sets direction;
14741  -spotAngle   sets spotlight angle;
14742  -spotExp     sets spotlight exponenta;
14743  -headlight   sets headlight flag;
14744  -castShadows enables/disables shadow casting;
14745  -constAtten  (obsolete) sets constant attenuation factor;
14746  -linearAtten (obsolete) sets linear   attenuation factor.
14747
14748 Light presentation parameters:
14749  -display     adds light source presentation;
14750  -showName    shows/hides the name of light source; 1 by default;
14751  -showRange   shows/hides the range of spot/positional light source; 1 by default;
14752  -prsZoomable makes light presentation zoomable/non-zoomable;
14753  -prsDraggable makes light presentation draggable/non-draggable;
14754  -prsSize     sets light presentation size;
14755  -arcSize     sets arc presentation size(in pixels)
14756               for rotation directional light source; 25 by default.
14757
14758 Examples:
14759  vlight redlight -type POSITIONAL -headlight 1 -pos 0 1 1 -color RED
14760  vlight redlight -delete
14761 )" /* [vlight] */);
14762
14763   addCmd ("vpbrenv", VPBREnvironment, /* [vpbrenv] */ R"(
14764 vpbrenv -clear|-generate
14765 Clears or generates PBR environment map of active view.
14766  -clear clears PBR environment (fills by white color);
14767  -generate generates PBR environment from current background cubemap.
14768 )" /* [vpbrenv] */);
14769
14770   addCmd ("vraytrace", VRenderParams, /* [vraytrace] */ R"(
14771 vraytrace [0|1] : Turns on/off ray-tracing renderer.
14772  'vraytrace 0' alias for 'vrenderparams -raster'.
14773  'vraytrace 1' alias for 'vrenderparams -rayTrace'.
14774 )" /* [vraytrace] */);
14775
14776   addCmd ("vrenderparams", VRenderParams, /* [vrenderparams] */ R"(
14777 Manages rendering parameters, affecting visual appearance, quality and performance.
14778 Should be applied taking into account GPU hardware capabilities and performance.
14779
14780 Common parameters:
14781 vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]
14782               [-msaa 0..8=0] [-rendScale scale=1]
14783               [-resolution value=72] [-fontHinting {off|normal|light}=off]
14784               [-fontAutoHinting {auto|force|disallow}=auto]
14785               [-oit {off|weight|peel}] [-oit weighted [depthFactor=0.0]] [-oit peeling [nbLayers=4]]
14786               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]
14787               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]
14788               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]
14789               [-sync {default|views}] [-reset]
14790  -raster          Disables GPU ray-tracing.
14791  -shadingModel    Controls shading model.
14792  -msaa            Specifies number of samples for MSAA.
14793  -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA).
14794  -resolution      Sets new pixels density (PPI) used as text scaling factor.
14795  -fontHinting     Enables/disables font hinting for better readability on low-resolution screens.
14796  -fontAutoHinting Manages font autohinting.
14797  -lineFeather     Sets line feather factor while displaying mesh edges.
14798  -alphaToCoverage Enables/disables alpha to coverage (needs MSAA).
14799  -oit             Enables/disables order-independent transparency (OIT) rendering;
14800       off         unordered transparency (but opaque objects implicitly draw first);
14801       weighted    weight OIT is managed by depth weight factor 0.0..1.0;
14802       peeling     depth peeling OIT is managed by number of peeling layers.
14803   -shadows         Enables/disables shadows rendering.
14804   -shadowMapResolution Shadow texture map resolution.
14805   -shadowMapBias   Shadow map bias.
14806   -depthPrePass    Enables/disables depth pre-pass.
14807   -frustumCulling  Enables/disables objects frustum clipping or
14808                    sets state to check structures culled previously.
14809   -sync            Sets active View parameters as Viewer defaults / to other Views.
14810   -reset           Resets active View parameters to Viewer defaults.
14811
14812 Diagnostic output (on-screen overlay):
14813 vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points
14814                                  |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]
14815               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]
14816  -perfCounters       Show/hide performance counters (flags can be combined).
14817  -perfUpdateInterval Performance counters update interval.
14818  -perfChart          Show frame timers chart limited by specified number of frames.
14819  -perfChartMax       Maximum time in seconds with the chart.
14820
14821 Ray-Tracing options:
14822 vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]
14823               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]
14824               [-gi {on|off}=off] [-brng {on|off}=off]
14825               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]
14826               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]
14827               [-maxRad {value>0}=30.0]
14828               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]
14829               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]
14830  -rayTrace     Enables  GPU ray-tracing.
14831  -rayDepth     Defines maximum ray-tracing depth.
14832  -reflections  Enables/disables specular reflections.
14833  -fsaa         Enables/disables adaptive anti-aliasing.
14834  -gleam        Enables/disables transparency shadow effects.
14835  -gi           Enables/disables global illumination effects (Path-Tracing).
14836  -env          Enables/disables environment map background.
14837  -ignoreNormalMap Enables/disables normal map ignoring during path tracing.
14838  -twoSide      Enables/disables two-sided BSDF models (PT mode).
14839  -iss          Enables/disables adaptive screen sampling (PT mode).
14840  -maxRad       Value used for clamping radiance estimation (PT mode).
14841  -tileSize     Specifies   size of screen tiles in ISS mode (32 by default).
14842  -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default).
14843  -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF).
14844  -focal        Focal distance of perspective camera for depth-of-field effect.
14845  -exposure     Exposure value for tone mapping (0.0 value disables the effect).
14846  -whitePoint   White point value for filmic tone mapping.
14847  -toneMapping  Tone mapping mode (disabled, filmic).
14848
14849 PBR environment baking parameters (advanced/debug):
14850 vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]
14851               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]
14852  -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size).
14853  -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map.
14854  -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during
14855                  diffuse IBL map's sherical harmonics calculation.
14856  -pbrEnvBSSN     Controls maximum number of samples per mipmap level
14857                  in Monte-Carlo integration during specular IBL maps generation.
14858  -pbrEnvBP       Controls strength of samples number reducing
14859                  during specular IBL maps generation (1 disables reducing).
14860
14861 Debug options:
14862 vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]
14863  -issd         Shows screen sampling distribution in ISS mode.
14864  -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging).
14865  -brng         Enables/disables blocked RNG (fast coherent PT).
14866 )" /* [vrenderparams] */);
14867
14868   addCmd ("vstatprofiler", VStatProfiler, /* [vstatprofiler] */ R"(
14869 vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups
14870                 |allArrays|fillArrays|lineArrays|pointArrays|textArrays
14871                 |triangles|points|geomMem|textureMem|frameMem
14872                 |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage
14873                 |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]
14874               [-noredraw]
14875 Prints rendering statistics for specified counters or for all when unspecified.
14876 Set '-noredraw' flag to avoid additional redraw call and use already collected values.
14877 )" /* [vstatprofiler] */);
14878
14879   addCmd ("vplace", VPlace, /* [vplace] */ R"(
14880 vplace dx dy : Places the point (in pixels) at the center of the window
14881 )" /* [vplace] */);
14882
14883   addCmd ("vxrotate", VXRotate, /* [vxrotate] */ R"(
14884 vxrotate
14885 )" /* [vxrotate] */);
14886
14887   addCmd ("vmanipulator", VManipulator, /* [vmanipulator] */ R"(
14888 vmanipulator Name [-attach AISObject | -detach | ...]
14889 Tool to create and manage AIS manipulators.
14890 Options:
14891  '-attach AISObject'                 attach manipulator to AISObject
14892  '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching
14893  '-adjustSize     {0|1}'             adjust size when attaching
14894  '-enableModes    {0|1}'             enable modes when attaching
14895  '-view  {active | [name of view]}'  display manipulator only in defined view,
14896                                      by default it is displayed in all views of the current viewer
14897  '-detach'                           detach manipulator
14898  '-startTransform mouse_x mouse_y' - invoke start of transformation
14899  '-transform      mouse_x mouse_y' - invoke transformation
14900  '-stopTransform  [abort]'         - invoke stop of transformation
14901  '-move x y z'                     - move attached object
14902  '-rotate x y z dx dy dz angle'    - rotate attached object
14903  '-scale factor'                   - scale attached object
14904  '-autoActivate      {0|1}'        - set activation on detection
14905  '-followTranslation {0|1}'        - set following translation transform
14906  '-followRotation    {0|1}'        - set following rotation transform
14907  '-followDragging    {0|1}'        - set following dragging transform
14908  '-gap value'                      - set gap between sub-parts
14909  '-part axis mode    {0|1}'        - set visual part
14910  '-parts axis mode   {0|1}'        - set visual part
14911  '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator
14912  '-size value'                     - set size of manipulator
14913  '-zoomable {0|1}'                 - set zoom persistence
14914 )" /* [vmanipulator] */);
14915
14916   addCmd ("vselprops", VSelectionProperties, /* [vselprops] */ R"(
14917 vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]
14918 Customizes selection and dynamic highlight parameters for the whole interactive context:
14919  -autoActivate {0|1}     disables|enables default computation
14920                          and activation of global selection mode
14921  -autoHighlight {0|1}    disables|enables automatic highlighting in 3D Viewer
14922  -highlightSelected {0|1} disables|enables highlighting of detected object in selected state
14923  -pickStrategy {first|topmost} : defines picking strategy
14924                'first'   to pick first acceptable (default)
14925                'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)
14926  -pixTol    value        sets up pixel tolerance
14927  -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth
14928  -depthTol {sensfactor}  use sensitive factor for sorting results by depth
14929  -preferClosest {0|1}    sets if depth should take precedence over priority while sorting results
14930  -dispMode  dispMode     sets display mode for highlighting
14931  -layer     ZLayer       sets ZLayer for highlighting
14932  -color     {name|r g b} sets highlight color
14933  -transp    value        sets transparency coefficient for highlight
14934  -material  material     sets highlight material
14935  -print                  prints current state of all mentioned parameters
14936 )" /* [vselprops] */);
14937
14938   addCmd ("vhighlightselected", VSelectionProperties, /* [vhighlightselected] */ R"(
14939 vhighlightselected [0|1] : alias for vselprops -highlightSelected.
14940 )" /* [vhighlightselected] */);
14941
14942   addCmd ("vseldump", VDumpSelectionImage, /* [vseldump] */ R"(
14943 vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|entityType|surfNormal}=depth
14944          -pickedIndex Index=1
14945          [-xrPose base|head=base]
14946 Generate an image based on detection results:
14947   depth       normalized depth values
14948   unnormDepth unnormalized depth values
14949   object      color of detected object
14950   owner       color of detected owner
14951   selMode     color of selection mode
14952   entity      color of detected entity
14953   entityType  color of detected entity type
14954   surfNormal  normal direction values
14955 )" /* [vseldump] */);
14956
14957   addCmd ("vviewcube", VViewCube, /* [vviewcube] */ R"(
14958 vviewcube name
14959 Displays interactive view manipulation object. Options:
14960  -reset                   reset geometric and visual attributes
14961  -size Size               adapted size of View Cube
14962  -boxSize Size            box size
14963  -axes  {0|1}             show/hide axes (trihedron)
14964  -edges {0|1}             show/hide edges of View Cube
14965  -vertices {0|1}          show/hide vertices of View Cube
14966  -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation
14967  -color Color             color of View Cube
14968  -boxColor Color          box color
14969  -boxSideColor Color      box sides color
14970  -boxEdgeColor Color      box edges color
14971  -boxCornerColor Color    box corner color
14972  -textColor Color         color of side text of view cube
14973  -innerColor Color        inner box color
14974  -transparency Value      transparency of object within [0, 1] range
14975  -boxTransparency Value   transparency of box    within [0, 1] range
14976  -xAxisTextColor Color    color of X axis label
14977  -yAxisTextColor Color    color of Y axis label
14978  -zAxisTextColor Color    color of Z axis label
14979  -font Name               font name
14980  -fontHeight Value        font height
14981  -boxFacetExtension Value box facet extension
14982  -boxEdgeGap Value        gap between box edges and box sides
14983  -boxEdgeMinSize Value    minimal box edge size
14984  -boxCornerMinSize Value  minimal box corner size
14985  -axesPadding Value       padding between box and arrows
14986  -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range
14987  -axesRadius Value        radius of axes of the trihedron
14988  -axesConeRadius Value    radius of the cone (arrow) of the trihedron
14989  -axesSphereRadius Value  radius of the sphere (central point) of trihedron
14990  -fixedAnimation {0|1}    uninterruptible animation loop
14991  -duration Seconds        animation duration in seconds
14992  -orthoPers               force orthographic projection persistence.
14993 )" /* [vviewcube] */);
14994
14995   addCmd ("vcolorconvert", VColorConvert, /* [vcolorconvert] */ R"(
14996 vcolorconvert [-from {sRGB|HLS|Lab|Lch|RGB}]=RGB [-to {sRGB|HLS|Lab|Lch|RGB|hex|name}]=RGB C1 C2 C2
14997 To convert color from specified color space to linear RGB:
14998   vcolorconvert -from {sRGB|HLS|Lab|Lch|RGB} C1 C2 C2
14999 To convert linear RGB color to specified color space:
15000   vcolorconvert -to {sRGB|HLS|Lab|Lch|RGB|hex|name} R G B
15001 )" /* [vcolorconvert] */);
15002
15003   addCmd ("vcolordiff", VColorDiff, /* [vcolordiff] */ R"(
15004 vcolordiff R1 G1 B1 R2 G2 B2 : returns CIEDE2000 color difference between two RGB colors.
15005 )" /* [vcolordiff] */);
15006
15007   addCmd ("vselbvhbuild", VSelBvhBuild, /* [vselbvhbuild] */ R"(
15008 vselbvhbuild [{0|1}] [-nbThreads value] [-wait]
15009 Turns on/off prebuilding of BVH within background thread(s).
15010  -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1);
15011  -wait        waits for building all of BVH.
15012 )" /* [vselbvhbuild] */);
15013
15014   addCmd ("vchangemousegesture", VChangeMouseGesture, /* [vchangemousegesture] */ R"(
15015 vchangemousegesture -button  {none|left|middle|right}=left
15016                     -gesture {none|selectRectangle|selectLasso|zoom|zoomWindow|pan|rotateOrbit|rotateView|drag}=rotateOrbit
15017 Changes the gesture for the mouse button.
15018  -button  the mouse button;
15019  -gesture the new gesture for the button.
15020 )" /* [vchangemousegesture] */);
15021 }