0032955: Draw Harness, ViewerTest - extend vcolorconvert command to print color in...
[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_AnimationCamera.hxx>
24 #include <AIS_AnimationObject.hxx>
25 #include <AIS_Axis.hxx>
26 #include <AIS_CameraFrustum.hxx>
27 #include <AIS_ColorScale.hxx>
28 #include <AIS_InteractiveContext.hxx>
29 #include <AIS_LightSource.hxx>
30 #include <AIS_ListOfInteractive.hxx>
31 #include <AIS_ListIteratorOfListOfInteractive.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.hxx>
40 #include <Draw_Appli.hxx>
41 #include <Draw_Interpretor.hxx>
42 #include <Draw_ProgressIndicator.hxx>
43 #include <gp_Dir.hxx>
44 #include <gp_Pln.hxx>
45 #include <gp_Pnt.hxx>
46 #include <Geom_Axis2Placement.hxx>
47 #include <Geom_CartesianPoint.hxx>
48 #include <Graphic3d_ArrayOfPolylines.hxx>
49 #include <Graphic3d_AspectFillArea3d.hxx>
50 #include <Graphic3d_AspectMarker3d.hxx>
51 #include <Graphic3d_ClipPlane.hxx>
52 #include <Graphic3d_CubeMapPacked.hxx>
53 #include <Graphic3d_CubeMapSeparate.hxx>
54 #include <Graphic3d_GraduatedTrihedron.hxx>
55 #include <Graphic3d_GraphicDriver.hxx>
56 #include <Graphic3d_GraphicDriverFactory.hxx>
57 #include <Graphic3d_NameOfTextureEnv.hxx>
58 #include <Graphic3d_Texture2D.hxx>
59 #include <Graphic3d_TextureEnv.hxx>
60 #include <Graphic3d_TextureParams.hxx>
61 #include <Graphic3d_TypeOfTextureFilter.hxx>
62 #include <Image_AlienPixMap.hxx>
63 #include <Image_Diff.hxx>
64 #include <Image_VideoRecorder.hxx>
65 #include <Message.hxx>
66 #include <Message_ProgressScope.hxx>
67 #include <Message_ProgressRange.hxx>
68 #include <NCollection_DataMap.hxx>
69 #include <NCollection_List.hxx>
70 #include <NCollection_LocalArray.hxx>
71 #include <NCollection_Vector.hxx>
72 #include <OSD.hxx>
73 #include <OSD_Parallel.hxx>
74 #include <OSD_Timer.hxx>
75 #include <Prs3d_ShadingAspect.hxx>
76 #include <Prs3d_DatumAspect.hxx>
77 #include <Prs3d_Drawer.hxx>
78 #include <Prs3d_LineAspect.hxx>
79 #include <Prs3d_Text.hxx>
80 #include <Select3D_SensitivePrimitiveArray.hxx>
81 #include <TColStd_HSequenceOfAsciiString.hxx>
82 #include <TColStd_SequenceOfInteger.hxx>
83 #include <TColStd_HSequenceOfReal.hxx>
84 #include <TColgp_Array1OfPnt2d.hxx>
85 #include <TColStd_MapOfAsciiString.hxx>
86 #include <ViewerTest_AutoUpdater.hxx>
87 #include <ViewerTest_ContinuousRedrawer.hxx>
88 #include <ViewerTest_EventManager.hxx>
89 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
90 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
91 #include <ViewerTest_CmdParser.hxx>
92 #include <ViewerTest_V3dView.hxx>
93 #include <V3d_AmbientLight.hxx>
94 #include <V3d_DirectionalLight.hxx>
95 #include <V3d_PositionalLight.hxx>
96 #include <V3d_SpotLight.hxx>
97 #include <V3d_Trihedron.hxx>
98 #include <V3d_Viewer.hxx>
99 #include <UnitsAPI.hxx>
100
101 #include <tcl.h>
102
103 #include <cstdlib>
104
105 #if defined(_WIN32)
106   #include <WNT_WClass.hxx>
107   #include <WNT_Window.hxx>
108   #include <WNT_HIDSpaceMouse.hxx>
109 #elif defined(HAVE_XLIB)
110   #include <Xw_Window.hxx>
111   #include <X11/Xlib.h>
112   #include <X11/Xutil.h>
113 #elif defined(__APPLE__)
114   #include <Cocoa_Window.hxx>
115 #elif defined(__EMSCRIPTEN__)
116   #include <Wasm_Window.hxx>
117   #include <emscripten/emscripten.h>
118 #else
119   #include <Aspect_NeutralWindow.hxx>
120 #endif
121
122 //==============================================================================
123 //  VIEWER GLOBAL VARIABLES
124 //==============================================================================
125
126 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
127 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
128
129 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
130 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
131
132 #if defined(_WIN32)
133 typedef WNT_Window ViewerTest_Window;
134 #elif defined(HAVE_XLIB)
135 typedef Xw_Window ViewerTest_Window;
136 static void VProcessEvents(ClientData,int);
137 #elif defined(__APPLE__)
138 typedef Cocoa_Window ViewerTest_Window;
139 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
140 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
141 #elif defined(__EMSCRIPTEN__)
142 typedef Wasm_Window ViewerTest_Window;
143 #else
144 typedef Aspect_NeutralWindow ViewerTest_Window;
145 #endif
146
147 #if defined(__EMSCRIPTEN__)
148 //! Return DOM id of default WebGL canvas from Module.canvas.
149 EM_JS(char*, occJSModuleCanvasId, (), {
150   const aCanvasId = Module.canvas.id;
151   const aNbBytes  = lengthBytesUTF8 (aCanvasId) + 1;
152   const aStrPtr   = Module._malloc (aNbBytes);
153   stringToUTF8 (aCanvasId, aStrPtr, aNbBytes);
154   return aStrPtr;
155 });
156
157 //! Return DOM id of default WebGL canvas from Module.canvas.
158 static TCollection_AsciiString getModuleCanvasId()
159 {
160   char* aRawId = occJSModuleCanvasId();
161   TCollection_AsciiString anId (aRawId != NULL ? aRawId : "");
162   free (aRawId);
163   return anId;
164 }
165 #endif
166
167 static Handle(ViewerTest_Window)& VT_GetWindow()
168 {
169   static Handle(ViewerTest_Window) aWindow;
170   return aWindow;
171 }
172
173 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
174 {
175   static Handle(Aspect_DisplayConnection) aDisplayConnection;
176   return aDisplayConnection;
177 }
178
179 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
180 {
181   GetDisplayConnection() = theDisplayConnection;
182 }
183
184 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
185 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
186 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
187
188 static struct
189 {
190   Quantity_Color FlatColor;
191   Quantity_Color GradientColor1;
192   Quantity_Color GradientColor2;
193   Aspect_GradientFillMethod FillMethod;
194
195   //! Sets the gradient filling for a background in a default viewer.
196   void SetDefaultGradient()
197   {
198     for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator aCtxIter (ViewerTest_myContexts);
199          aCtxIter.More(); aCtxIter.Next())
200     {
201       const Handle (V3d_Viewer)& aViewer = aCtxIter.Value()->CurrentViewer();
202       aViewer->SetDefaultBgGradientColors (GradientColor1, GradientColor2, FillMethod);
203     }
204   }
205
206   //! Sets the color used for filling a background in a default viewer.
207   void SetDefaultColor()
208   {
209     for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator aCtxIter (ViewerTest_myContexts);
210          aCtxIter.More(); aCtxIter.Next())
211     {
212       const Handle (V3d_Viewer)& aViewer = aCtxIter.Value()->CurrentViewer();
213       aViewer->SetDefaultBackgroundColor (FlatColor);
214     }
215   }
216
217 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GradientFillMethod_None };
218
219 //==============================================================================
220 //  EVENT GLOBAL VARIABLES
221 //==============================================================================
222
223 #ifdef _WIN32
224 static LRESULT WINAPI AdvViewerWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
225 #endif
226
227 //==============================================================================
228 //function : WClass
229 //purpose  :
230 //==============================================================================
231
232 const Handle(WNT_WClass)& ViewerTest::WClass()
233 {
234   static Handle(WNT_WClass) theWClass;
235 #if defined(_WIN32)
236   if (theWClass.IsNull())
237   {
238     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
239                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
240                                 ::LoadCursor (NULL, IDC_ARROW));
241   }
242 #endif
243   return theWClass;
244 }
245
246 //==============================================================================
247 //function : CreateName
248 //purpose  : Create numerical name for new object in theMap
249 //==============================================================================
250 template <typename ObjectType>
251 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
252                                     const TCollection_AsciiString& theDefaultString)
253 {
254   if (theObjectMap.IsEmpty())
255     return theDefaultString + TCollection_AsciiString(1);
256
257   Standard_Integer aNextKey = 1;
258   Standard_Boolean isFound = Standard_False;
259   while (!isFound)
260   {
261     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
262     // Look for objects with default names
263     if (theObjectMap.IsBound1(aStringKey))
264     {
265       aNextKey++;
266     }
267     else
268       isFound = Standard_True;
269   }
270
271   return theDefaultString + TCollection_AsciiString(aNextKey);
272 }
273
274 //==============================================================================
275 //structure : ViewerTest_Names
276 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
277 //==============================================================================
278 struct ViewerTest_Names
279 {
280 private:
281   TCollection_AsciiString myDriverName;
282   TCollection_AsciiString myViewerName;
283   TCollection_AsciiString myViewName;
284
285 public:
286
287   const TCollection_AsciiString& GetDriverName () const
288   {
289     return myDriverName;
290   }
291   void SetDriverName (const TCollection_AsciiString& theDriverName)
292   {
293     myDriverName = theDriverName;
294   }
295   const TCollection_AsciiString& GetViewerName () const
296   {
297     return myViewerName;
298   }
299   void SetViewerName (const TCollection_AsciiString& theViewerName)
300   {
301     myViewerName = theViewerName;
302   }
303   const TCollection_AsciiString& GetViewName () const
304   {
305     return myViewName;
306   }
307   void SetViewName (const TCollection_AsciiString& theViewName)
308   {
309     myViewName = theViewName;
310   }
311
312   //===========================================================================
313   //function : Constructor for ViewerTest_Names
314   //purpose  : Get view, viewer, driver names from custom string
315   //===========================================================================
316
317   ViewerTest_Names (const TCollection_AsciiString& theInputString)
318   {
319     TCollection_AsciiString aName(theInputString);
320     if (theInputString.IsEmpty())
321     {
322       // Get current configuration
323       if (ViewerTest_myDrivers.IsEmpty())
324         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
325           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
326       else
327         myDriverName = ViewerTest_myDrivers.Find2
328         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
329
330       if(ViewerTest_myContexts.IsEmpty())
331       {
332         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
333           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
334       }
335       else
336       {
337         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
338       }
339
340       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
341     }
342     else
343     {
344       // There is at least view name
345       Standard_Integer aParserNumber = 0;
346       for (Standard_Integer i = 0; i < 3; ++i)
347       {
348         Standard_Integer aParserPos = aName.SearchFromEnd("/");
349         if(aParserPos != -1)
350         {
351           aParserNumber++;
352           aName.Split(aParserPos-1);
353         }
354         else
355           break;
356       }
357       if (aParserNumber == 0)
358       {
359         // Only view name
360         if (!ViewerTest::GetAISContext().IsNull())
361         {
362           myDriverName = ViewerTest_myDrivers.Find2
363           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
364           myViewerName = ViewerTest_myContexts.Find2
365           (ViewerTest::GetAISContext());
366         }
367         else
368         {
369           // There is no opened contexts here, need to create names for viewer and driver
370           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
371             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
372
373           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
374             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
375         }
376         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
377       }
378       else if (aParserNumber == 1)
379       {
380         // Here is viewerName/viewName
381         if (!ViewerTest::GetAISContext().IsNull())
382           myDriverName = ViewerTest_myDrivers.Find2
383           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
384         else
385         {
386           // There is no opened contexts here, need to create name for driver
387           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
388             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
389         }
390         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
391
392         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
393       }
394       else
395       {
396         //Here is driverName/viewerName/viewName
397         myDriverName = TCollection_AsciiString(aName);
398
399         TCollection_AsciiString aViewerName(theInputString);
400         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
401         myViewerName = TCollection_AsciiString(aViewerName);
402
403         myViewName = TCollection_AsciiString(theInputString);
404       }
405     }
406   }
407 };
408
409 //==============================================================================
410 //function : FindContextByView
411 //purpose  : Find AIS_InteractiveContext by View
412 //==============================================================================
413
414 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
415 {
416   Handle(AIS_InteractiveContext) anAISContext;
417
418   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
419        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
420   {
421     if (anIter.Value()->CurrentViewer() == theView->Viewer())
422        return anIter.Key2();
423   }
424   return anAISContext;
425 }
426
427 //==============================================================================
428 //function : IsWindowOverlapped
429 //purpose  : Check if theWindow overlapp another view
430 //==============================================================================
431
432 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
433                                      const Standard_Integer thePxTop,
434                                      const Standard_Integer thePxRight,
435                                      const Standard_Integer thePxBottom,
436                                      TCollection_AsciiString& theViewId)
437 {
438   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
439       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
440   {
441     Standard_Integer aTop = 0,
442       aLeft = 0,
443       aRight = 0,
444       aBottom = 0;
445     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
446     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
447         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
448         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
449         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
450     {
451       theViewId = anIter.Key1();
452       return Standard_True;
453     }
454   }
455   return Standard_False;
456 }
457
458 // Workaround: to create and delete non-orthographic views outside ViewerTest
459 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
460 {
461   ViewerTest_myViews.UnBind1 (theName);
462 }
463
464 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
465                                const Handle(V3d_View)& theView)
466 {
467   ViewerTest_myViews.Bind (theName, theView);
468 }
469
470 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
471 {
472   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
473 }
474
475 //==============================================================================
476 //function : ViewerInit
477 //purpose  : Create the window viewer and initialize all the global variable
478 //==============================================================================
479
480 TCollection_AsciiString ViewerTest::ViewerInit (const ViewerTest_VinitParams& theParams)
481 {
482   // Default position and dimension of the viewer window.
483   // Note that left top corner is set to be sufficiently small to have
484   // window fit in the small screens (actual for remote desktops, see #23003).
485   // The position corresponds to the window's client area, thus some
486   // gap is added for window frame to be visible.
487   Graphic3d_Vec2d aPxTopLeft (20, 40);
488   Graphic3d_Vec2d aPxSize (409, 409);
489   Standard_Boolean isDefViewSize = Standard_True;
490   Standard_Boolean toCreateViewer = Standard_False;
491   const Standard_Boolean isVirtual = Draw_VirtualWindows || theParams.IsVirtual;
492   if (!theParams.ViewToClone.IsNull())
493   {
494     Graphic3d_Vec2i aCloneSize;
495     theParams.ViewToClone->Window()->Size (aCloneSize.x(), aCloneSize.y());
496     aPxSize = Graphic3d_Vec2d (aCloneSize);
497     isDefViewSize = Standard_False;
498   #if !defined(__EMSCRIPTEN__)
499     (void )isDefViewSize;
500   #endif
501   }
502
503   Handle(Graphic3d_GraphicDriverFactory) aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
504   if (aFactory.IsNull())
505   {
506     Draw::GetInterpretor().Eval ("pload OPENGL");
507     aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
508     if (aFactory.IsNull())
509     {
510       Draw::GetInterpretor().Eval ("pload GLES");
511       aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
512       if (aFactory.IsNull())
513       {
514         throw Standard_ProgramError("Error: no graphic driver factory found");
515       }
516     }
517   }
518
519   Handle(Graphic3d_GraphicDriver) aGraphicDriver;
520   ViewerTest_Names aViewNames (theParams.ViewName);
521   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
522   {
523     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
524   }
525
526   // Get graphic driver (create it or get from another view)
527   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
528   if (isNewDriver)
529   {
530     // Get connection string
531   #if defined(HAVE_XLIB)
532     if (!theParams.DisplayName.IsEmpty())
533     {
534       SetDisplayConnection (new Aspect_DisplayConnection (theParams.DisplayName));
535     }
536     else
537     {
538       Aspect_XDisplay* aDispX = NULL;
539       // create dedicated display connection instead of reusing Tk connection
540       // so that to proceed events independently through VProcessEvents()/ViewerMainLoop() callbacks
541       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
542       Tcl_Interp* aTclInterp = aCommands.Interp();
543       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
544       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
545       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
546     }
547   #else
548     SetDisplayConnection (new Aspect_DisplayConnection ());
549   #endif
550
551     aGraphicDriver = aFactory->CreateDriver (GetDisplayConnection());
552     if (isVirtual)
553     {
554       // don't waste the time waiting for VSync when window is not displayed on the screen
555       aGraphicDriver->SetVerticalSync (false);
556     }
557
558     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
559     toCreateViewer = Standard_True;
560   }
561   else
562   {
563     aGraphicDriver = ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName());
564   }
565
566   // Get screen resolution
567   Graphic3d_Vec2i aScreenSize;
568 #if defined(_WIN32)
569   RECT aWindowSize;
570   GetClientRect(GetDesktopWindow(), &aWindowSize);
571   aScreenSize.SetValues (aWindowSize.right, aWindowSize.bottom);
572 #elif defined(HAVE_XLIB)
573   ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
574   Screen* aScreen = DefaultScreenOfDisplay(aDispX);
575   aScreenSize.x() = WidthOfScreen(aScreen);
576   aScreenSize.y() = HeightOfScreen(aScreen);
577 #elif defined(__APPLE__)
578   GetCocoaScreenResolution (aScreenSize.x(), aScreenSize.y());
579 #else
580   // not implemented
581 #endif
582
583   if (!theParams.ParentView.IsNull())
584   {
585     aPxTopLeft.SetValues (0, 0);
586   }
587   if (theParams.Offset.x() != 0)
588   {
589     aPxTopLeft.x() = theParams.Offset.x();
590   }
591   if (theParams.Offset.y() != 0)
592   {
593     aPxTopLeft.y() = theParams.Offset.y();
594   }
595   if (theParams.Size.x() != 0)
596   {
597     isDefViewSize = Standard_False;
598     aPxSize.x() = theParams.Size.x();
599     if (aPxSize.x() <= 1.0
600      && aScreenSize.x() > 0
601      && theParams.ParentView.IsNull())
602     {
603       aPxSize.x() = aPxSize.x() * double(aScreenSize.x());
604     }
605   }
606   if (theParams.Size.y() != 0)
607   {
608     isDefViewSize = Standard_False;
609     aPxSize.y() = theParams.Size.y();
610     if (aPxSize.y() <= 1.0
611      && aScreenSize.y() > 0
612      && theParams.ParentView.IsNull())
613     {
614       aPxSize.y() = aPxSize.y() * double(aScreenSize.y());
615     }
616   }
617
618   //Dispose the window if input parameters are default
619   if (!ViewerTest_myViews.IsEmpty()
620     && theParams.ParentView.IsNull()
621     && theParams.Offset.x() == 0
622     && theParams.Offset.y() == 0)
623   {
624     Standard_Integer aTop = 0, aLeft = 0, aRight = 0, aBottom = 0;
625     TCollection_AsciiString anOverlappedViewId("");
626     while (IsWindowOverlapped ((int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
627                                (int )aPxTopLeft.x() + (int )aPxSize.x(),
628                                (int )aPxTopLeft.y() + (int )aPxSize.y(), anOverlappedViewId))
629     {
630       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
631
632       if (IsWindowOverlapped (aRight + 20, (int )aPxTopLeft.y(), aRight + 20 + (int )aPxSize.x(),
633                               (int )aPxTopLeft.y() + (int )aPxSize.y(), anOverlappedViewId)
634         && aRight + 2 * aPxSize.x() + 40 > aScreenSize.x())
635       {
636         if (aBottom + aPxSize.y() + 40 > aScreenSize.y())
637         {
638           aPxTopLeft.x() = 20;
639           aPxTopLeft.y() = 40;
640           break;
641         }
642         aPxTopLeft.x() = 20;
643         aPxTopLeft.y() = aBottom + 40;
644       }
645       else
646       {
647         aPxTopLeft.x() = aRight + 20;
648       }
649     }
650   }
651
652   // Get viewer name
653   TCollection_AsciiString aTitle("3D View - ");
654   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
655
656   // Change name of current active window
657   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
658   {
659     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
660   }
661
662   // Create viewer
663   Handle(V3d_Viewer) a3DViewer;
664   // If it's the single view, we first look for empty context
665   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
666   {
667     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
668       anIter(ViewerTest_myContexts);
669     if (anIter.More())
670       ViewerTest::SetAISContext (anIter.Value());
671     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
672   }
673   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
674   {
675     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
676     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
677   }
678   else if (a3DViewer.IsNull())
679   {
680     toCreateViewer = Standard_True;
681     a3DViewer = new V3d_Viewer(aGraphicDriver);
682     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
683     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
684                                            ViewerTest_DefaultBackground.GradientColor2,
685                                            ViewerTest_DefaultBackground.FillMethod);
686   }
687
688   // AIS context setup
689   if (ViewerTest::GetAISContext().IsNull() ||
690       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
691   {
692     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
693     ViewerTest::SetAISContext (aContext);
694     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
695   }
696   else
697   {
698     ViewerTest::ResetEventManager();
699   }
700
701   // Create window
702   if (!theParams.ParentView.IsNull())
703   {
704     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast (theParams.ParentView->Window());
705   }
706   else
707   {
708   #if defined(_WIN32)
709     VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
710                                      isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
711                                      (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
712                                      (int )aPxSize.x(), (int )aPxSize.y(),
713                                      Quantity_NOC_BLACK);
714     VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
715   #elif defined(HAVE_XLIB)
716     VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
717                                     aTitle.ToCString(),
718                                     (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
719                                     (int )aPxSize.x(), (int )aPxSize.y());
720   #elif defined(__APPLE__)
721     VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
722                                        (int )aPxTopLeft.x(), (int )aPxTopLeft.y(),
723                                        (int )aPxSize.x(), (int )aPxSize.y());
724     ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
725   #elif defined(__EMSCRIPTEN__)
726     // current EGL implementation in Emscripten supports only one global WebGL canvas returned by Module.canvas property;
727     // the code should be revised for handling multiple canvas elements (which is technically also possible)
728     TCollection_AsciiString aCanvasId = getModuleCanvasId();
729     if (!aCanvasId.IsEmpty())
730     {
731       aCanvasId = TCollection_AsciiString("#") + aCanvasId;
732     }
733
734     VT_GetWindow() = new Wasm_Window (aCanvasId);
735     Graphic3d_Vec2i aRealSize;
736     VT_GetWindow()->Size (aRealSize.x(), aRealSize.y());
737     if (!isDefViewSize || (aRealSize.x() <= 0 && aRealSize.y() <= 0))
738     {
739       // Wasm_Window wraps an existing HTML element without creating a new one.
740       // Keep size defined on a web page instead of defaulting to 409x409 (as in case of other platform),
741       // but resize canvas if vinit has been called with explicitly specified dimensions.
742       VT_GetWindow()->SetSizeLogical (Graphic3d_Vec2d (aPxSize));
743     }
744   #else
745     // not implemented
746     VT_GetWindow() = new Aspect_NeutralWindow();
747     VT_GetWindow()->SetSize ((int )aPxSize.x(), (int )aPxSize.y());
748   #endif
749     VT_GetWindow()->SetVirtual (isVirtual);
750   }
751
752   // View setup
753   Handle(V3d_View) aView;
754   if (!theParams.ViewToClone.IsNull())
755   {
756     aView = new ViewerTest_V3dView (a3DViewer, theParams.ViewToClone);
757   }
758   else
759   {
760     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
761   }
762
763   aView->View()->SetSubviewComposer (theParams.IsComposer);
764   if (!theParams.ParentView.IsNull())
765   {
766     aView->SetWindow (theParams.ParentView, aPxSize, theParams.Corner, aPxTopLeft, theParams.SubviewMargins);
767   }
768   else
769   {
770     aView->SetWindow (VT_GetWindow());
771   }
772   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
773
774   ViewerTest::CurrentView(aView);
775   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
776
777   // Setup for X11 or NT
778   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
779   ViewerTest_EventManager::SetupWindowCallbacks (VT_GetWindow());
780
781   // Set parameters for V3d_View and V3d_Viewer
782   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
783   aV3dView->SetComputedMode(Standard_False);
784
785   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
786   if (toCreateViewer)
787   {
788     a3DViewer->SetDefaultLights();
789     a3DViewer->SetLightOn();
790   }
791
792 #if defined(HAVE_XLIB)
793   if (isNewDriver)
794   {
795     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
796     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
797   }
798 #endif
799
800   VT_GetWindow()->Map();
801
802   // Set the handle of created view in the event manager
803   ViewerTest::ResetEventManager();
804
805   ViewerTest::CurrentView()->Redraw();
806
807   aView.Nullify();
808   a3DViewer.Nullify();
809
810   return aViewNames.GetViewName();
811 }
812
813 //==============================================================================
814 //function : RedrawAllViews
815 //purpose  : Redraw all created views
816 //==============================================================================
817 void ViewerTest::RedrawAllViews()
818 {
819   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
820   for (; aViewIt.More(); aViewIt.Next())
821   {
822     const Handle(V3d_View)& aView = aViewIt.Key2();
823     aView->Redraw();
824   }
825 }
826
827 //==============================================================================
828 //function : VDriver
829 //purpose  :
830 //==============================================================================
831 static int VDriver (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
832 {
833   if (theArgsNb == 1)
834   {
835     theDi << "Registered: ";
836     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
837          aFactoryIter.More(); aFactoryIter.Next())
838     {
839       const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
840       theDi << aFactory->Name() << " ";
841     }
842
843     theDi << "\n";
844     theDi << "Default: ";
845     if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
846     {
847       theDi << aFactory->Name();
848     }
849     else
850     {
851       theDi << "NONE";
852     }
853     return 0;
854   }
855
856   TCollection_AsciiString aNewActive;
857   bool toLoad = false;
858   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
859   {
860     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
861     anArgCase.LowerCase();
862     if (anArgCase == "-list")
863     {
864       for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
865            aFactoryIter.More(); aFactoryIter.Next())
866       {
867         const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
868         theDi << aFactory->Name() << " ";
869       }
870     }
871     else if ((anArgCase == "-default"
872            || anArgCase == "-load")
873           && aNewActive.IsEmpty())
874     {
875       toLoad = (anArgCase == "-load");
876       if (anArgIter + 1 < theArgsNb)
877       {
878         aNewActive = theArgVec[++anArgIter];
879       }
880       else if (toLoad)
881       {
882         theDi << "Syntax error at '" << theArgVec[anArgIter] << "'";
883         return 1;
884       }
885       else
886       {
887         if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
888         {
889           theDi << aFactory->Name();
890         }
891         else
892         {
893           theDi << "NONE";
894         }
895       }
896     }
897     else if (aNewActive.IsEmpty())
898     {
899       aNewActive = theArgVec[anArgIter];
900     }
901     else
902     {
903       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
904       return 1;
905     }
906   }
907
908   if (!aNewActive.IsEmpty())
909   {
910     const TCollection_AsciiString aNameCopy = aNewActive;
911     if (TCollection_AsciiString::IsSameString (aNewActive, "gl", false)
912      || TCollection_AsciiString::IsSameString (aNewActive, "opengl", false)
913      || TCollection_AsciiString::IsSameString (aNewActive, "tkopengl", false))
914     {
915       aNewActive = "tkopengl";
916     }
917     else if (TCollection_AsciiString::IsSameString (aNewActive, "gles", false)
918           || TCollection_AsciiString::IsSameString (aNewActive, "opengles", false)
919           || TCollection_AsciiString::IsSameString (aNewActive, "tkopengles", false))
920     {
921       aNewActive = "tkopengles";
922     }
923     else if (TCollection_AsciiString::IsSameString (aNewActive, "d3d", false)
924           || TCollection_AsciiString::IsSameString (aNewActive, "d3dhost", false)
925           || TCollection_AsciiString::IsSameString (aNewActive, "tkd3dhost", false))
926     {
927       aNewActive = "tkd3dhost";
928     }
929
930     if (toLoad)
931     {
932       if (aNewActive == "tkopengl")
933       {
934         Draw::GetInterpretor().Eval ("pload OPENGL");
935       }
936       else if (aNewActive == "tkopengles")
937       {
938         Draw::GetInterpretor().Eval ("pload GLES");
939       }
940       else if (aNewActive == "tkd3dhost")
941       {
942         Draw::GetInterpretor().Eval ("pload D3DHOST");
943       }
944       else
945       {
946         theDi << "Syntax error: unable to load plugin for unknown driver factory '" << aNameCopy << "'";
947         return 1;
948       }
949     }
950
951     bool isFound = false;
952     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
953          aFactoryIter.More(); aFactoryIter.Next())
954     {
955       Handle(Graphic3d_GraphicDriverFactory) aFactory = aFactoryIter.Value();
956       if (TCollection_AsciiString::IsSameString (aFactory->Name(), aNewActive, false))
957       {
958         Graphic3d_GraphicDriverFactory::RegisterFactory (aFactory, true);
959         isFound = true;
960         break;
961       }
962     }
963
964     if (!isFound)
965     {
966       theDi << "Syntax error: driver factory '" << aNameCopy << "' not found";
967       return 1;
968     }
969   }
970
971   return 0;
972 }
973
974 //==============================================================================
975 //function : Vinit
976 //purpose  : Create the window viewer and initialize all the global variable
977 //    Use Tcl_CreateFileHandler on UNIX to catch the X11 Viewer event
978 //==============================================================================
979 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
980 {
981   ViewerTest_VinitParams aParams;
982   TCollection_AsciiString aName, aValue;
983   int is2dMode = -1, aDpiAware = -1;
984   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
985   {
986     const TCollection_AsciiString anArg = theArgVec[anArgIt];
987     TCollection_AsciiString anArgCase = anArg;
988     anArgCase.LowerCase();
989     if (anArgIt + 1 < theArgsNb
990      && anArgCase == "-name")
991     {
992       aParams.ViewName = theArgVec[++anArgIt];
993     }
994     else if (anArgIt + 1 < theArgsNb
995           && (anArgCase == "-left"
996            || anArgCase == "-l")
997            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Offset.x()))
998     {
999       ++anArgIt;
1000     }
1001     else if (anArgIt + 1 < theArgsNb
1002           && (anArgCase == "-top"
1003            || anArgCase == "-t")
1004            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Offset.y()))
1005     {
1006       ++anArgIt;
1007     }
1008     else if (anArgIt + 1 < theArgsNb
1009           && (anArgCase == "-width"
1010            || anArgCase == "-w")
1011            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Size.x()))
1012     {
1013       ++anArgIt;
1014     }
1015     else if (anArgIt + 1 < theArgsNb
1016           && (anArgCase == "-height"
1017            || anArgCase == "-h")
1018            && Draw::ParseReal (theArgVec[anArgIt + 1], aParams.Size.y()))
1019     {
1020       ++anArgIt;
1021     }
1022     else if (anArgIt + 1 < theArgsNb
1023           && (anArgCase == "-pos"
1024            || anArgCase == "-position"
1025            || anArgCase == "-corner")
1026           && ViewerTest::ParseCorner (theArgVec[anArgIt + 1], aParams.Corner))
1027     {
1028       ++anArgIt;
1029     }
1030     else if (anArgIt + 2 < theArgsNb
1031           && anArgCase == "-margins"
1032           && Draw::ParseInteger (theArgVec[anArgIt + 1], aParams.SubviewMargins.x())
1033           && Draw::ParseInteger (theArgVec[anArgIt + 2], aParams.SubviewMargins.y()))
1034     {
1035       anArgIt += 2;
1036     }
1037     else if (anArgCase == "-virtual"
1038           || anArgCase == "-offscreen")
1039     {
1040       aParams.IsVirtual = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1041     }
1042     else if (anArgCase == "-composer")
1043     {
1044       aParams.IsComposer = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
1045     }
1046     else if (anArgCase == "-exitonclose")
1047     {
1048       ViewerTest_EventManager::ToExitOnCloseView() = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1049     }
1050     else if (anArgCase == "-closeonescape"
1051           || anArgCase == "-closeonesc")
1052     {
1053       ViewerTest_EventManager::ToCloseViewOnEscape() = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1054     }
1055     else if (anArgCase == "-2d_mode"
1056           || anArgCase == "-2dmode"
1057           || anArgCase == "-2d")
1058     {
1059       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);;
1060       is2dMode = toEnable ? 1 : 0;
1061     }
1062     else if (anArgIt + 1 < theArgsNb
1063           && (anArgCase == "-disp"
1064            || anArgCase == "-display"))
1065     {
1066       aParams.DisplayName = theArgVec[++anArgIt];
1067     }
1068     else if (anArgCase == "-dpiaware")
1069     {
1070       aDpiAware = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt) ? 1 : 0;
1071     }
1072     else if (!ViewerTest::CurrentView().IsNull()
1073           &&  aParams.ViewToClone.IsNull()
1074           && (anArgCase == "-copy"
1075            || anArgCase == "-clone"
1076            || anArgCase == "-cloneactive"
1077            || anArgCase == "-cloneactiveview"))
1078     {
1079       aParams.ViewToClone = ViewerTest::CurrentView();
1080     }
1081     else if (!ViewerTest::CurrentView().IsNull()
1082            && aParams.ParentView.IsNull()
1083            && anArgCase == "-subview")
1084     {
1085       aParams.ParentView = ViewerTest::CurrentView();
1086       if (aParams.ParentView.IsNull())
1087       {
1088         Message::SendFail() << "Syntax error: cannot create of subview without parent";
1089         return 1;
1090       }
1091       if (aParams.ParentView->IsSubview())
1092       {
1093         aParams.ParentView = aParams.ParentView->ParentView();
1094       }
1095     }
1096     else if (!ViewerTest::CurrentView().IsNull()
1097            && aParams.ParentView.IsNull()
1098            && anArgCase == "-parent"
1099            && anArgIt + 1 < theArgsNb)
1100     {
1101       TCollection_AsciiString aParentStr (theArgVec[++anArgIt]);
1102       ViewerTest_Names aViewNames (aParentStr);
1103       if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1104       {
1105         Message::SendFail() << "Syntax error: parent view '" << aParentStr << "' not found";
1106         return 1;
1107       }
1108
1109       aParams.ParentView = ViewerTest_myViews.Find1(aViewNames.GetViewName());
1110       if (aParams.ParentView->IsSubview())
1111       {
1112         aParams.ParentView = aParams.ParentView->ParentView();
1113       }
1114     }
1115     // old syntax
1116     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
1117     {
1118       aName.LowerCase();
1119       if (aName == "name")
1120       {
1121         aParams.ViewName = aValue;
1122       }
1123       else if (aName == "l"
1124             || aName == "left")
1125       {
1126         aParams.Offset.x() = (float)aValue.RealValue();
1127       }
1128       else if (aName == "t"
1129             || aName == "top")
1130       {
1131         aParams.Offset.y() = (float)aValue.RealValue();
1132       }
1133       else if (aName == "disp"
1134             || aName == "display")
1135       {
1136         aParams.DisplayName = aValue;
1137       }
1138       else if (aName == "w"
1139             || aName == "width")
1140       {
1141         aParams.Size.x() = (float )aValue.RealValue();
1142       }
1143       else if (aName == "h"
1144             || aName == "height")
1145       {
1146         aParams.Size.y() = (float)aValue.RealValue();
1147       }
1148       else
1149       {
1150         Message::SendFail() << "Syntax error: unknown argument " << anArg;
1151         return 1;
1152       }
1153     }
1154     else if (aParams.ViewName.IsEmpty())
1155     {
1156       aParams.ViewName = anArg;
1157     }
1158     else
1159     {
1160       Message::SendFail() << "Syntax error: unknown argument " << anArg;
1161       return 1;
1162     }
1163   }
1164
1165 #if defined(_WIN32)
1166   if (aDpiAware != -1)
1167   {
1168     typedef void* (WINAPI *SetThreadDpiAwarenessContext_t)(void*);
1169     if (HMODULE aUser32Module = GetModuleHandleW (L"User32"))
1170     {
1171       SetThreadDpiAwarenessContext_t aSetDpiAware = (SetThreadDpiAwarenessContext_t )GetProcAddress (aUser32Module, "SetThreadDpiAwarenessContext");
1172       if (aDpiAware == 1)
1173       {
1174         // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
1175         if (aSetDpiAware ((void* )-4) == NULL)
1176         {
1177           // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE for older systems
1178           if (aSetDpiAware ((void* )-3) == NULL)
1179           {
1180             Message::SendFail() << "Error: unable to enable DPI awareness";
1181           }
1182         }
1183       }
1184       else
1185       {
1186         // DPI_AWARENESS_CONTEXT_UNAWARE
1187         if (aSetDpiAware ((void* )-1) == NULL)
1188         {
1189           Message::SendFail() << "Error: unable to disable DPI awareness";
1190         }
1191       }
1192     }
1193   }
1194 #else
1195   (void )aDpiAware;
1196 #if !defined(HAVE_XLIB)
1197   if (!aParams.DisplayName.IsEmpty())
1198   {
1199     aParams.DisplayName.Clear();
1200     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
1201   }
1202 #endif
1203 #endif
1204
1205   ViewerTest_Names aViewNames (aParams.ViewName);
1206   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1207   {
1208     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
1209     theDi.Eval (aCommand.ToCString());
1210     if (is2dMode != -1)
1211     {
1212       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1213     }
1214     return 0;
1215   }
1216
1217   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aParams);
1218   if (is2dMode != -1)
1219   {
1220     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1221   }
1222   theDi << aViewId;
1223   return 0;
1224 }
1225
1226 //! Parse HLR algo type.
1227 static Standard_Boolean parseHlrAlgoType (const char* theName,
1228                                           Prs3d_TypeOfHLR& theType)
1229 {
1230   TCollection_AsciiString aName (theName);
1231   aName.LowerCase();
1232   if (aName == "polyalgo")
1233   {
1234     theType = Prs3d_TOH_PolyAlgo;
1235   }
1236   else if (aName == "algo")
1237   {
1238     theType = Prs3d_TOH_Algo;
1239   }
1240   else
1241   {
1242     return Standard_False;
1243   }
1244   return Standard_True;
1245 }
1246
1247 //==============================================================================
1248 //function : VHLR
1249 //purpose  : hidden lines removal algorithm
1250 //==============================================================================
1251
1252 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
1253 {
1254   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1255   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1256   if (aView.IsNull())
1257   {
1258     Message::SendFail ("Error: no active viewer");
1259     return 1;
1260   }
1261
1262   Standard_Boolean hasHlrOnArg = Standard_False;
1263   Standard_Boolean hasShowHiddenArg = Standard_False;
1264   Standard_Boolean isHLROn = Standard_False;
1265   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
1266   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
1267   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1268   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1269   {
1270     TCollection_AsciiString anArg (argv[anArgIter]);
1271     anArg.LowerCase();
1272     if (anUpdateTool.parseRedrawMode (anArg))
1273     {
1274       continue;
1275     }
1276     else if (anArg == "-showhidden"
1277           && anArgIter + 1 < argc
1278           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
1279     {
1280       ++anArgIter;
1281       hasShowHiddenArg = Standard_True;
1282       continue;
1283     }
1284     else if ((anArg == "-type"
1285            || anArg == "-algo"
1286            || anArg == "-algotype")
1287           && anArgIter + 1 < argc
1288           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1289     {
1290       ++anArgIter;
1291       continue;
1292     }
1293     else if (!hasHlrOnArg
1294           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
1295     {
1296       hasHlrOnArg = Standard_True;
1297       continue;
1298     }
1299     // old syntax
1300     else if (!hasShowHiddenArg
1301           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
1302     {
1303       hasShowHiddenArg = Standard_True;
1304       continue;
1305     }
1306     else
1307     {
1308       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
1309       return 1;
1310     }
1311   }
1312   if (!hasHlrOnArg)
1313   {
1314     di << "HLR:        " << aView->ComputedMode() << "\n";
1315     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
1316     di << "HlrAlgo:    ";
1317     switch (aCtx->DefaultDrawer()->TypeOfHLR())
1318     {
1319       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
1320       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
1321       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
1322     }
1323     anUpdateTool.Invalidate();
1324     return 0;
1325   }
1326
1327   Standard_Boolean toRecompute = Standard_False;
1328   if (aTypeOfHLR != Prs3d_TOH_NotSet
1329    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
1330   {
1331     toRecompute = Standard_True;
1332     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1333   }
1334   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
1335   {
1336     toRecompute = Standard_True;
1337     if (toShowHidden)
1338     {
1339       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
1340     }
1341     else
1342     {
1343       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
1344     }
1345   }
1346
1347   // redisplay shapes
1348   if (aView->ComputedMode() && isHLROn && toRecompute)
1349   {
1350     AIS_ListOfInteractive aListOfShapes;
1351     aCtx->DisplayedObjects (aListOfShapes);
1352     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
1353     {
1354       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
1355       {
1356         aCtx->Redisplay (aShape, Standard_False);
1357       }
1358     }
1359   }
1360
1361   aView->SetComputedMode (isHLROn);
1362   return 0;
1363 }
1364
1365 //==============================================================================
1366 //function : VHLRType
1367 //purpose  : change type of using HLR algorithm
1368 //==============================================================================
1369
1370 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
1371 {
1372   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1373   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1374   if (aView.IsNull())
1375   {
1376     Message::SendFail ("Error: no active viewer");
1377     return 1;
1378   }
1379
1380   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
1381   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1382   AIS_ListOfInteractive aListOfShapes;
1383   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1384   {
1385     TCollection_AsciiString anArg (argv[anArgIter]);
1386     anArg.LowerCase();
1387     if (anUpdateTool.parseRedrawMode (anArg))
1388     {
1389       continue;
1390     }
1391     else if ((anArg == "-type"
1392            || anArg == "-algo"
1393            || anArg == "-algotype")
1394           && anArgIter + 1 < argc
1395           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1396     {
1397       ++anArgIter;
1398       continue;
1399     }
1400     // old syntax
1401     else if (aTypeOfHLR == Prs3d_TOH_NotSet
1402           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
1403     {
1404       continue;
1405     }
1406     else
1407     {
1408       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
1409       TCollection_AsciiString aName (argv[anArgIter]);
1410       if (!aMap.IsBound2 (aName))
1411       {
1412         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
1413         return 1;
1414       }
1415
1416       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
1417       if (aShape.IsNull())
1418       {
1419         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
1420         return 1;
1421       }
1422       aListOfShapes.Append (aShape);
1423       continue;
1424     }
1425   }
1426   if (aTypeOfHLR == Prs3d_TOH_NotSet)
1427   {
1428     Message::SendFail ("Syntax error: wrong number of arguments");
1429     return 1;
1430   }
1431
1432   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
1433   if (isGlobal)
1434   {
1435     aCtx->DisplayedObjects (aListOfShapes);
1436     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1437   }
1438
1439   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
1440   {
1441     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
1442     if (aShape.IsNull())
1443     {
1444       continue;
1445     }
1446
1447     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
1448                             && aView->ComputedMode();
1449     if (!isGlobal
1450      || aShape->TypeOfHLR() != aTypeOfHLR)
1451     {
1452       aShape->SetTypeOfHLR (aTypeOfHLR);
1453     }
1454     if (toUpdateShape)
1455     {
1456       aCtx->Redisplay (aShape, Standard_False);
1457     }
1458   }
1459   return 0;
1460 }
1461
1462 //==============================================================================
1463 //function : FindViewIdByWindowHandle
1464 //purpose  : Find theView Id in the map of views by window handle
1465 //==============================================================================
1466 #if defined(_WIN32) || defined(HAVE_XLIB)
1467 static TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
1468 {
1469   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
1470        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1471   {
1472     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
1473     if (aWindowHandle == theWindowHandle)
1474       return anIter.Key1();
1475   }
1476   return TCollection_AsciiString("");
1477 }
1478 #endif
1479
1480 //! Make the view active
1481 void ActivateView (const TCollection_AsciiString& theViewName,
1482                    Standard_Boolean theToUpdate = Standard_True)
1483 {
1484   if (const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName))
1485   {
1486     ViewerTest::ActivateView (aView, theToUpdate);
1487   }
1488 }
1489
1490 //==============================================================================
1491 //function : ActivateView
1492 //purpose  :
1493 //==============================================================================
1494 void ViewerTest::ActivateView (const Handle(V3d_View)& theView,
1495                                Standard_Boolean theToUpdate)
1496 {
1497   Handle(V3d_View) aView = theView;
1498   const TCollection_AsciiString* aViewName = ViewerTest_myViews.Seek2 (aView);
1499   if (aViewName == nullptr)
1500   {
1501     return;
1502   }
1503
1504   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
1505   if (anAISContext.IsNull())
1506   {
1507     return;
1508   }
1509
1510   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1511   {
1512     if (!aCurrentView->Window().IsNull())
1513     {
1514       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1515     }
1516   }
1517
1518   ViewerTest::CurrentView (aView);
1519   ViewerTest::SetAISContext (anAISContext);
1520   if (aView->IsSubview())
1521   {
1522     aView->ParentView()->Window()->SetTitle (TCollection_AsciiString("3D View - ") + *aViewName + "(*)");
1523     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(aView->View()->ParentView()->Window());
1524   }
1525   else
1526   {
1527     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(aView->Window());
1528   }
1529   if (!VT_GetWindow().IsNull())
1530   {
1531     VT_GetWindow()->SetTitle (TCollection_AsciiString("3D View - ") + *aViewName + "(*)");
1532   }
1533   SetDisplayConnection(aView->Viewer()->Driver()->GetDisplayConnection());
1534   if (theToUpdate)
1535   {
1536     aView->Redraw();
1537   }
1538 }
1539
1540 //==============================================================================
1541 //function : RemoveView
1542 //purpose  :
1543 //==============================================================================
1544 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
1545                              const Standard_Boolean  theToRemoveContext)
1546 {
1547   if (!ViewerTest_myViews.IsBound2 (theView))
1548   {
1549     return;
1550   }
1551
1552   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
1553   RemoveView (aViewName, theToRemoveContext);
1554 }
1555
1556 //==============================================================================
1557 //function : RemoveView
1558 //purpose  : Close and remove view from display, clear maps if necessary
1559 //==============================================================================
1560 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
1561 {
1562   if (!ViewerTest_myViews.IsBound1(theViewName))
1563   {
1564     Message::SendFail() << "Wrong view name";
1565     return;
1566   }
1567
1568   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1569   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
1570   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
1571   aRedrawer.Stop (aView);
1572   if (!aView->Subviews().IsEmpty())
1573   {
1574     NCollection_Sequence<Handle(V3d_View)> aSubviews = aView->Subviews();
1575     for (const Handle(V3d_View)& aSubviewIter : aSubviews)
1576     {
1577       RemoveView (aSubviewIter, isContextRemoved);
1578     }
1579   }
1580
1581   // Activate another view if it's active now
1582   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
1583   {
1584     if (ViewerTest_myViews.Extent() > 1)
1585     {
1586       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1587            anIter.More(); anIter.Next())
1588       {
1589         if (anIter.Key1() != theViewName)
1590         {
1591           ActivateView (anIter.Value(), true);
1592           break;
1593         }
1594       }
1595     }
1596     else
1597     {
1598       VT_GetWindow().Nullify();
1599       ViewerTest::CurrentView (Handle(V3d_View)());
1600       if (isContextRemoved)
1601       {
1602         Handle(AIS_InteractiveContext) anEmptyContext;
1603         ViewerTest::SetAISContext(anEmptyContext);
1604       }
1605     }
1606   }
1607
1608   // Delete view
1609   ViewerTest_myViews.UnBind1(theViewName);
1610   if (!aView->Window().IsNull())
1611   {
1612     aView->Window()->Unmap();
1613   }
1614   aView->Remove();
1615
1616 #if defined(HAVE_XLIB)
1617   XFlush ((::Display* )GetDisplayConnection()->GetDisplayAspect());
1618 #endif
1619
1620   // Keep context opened only if the closed view is last to avoid
1621   // unused empty contexts
1622   if (!aCurrentContext.IsNull())
1623   {
1624     // Check if there are more defined views in the viewer
1625     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
1626      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
1627     {
1628       // Remove driver if there is no viewers that use it
1629       Standard_Boolean isRemoveDriver = Standard_True;
1630       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1631           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
1632       {
1633         if (aCurrentContext != anIter.Key2() &&
1634           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
1635         {
1636           isRemoveDriver = Standard_False;
1637           break;
1638         }
1639       }
1640
1641       aCurrentContext->RemoveAll (Standard_False);
1642       if(isRemoveDriver)
1643       {
1644         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
1645       #if defined(HAVE_XLIB)
1646         Tcl_DeleteFileHandler (XConnectionNumber ((::Display* )aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplayAspect()));
1647       #endif
1648       }
1649
1650       ViewerTest_myContexts.UnBind2(aCurrentContext);
1651     }
1652   }
1653   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
1654   if (ViewerTest_EventManager::ToExitOnCloseView())
1655   {
1656     Draw_Interprete ("exit");
1657   }
1658 }
1659
1660 //==============================================================================
1661 //function : VClose
1662 //purpose  : Remove the view defined by its name
1663 //==============================================================================
1664
1665 static int VClose (Draw_Interpretor& /*theDi*/,
1666                    Standard_Integer  theArgsNb,
1667                    const char**      theArgVec)
1668 {
1669   NCollection_List<TCollection_AsciiString> aViewList;
1670   if (theArgsNb > 1)
1671   {
1672     TCollection_AsciiString anArg (theArgVec[1]);
1673     anArg.UpperCase();
1674     if (anArg.IsEqual ("ALL")
1675      || anArg.IsEqual ("*"))
1676     {
1677       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1678            anIter.More(); anIter.Next())
1679       {
1680         aViewList.Append (anIter.Key1());
1681       }
1682       if (aViewList.IsEmpty())
1683       {
1684         std::cout << "No view to close\n";
1685         return 0;
1686       }
1687     }
1688     else
1689     {
1690       ViewerTest_Names aViewName (theArgVec[1]);
1691       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
1692       {
1693         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
1694         return 1;
1695       }
1696       aViewList.Append (aViewName.GetViewName());
1697     }
1698   }
1699   else
1700   {
1701     // close active view
1702     if (ViewerTest::CurrentView().IsNull())
1703     {
1704       Message::SendFail ("Error: no active view");
1705       return 1;
1706     }
1707     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1708   }
1709
1710   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
1711   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
1712        anIter.More(); anIter.Next())
1713   {
1714     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
1715   }
1716
1717   return 0;
1718 }
1719
1720 //==============================================================================
1721 //function : VActivate
1722 //purpose  : Activate the view defined by its ID
1723 //==============================================================================
1724
1725 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1726 {
1727   if (theArgsNb == 1)
1728   {
1729     theDi.Eval("vviewlist");
1730     return 0;
1731   }
1732
1733   TCollection_AsciiString aNameString;
1734   Standard_Boolean toUpdate = Standard_True;
1735   Standard_Boolean toActivate = Standard_True;
1736   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
1737   {
1738     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1739     anArg.LowerCase();
1740     if (toUpdate
1741      && anArg == "-noupdate")
1742     {
1743       toUpdate = Standard_False;
1744     }
1745     else if (toActivate
1746           && aNameString.IsEmpty()
1747           && anArg == "none")
1748     {
1749       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1750       VT_GetWindow().Nullify();
1751       ViewerTest::CurrentView (Handle(V3d_View)());
1752       ViewerTest::ResetEventManager();
1753       theDi << theArgVec[0] << ": all views are inactive\n";
1754       toActivate = Standard_False;
1755     }
1756     else if (toActivate
1757           && aNameString.IsEmpty())
1758     {
1759       aNameString = theArgVec[anArgIter];
1760     }
1761     else
1762     {
1763       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
1764       return 1;
1765     }
1766   }
1767
1768   if (!toActivate)
1769   {
1770     return 0;
1771   }
1772   else if (aNameString.IsEmpty())
1773   {
1774     Message::SendFail ("Syntax error: wrong number of arguments");
1775     return 1;
1776   }
1777
1778   // Check if this view exists in the viewer with the driver
1779   ViewerTest_Names aViewNames (aNameString);
1780   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
1781   {
1782     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
1783     return 1;
1784   }
1785
1786   // Check if it is active already
1787   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
1788   {
1789     theDi << theArgVec[0] << ": the view is active already\n";
1790     return 0;
1791   }
1792
1793   ActivateView (aViewNames.GetViewName(), toUpdate);
1794   return 0;
1795 }
1796
1797 //==============================================================================
1798 //function : VViewList
1799 //purpose  : Print current list of views per viewer and graphic driver ID
1800 //           shared between viewers
1801 //==============================================================================
1802
1803 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1804 {
1805   if (theArgsNb > 2)
1806   {
1807     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
1808           << "Usage: " << theArgVec[0] << " name";
1809     return 1;
1810   }
1811   if (ViewerTest_myContexts.Size() < 1)
1812     return 0;
1813
1814   Standard_Boolean isTreeView =
1815     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
1816
1817   if (isTreeView)
1818   {
1819     theDi << theArgVec[0] <<":\n";
1820   }
1821
1822   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
1823        aDriverIter.More(); aDriverIter.Next())
1824   {
1825     if (isTreeView)
1826       theDi << aDriverIter.Key1() << ":\n";
1827
1828     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1829       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
1830     {
1831       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
1832       {
1833         if (isTreeView)
1834         {
1835           TCollection_AsciiString aContextName(aContextIter.Key1());
1836           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
1837         }
1838
1839         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
1840              aViewIter.More(); aViewIter.Next())
1841         {
1842           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
1843           {
1844             TCollection_AsciiString aViewName(aViewIter.Key1());
1845             if (isTreeView)
1846             {
1847               if (aViewIter.Value() == ViewerTest::CurrentView())
1848                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
1849               else
1850                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
1851             }
1852             else
1853             {
1854               theDi << aViewName << " ";
1855             }
1856           }
1857         }
1858       }
1859     }
1860   }
1861   return 0;
1862 }
1863
1864 //==============================================================================
1865 //function : GetMousePosition
1866 //purpose  :
1867 //==============================================================================
1868 void ViewerTest::GetMousePosition (Standard_Integer& theX,
1869                                    Standard_Integer& theY)
1870 {
1871   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
1872   {
1873     theX = aViewCtrl->LastMousePosition().x();
1874     theY = aViewCtrl->LastMousePosition().y();
1875   }
1876 }
1877
1878 //==============================================================================
1879 //function : VViewProj
1880 //purpose  : Switch view projection
1881 //==============================================================================
1882 static int VViewProj (Draw_Interpretor& ,
1883                       Standard_Integer theNbArgs,
1884                       const char** theArgVec)
1885 {
1886   static Standard_Boolean isYup = Standard_False;
1887   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
1888   if (aView.IsNull())
1889   {
1890     Message::SendFail ("Error: no active viewer");
1891     return 1;
1892   }
1893
1894   TCollection_AsciiString aCmdName (theArgVec[0]);
1895   Standard_Boolean isGeneralCmd = Standard_False;
1896   if (aCmdName == "vfront")
1897   {
1898     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1899   }
1900   else if (aCmdName == "vback")
1901   {
1902     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1903   }
1904   else if (aCmdName == "vtop")
1905   {
1906     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1907   }
1908   else if (aCmdName == "vbottom")
1909   {
1910     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1911   }
1912   else if (aCmdName == "vleft")
1913   {
1914     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1915   }
1916   else if (aCmdName == "vright")
1917   {
1918     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1919   }
1920   else if (aCmdName == "vaxo")
1921   {
1922     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1923   }
1924   else
1925   {
1926     isGeneralCmd = Standard_True;
1927     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
1928     {
1929       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
1930       anArgCase.LowerCase();
1931       if (anArgCase == "-zup")
1932       {
1933         isYup = Standard_False;
1934       }
1935       else if (anArgCase == "-yup")
1936       {
1937         isYup = Standard_True;
1938       }
1939       else if (anArgCase == "-front"
1940             || anArgCase == "front"
1941             || anArgCase == "-f"
1942             || anArgCase == "f")
1943       {
1944         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1945       }
1946       else if (anArgCase == "-back"
1947             || anArgCase == "back"
1948             || anArgCase == "-b"
1949             || anArgCase == "b")
1950       {
1951         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1952       }
1953       else if (anArgCase == "-top"
1954             || anArgCase == "top"
1955             || anArgCase == "-t"
1956             || anArgCase == "t")
1957       {
1958         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1959       }
1960       else if (anArgCase == "-bottom"
1961             || anArgCase == "bottom"
1962             || anArgCase == "-bot"
1963             || anArgCase == "bot"
1964             || anArgCase == "-b"
1965             || anArgCase == "b")
1966       {
1967         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1968       }
1969       else if (anArgCase == "-left"
1970             || anArgCase == "left"
1971             || anArgCase == "-l"
1972             || anArgCase == "l")
1973       {
1974         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1975       }
1976       else if (anArgCase == "-right"
1977             || anArgCase == "right"
1978             || anArgCase == "-r"
1979             || anArgCase == "r")
1980       {
1981         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1982       }
1983       else if (anArgCase == "-axoleft"
1984             || anArgCase == "-leftaxo"
1985             || anArgCase == "axoleft"
1986             || anArgCase == "leftaxo")
1987       {
1988         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
1989       }
1990       else if (anArgCase == "-axo"
1991             || anArgCase == "axo"
1992             || anArgCase == "-a"
1993             || anArgCase == "a"
1994             || anArgCase == "-axoright"
1995             || anArgCase == "-rightaxo"
1996             || anArgCase == "axoright"
1997             || anArgCase == "rightaxo")
1998       {
1999         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2000       }
2001       else if (anArgCase == "+x")
2002       {
2003         aView->SetProj (V3d_Xpos, isYup);
2004       }
2005       else if (anArgCase == "-x")
2006       {
2007         aView->SetProj (V3d_Xneg, isYup);
2008       }
2009       else if (anArgCase == "+y")
2010       {
2011         aView->SetProj (V3d_Ypos, isYup);
2012       }
2013       else if (anArgCase == "-y")
2014       {
2015         aView->SetProj (V3d_Yneg, isYup);
2016       }
2017       else if (anArgCase == "+z")
2018       {
2019         aView->SetProj (V3d_Zpos, isYup);
2020       }
2021       else if (anArgCase == "-z")
2022       {
2023         aView->SetProj (V3d_Zneg, isYup);
2024       }
2025       else if (anArgCase == "+x+y+z")
2026       {
2027         aView->SetProj (V3d_XposYposZpos, isYup);
2028       }
2029       else if (anArgCase == "+x+y-z")
2030       {
2031         aView->SetProj (V3d_XposYposZneg, isYup);
2032       }
2033       else if (anArgCase == "+x-y+z")
2034       {
2035         aView->SetProj (V3d_XposYnegZpos, isYup);
2036       }
2037       else if (anArgCase == "+x-y-z")
2038       {
2039         aView->SetProj (V3d_XposYnegZneg, isYup);
2040       }
2041       else if (anArgCase == "-x+y+z")
2042       {
2043         aView->SetProj (V3d_XnegYposZpos, isYup);
2044       }
2045       else if (anArgCase == "-x+y-z")
2046       {
2047         aView->SetProj (V3d_XnegYposZneg, isYup);
2048       }
2049       else if (anArgCase == "-x-y+z")
2050       {
2051         aView->SetProj (V3d_XnegYnegZpos, isYup);
2052       }
2053       else if (anArgCase == "-x-y-z")
2054       {
2055         aView->SetProj (V3d_XnegYnegZneg, isYup);
2056       }
2057       else if (anArgCase == "+x+y")
2058       {
2059         aView->SetProj (V3d_XposYpos, isYup);
2060       }
2061       else if (anArgCase == "+x-y")
2062       {
2063         aView->SetProj (V3d_XposYneg, isYup);
2064       }
2065       else if (anArgCase == "-x+y")
2066       {
2067         aView->SetProj (V3d_XnegYpos, isYup);
2068       }
2069       else if (anArgCase == "-x-y")
2070       {
2071         aView->SetProj (V3d_XnegYneg, isYup);
2072       }
2073       else if (anArgCase == "+x+z")
2074       {
2075         aView->SetProj (V3d_XposZpos, isYup);
2076       }
2077       else if (anArgCase == "+x-z")
2078       {
2079         aView->SetProj (V3d_XposZneg, isYup);
2080       }
2081       else if (anArgCase == "-x+z")
2082       {
2083         aView->SetProj (V3d_XnegZpos, isYup);
2084       }
2085       else if (anArgCase == "-x-z")
2086       {
2087         aView->SetProj (V3d_XnegZneg, isYup);
2088       }
2089       else if (anArgCase == "+y+z")
2090       {
2091         aView->SetProj (V3d_YposZpos, isYup);
2092       }
2093       else if (anArgCase == "+y-z")
2094       {
2095         aView->SetProj (V3d_YposZneg, isYup);
2096       }
2097       else if (anArgCase == "-y+z")
2098       {
2099         aView->SetProj (V3d_YnegZpos, isYup);
2100       }
2101       else if (anArgCase == "-y-z")
2102       {
2103         aView->SetProj (V3d_YnegZneg, isYup);
2104       }
2105       else if (anArgIter + 1 < theNbArgs
2106             && anArgCase == "-frame"
2107             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2108       {
2109         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2110         aFrameDef.LowerCase();
2111         gp_Dir aRight, anUp;
2112         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2113         {
2114           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2115           return 1;
2116         }
2117
2118         if (aFrameDef.Value (2) == 'x')
2119         {
2120           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2121         }
2122         else if (aFrameDef.Value (2) == 'y')
2123         {
2124           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2125         }
2126         else if (aFrameDef.Value (2) == 'z')
2127         {
2128           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2129         }
2130         else
2131         {
2132           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2133           return 1;
2134         }
2135
2136         if (aFrameDef.Value (4) == 'x')
2137         {
2138           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2139         }
2140         else if (aFrameDef.Value (4) == 'y')
2141         {
2142           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2143         }
2144         else if (aFrameDef.Value (4) == 'z')
2145         {
2146           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2147         }
2148         else
2149         {
2150           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2151           return 1;
2152         }
2153
2154         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2155         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2156         const gp_Dir aDir = anUp.Crossed (aRight);
2157         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2158         aCamera->SetDirection (aDir);
2159         aCamera->SetUp (anUp);
2160         aCamera->OrthogonalizeUp();
2161
2162         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2163         aView->Update();
2164       }
2165       else
2166       {
2167         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2168         return 1;
2169       }
2170     }
2171   }
2172
2173   if (!isGeneralCmd
2174     && theNbArgs != 1)
2175   {
2176     Message::SendFail ("Syntax error: wrong number of arguments");
2177     return 1;
2178   }
2179   return 0;
2180 }
2181
2182 //==============================================================================
2183 //function : VHelp
2184 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
2185 //Draw arg : No args
2186 //==============================================================================
2187
2188 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
2189 {
2190   di << "=========================\n";
2191   di << "F : FitAll\n";
2192   di << "T : TopView\n";
2193   di << "B : BottomView\n";
2194   di << "R : RightView\n";
2195   di << "L : LeftView\n";
2196   di << "Backspace : AxonometricView\n";
2197
2198   di << "=========================\n";
2199   di << "W, S : Fly   forward/backward\n";
2200   di << "A, D : Slide left/right\n";
2201   di << "Q, E : Bank  left/right\n";
2202   di << "-, + : Change flying speed\n";
2203   di << "Arrows : look left/right/up/down\n";
2204   di << "Arrows+Shift : slide left/right/up/down\n";
2205
2206   di << "=========================\n";
2207   di << "S + Ctrl : Shading\n";
2208   di << "W + Ctrl : Wireframe\n";
2209   di << "H : HiddenLineRemoval\n";
2210   di << "U : Unset display mode\n";
2211   di << "Delete : Remove selection from viewer\n";
2212
2213   di << "=========================\n";
2214   di << "Selection mode \n";
2215   di << "0 : Shape\n";
2216   di << "1 : Vertex\n";
2217   di << "2 : Edge\n";
2218   di << "3 : Wire\n";
2219   di << "4 : Face\n";
2220   di << "5 : Shell\n";
2221   di << "6 : Solid\n";
2222   di << "7 : Compound\n";
2223
2224   di << "=========================\n";
2225   di << "< : Hilight next detected\n";
2226   di << "> : Hilight previous detected\n";
2227
2228   return 0;
2229 }
2230
2231 #ifdef _WIN32
2232
2233 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
2234                                            UINT theMsg,
2235                                            WPARAM wParam,
2236                                            LPARAM lParam )
2237 {
2238   if (ViewerTest_myViews.IsEmpty())
2239   {
2240     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2241   }
2242
2243   switch (theMsg)
2244   {
2245     case WM_CLOSE:
2246     {
2247       // Delete view from map of views
2248       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
2249       return 0;
2250     }
2251     case WM_ACTIVATE:
2252     {
2253       if (LOWORD(wParam) == WA_CLICKACTIVE
2254        || LOWORD(wParam) == WA_ACTIVE
2255        || ViewerTest::CurrentView().IsNull())
2256       {
2257         // Activate inactive window
2258         if (VT_GetWindow().IsNull()
2259          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
2260         {
2261           ActivateView (FindViewIdByWindowHandle (theWinHandle));
2262         }
2263       }
2264       return 0;
2265     }
2266     default:
2267     {
2268       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2269       if (!aView.IsNull()
2270        && !VT_GetWindow().IsNull())
2271       {
2272         MSG aMsg = {};
2273         aMsg.hwnd = theWinHandle;
2274         aMsg.message = theMsg;
2275         aMsg.wParam = wParam;
2276         aMsg.lParam = lParam;
2277         if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg))
2278         {
2279           return 0;
2280         }
2281       }
2282     }
2283   }
2284   return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2285 }
2286
2287 //==============================================================================
2288 //function : ViewerMainLoop
2289 //purpose  : Get a Event on the view and dispatch it
2290 //==============================================================================
2291
2292 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2293 {
2294   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
2295   if (aViewCtrl.IsNull()
2296    || theNbArgs < 4)
2297   {
2298     return 0;
2299   }
2300
2301   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2302
2303   std::cout << "Start picking\n";
2304
2305   MSG aMsg;
2306   aMsg.wParam = 1;
2307   while (aViewCtrl->ToPickPoint())
2308   {
2309     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
2310     if (GetMessageW (&aMsg, NULL, 0, 0))
2311     {
2312       TranslateMessage (&aMsg);
2313       DispatchMessageW (&aMsg);
2314     }
2315   }
2316
2317   std::cout << "Picking done\n";
2318   return 0;
2319 }
2320
2321 #elif defined(HAVE_XLIB)
2322
2323 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2324 {
2325   static XEvent aReport;
2326   const Standard_Boolean toPick = theNbArgs > 0;
2327   if (theNbArgs > 0)
2328   {
2329     if (ViewerTest::CurrentEventManager().IsNull())
2330     {
2331       return 0;
2332     }
2333     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2334   }
2335
2336   Display* aDisplay = (Display* )GetDisplayConnection()->GetDisplayAspect();
2337   XNextEvent (aDisplay, &aReport);
2338
2339   // Handle event for the chosen display connection
2340   switch (aReport.type)
2341   {
2342     case ClientMessage:
2343     {
2344       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
2345       {
2346         // Close the window
2347         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
2348         return toPick ? 0 : 1;
2349       }
2350       break;
2351     }
2352     case FocusIn:
2353     {
2354       // Activate inactive view
2355       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
2356       if (aWindow != aReport.xfocus.window)
2357       {
2358         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
2359       }
2360       break;
2361     }
2362     default:
2363     {
2364       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2365       if (!aView.IsNull()
2366        && !VT_GetWindow().IsNull())
2367       {
2368         VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aReport);
2369       }
2370       break;
2371     }
2372   }
2373   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
2374 }
2375
2376 //==============================================================================
2377 //function : VProcessEvents
2378 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
2379 //==============================================================================
2380 static void VProcessEvents (ClientData theDispX, int)
2381 {
2382   Display* aDispX = (Display* )theDispX;
2383   Handle(Aspect_DisplayConnection) aDispConn;
2384   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
2385        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
2386   {
2387     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
2388     if ((Display* )aDispConnTmp->GetDisplayAspect() == aDispX)
2389     {
2390       aDispConn = aDispConnTmp;
2391       break;
2392     }
2393   }
2394   if (aDispConn.IsNull())
2395   {
2396     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
2397     return;
2398   }
2399
2400   // process new events in queue
2401   SetDisplayConnection (aDispConn);
2402   int aNbRemain = 0;
2403   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
2404   {
2405     const int anEventResult = ViewerMainLoop (0, NULL);
2406     if (anEventResult == 0)
2407     {
2408       return;
2409     }
2410
2411     aNbRemain = XPending (aDispX);
2412     if (++anEventIter >= aNbEventsMax
2413      || aNbRemain <= 0)
2414     {
2415       break;
2416     }
2417   }
2418
2419   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
2420   // it is possible that new events will arrive to queue before the end of this callback
2421   // so that either this callback should go into an infinite loop (blocking processing of other events)
2422   // or to keep unprocessed events till the next queue update (which can arrive not soon).
2423   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
2424   if (aNbRemain != 0)
2425   {
2426     XEvent aDummyEvent;
2427     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
2428     aDummyEvent.type = ClientMessage;
2429     aDummyEvent.xclient.format = 32;
2430     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
2431     XFlush (aDispX);
2432   }
2433
2434   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
2435   {
2436     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
2437   }
2438 }
2439 #elif !defined(__APPLE__)
2440 // =======================================================================
2441 // function : ViewerMainLoop
2442 // purpose  :
2443 // =======================================================================
2444 int ViewerMainLoop (Standard_Integer , const char** )
2445 {
2446   // unused
2447   return 0;
2448 }
2449 #endif
2450
2451 //==============================================================================
2452 //function : VFit
2453 //purpose  :
2454 //==============================================================================
2455
2456 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
2457 {
2458   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2459   if (aView.IsNull())
2460   {
2461     Message::SendFail ("Error: no active viewer");
2462     return 1;
2463   }
2464
2465   Standard_Boolean toFit = Standard_True;
2466   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2467   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2468   {
2469     TCollection_AsciiString anArg (theArgv[anArgIter]);
2470     anArg.LowerCase();
2471     if (anUpdateTool.parseRedrawMode (anArg))
2472     {
2473       continue;
2474     }
2475     else if (anArg == "-selected")
2476     {
2477       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
2478       toFit = Standard_False;
2479     }
2480     else
2481     {
2482       Message::SendFail() << "Syntax error at '" << anArg << "'";
2483     }
2484   }
2485
2486   if (toFit)
2487   {
2488     aView->FitAll (0.01, Standard_False);
2489   }
2490   return 0;
2491 }
2492
2493 //=======================================================================
2494 //function : VFitArea
2495 //purpose  : Fit view to show area located between two points
2496 //         : given in world 2D or 3D coordinates.
2497 //=======================================================================
2498 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
2499 {
2500   Handle(V3d_View) aView = ViewerTest::CurrentView();
2501   if (aView.IsNull())
2502   {
2503     Message::SendFail ("Error: No active viewer");
2504     return 1;
2505   }
2506
2507   // Parse arguments.
2508   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
2509   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
2510
2511   if (theArgNb == 5)
2512   {
2513     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2514     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2515     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
2516     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
2517   }
2518   else if (theArgNb == 7)
2519   {
2520     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2521     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2522     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
2523     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
2524     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
2525     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
2526   }
2527   else
2528   {
2529     Message::SendFail ("Syntax error: Invalid number of arguments");
2530     theDI.PrintHelp(theArgVec[0]);
2531     return 1;
2532   }
2533
2534   // Convert model coordinates to view space
2535   Handle(Graphic3d_Camera) aCamera = aView->Camera();
2536   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
2537   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
2538
2539   // Determine fit area
2540   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
2541   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
2542
2543   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
2544
2545   if (aDiagonal < Precision::Confusion())
2546   {
2547     Message::SendFail ("Error: view area is too small");
2548     return 1;
2549   }
2550
2551   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
2552   return 0;
2553 }
2554
2555 //==============================================================================
2556 //function : VZFit
2557 //purpose  : ZFitall, no DRAW arguments
2558 //Draw arg : No args
2559 //==============================================================================
2560 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
2561 {
2562   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
2563
2564   if (aCurrentView.IsNull())
2565   {
2566     Message::SendFail ("Error: no active viewer");
2567     return 1;
2568   }
2569
2570   if (theArgsNb == 1)
2571   {
2572     aCurrentView->ZFitAll();
2573     aCurrentView->Redraw();
2574     return 0;
2575   }
2576
2577   Standard_Real aScale = 1.0;
2578
2579   if (theArgsNb >= 2)
2580   {
2581     aScale = Draw::Atoi (theArgVec[1]);
2582   }
2583
2584   aCurrentView->ZFitAll (aScale);
2585   aCurrentView->Redraw();
2586
2587   return 0;
2588 }
2589
2590 //==============================================================================
2591 //function : VRepaint
2592 //purpose  :
2593 //==============================================================================
2594 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
2595 {
2596   Handle(V3d_View) aView = ViewerTest::CurrentView();
2597   if (aView.IsNull())
2598   {
2599     Message::SendFail ("Error: no active viewer");
2600     return 1;
2601   }
2602
2603   Standard_Boolean isImmediateUpdate = Standard_False;
2604   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2605   {
2606     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2607     anArg.LowerCase();
2608     if (anArg == "-immediate"
2609      || anArg == "-imm")
2610     {
2611       isImmediateUpdate = Standard_True;
2612       if (anArgIter + 1 < theArgNb
2613        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
2614       {
2615         ++anArgIter;
2616       }
2617     }
2618     else if (anArg == "-continuous"
2619           || anArg == "-cont"
2620           || anArg == "-fps"
2621           || anArg == "-framerate")
2622     {
2623       Standard_Real aFps = -1.0;
2624       if (anArgIter + 1 < theArgNb
2625        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
2626       {
2627         aFps = Draw::Atof (theArgVec[++anArgIter]);
2628       }
2629
2630       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2631       ViewerTest::CurrentEventManager()->SetContinuousRedraw (false);
2632       if (aFps >= 1.0)
2633       {
2634         aRedrawer.Start (aView, aFps);
2635       }
2636       else if (aFps < 0.0)
2637       {
2638         if (ViewerTest::GetViewerFromContext()->ActiveViews().Extent() == 1)
2639         {
2640           aRedrawer.Stop();
2641           ViewerTest::CurrentEventManager()->SetContinuousRedraw (true);
2642           ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
2643           continue;
2644         }
2645         aRedrawer.Start (aView, aFps);
2646       }
2647       else
2648       {
2649         aRedrawer.Stop();
2650       }
2651     }
2652     else
2653     {
2654       Message::SendFail() << "Syntax error at '" << anArg << "'";
2655       return 1;
2656     }
2657   }
2658
2659   if (isImmediateUpdate)
2660   {
2661     aView->RedrawImmediate();
2662   }
2663   else
2664   {
2665     aView->Redraw();
2666   }
2667   return 0;
2668 }
2669
2670 //==============================================================================
2671 //function : VClear
2672 //purpose  : Remove all the object from the viewer
2673 //Draw arg : No args
2674 //==============================================================================
2675
2676 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
2677 {
2678   Handle(V3d_View) V = ViewerTest::CurrentView();
2679   if(!V.IsNull())
2680     ViewerTest::Clear();
2681   return 0;
2682 }
2683
2684 //==============================================================================
2685 //function : VPick
2686 //purpose  :
2687 //==============================================================================
2688
2689 static int VPick (Draw_Interpretor& ,
2690                   Standard_Integer theNbArgs,
2691                   const char** theArgVec)
2692 {
2693   if (ViewerTest::CurrentView().IsNull())
2694   {
2695     return 1;
2696   }
2697
2698   if (theNbArgs < 4)
2699   {
2700     Message::SendFail ("Syntax error: wrong number of arguments");
2701     return 1;
2702   }
2703
2704   while (ViewerMainLoop (theNbArgs, theArgVec))
2705   {
2706     //
2707   }
2708
2709   return 0;
2710 }
2711
2712 //! Parse image fill method.
2713 static bool parseImageMode (const TCollection_AsciiString& theName,
2714                             Aspect_FillMethod& theMode)
2715 {
2716   TCollection_AsciiString aName = theName;
2717   aName.LowerCase();
2718   if (aName == "none")
2719   {
2720     theMode = Aspect_FM_NONE;
2721   }
2722   else if (aName == "centered")
2723   {
2724     theMode = Aspect_FM_CENTERED;
2725   }
2726   else if (aName == "tiled")
2727   {
2728     theMode = Aspect_FM_TILED;
2729   }
2730   else if (aName == "stretch")
2731   {
2732     theMode = Aspect_FM_STRETCH;
2733   }
2734   else
2735   {
2736     return false;
2737   }
2738   return true;
2739 }
2740
2741 //! Parse gradient fill method.
2742 static bool parseGradientMode (const TCollection_AsciiString& theName,
2743                                Aspect_GradientFillMethod& theMode)
2744 {
2745   TCollection_AsciiString aName = theName;
2746   aName.LowerCase();
2747   if (aName == "none")
2748   {
2749     theMode = Aspect_GradientFillMethod_None;
2750   }
2751   else if (aName == "hor"
2752         || aName == "horizontal")
2753   {
2754     theMode = Aspect_GradientFillMethod_Horizontal;
2755   }
2756   else if (aName == "ver"
2757         || aName == "vert"
2758         || aName == "vertical")
2759   {
2760     theMode = Aspect_GradientFillMethod_Vertical;
2761   }
2762   else if (aName == "diag"
2763         || aName == "diagonal"
2764         || aName == "diag1"
2765         || aName == "diagonal1")
2766   {
2767     theMode = Aspect_GradientFillMethod_Diagonal1;
2768   }
2769   else if (aName == "diag2"
2770         || aName == "diagonal2")
2771   {
2772     theMode = Aspect_GradientFillMethod_Diagonal2;
2773   }
2774   else if (aName == "corner1")
2775   {
2776     theMode = Aspect_GradientFillMethod_Corner1;
2777   }
2778   else if (aName == "corner2")
2779   {
2780     theMode = Aspect_GradientFillMethod_Corner2;
2781   }
2782   else if (aName == "corner3")
2783   {
2784     theMode = Aspect_GradientFillMethod_Corner3;
2785   }
2786   else if (aName == "corner4")
2787   {
2788     theMode = Aspect_GradientFillMethod_Corner4;
2789   }
2790   else if (aName == "ellip"
2791         || aName == "elliptical")
2792   {
2793     theMode = Aspect_GradientFillMethod_Elliptical;
2794   }
2795   else
2796   {
2797     return false;
2798   }
2799   return true;
2800 }
2801
2802 //==============================================================================
2803 //function : VBackground
2804 //purpose  :
2805 //==============================================================================
2806 static int VBackground (Draw_Interpretor& theDI,
2807                         Standard_Integer  theNbArgs,
2808                         const char**      theArgVec)
2809 {
2810   if (theNbArgs < 2)
2811   {
2812     theDI << "Syntax error: wrong number of arguments";
2813     return 1;
2814   }
2815
2816   const TCollection_AsciiString aCmdName (theArgVec[0]);
2817   bool isDefault = aCmdName == "vsetdefaultbg";
2818   Standard_Integer aNbColors = 0;
2819   Quantity_ColorRGBA aColors[2];
2820
2821   Aspect_GradientFillMethod aGradientMode = Aspect_GradientFillMethod_None;
2822   bool hasGradientMode = false;
2823
2824   TCollection_AsciiString anImagePath;
2825   Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
2826   bool hasImageMode = false;
2827
2828   bool isSkydomeBg = false;
2829   Aspect_SkydomeBackground aSkydomeAspect;
2830
2831   NCollection_Sequence<TCollection_AsciiString> aCubeMapSeq;
2832   Graphic3d_CubeMapOrder aCubeOrder = Graphic3d_CubeMapOrder::Default();
2833   bool isCubeZInverted = false;
2834   bool isSRgb = true;
2835
2836   int toUseIBL = 1;
2837
2838   Handle(V3d_View) aView = ViewerTest::CurrentView();
2839   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
2840   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2841   {
2842     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2843     anArg.LowerCase();
2844     if (anUpdateTool.parseRedrawMode (anArg))
2845     {
2846       continue;
2847     }
2848     else if (anArg == "-default"
2849           || anArg == "-def")
2850     {
2851       isDefault = true;
2852     }
2853     else if (anArgIter + 1 < theNbArgs
2854           && (anArg == "-imagefile"
2855            || anArg == "-imgfile"
2856            || anArg == "-image"
2857            || anArg == "-img"))
2858     {
2859       anImagePath = theArgVec[++anArgIter];
2860     }
2861     else if (anArg == "-skydome"
2862           || anArg == "-sky")
2863     {
2864       isSkydomeBg = true;
2865     }
2866     else if (anArgIter + 3 < theNbArgs
2867           && isSkydomeBg
2868           && anArg == "-sundir")
2869     {
2870       float aX = (float) Draw::Atof (theArgVec[++anArgIter]);
2871       float aY = (float) Draw::Atof (theArgVec[++anArgIter]);
2872       float aZ = (float) Draw::Atof (theArgVec[++anArgIter]);
2873       aSkydomeAspect.SetSunDirection (gp_Dir(aX, aY, aZ));
2874     }
2875     else if (anArgIter + 1 < theNbArgs
2876           && isSkydomeBg
2877           && anArg == "-cloud")
2878     {
2879       float aCloudy = (float) Draw::Atof (theArgVec[++anArgIter]);
2880       aSkydomeAspect.SetCloudiness (aCloudy);
2881     }
2882     else if (anArgIter + 1 < theNbArgs
2883           && isSkydomeBg
2884           && anArg == "-time")
2885     {
2886       float aTime = (float) Draw::Atof (theArgVec[++anArgIter]);
2887       aSkydomeAspect.SetTimeParameter (aTime);
2888     }
2889     else if (anArgIter + 1 < theNbArgs
2890           && isSkydomeBg
2891           && anArg == "-fog")
2892     {
2893       float aFoggy = (float) Draw::Atof (theArgVec[++anArgIter]);
2894       aSkydomeAspect.SetFogginess (aFoggy);
2895     }
2896     else if (anArgIter + 1 < theNbArgs
2897           && isSkydomeBg
2898           && anArg == "-size")
2899     {
2900       Standard_Integer aSize = Draw::Atoi (theArgVec[++anArgIter]);
2901       aSkydomeAspect.SetSize (aSize);
2902     }
2903     else if (anArgIter + 1 < theNbArgs
2904           && aCubeMapSeq.IsEmpty()
2905           && (anArg == "-cubemap"
2906            || anArg == "-cmap"
2907            || anArg == "-cm"))
2908     {
2909       aCubeMapSeq.Append (theArgVec[++anArgIter]);
2910       for (Standard_Integer aCubeSideIter = 1; anArgIter + aCubeSideIter < theNbArgs; ++aCubeSideIter)
2911       {
2912         TCollection_AsciiString aSideArg (theArgVec[anArgIter + aCubeSideIter]);
2913         if (!aSideArg.IsEmpty()
2914           && aSideArg.Value (1) == '-')
2915         {
2916           break;
2917         }
2918
2919         aCubeMapSeq.Append (aSideArg);
2920         if (aCubeMapSeq.Size() == 6)
2921         {
2922           anArgIter += 5;
2923           break;
2924         }
2925       }
2926
2927       if (aCubeMapSeq.Size() > 1
2928        && aCubeMapSeq.Size() < 6)
2929       {
2930         aCubeMapSeq.Remove (2, aCubeMapSeq.Size());
2931       }
2932     }
2933     else if (anArgIter + 6 < theNbArgs
2934           && anArg == "-order")
2935     {
2936       for (Standard_Integer aCubeSideIter = 0; aCubeSideIter < 6; ++aCubeSideIter)
2937       {
2938         Standard_Integer aSideArg = 0;
2939         if (!Draw::ParseInteger (theArgVec[anArgIter + aCubeSideIter + 1], aSideArg)
2940          || aSideArg < 0
2941          || aSideArg > 5)
2942         {
2943           theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2944           return 1;
2945         }
2946         aCubeOrder.Set ((Graphic3d_CubeMapSide )aCubeSideIter, (unsigned char )aSideArg);
2947       }
2948       if (!aCubeOrder.IsValid())
2949       {
2950         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2951         return 1;
2952       }
2953       anArgIter += 6;
2954     }
2955     else if (anArg == "-invertedz"
2956           || anArg == "-noinvertedz"
2957           || anArg == "-invz"
2958           || anArg == "-noinvz")
2959     {
2960       isCubeZInverted = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2961     }
2962     else if (anArg == "-pbrenv"
2963           || anArg == "-nopbrenv"
2964           || anArg == "-ibl"
2965           || anArg == "-noibl")
2966     {
2967       toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2968       if (anArgIter + 1 < theNbArgs)
2969       {
2970         TCollection_AsciiString anIblArg (theArgVec[anArgIter + 1]);
2971         anIblArg.LowerCase();
2972         if (anIblArg == "keep"
2973          || anIblArg == "-1")
2974         {
2975           toUseIBL = -1;
2976           ++anArgIter;
2977         }
2978         else if (anIblArg == "ibl"
2979               || anIblArg == "1"
2980               || anIblArg == "on")
2981         {
2982           toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2983           ++anArgIter;
2984         }
2985         else if (anIblArg == "noibl"
2986               || anIblArg == "0"
2987               || anIblArg == "off")
2988         {
2989           toUseIBL = !anArg.StartsWith ("-no") ? 0 : 1;
2990           ++anArgIter;
2991         }
2992       }
2993     }
2994     else if (anArg == "-srgb"
2995           || anArg == "-nosrgb")
2996     {
2997       isSRgb = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2998     }
2999     else if (aNbColors < 2
3000           && (anArg == "-color"
3001            || anArg == "-col"))
3002     {
3003       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - (anArgIter + 1),
3004                                                      theArgVec + (anArgIter + 1),
3005                                                      aColors[aNbColors].ChangeRGB());
3006       if (aNbParsed == 0)
3007       {
3008         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3009         return 1;
3010       }
3011       anArgIter += aNbParsed;
3012       ++aNbColors;
3013     }
3014     else if (anArgIter + 1 < theNbArgs
3015           && (anArg == "-gradientmode"
3016            || anArg == "-gradmode"
3017            || anArg == "-gradmd"
3018            || anArg == "-grmode"
3019            || anArg == "-grmd")
3020           && parseGradientMode (theArgVec[anArgIter + 1], aGradientMode))
3021     {
3022       ++anArgIter;
3023       hasGradientMode = true;
3024     }
3025     else if (anArgIter + 1 < theNbArgs
3026           && (anArg == "-imagemode"
3027            || anArg == "-imgmode"
3028            || anArg == "-imagemd"
3029            || anArg == "-imgmd")
3030           && parseImageMode (theArgVec[anArgIter + 1], anImageMode))
3031     {
3032       ++anArgIter;
3033       hasImageMode = true;
3034     }
3035     else if (aNbColors == 0
3036           && anArgIter + 2 < theNbArgs
3037           && (anArg == "-gradient"
3038            || anArg == "-grad"
3039            || anArg == "-gr"))
3040     {
3041       Standard_Integer aNbParsed1 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
3042                                                       theArgVec + (anArgIter + 1),
3043                                                       aColors[aNbColors].ChangeRGB());
3044       anArgIter += aNbParsed1;
3045       ++aNbColors;
3046       if (aNbParsed1 == 0)
3047       {
3048         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3049         return 1;
3050       }
3051       Standard_Integer aNbParsed2 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
3052                                                       theArgVec + (anArgIter + 1),
3053                                                       aColors[aNbColors].ChangeRGB());
3054       anArgIter += aNbParsed2;
3055       ++aNbColors;
3056       if (aNbParsed2 == 0)
3057       {
3058         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3059         return 1;
3060       }
3061     }
3062     else if (parseGradientMode (theArgVec[anArgIter], aGradientMode))
3063     {
3064       hasGradientMode = true;
3065     }
3066     else if (aNbColors < 2
3067           && (Quantity_ColorRGBA::ColorFromName(theArgVec[anArgIter], aColors[aNbColors])
3068            || Quantity_ColorRGBA::ColorFromHex (theArgVec[anArgIter], aColors[aNbColors])))
3069     {
3070       ++aNbColors;
3071     }
3072     else if (anImagePath.IsEmpty()
3073          &&  aNbColors == 0
3074          && !hasGradientMode
3075          &&  aCubeMapSeq.IsEmpty())
3076     {
3077       anImagePath = theArgVec[anArgIter];
3078     }
3079     else
3080     {
3081       theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
3082       return 1;
3083     }
3084   }
3085
3086   if (!isDefault
3087    && aView.IsNull())
3088   {
3089     theDI << "Error: no active viewer";
3090     return 1;
3091   }
3092   else if (isDefault
3093        &&  aNbColors == 0
3094        && !hasGradientMode)
3095   {
3096     theDI << "Syntax error at '-default'";
3097     return 1;
3098   }
3099
3100   if (aNbColors == 1)
3101   {
3102     if (isDefault)
3103     {
3104       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
3105       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
3106       ViewerTest_DefaultBackground.FillMethod     = Aspect_GradientFillMethod_None;
3107       ViewerTest_DefaultBackground.FlatColor      = aColors[0].GetRGB();
3108       ViewerTest_DefaultBackground.SetDefaultGradient();
3109       ViewerTest_DefaultBackground.SetDefaultColor();
3110     }
3111     else
3112     {
3113       aView->SetBgGradientStyle (hasGradientMode ? aGradientMode : Aspect_GradientFillMethod_None);
3114       aView->SetBackgroundColor (aColors[0].GetRGB());
3115       if (toUseIBL != -1)
3116       {
3117         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
3118       }
3119     }
3120   }
3121   else if (aNbColors == 2)
3122   {
3123     if (isDefault)
3124     {
3125       ViewerTest_DefaultBackground.GradientColor1 = aColors[0].GetRGB();
3126       ViewerTest_DefaultBackground.GradientColor2 = aColors[1].GetRGB();
3127       if (hasGradientMode)
3128       {
3129         ViewerTest_DefaultBackground.FillMethod = aGradientMode;
3130       }
3131       else if (ViewerTest_DefaultBackground.FillMethod == Aspect_GradientFillMethod_None)
3132       {
3133         ViewerTest_DefaultBackground.FillMethod = Aspect_GradientFillMethod_Vertical;
3134       }
3135       ViewerTest_DefaultBackground.SetDefaultGradient();
3136     }
3137     else
3138     {
3139       if (!hasGradientMode)
3140       {
3141         aGradientMode = aView->GradientBackground().BgGradientFillMethod();
3142         if (aGradientMode == Aspect_GradientFillMethod_None)
3143         {
3144           aGradientMode = Aspect_GradientFillMethod_Vertical;
3145         }
3146       }
3147       aView->SetBgGradientColors (aColors[0].GetRGB(), aColors[1].GetRGB(), aGradientMode);
3148       if (toUseIBL != -1)
3149       {
3150         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
3151       }
3152     }
3153   }
3154   else if (hasGradientMode)
3155   {
3156     if (isDefault)
3157     {
3158       ViewerTest_DefaultBackground.FillMethod = aGradientMode;
3159       ViewerTest_DefaultBackground.SetDefaultGradient();
3160     }
3161     else
3162     {
3163       aView->SetBgGradientStyle (aGradientMode);
3164     }
3165   }
3166
3167   if (!anImagePath.IsEmpty())
3168   {
3169     Handle(Graphic3d_Texture2D) aTextureMap = new Graphic3d_Texture2D (anImagePath);
3170     aTextureMap->DisableModulate();
3171     aTextureMap->SetColorMap (isSRgb);
3172     if (!aTextureMap->IsDone())
3173     {
3174       theDI << "Syntax error at '" << anImagePath << "'";
3175       return 1;
3176     }
3177     aView->SetBackgroundImage (aTextureMap, anImageMode);
3178   }
3179   else if (hasImageMode)
3180   {
3181     aView->SetBgImageStyle (anImageMode);
3182   }
3183
3184   if (isSkydomeBg)
3185   {
3186     aView->SetBackgroundSkydome (aSkydomeAspect, toUseIBL != -1);
3187   }
3188
3189   if (!aCubeMapSeq.IsEmpty())
3190   {
3191     Handle(Graphic3d_CubeMap) aCubeMap;
3192     if (aCubeMapSeq.Size() == 1)
3193     {
3194       aCubeMap = new Graphic3d_CubeMapPacked (aCubeMapSeq.First(), aCubeOrder.Validated());
3195     }
3196     else
3197     {
3198       NCollection_Array1<TCollection_AsciiString> aCubeMapArr (0, 5);
3199       Standard_Integer aCubeSide = 0;
3200       for (NCollection_Sequence<TCollection_AsciiString>::Iterator aFileIter (aCubeMapSeq); aFileIter.More(); aFileIter.Next(), ++aCubeSide)
3201       {
3202         aCubeMapArr[aCubeSide] = aFileIter.Value();
3203       }
3204       aCubeMap = new Graphic3d_CubeMapSeparate (aCubeMapArr);
3205     }
3206
3207     aCubeMap->SetZInversion (isCubeZInverted);
3208     aCubeMap->SetColorMap (isSRgb);
3209
3210     aCubeMap->GetParams()->SetFilter (Graphic3d_TOTF_BILINEAR);
3211     aCubeMap->GetParams()->SetRepeat (false);
3212     aCubeMap->GetParams()->SetTextureUnit (Graphic3d_TextureUnit_EnvMap);
3213
3214     aView->SetBackgroundCubeMap (aCubeMap, toUseIBL != -1);
3215   }
3216   if (toUseIBL != -1
3217   && !aView.IsNull())
3218   {
3219     aView->SetImageBasedLighting (toUseIBL == 1);
3220   }
3221
3222   return 0;
3223 }
3224
3225 //==============================================================================
3226 //function : VScale
3227 //purpose  : View Scaling
3228 //==============================================================================
3229
3230 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3231 {
3232   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3233   if ( V3dView.IsNull() ) return 1;
3234
3235   if ( argc != 4 ) {
3236     di << argv[0] << "Invalid number of arguments\n";
3237     return 1;
3238   }
3239   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3240   return 0;
3241 }
3242 //==============================================================================
3243 //function : VZBuffTrihedron
3244 //purpose  :
3245 //==============================================================================
3246
3247 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3248                             Standard_Integer  theArgNb,
3249                             const char**      theArgVec)
3250 {
3251   Handle(V3d_View) aView = ViewerTest::CurrentView();
3252   if (aView.IsNull())
3253   {
3254     Message::SendFail ("Error: no active viewer");
3255     return 1;
3256   }
3257
3258   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3259
3260   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3261   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3262   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
3263   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
3264   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
3265   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3266   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3267   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3268   Standard_Real                 aScale        = 0.1;
3269   Standard_Real                 aSizeRatio    = 0.8;
3270   Standard_Real                 anArrowDiam   = 0.05;
3271   Standard_Integer              aNbFacets     = 12;
3272   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3273   {
3274     Standard_CString        anArg = theArgVec[anArgIter];
3275     TCollection_AsciiString aFlag (anArg);
3276     aFlag.LowerCase();
3277     if (anUpdateTool.parseRedrawMode (aFlag))
3278     {
3279       continue;
3280     }
3281     else if (aFlag == "-on")
3282     {
3283       continue;
3284     }
3285     else if (aFlag == "-off")
3286     {
3287       aView->TriedronErase();
3288       return 0;
3289     }
3290     else if (aFlag == "-pos"
3291           || aFlag == "-position"
3292           || aFlag == "-corner")
3293     {
3294       if (++anArgIter >= theArgNb)
3295       {
3296         Message::SendFail() << "Syntax error at '" << anArg << "'";
3297         return 1;
3298       }
3299
3300       if (!ViewerTest::ParseCorner (theArgVec[anArgIter], aPosition))
3301       {
3302         Message::SendFail() << "Syntax error at '" << anArg << "' - unknown position '" << theArgVec[anArgIter] << "'";
3303         return 1;
3304       }
3305     }
3306     else if (aFlag == "-type")
3307     {
3308       if (++anArgIter >= theArgNb)
3309       {
3310         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3311         return 1;
3312       }
3313
3314       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
3315       aTypeName.LowerCase();
3316       if (aTypeName == "wireframe"
3317        || aTypeName == "wire")
3318       {
3319         aVisType = V3d_WIREFRAME;
3320       }
3321       else if (aTypeName == "zbuffer"
3322             || aTypeName == "shaded")
3323       {
3324         aVisType = V3d_ZBUFFER;
3325       }
3326       else
3327       {
3328         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
3329       }
3330     }
3331     else if (aFlag == "-scale")
3332     {
3333       if (++anArgIter >= theArgNb)
3334       {
3335         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3336         return 1;
3337       }
3338
3339       aScale = Draw::Atof (theArgVec[anArgIter]);
3340     }
3341     else if (aFlag == "-size"
3342           || aFlag == "-sizeratio")
3343     {
3344       if (++anArgIter >= theArgNb)
3345       {
3346         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3347         return 1;
3348       }
3349
3350       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
3351     }
3352     else if (aFlag == "-arrowdiam"
3353           || aFlag == "-arrowdiameter")
3354     {
3355       if (++anArgIter >= theArgNb)
3356       {
3357         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3358         return 1;
3359       }
3360
3361       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
3362     }
3363     else if (aFlag == "-nbfacets")
3364     {
3365       if (++anArgIter >= theArgNb)
3366       {
3367         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3368         return 1;
3369       }
3370
3371       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
3372     }
3373     else if (aFlag == "-colorlabel"
3374           || aFlag == "-colorlabels"
3375           || aFlag == "-colorlabelx"
3376           || aFlag == "-colorlabely"
3377           || aFlag == "-colorlabelz"
3378           || aFlag == "-colorarrowx"
3379           || aFlag == "-colorarrowy"
3380           || aFlag == "-colorarrowz")
3381     {
3382       Quantity_Color aColor;
3383       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
3384                                                      theArgVec + anArgIter + 1,
3385                                                      aColor);
3386       if (aNbParsed == 0)
3387       {
3388         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3389         return 1;
3390       }
3391
3392       if (aFlag == "-colorarrowx")
3393       {
3394         anArrowColorX = aColor;
3395       }
3396       else if (aFlag == "-colorarrowy")
3397       {
3398         anArrowColorY = aColor;
3399       }
3400       else if (aFlag == "-colorarrowz")
3401       {
3402         anArrowColorZ = aColor;
3403       }
3404       else if (aFlag == "-colorlabelx")
3405       {
3406         aLabelsColorX = aColor;
3407       }
3408       else if (aFlag == "-colorlabely")
3409       {
3410         aLabelsColorY = aColor;
3411       }
3412       else if (aFlag == "-colorlabelz")
3413       {
3414         aLabelsColorZ = aColor;
3415       }
3416       else
3417       {
3418         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
3419       }
3420       anArgIter += aNbParsed;
3421     }
3422     else
3423     {
3424       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3425       return 1;
3426     }
3427   }
3428
3429   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
3430   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
3431   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
3432   aTrihedron->SetSizeRatio    (aSizeRatio);
3433   aTrihedron->SetNbFacets     (aNbFacets);
3434   aTrihedron->SetArrowDiameter(anArrowDiam);
3435   aTrihedron->SetScale        (aScale);
3436   aTrihedron->SetPosition     (aPosition);
3437   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
3438   aTrihedron->Display (aView);
3439
3440   aView->ZFitAll();
3441   return 0;
3442 }
3443
3444 //==============================================================================
3445 //function : VRotate
3446 //purpose  : Camera Rotating
3447 //==============================================================================
3448
3449 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
3450 {
3451   Handle(V3d_View) aView = ViewerTest::CurrentView();
3452   if (aView.IsNull())
3453   {
3454     Message::SendFail ("Error: no active viewer");
3455     return 1;
3456   }
3457
3458   Standard_Boolean hasFlags = Standard_False;
3459   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3460   {
3461     Standard_CString        anArg (theArgVec[anArgIter]);
3462     TCollection_AsciiString aFlag (anArg);
3463     aFlag.LowerCase();
3464     if (aFlag == "-mousestart"
3465      || aFlag == "-mousefrom")
3466     {
3467       hasFlags = Standard_True;
3468       if (anArgIter + 2 >= theArgNb)
3469       {
3470         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3471         return 1;
3472       }
3473
3474       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3475       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3476       aView->StartRotation (anX, anY);
3477     }
3478     else if (aFlag == "-mousemove")
3479     {
3480       hasFlags = Standard_True;
3481       if (anArgIter + 2 >= theArgNb)
3482       {
3483         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3484         return 1;
3485       }
3486
3487       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3488       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3489       aView->Rotation (anX, anY);
3490     }
3491     else if (theArgNb != 4
3492           && theArgNb != 7)
3493     {
3494       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3495       return 1;
3496     }
3497   }
3498
3499   if (hasFlags)
3500   {
3501     return 0;
3502   }
3503   else if (theArgNb == 4)
3504   {
3505     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3506     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3507     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3508     aView->Rotate (anAX, anAY, anAZ);
3509     return 0;
3510   }
3511   else if (theArgNb == 7)
3512   {
3513     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3514     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3515     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3516
3517     Standard_Real anX = Draw::Atof (theArgVec[4]);
3518     Standard_Real anY = Draw::Atof (theArgVec[5]);
3519     Standard_Real anZ = Draw::Atof (theArgVec[6]);
3520
3521     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
3522     return 0;
3523   }
3524
3525   Message::SendFail ("Error: Invalid number of arguments");
3526   return 1;
3527 }
3528
3529 //==============================================================================
3530 //function : VZoom
3531 //purpose  : View zoom in / out (relative to current zoom)
3532 //==============================================================================
3533
3534 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3535   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3536   if ( V3dView.IsNull() ) {
3537     return 1;
3538   }
3539
3540   if ( argc == 2 ) {
3541     Standard_Real coef = Draw::Atof(argv[1]);
3542     if ( coef <= 0.0 ) {
3543       di << argv[1] << "Invalid value\n";
3544       return 1;
3545     }
3546     V3dView->SetZoom( Draw::Atof(argv[1]) );
3547     return 0;
3548   } else {
3549     di << argv[0] << " Invalid number of arguments\n";
3550     return 1;
3551   }
3552 }
3553
3554 //==============================================================================
3555 //function : VPan
3556 //purpose  : View panning (in pixels)
3557 //==============================================================================
3558
3559 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3560   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3561   if ( V3dView.IsNull() ) return 1;
3562
3563   if ( argc == 3 ) {
3564     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
3565     return 0;
3566   } else {
3567     di << argv[0] << " Invalid number of arguments\n";
3568     return 1;
3569   }
3570 }
3571
3572 //==============================================================================
3573 //function : VPlace
3574 //purpose  : Place the point (in pixels) at the center of the window
3575 //==============================================================================
3576 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
3577 {
3578   Handle(V3d_View) aView = ViewerTest::CurrentView();
3579   if (aView.IsNull())
3580   {
3581     Message::SendFail ("Error: no active viewer");
3582     return 1;
3583   }
3584
3585   if (theArgNb != 3)
3586   {
3587     Message::SendFail ("Syntax error: wrong number of arguments");
3588     return 1;
3589   }
3590
3591   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
3592
3593   return 0;
3594 }
3595
3596 static int VColorScale (Draw_Interpretor& theDI,
3597                         Standard_Integer  theArgNb,
3598                         const char**      theArgVec)
3599 {
3600   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
3601   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
3602   if (aContext.IsNull())
3603   {
3604     Message::SendFail ("Error: no active viewer");
3605     return 1;
3606   }
3607   if (theArgNb <= 1)
3608   {
3609     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
3610     return 1;
3611   }
3612
3613   Handle(AIS_ColorScale) aColorScale;
3614   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
3615   {
3616     // find existing object
3617     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
3618     if (aColorScale.IsNull())
3619     {
3620       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
3621       return 1;
3622     }
3623   }
3624
3625   if (theArgNb <= 2)
3626   {
3627     if (aColorScale.IsNull())
3628     {
3629       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
3630       return 1;
3631     }
3632
3633     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
3634           << "Min range: "            << aColorScale->GetMin() << "\n"
3635           << "Max range: "            << aColorScale->GetMax() << "\n"
3636           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
3637           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
3638           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
3639           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
3640           << "Label position: ";
3641     switch (aColorScale->GetLabelPosition())
3642     {
3643       case Aspect_TOCSP_NONE:
3644         theDI << "None\n";
3645         break;
3646       case Aspect_TOCSP_LEFT:
3647         theDI << "Left\n";
3648         break;
3649       case Aspect_TOCSP_RIGHT:
3650         theDI << "Right\n";
3651         break;
3652       case Aspect_TOCSP_CENTER:
3653         theDI << "Center\n";
3654         break;
3655     }
3656     return 0;
3657   }
3658
3659   if (aColorScale.IsNull())
3660   {
3661     aColorScale = new AIS_ColorScale();
3662     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
3663     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
3664   }
3665
3666   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
3667   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
3668   {
3669     Standard_CString        anArg = theArgVec[anArgIter];
3670     TCollection_AsciiString aFlag (anArg);
3671     aFlag.LowerCase();
3672     if (anUpdateTool.parseRedrawMode (aFlag))
3673     {
3674       continue;
3675     }
3676     else if (aFlag == "-range")
3677     {
3678       if (anArgIter + 3 >= theArgNb)
3679       {
3680         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
3681         return 1;
3682       }
3683
3684       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
3685       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
3686       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
3687       if (!aRangeMin.IsRealValue (Standard_True)
3688        || !aRangeMax.IsRealValue (Standard_True))
3689       {
3690         Message::SendFail ("Syntax error: the range values should be real");
3691         return 1;
3692       }
3693       else if (!aNbIntervals.IsIntegerValue())
3694       {
3695         Message::SendFail ("Syntax error: the number of intervals should be integer");
3696         return 1;
3697       }
3698
3699       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
3700       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
3701     }
3702     else if (aFlag == "-font")
3703     {
3704       if (anArgIter + 1 >= theArgNb)
3705       {
3706         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3707         return 1;
3708       }
3709       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
3710       if (!aFontArg.IsIntegerValue())
3711       {
3712         Message::SendFail ("Syntax error: HeightFont value should be integer");
3713         return 1;
3714       }
3715
3716       aColorScale->SetTextHeight (aFontArg.IntegerValue());
3717       anArgIter += 1;
3718     }
3719     else if (aFlag == "-textpos")
3720     {
3721       if (anArgIter + 1 >= theArgNb)
3722       {
3723         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3724         return 1;
3725       }
3726
3727       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
3728       aTextPosArg.LowerCase();
3729       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
3730       if (aTextPosArg == "none")
3731       {
3732         aLabPosition = Aspect_TOCSP_NONE;
3733       }
3734       else if (aTextPosArg == "left")
3735       {
3736         aLabPosition = Aspect_TOCSP_LEFT;
3737       }
3738       else if (aTextPosArg == "right")
3739       {
3740         aLabPosition = Aspect_TOCSP_RIGHT;
3741       }
3742       else if (aTextPosArg == "center")
3743       {
3744         aLabPosition = Aspect_TOCSP_CENTER;
3745       }
3746       else
3747       {
3748         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
3749         return 1;
3750       }
3751       aColorScale->SetLabelPosition (aLabPosition);
3752     }
3753     else if (aFlag == "-logarithmic"
3754           || aFlag == "-log")
3755     {
3756       if (anArgIter + 1 >= theArgNb)
3757       {
3758         Message::SendFail() << "Synta error at argument '" << anArg << "'";
3759         return 1;
3760       }
3761
3762       Standard_Boolean IsLog;
3763       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
3764       {
3765         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3766         return 1;
3767       }
3768       aColorScale->SetLogarithmic (IsLog);
3769     }
3770     else if (aFlag == "-huerange"
3771           || aFlag == "-hue")
3772     {
3773       if (anArgIter + 2 >= theArgNb)
3774       {
3775         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3776         return 1;
3777       }
3778
3779       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
3780       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
3781       aColorScale->SetHueRange (aHueMin, aHueMax);
3782     }
3783     else if (aFlag == "-colorrange")
3784     {
3785       Quantity_Color aColorMin, aColorMax;
3786       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3787                                                       theArgVec + (anArgIter + 1),
3788                                                       aColorMin);
3789       anArgIter += aNbParsed1;
3790       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3791                                                       theArgVec + (anArgIter + 1),
3792                                                       aColorMax);
3793       anArgIter += aNbParsed2;
3794       if (aNbParsed1 == 0
3795        || aNbParsed2 == 0)
3796       {
3797         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3798         return 1;
3799       }
3800
3801       aColorScale->SetColorRange (aColorMin, aColorMax);
3802     }
3803     else if (aFlag == "-reversed"
3804           || aFlag == "-inverted"
3805           || aFlag == "-topdown"
3806           || aFlag == "-bottomup")
3807     {
3808       Standard_Boolean toEnable = Standard_True;
3809       if (anArgIter + 1 < theArgNb
3810        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
3811       {
3812         ++anArgIter;
3813       }
3814       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
3815     }
3816     else if (aFlag == "-smooth"
3817           || aFlag == "-smoothtransition")
3818     {
3819       Standard_Boolean toEnable = Standard_True;
3820       if (anArgIter + 1 < theArgNb
3821        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3822       {
3823         ++anArgIter;
3824       }
3825       aColorScale->SetSmoothTransition (toEnable);
3826     }
3827     else if (aFlag == "-xy")
3828     {
3829       if (anArgIter + 2 >= theArgNb)
3830       {
3831         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3832         return 1;
3833       }
3834
3835       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
3836       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
3837       if (!anX.IsIntegerValue()
3838        || !anY.IsIntegerValue())
3839       {
3840         Message::SendFail ("Syntax error: coordinates should be integer values");
3841         return 1;
3842       }
3843
3844       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
3845     }
3846     else if (aFlag == "-width"
3847           || aFlag == "-w"
3848           || aFlag == "-breadth")
3849     {
3850       if (anArgIter + 1 >= theArgNb)
3851       {
3852         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3853         return 1;
3854       }
3855
3856       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
3857       if (!aBreadth.IsIntegerValue())
3858       {
3859         Message::SendFail ("Syntax error: a width should be an integer value");
3860         return 1;
3861       }
3862       aColorScale->SetBreadth (aBreadth.IntegerValue());
3863     }
3864     else if (aFlag == "-height"
3865           || aFlag == "-h")
3866     {
3867       if (anArgIter + 1 >= theArgNb)
3868       {
3869         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3870         return 1;
3871       }
3872
3873       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
3874       if (!aHeight.IsIntegerValue())
3875       {
3876         Message::SendFail ("Syntax error: a width should be an integer value");
3877         return 1;
3878       }
3879       aColorScale->SetHeight (aHeight.IntegerValue());
3880     }
3881     else if (aFlag == "-color")
3882     {
3883       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3884       {
3885         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
3886         return 1;
3887       }
3888       else if (anArgIter + 2 >= theArgNb)
3889       {
3890         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3891         return 1;
3892       }
3893
3894       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
3895       if (!anInd.IsIntegerValue())
3896       {
3897         Message::SendFail ("Syntax error: Index value should be integer");
3898         return 1;
3899       }
3900       const Standard_Integer anIndex = anInd.IntegerValue();
3901       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
3902       {
3903         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
3904         return 1;
3905       }
3906
3907       Quantity_Color aColor;
3908       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3909                                                      theArgVec + (anArgIter + 1),
3910                                                      aColor);
3911       if (aNbParsed == 0)
3912       {
3913         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3914         return 1;
3915       }
3916       aColorScale->SetIntervalColor (aColor, anIndex);
3917       aColorScale->SetColorType (Aspect_TOCSD_USER);
3918       anArgIter += aNbParsed;
3919     }
3920     else if (aFlag == "-label")
3921     {
3922       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3923       {
3924         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
3925         return 1;
3926       }
3927       else if (anArgIter + 2 >= theArgNb)
3928       {
3929         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3930         return 1;
3931       }
3932
3933       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
3934       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
3935       {
3936         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
3937         return 1;
3938       }
3939
3940       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
3941       aColorScale->SetLabel     (aText, anIndex);
3942       aColorScale->SetLabelType (Aspect_TOCSD_USER);
3943       anArgIter += 2;
3944     }
3945     else if (aFlag == "-labelat"
3946           || aFlag == "-labat"
3947           || aFlag == "-labelatborder"
3948           || aFlag == "-labatborder"
3949           || aFlag == "-labelatcenter"
3950           || aFlag == "-labatcenter")
3951     {
3952       Standard_Boolean toEnable = Standard_True;
3953       if (aFlag == "-labelat"
3954        || aFlag == "-labat")
3955       {
3956         Standard_Integer aLabAtBorder = -1;
3957         if (++anArgIter >= theArgNb)
3958         {
3959           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
3960           anAtBorder.LowerCase();
3961           if (anAtBorder == "border")
3962           {
3963             aLabAtBorder = 1;
3964           }
3965           else if (anAtBorder == "center")
3966           {
3967             aLabAtBorder = 0;
3968           }
3969         }
3970         if (aLabAtBorder == -1)
3971         {
3972           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3973           return 1;
3974         }
3975         toEnable = (aLabAtBorder == 1);
3976       }
3977       else if (anArgIter + 1 < theArgNb
3978             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3979       {
3980         ++anArgIter;
3981       }
3982       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
3983                                   || aFlag == "-labatcenter"
3984                                    ? !toEnable
3985                                    :  toEnable);
3986     }
3987     else if (aFlag == "-colors")
3988     {
3989       Aspect_SequenceOfColor aSeq;
3990       for (;;)
3991       {
3992         Quantity_Color aColor;
3993         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3994                                                        theArgVec + (anArgIter + 1),
3995                                                        aColor);
3996         if (aNbParsed == 0)
3997         {
3998           break;
3999         }
4000         anArgIter += aNbParsed;
4001         aSeq.Append (aColor);
4002       }
4003       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4004       {
4005         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4006                             << aColorScale->GetNumberOfIntervals() << " intervals";
4007         return 1;
4008       }
4009
4010       aColorScale->SetColors    (aSeq);
4011       aColorScale->SetColorType (Aspect_TOCSD_USER);
4012     }
4013     else if (aFlag == "-uniform")
4014     {
4015       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4016       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4017       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4018       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4019       aColorScale->SetColorType (Aspect_TOCSD_USER);
4020     }
4021     else if (aFlag == "-labels"
4022           || aFlag == "-freelabels")
4023     {
4024       if (anArgIter + 1 >= theArgNb)
4025       {
4026         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4027         return 1;
4028       }
4029
4030       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4031                                  ? aColorScale->GetNumberOfIntervals() + 1
4032                                  : aColorScale->GetNumberOfIntervals();
4033       if (aFlag == "-freelabels")
4034       {
4035         ++anArgIter;
4036         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4037       }
4038       if (anArgIter + aNbLabels >= theArgNb)
4039       {
4040         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4041         return 1;
4042       }
4043
4044       TColStd_SequenceOfExtendedString aSeq;
4045       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4046       {
4047         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
4048       }
4049       aColorScale->SetLabels (aSeq);
4050       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4051     }
4052     else if (aFlag == "-title")
4053     {
4054       if (anArgIter + 1 >= theArgNb)
4055       {
4056         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4057         return 1;
4058       }
4059
4060       Standard_Boolean isTwoArgs = Standard_False;
4061       if (anArgIter + 2 < theArgNb)
4062       {
4063         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4064         aSecondArg.LowerCase();
4065       Standard_DISABLE_DEPRECATION_WARNINGS
4066         if (aSecondArg == "none")
4067         {
4068           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4069           isTwoArgs = Standard_True;
4070         }
4071         else if (aSecondArg == "left")
4072         {
4073           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4074           isTwoArgs = Standard_True;
4075         }
4076         else if (aSecondArg == "right")
4077         {
4078           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4079           isTwoArgs = Standard_True;
4080         }
4081         else if (aSecondArg == "center")
4082         {
4083           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4084           isTwoArgs = Standard_True;
4085         }
4086       Standard_ENABLE_DEPRECATION_WARNINGS
4087       }
4088
4089       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
4090       aColorScale->SetTitle (aTitle);
4091       if (isTwoArgs)
4092       {
4093         anArgIter += 1;
4094       }
4095       anArgIter += 1;
4096     }
4097     else if (aFlag == "-demoversion"
4098           || aFlag == "-demo")
4099     {
4100       aColorScale->SetPosition (0, 0);
4101       aColorScale->SetTextHeight (16);
4102       aColorScale->SetRange (0.0, 100.0);
4103       aColorScale->SetNumberOfIntervals (10);
4104       aColorScale->SetBreadth (0);
4105       aColorScale->SetHeight  (0);
4106       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4107       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4108       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4109     }
4110     else if (aFlag == "-findcolor")
4111     {
4112       if (anArgIter + 1 >= theArgNb)
4113       {
4114         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4115         return 1;
4116       }
4117
4118       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4119
4120       if (!anArg1.IsRealValue (Standard_True))
4121       {
4122         Message::SendFail ("Syntax error: the value should be real");
4123         return 1;
4124       }
4125
4126       Quantity_Color aColor;
4127       aColorScale->FindColor (anArg1.RealValue(), aColor);
4128       theDI << Quantity_Color::StringName (aColor.Name());
4129       return 0;
4130     }
4131     else
4132     {
4133       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4134       return 1;
4135     }
4136   }
4137
4138   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4139   aView->Window()->Size (aWinWidth, aWinHeight);
4140   if (aColorScale->GetBreadth() == 0)
4141   {
4142     aColorScale->SetBreadth (aWinWidth);
4143   }
4144   if (aColorScale->GetHeight() == 0)
4145   {
4146     aColorScale->SetHeight (aWinHeight);
4147   }
4148   aColorScale->SetToUpdate();
4149   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4150   return 0;
4151 }
4152
4153 //==============================================================================
4154 //function : VGraduatedTrihedron
4155 //purpose  : Displays or hides a graduated trihedron
4156 //==============================================================================
4157 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4158                                   Quantity_Color& theColor)
4159 {
4160   Quantity_NameOfColor aColorName;
4161   TCollection_AsciiString aVal = theValue;
4162   aVal.UpperCase();
4163   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4164   {
4165     return Standard_False;
4166   }
4167   theColor = Quantity_Color (aColorName);
4168   return Standard_True;
4169 }
4170
4171 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4172 {
4173   if (theArgNum < 2)
4174   {
4175     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4176                         << theArgs[0] <<"' for more information";
4177     return 1;
4178   }
4179
4180   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4181   TCollection_AsciiString aParseKey;
4182   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4183   {
4184     TCollection_AsciiString anArg (theArgs [anArgIt]);
4185
4186     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4187     {
4188       aParseKey = anArg;
4189       aParseKey.Remove (1);
4190       aParseKey.LowerCase();
4191       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4192       continue;
4193     }
4194
4195     if (aParseKey.IsEmpty())
4196     {
4197       continue;
4198     }
4199
4200     aMapOfArgs(aParseKey)->Append (anArg);
4201   }
4202
4203   // Check parameters
4204   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4205        aMapIt.More(); aMapIt.Next())
4206   {
4207     const TCollection_AsciiString& aKey = aMapIt.Key();
4208     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4209
4210     // Bool key, without arguments
4211     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4212         && anArgs->IsEmpty())
4213     {
4214       continue;
4215     }
4216
4217     // One argument
4218     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4219           && anArgs->Length() == 1)
4220     {
4221       continue;
4222     }
4223
4224     // On/off arguments
4225     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4226         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4227         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4228         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4229         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4230     {
4231       continue;
4232     }
4233
4234     // One string argument
4235     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4236           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4237           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4238     {
4239       continue;
4240     }
4241
4242     // One integer argument
4243     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4244           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4245           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4246           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4247          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4248     {
4249       continue;
4250     }
4251
4252     // One real argument
4253     if ( aKey.IsEqual ("arrowlength")
4254          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
4255     {
4256       continue;
4257     }
4258
4259     // Two string arguments
4260     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
4261          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4262     {
4263       continue;
4264     }
4265
4266     TCollection_AsciiString aLowerKey;
4267     aLowerKey  = "-";
4268     aLowerKey += aKey;
4269     aLowerKey.LowerCase();
4270     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
4271                         << "Type help for more information";
4272     return 1;
4273   }
4274
4275   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
4276   if (anAISContext.IsNull())
4277   {
4278     Message::SendFail ("Error: no active viewer");
4279     return 1;
4280   }
4281
4282   Standard_Boolean toDisplay = Standard_True;
4283   Quantity_Color aColor;
4284   Graphic3d_GraduatedTrihedron aTrihedronData;
4285   // Process parameters
4286   Handle(TColStd_HSequenceOfAsciiString) aValues;
4287   if (aMapOfArgs.Find ("off", aValues))
4288   {
4289     toDisplay = Standard_False;
4290   }
4291
4292   // AXES NAMES
4293   if (aMapOfArgs.Find ("xname", aValues))
4294   {
4295     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
4296   }
4297   if (aMapOfArgs.Find ("yname", aValues))
4298   {
4299     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
4300   }
4301   if (aMapOfArgs.Find ("zname", aValues))
4302   {
4303     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
4304   }
4305   if (aMapOfArgs.Find ("xdrawname", aValues))
4306   {
4307     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4308   }
4309   if (aMapOfArgs.Find ("ydrawname", aValues))
4310   {
4311     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4312   }
4313   if (aMapOfArgs.Find ("zdrawname", aValues))
4314   {
4315     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4316   }
4317   if (aMapOfArgs.Find ("xnameoffset", aValues))
4318   {
4319     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4320   }
4321   if (aMapOfArgs.Find ("ynameoffset", aValues))
4322   {
4323     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4324   }
4325   if (aMapOfArgs.Find ("znameoffset", aValues))
4326   {
4327     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4328   }
4329
4330   // COLORS
4331   if (aMapOfArgs.Find ("xnamecolor", aValues))
4332   {
4333     if (!GetColor (aValues->Value(1), aColor))
4334     {
4335       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
4336       return 1;
4337     }
4338     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
4339   }
4340   if (aMapOfArgs.Find ("ynamecolor", aValues))
4341   {
4342     if (!GetColor (aValues->Value(1), aColor))
4343     {
4344       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
4345       return 1;
4346     }
4347     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
4348   }
4349   if (aMapOfArgs.Find ("znamecolor", aValues))
4350   {
4351     if (!GetColor (aValues->Value(1), aColor))
4352     {
4353       Message::SendFail ("Syntax error: -znamecolor wrong color name");
4354       return 1;
4355     }
4356     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
4357   }
4358   if (aMapOfArgs.Find ("xcolor", aValues))
4359   {
4360     if (!GetColor (aValues->Value(1), aColor))
4361     {
4362       Message::SendFail ("Syntax error: -xcolor wrong color name");
4363       return 1;
4364     }
4365     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
4366   }
4367   if (aMapOfArgs.Find ("ycolor", aValues))
4368   {
4369     if (!GetColor (aValues->Value(1), aColor))
4370     {
4371       Message::SendFail ("Syntax error: -ycolor wrong color name");
4372       return 1;
4373     }
4374     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
4375   }
4376   if (aMapOfArgs.Find ("zcolor", aValues))
4377   {
4378     if (!GetColor (aValues->Value(1), aColor))
4379     {
4380       Message::SendFail ("Syntax error: -zcolor wrong color name");
4381       return 1;
4382     }
4383     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
4384   }
4385
4386   // TICKMARKS
4387   if (aMapOfArgs.Find ("xticks", aValues))
4388   {
4389     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4390   }
4391   if (aMapOfArgs.Find ("yticks", aValues))
4392   {
4393     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4394   }
4395   if (aMapOfArgs.Find ("zticks", aValues))
4396   {
4397     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4398   }
4399   if (aMapOfArgs.Find ("xticklength", aValues))
4400   {
4401     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4402   }
4403   if (aMapOfArgs.Find ("yticklength", aValues))
4404   {
4405     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4406   }
4407   if (aMapOfArgs.Find ("zticklength", aValues))
4408   {
4409     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4410   }
4411   if (aMapOfArgs.Find ("xdrawticks", aValues))
4412   {
4413     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4414   }
4415   if (aMapOfArgs.Find ("ydrawticks", aValues))
4416   {
4417     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4418   }
4419   if (aMapOfArgs.Find ("zdrawticks", aValues))
4420   {
4421     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4422   }
4423
4424   // VALUES
4425   if (aMapOfArgs.Find ("xdrawvalues", aValues))
4426   {
4427     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4428   }
4429   if (aMapOfArgs.Find ("ydrawvalues", aValues))
4430   {
4431     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4432   }
4433   if (aMapOfArgs.Find ("zdrawvalues", aValues))
4434   {
4435     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4436   }
4437   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
4438   {
4439     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4440   }
4441   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
4442   {
4443     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4444   }
4445   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
4446   {
4447     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4448   }
4449
4450   // ARROWS
4451   if (aMapOfArgs.Find ("arrowlength", aValues))
4452   {
4453     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
4454   }
4455
4456   // FONTS
4457   if (aMapOfArgs.Find ("namefont", aValues))
4458   {
4459     aTrihedronData.SetNamesFont (aValues->Value(1));
4460   }
4461   if (aMapOfArgs.Find ("valuesfont", aValues))
4462   {
4463     aTrihedronData.SetValuesFont (aValues->Value(1));
4464   }
4465
4466   if (aMapOfArgs.Find ("drawgrid", aValues))
4467   {
4468     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
4469   }
4470   if (aMapOfArgs.Find ("drawaxes", aValues))
4471   {
4472     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
4473   }
4474
4475   // The final step: display of erase trihedron
4476   if (toDisplay)
4477   {
4478     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
4479   }
4480   else
4481   {
4482     ViewerTest::CurrentView()->GraduatedTrihedronErase();
4483   }
4484
4485   ViewerTest::GetAISContext()->UpdateCurrentViewer();
4486   ViewerTest::CurrentView()->Redraw();
4487
4488   return 0;
4489 }
4490
4491 //==============================================================================
4492 //function : VTile
4493 //purpose  :
4494 //==============================================================================
4495 static int VTile (Draw_Interpretor& theDI,
4496                   Standard_Integer  theArgNb,
4497                   const char**      theArgVec)
4498 {
4499   Handle(V3d_View) aView = ViewerTest::CurrentView();
4500   if (aView.IsNull())
4501   {
4502     Message::SendFail ("Error: no active viewer");
4503     return 1;
4504   }
4505
4506   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
4507   if (theArgNb < 2)
4508   {
4509     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
4510           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
4511           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
4512     return 0;
4513   }
4514
4515   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
4516   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4517   {
4518     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4519     anArg.LowerCase();
4520     if (anArg == "-lowerleft"
4521      || anArg == "-upperleft")
4522     {
4523       if (anArgIter + 3 < theArgNb)
4524       {
4525         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4526         return 1;
4527       }
4528       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
4529       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4530       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4531     }
4532     else if (anArg == "-total"
4533           || anArg == "-totalsize"
4534           || anArg == "-viewsize")
4535     {
4536       if (anArgIter + 3 < theArgNb)
4537       {
4538         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4539         return 1;
4540       }
4541       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4542       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4543       if (aTile.TotalSize.x() < 1
4544        || aTile.TotalSize.y() < 1)
4545       {
4546         Message::SendFail ("Error: total size is incorrect");
4547         return 1;
4548       }
4549     }
4550     else if (anArg == "-tilesize")
4551     {
4552       if (anArgIter + 3 < theArgNb)
4553       {
4554         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4555         return 1;
4556       }
4557
4558       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4559       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4560       if (aTile.TileSize.x() < 1
4561        || aTile.TileSize.y() < 1)
4562       {
4563         Message::SendFail ("Error: tile size is incorrect");
4564         return 1;
4565       }
4566     }
4567     else if (anArg == "-unset")
4568     {
4569       aView->Camera()->SetTile (Graphic3d_CameraTile());
4570       aView->Redraw();
4571       return 0;
4572     }
4573   }
4574
4575   if (aTile.TileSize.x() < 1
4576    || aTile.TileSize.y() < 1)
4577   {
4578     Message::SendFail ("Error: tile size is undefined");
4579     return 1;
4580   }
4581   else if (aTile.TotalSize.x() < 1
4582         || aTile.TotalSize.y() < 1)
4583   {
4584     Message::SendFail ("Error: total size is undefined");
4585     return 1;
4586   }
4587
4588   aView->Camera()->SetTile (aTile);
4589   aView->Redraw();
4590   return 0;
4591 }
4592
4593 //! Format ZLayer ID.
4594 inline const char* formZLayerId (const Standard_Integer theLayerId)
4595 {
4596   switch (theLayerId)
4597   {
4598     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
4599     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
4600     case Graphic3d_ZLayerId_Top:     return "[TOP]";
4601     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
4602     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
4603     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
4604   }
4605   return "";
4606 }
4607
4608 //! Print the ZLayer information.
4609 inline void printZLayerInfo (Draw_Interpretor& theDI,
4610                              const Graphic3d_ZLayerSettings& theLayer)
4611 {
4612   if (!theLayer.Name().IsEmpty())
4613   {
4614     theDI << "  Name: " << theLayer.Name() << "\n";
4615   }
4616   if (theLayer.IsImmediate())
4617   {
4618     theDI << "  Immediate: TRUE\n";
4619   }
4620   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
4621   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
4622   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
4623   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
4624   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
4625   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
4626   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
4627   {
4628     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
4629   }
4630 }
4631
4632 //==============================================================================
4633 //function : VZLayer
4634 //purpose  : Test z layer operations for v3d viewer
4635 //==============================================================================
4636 static int VZLayer (Draw_Interpretor& theDI,
4637                     Standard_Integer  theArgNb,
4638                     const char**      theArgVec)
4639 {
4640   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
4641   if (aContextAIS.IsNull())
4642   {
4643     Message::SendFail ("Error: no active viewer");
4644     return 1;
4645   }
4646
4647   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
4648   if (theArgNb < 2)
4649   {
4650     TColStd_SequenceOfInteger aLayers;
4651     aViewer->GetAllZLayers (aLayers);
4652     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4653     {
4654       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
4655       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
4656       printZLayerInfo (theDI, aSettings);
4657     }
4658     return 0;
4659   }
4660
4661   Standard_Integer anArgIter = 1;
4662   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4663   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
4664   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
4665   {
4666     ++anArgIter;
4667   }
4668
4669   {
4670     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
4671     if (aFirstArg.IsIntegerValue())
4672     {
4673       ++anArgIter;
4674       aLayerId = aFirstArg.IntegerValue();
4675     }
4676     else
4677     {
4678       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
4679       {
4680         ++anArgIter;
4681       }
4682     }
4683   }
4684
4685   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
4686   for (; anArgIter < theArgNb; ++anArgIter)
4687   {
4688     // perform operation
4689     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4690     anArg.LowerCase();
4691     if (anUpdateTool.parseRedrawMode (anArg))
4692     {
4693       //
4694     }
4695     else if (anArg == "-add"
4696           || anArg == "add")
4697     {
4698       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4699       if (!aViewer->AddZLayer (aLayerId))
4700       {
4701         Message::SendFail ("Error: can not add a new z layer");
4702         return 0;
4703       }
4704
4705       theDI << aLayerId;
4706     }
4707     else if (anArg == "-insertbefore"
4708           && anArgIter + 1 < theArgNb
4709           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4710     {
4711       ++anArgIter;
4712       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4713       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4714       {
4715         Message::SendFail ("Error: can not add a new z layer");
4716         return 0;
4717       }
4718
4719       theDI << aLayerId;
4720     }
4721     else if (anArg == "-insertafter"
4722           && anArgIter + 1 < theArgNb
4723           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4724     {
4725       ++anArgIter;
4726       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4727       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4728       {
4729         Message::SendFail ("Error: can not add a new z layer");
4730         return 0;
4731       }
4732
4733       theDI << aLayerId;
4734     }
4735     else if (anArg == "-del"
4736           || anArg == "-delete"
4737           || anArg == "del")
4738     {
4739       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4740       {
4741         if (++anArgIter >= theArgNb)
4742         {
4743           Message::SendFail ("Syntax error: id of z layer to remove is missing");
4744           return 1;
4745         }
4746
4747         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4748       }
4749
4750       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
4751        || aLayerId == Graphic3d_ZLayerId_Default
4752        || aLayerId == Graphic3d_ZLayerId_Top
4753        || aLayerId == Graphic3d_ZLayerId_Topmost
4754        || aLayerId == Graphic3d_ZLayerId_TopOSD
4755        || aLayerId == Graphic3d_ZLayerId_BotOSD)
4756       {
4757         Message::SendFail ("Syntax error: standard Z layer can not be removed");
4758         return 1;
4759       }
4760
4761       // move all object displayed in removing layer to default layer
4762       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
4763            anObjIter.More(); anObjIter.Next())
4764       {
4765         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
4766         if (aPrs.IsNull()
4767          || aPrs->ZLayer() != aLayerId)
4768         {
4769           continue;
4770         }
4771         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
4772       }
4773
4774       if (!aViewer->RemoveZLayer (aLayerId))
4775       {
4776         Message::SendFail ("Z layer can not be removed");
4777       }
4778       else
4779       {
4780         theDI << aLayerId << " ";
4781       }
4782     }
4783     else if (anArg == "-get"
4784           || anArg == "get")
4785     {
4786       TColStd_SequenceOfInteger aLayers;
4787       aViewer->GetAllZLayers (aLayers);
4788       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4789       {
4790         theDI << aLayeriter.Value() << " ";
4791       }
4792
4793       theDI << "\n";
4794     }
4795     else if (anArg == "-name")
4796     {
4797       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4798       {
4799         Message::SendFail ("Syntax error: id of Z layer is missing");
4800         return 1;
4801       }
4802
4803       if (++anArgIter >= theArgNb)
4804       {
4805         Message::SendFail ("Syntax error: name is missing");
4806         return 1;
4807       }
4808
4809       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4810       aSettings.SetName (theArgVec[anArgIter]);
4811       aViewer->SetZLayerSettings (aLayerId, aSettings);
4812     }
4813     else if (anArg == "-origin")
4814     {
4815       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4816       {
4817         Message::SendFail ("Syntax error: id of Z layer is missing");
4818         return 1;
4819       }
4820
4821       if (anArgIter + 2 >= theArgNb)
4822       {
4823         Message::SendFail ("Syntax error: origin coordinates are missing");
4824         return 1;
4825       }
4826
4827       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4828       gp_XYZ anOrigin;
4829       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
4830       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
4831       anOrigin.SetZ (0.0);
4832       if (anArgIter + 3 < theArgNb)
4833       {
4834         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
4835         anArgIter += 3;
4836       }
4837       else
4838       {
4839         anArgIter += 2;
4840       }
4841       aSettings.SetOrigin (anOrigin);
4842       aViewer->SetZLayerSettings (aLayerId, aSettings);
4843     }
4844     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4845           && anArgIter + 1 < theArgNb
4846           && (anArg == "-cullingdistance"
4847            || anArg == "-cullingdist"
4848            || anArg == "-culldistance"
4849            || anArg == "-culldist"
4850            || anArg == "-distcull"
4851            || anArg == "-distculling"
4852            || anArg == "-distanceculling"))
4853     {
4854       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4855       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
4856       aSettings.SetCullingDistance (aDist);
4857       aViewer->SetZLayerSettings (aLayerId, aSettings);
4858     }
4859     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4860           && anArgIter + 1 < theArgNb
4861           && (anArg == "-cullingsize"
4862            || anArg == "-cullsize"
4863            || anArg == "-sizecull"
4864            || anArg == "-sizeculling"))
4865     {
4866       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4867       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
4868       aSettings.SetCullingSize (aSize);
4869       aViewer->SetZLayerSettings (aLayerId, aSettings);
4870     }
4871     else if (anArg == "-settings"
4872           || anArg == "settings")
4873     {
4874       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4875       {
4876         if (++anArgIter >= theArgNb)
4877         {
4878           Message::SendFail ("Syntax error: id of Z layer is missing");
4879           return 1;
4880         }
4881
4882         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4883       }
4884
4885       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4886       printZLayerInfo (theDI, aSettings);
4887     }
4888     else if (anArg == "-enable"
4889           || anArg == "enable"
4890           || anArg == "-disable"
4891           || anArg == "disable")
4892     {
4893       const Standard_Boolean toEnable = anArg == "-enable"
4894                                      || anArg == "enable";
4895       if (++anArgIter >= theArgNb)
4896       {
4897         Message::SendFail ("Syntax error: option name is missing");
4898         return 1;
4899       }
4900
4901       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
4902       aSubOp.LowerCase();
4903       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4904       {
4905         if (++anArgIter >= theArgNb)
4906         {
4907           Message::SendFail ("Syntax error: id of Z layer is missing");
4908           return 1;
4909         }
4910
4911         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4912       }
4913
4914       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4915       if (aSubOp == "depthtest"
4916        || aSubOp == "test")
4917       {
4918         aSettings.SetEnableDepthTest (toEnable);
4919       }
4920       else if (aSubOp == "depthwrite"
4921             || aSubOp == "write")
4922       {
4923         aSettings.SetEnableDepthWrite (toEnable);
4924       }
4925       else if (aSubOp == "depthclear"
4926             || aSubOp == "clear")
4927       {
4928         aSettings.SetClearDepth (toEnable);
4929       }
4930       else if (aSubOp == "depthoffset"
4931             || aSubOp == "offset")
4932       {
4933         Graphic3d_PolygonOffset aParams;
4934         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
4935         if (toEnable)
4936         {
4937           if (anArgIter + 2 >= theArgNb)
4938           {
4939             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
4940             return 1;
4941           }
4942
4943           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4944           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4945         }
4946         aSettings.SetPolygonOffset (aParams);
4947       }
4948       else if (aSubOp == "positiveoffset"
4949             || aSubOp == "poffset")
4950       {
4951         if (toEnable)
4952         {
4953           aSettings.SetDepthOffsetPositive();
4954         }
4955         else
4956         {
4957           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
4958         }
4959       }
4960       else if (aSubOp == "negativeoffset"
4961             || aSubOp == "noffset")
4962       {
4963         if (toEnable)
4964         {
4965           aSettings.SetDepthOffsetNegative();
4966         }
4967         else
4968         {
4969           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
4970         }
4971       }
4972       else if (aSubOp == "textureenv")
4973       {
4974         aSettings.SetEnvironmentTexture (toEnable);
4975       }
4976       else if (aSubOp == "raytracing")
4977       {
4978         aSettings.SetRaytracable (toEnable);
4979       }
4980
4981       aViewer->SetZLayerSettings (aLayerId, aSettings);
4982     }
4983     else
4984     {
4985       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
4986       return 1;
4987     }
4988   }
4989
4990   return 0;
4991 }
4992
4993 // The interactive presentation of 2d layer item
4994 // for "vlayerline" command it provides a presentation of
4995 // line with user-defined linewidth, linetype and transparency.
4996 class V3d_LineItem : public AIS_InteractiveObject
4997 {
4998 public:
4999   // CASCADE RTTI
5000   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
5001
5002   // constructor
5003   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5004                                Standard_Real X2, Standard_Real Y2,
5005                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5006                                Standard_Real theWidth    = 0.5,
5007                                Standard_Real theTransp   = 1.0);
5008
5009 private:
5010
5011   virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
5012                         const Handle(Prs3d_Presentation)& thePrs,
5013                         const Standard_Integer theMode) Standard_OVERRIDE;
5014
5015   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& ,
5016                                  const Standard_Integer ) Standard_OVERRIDE
5017   {}
5018
5019 private:
5020
5021   Standard_Real       myX1, myY1, myX2, myY2;
5022   Aspect_TypeOfLine   myType;
5023   Standard_Real       myWidth;
5024 };
5025
5026 // default constructor for line item
5027 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5028                            Standard_Real X2, Standard_Real Y2,
5029                            Aspect_TypeOfLine theType,
5030                            Standard_Real theWidth,
5031                            Standard_Real theTransp) :
5032   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5033   myType(theType), myWidth(theWidth)
5034 {
5035   SetTransparency (1-theTransp);
5036 }
5037
5038 // render line
5039 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager)& ,
5040                             const Handle(Prs3d_Presentation)& thePresentation,
5041                             const Standard_Integer )
5042 {
5043   thePresentation->Clear();
5044   Quantity_Color aColor (Quantity_NOC_RED);
5045   Standard_Integer aWidth, aHeight;
5046   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5047   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
5048   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5049   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5050   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5051   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5052   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5053   aGroup->AddPrimitiveArray (aPrim);
5054 }
5055
5056 //=============================================================================
5057 //function : VLayerLine
5058 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5059 //         : linewidth, transparency coefficient
5060 //============================================================================
5061 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5062 {
5063   // get the active view
5064   Handle(V3d_View) aView = ViewerTest::CurrentView();
5065   if (aView.IsNull())
5066   {
5067     di << "Call vinit before!\n";
5068     return 1;
5069   }
5070   else if (argc < 5)
5071   {
5072     di << "Use: " << argv[0];
5073     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5074     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5075     di << "              0 - solid  \n";
5076     di << "              1 - dashed \n";
5077     di << "              2 - dot    \n";
5078     di << "              3 - dashdot\n";
5079     di << " transparency : { 0.0 - 1.0 } \n";
5080     di << "                  0.0 - transparent\n";
5081     di << "                  1.0 - visible    \n";
5082     return 1;
5083   }
5084
5085   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5086   // get the input params
5087   Standard_Real X1 = Draw::Atof(argv[1]);
5088   Standard_Real Y1 = Draw::Atof(argv[2]);
5089   Standard_Real X2 = Draw::Atof(argv[3]);
5090   Standard_Real Y2 = Draw::Atof(argv[4]);
5091
5092   Standard_Real aWidth = 0.5;
5093   Standard_Real aTransparency = 1.0;
5094
5095   // has width
5096   if (argc > 5)
5097     aWidth = Draw::Atof(argv[5]);
5098
5099   // select appropriate line type
5100   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5101   if (argc > 6
5102   && !ViewerTest::ParseLineType (argv[6], aLineType))
5103   {
5104     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5105     return 1;
5106   }
5107
5108   // has transparency
5109   if (argc > 7)
5110   {
5111     aTransparency = Draw::Atof(argv[7]);
5112     if (aTransparency < 0 || aTransparency > 1.0)
5113       aTransparency = 1.0;
5114   }
5115
5116   static Handle (V3d_LineItem) aLine;
5117   if (!aLine.IsNull())
5118   {
5119     aContext->Erase (aLine, Standard_False);
5120   }
5121   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5122                             aLineType, aWidth,
5123                             aTransparency);
5124
5125   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5126   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5127   aLine->SetToUpdate();
5128   aContext->Display (aLine, Standard_True);
5129
5130   return 0;
5131 }
5132
5133
5134 //==============================================================================
5135 //function : VGrid
5136 //purpose  :
5137 //==============================================================================
5138
5139 static int VGrid (Draw_Interpretor& /*theDI*/,
5140                   Standard_Integer  theArgNb,
5141                   const char**      theArgVec)
5142 {
5143   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5144   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5145   if (aView.IsNull() || aViewer.IsNull())
5146   {
5147     Message::SendFail ("Error: no active viewer");
5148     return 1;
5149   }
5150
5151   Aspect_GridType     aType = aViewer->GridType();
5152   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5153   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5154   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5155   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5156   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5157   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5158   {
5159     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5160     anArg.LowerCase();
5161     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5162     {
5163       continue;
5164     }
5165     else if (anArgIter + 1 < theArgNb
5166           && anArg == "-type")
5167     {
5168       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5169       anArgNext.LowerCase();
5170       if (anArgNext == "r"
5171        || anArgNext == "rect"
5172        || anArgNext == "rectangular")
5173       {
5174         aType = Aspect_GT_Rectangular;
5175       }
5176       else if (anArgNext == "c"
5177             || anArgNext == "circ"
5178             || anArgNext == "circular")
5179       {
5180         aType = Aspect_GT_Circular;
5181       }
5182       else
5183       {
5184         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5185         return 1;
5186       }
5187     }
5188     else if (anArgIter + 1 < theArgNb
5189           && anArg == "-mode")
5190     {
5191       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5192       anArgNext.LowerCase();
5193       if (anArgNext == "l"
5194        || anArgNext == "line"
5195        || anArgNext == "lines")
5196       {
5197         aMode = Aspect_GDM_Lines;
5198       }
5199       else if (anArgNext == "p"
5200             || anArgNext == "point"
5201             || anArgNext == "points")
5202       {
5203         aMode = Aspect_GDM_Points;
5204       }
5205       else
5206       {
5207         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5208         return 1;
5209       }
5210     }
5211     else if (anArgIter + 2 < theArgNb
5212           && (anArg == "-origin"
5213            || anArg == "-orig"))
5214     {
5215       hasOrigin = true;
5216       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5217                               Draw::Atof (theArgVec[anArgIter + 2]));
5218       anArgIter += 2;
5219     }
5220     else if (anArgIter + 2 < theArgNb
5221           && anArg == "-step")
5222     {
5223       hasStep = true;
5224       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5225                             Draw::Atof (theArgVec[anArgIter + 2]));
5226       if (aNewStepXY.x() <= 0.0
5227        || aNewStepXY.y() <= 0.0)
5228       {
5229         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5230         return 1;
5231       }
5232       anArgIter += 2;
5233     }
5234     else if (anArgIter + 1 < theArgNb
5235           && (anArg == "-angle"
5236            || anArg == "-rotangle"
5237            || anArg == "-rotationangle"))
5238     {
5239       hasRotAngle = true;
5240       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5241     }
5242     else if (anArgIter + 1 < theArgNb
5243           && (anArg == "-zoffset"
5244            || anArg == "-dz"))
5245     {
5246       hasZOffset = true;
5247       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5248     }
5249     else if (anArgIter + 1 < theArgNb
5250           && anArg == "-radius")
5251     {
5252       hasSize = true;
5253       ++anArgIter;
5254       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
5255       if (aNewStepXY.x() <= 0.0)
5256       {
5257         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
5258         return 1;
5259       }
5260     }
5261     else if (anArgIter + 2 < theArgNb
5262           && anArg == "-size")
5263     {
5264       hasSize = true;
5265       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5266                             Draw::Atof (theArgVec[anArgIter + 2]));
5267       if (aNewStepXY.x() <= 0.0
5268        || aNewStepXY.y() <= 0.0)
5269       {
5270         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5271         return 1;
5272       }
5273       anArgIter += 2;
5274     }
5275     else if (anArg == "r"
5276           || anArg == "rect"
5277           || anArg == "rectangular")
5278     {
5279       aType = Aspect_GT_Rectangular;
5280     }
5281     else if (anArg == "c"
5282           || anArg == "circ"
5283           || anArg == "circular")
5284     {
5285       aType = Aspect_GT_Circular;
5286     }
5287     else if (anArg == "l"
5288           || anArg == "line"
5289           || anArg == "lines")
5290     {
5291       aMode = Aspect_GDM_Lines;
5292     }
5293     else if (anArg == "p"
5294           || anArg == "point"
5295           || anArg == "points")
5296     {
5297       aMode = Aspect_GDM_Points;
5298     }
5299     else if (anArgIter + 1 >= theArgNb
5300           && anArg == "off")
5301     {
5302       aViewer->DeactivateGrid();
5303       return 0;
5304     }
5305     else
5306     {
5307       Message::SendFail() << "Syntax error at '" << anArg << "'";
5308       return 1;
5309     }
5310   }
5311
5312   if (aType == Aspect_GT_Rectangular)
5313   {
5314     Graphic3d_Vec2d anOrigXY, aStepXY;
5315     Standard_Real aRotAngle = 0.0;
5316     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5317     if (hasOrigin)
5318     {
5319       anOrigXY = aNewOriginXY;
5320     }
5321     if (hasStep)
5322     {
5323       aStepXY = aNewStepXY;
5324     }
5325     if (hasRotAngle)
5326     {
5327       aRotAngle = aNewRotAngle;
5328     }
5329     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5330     if (hasSize || hasZOffset)
5331     {
5332       Graphic3d_Vec3d aSize;
5333       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5334       if (hasSize)
5335       {
5336         aSize.x() = aNewSizeXY.x();
5337         aSize.y() = aNewSizeXY.y();
5338       }
5339       if (hasZOffset)
5340       {
5341         aSize.z() = aNewZOffset;
5342       }
5343       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5344     }
5345   }
5346   else if (aType == Aspect_GT_Circular)
5347   {
5348     Graphic3d_Vec2d anOrigXY;
5349     Standard_Real aRadiusStep;
5350     Standard_Integer aDivisionNumber;
5351     Standard_Real aRotAngle = 0.0;
5352     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5353     if (hasOrigin)
5354     {
5355       anOrigXY = aNewOriginXY;
5356     }
5357     if (hasStep)
5358     {
5359       aRadiusStep     = aNewStepXY[0];
5360       aDivisionNumber = (int )aNewStepXY[1];
5361       if (aDivisionNumber < 1)
5362       {
5363         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
5364         return 1;
5365       }
5366     }
5367     if (hasRotAngle)
5368     {
5369       aRotAngle = aNewRotAngle;
5370     }
5371
5372     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5373     if (hasSize || hasZOffset)
5374     {
5375       Standard_Real aRadius = 0.0, aZOffset = 0.0;
5376       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
5377       if (hasSize)
5378       {
5379         aRadius = aNewSizeXY.x();
5380         if (aNewSizeXY.y() != 0.0)
5381         {
5382           Message::SendFail ("Syntax error: circular size should be specified as radius");
5383           return 1;
5384         }
5385       }
5386       if (hasZOffset)
5387       {
5388         aZOffset = aNewZOffset;
5389       }
5390       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
5391     }
5392   }
5393   aViewer->ActivateGrid (aType, aMode);
5394   return 0;
5395 }
5396
5397 //==============================================================================
5398 //function : VPriviledgedPlane
5399 //purpose  :
5400 //==============================================================================
5401
5402 static int VPriviledgedPlane (Draw_Interpretor& theDI,
5403                               Standard_Integer  theArgNb,
5404                               const char**      theArgVec)
5405 {
5406   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
5407   {
5408     Message::SendFail ("Error: wrong number of arguments! See usage:");
5409     theDI.PrintHelp (theArgVec[0]);
5410     return 1;
5411   }
5412
5413   // get the active viewer
5414   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5415   if (aViewer.IsNull())
5416   {
5417     Message::SendFail ("Error: no active viewer");
5418     return 1;
5419   }
5420
5421   if (theArgNb == 1)
5422   {
5423     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
5424     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
5425     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
5426     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
5427     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
5428           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
5429           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
5430     return 0;
5431   }
5432
5433   Standard_Integer anArgIdx = 1;
5434   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
5435   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
5436   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
5437   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
5438   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
5439   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
5440
5441   gp_Ax3 aPriviledgedPlane;
5442   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
5443   gp_Dir aNorm (aNormX, aNormY, aNormZ);
5444   if (theArgNb > 7)
5445   {
5446     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
5447     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
5448     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
5449     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
5450     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
5451   }
5452   else
5453   {
5454     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
5455   }
5456
5457   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
5458
5459   return 0;
5460 }
5461
5462 //==============================================================================
5463 //function : VConvert
5464 //purpose  :
5465 //==============================================================================
5466
5467 static int VConvert (Draw_Interpretor& theDI,
5468                      Standard_Integer  theArgNb,
5469                      const char**      theArgVec)
5470 {
5471   // get the active view
5472   Handle(V3d_View) aView = ViewerTest::CurrentView();
5473   if (aView.IsNull())
5474   {
5475     Message::SendFail ("Error: no active viewer");
5476     return 1;
5477   }
5478
5479   enum { Model, Ray, View, Window, Grid } aMode = Model;
5480
5481   // access coordinate arguments
5482   TColStd_SequenceOfReal aCoord;
5483   Standard_Integer anArgIdx = 1;
5484   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
5485   {
5486     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5487     if (!anArg.IsRealValue (Standard_True))
5488     {
5489       break;
5490     }
5491     aCoord.Append (anArg.RealValue());
5492   }
5493
5494   // non-numeric argument too early
5495   if (aCoord.IsEmpty())
5496   {
5497     Message::SendFail ("Error: wrong number of arguments! See usage:");
5498     theDI.PrintHelp (theArgVec[0]);
5499     return 1;
5500   }
5501
5502   // collect all other arguments and options
5503   for (; anArgIdx < theArgNb; ++anArgIdx)
5504   {
5505     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5506     anArg.LowerCase();
5507     if      (anArg == "window") aMode = Window;
5508     else if (anArg == "view")   aMode = View;
5509     else if (anArg == "grid")   aMode = Grid;
5510     else if (anArg == "ray")    aMode = Ray;
5511     else
5512     {
5513       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
5514       theDI.PrintHelp (theArgVec[0]);
5515       return 1;
5516     }
5517   }
5518
5519   // complete input checks
5520   if ((aCoord.Length() == 1 && theArgNb > 3) ||
5521       (aCoord.Length() == 2 && theArgNb > 4) ||
5522       (aCoord.Length() == 3 && theArgNb > 5))
5523   {
5524     Message::SendFail ("Error: wrong number of arguments! See usage:");
5525     theDI.PrintHelp (theArgVec[0]);
5526     return 1;
5527   }
5528
5529   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
5530   Standard_Integer aXYp[2] = {0, 0};
5531
5532   // convert one-dimensional coordinate
5533   if (aCoord.Length() == 1)
5534   {
5535     switch (aMode)
5536     {
5537       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
5538       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
5539       default:
5540         Message::SendFail ("Error: wrong arguments! See usage:");
5541         theDI.PrintHelp (theArgVec[0]);
5542         return 1;
5543     }
5544   }
5545
5546   // convert 2D coordinates from projection or view reference space
5547   if (aCoord.Length() == 2)
5548   {
5549     switch (aMode)
5550     {
5551       case Model :
5552         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5553         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5554         return 0;
5555
5556       case View :
5557         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
5558         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
5559         return 0;
5560
5561       case Window :
5562         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
5563         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5564         return 0;
5565
5566       case Grid :
5567         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5568         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
5569         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5570         return 0;
5571
5572       case Ray :
5573         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
5574                                 (Standard_Integer) aCoord (2),
5575                                 aXYZ[0], aXYZ[1], aXYZ[2],
5576                                 aXYZ[3], aXYZ[4], aXYZ[5]);
5577         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5578         return 0;
5579
5580       default:
5581         Message::SendFail ("Error: wrong arguments! See usage:");
5582         theDI.PrintHelp (theArgVec[0]);
5583         return 1;
5584     }
5585   }
5586
5587   // convert 3D coordinates from view reference space
5588   else if (aCoord.Length() == 3)
5589   {
5590     switch (aMode)
5591     {
5592       case Window :
5593         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
5594         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5595         return 0;
5596
5597       case Grid :
5598         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
5599         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5600         return 0;
5601
5602       default:
5603         Message::SendFail ("Error: wrong arguments! See usage:");
5604         theDI.PrintHelp (theArgVec[0]);
5605         return 1;
5606     }
5607   }
5608
5609   return 0;
5610 }
5611
5612 //==============================================================================
5613 //function : VFps
5614 //purpose  :
5615 //==============================================================================
5616
5617 static int VFps (Draw_Interpretor& theDI,
5618                  Standard_Integer  theArgNb,
5619                  const char**      theArgVec)
5620 {
5621   // get the active view
5622   Handle(V3d_View) aView = ViewerTest::CurrentView();
5623   if (aView.IsNull())
5624   {
5625     Message::SendFail ("Error: no active viewer");
5626     return 1;
5627   }
5628
5629   Standard_Integer aFramesNb = -1;
5630   Standard_Real aDuration = -1.0;
5631   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5632   {
5633     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5634     anArg.LowerCase();
5635     if (aDuration < 0.0
5636      && anArgIter + 1 < theArgNb
5637      && (anArg == "-duration"
5638       || anArg == "-dur"
5639       || anArg == "-time"))
5640     {
5641       aDuration = Draw::Atof (theArgVec[++anArgIter]);
5642     }
5643     else if (aFramesNb < 0
5644           && anArg.IsIntegerValue())
5645     {
5646       aFramesNb = anArg.IntegerValue();
5647       if (aFramesNb <= 0)
5648       {
5649         Message::SendFail() << "Syntax error at '" << anArg << "'";
5650         return 1;
5651       }
5652     }
5653     else
5654     {
5655       Message::SendFail() << "Syntax error at '" << anArg << "'";
5656       return 1;
5657     }
5658   }
5659   if (aFramesNb < 0 && aDuration < 0.0)
5660   {
5661     aFramesNb = 100;
5662   }
5663
5664   // the time is meaningless for first call
5665   // due to async OpenGl rendering
5666   aView->Redraw();
5667
5668   // redraw view in loop to estimate average values
5669   OSD_Timer aTimer;
5670   aTimer.Start();
5671   Standard_Integer aFrameIter = 1;
5672   for (;; ++aFrameIter)
5673   {
5674     aView->Redraw();
5675     if ((aFramesNb > 0
5676       && aFrameIter >= aFramesNb)
5677      || (aDuration > 0.0
5678       && aTimer.ElapsedTime() >= aDuration))
5679     {
5680       break;
5681     }
5682   }
5683   aTimer.Stop();
5684   Standard_Real aCpu;
5685   const Standard_Real aTime = aTimer.ElapsedTime();
5686   aTimer.OSD_Chronometer::Show (aCpu);
5687
5688   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
5689   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
5690
5691   // return statistics
5692   theDI << "FPS: " << aFpsAver << "\n"
5693         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
5694
5695   // compute additional statistics in ray-tracing mode
5696   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
5697   if (aParams.Method == Graphic3d_RM_RAYTRACING)
5698   {
5699     Graphic3d_Vec2i aWinSize (0, 0);
5700     aView->Window()->Size (aWinSize.x(), aWinSize.y());
5701
5702     // 1 shadow ray and 1 secondary ray pew each bounce
5703     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
5704     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
5705   }
5706
5707   return 0;
5708 }
5709
5710
5711 //==============================================================================
5712 //function : VMemGpu
5713 //purpose  :
5714 //==============================================================================
5715
5716 static int VMemGpu (Draw_Interpretor& theDI,
5717                     Standard_Integer  theArgNb,
5718                     const char**      theArgVec)
5719 {
5720   // get the context
5721   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5722   if (aContextAIS.IsNull())
5723   {
5724     Message::SendFail ("Error: no active viewer");
5725     return 1;
5726   }
5727
5728   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
5729   if (aDriver.IsNull())
5730   {
5731     Message::SendFail ("Error: graphic driver not available");
5732     return 1;
5733   }
5734
5735   Standard_Size aFreeBytes = 0;
5736   TCollection_AsciiString anInfo;
5737   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
5738   {
5739     Message::SendFail ("Error: information not available");
5740     return 1;
5741   }
5742
5743   if (theArgNb > 1 && *theArgVec[1] == 'f')
5744   {
5745     theDI << Standard_Real (aFreeBytes);
5746   }
5747   else
5748   {
5749     theDI << anInfo;
5750   }
5751
5752   return 0;
5753 }
5754
5755 // ==============================================================================
5756 // function : VReadPixel
5757 // purpose  :
5758 // ==============================================================================
5759 static int VReadPixel (Draw_Interpretor& theDI,
5760                        Standard_Integer  theArgNb,
5761                        const char**      theArgVec)
5762 {
5763   // get the active view
5764   Handle(V3d_View) aView = ViewerTest::CurrentView();
5765   if (aView.IsNull())
5766   {
5767     Message::SendFail ("Error: no active viewer");
5768     return 1;
5769   }
5770   else if (theArgNb < 3)
5771   {
5772     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
5773                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
5774     return 1;
5775   }
5776
5777   Image_Format         aFormat     = Image_Format_RGBA;
5778   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
5779
5780   Standard_Integer aWidth, aHeight;
5781   aView->Window()->Size (aWidth, aHeight);
5782   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
5783   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
5784   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
5785   {
5786     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
5787     return 1;
5788   }
5789
5790   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
5791   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
5792   {
5793     TCollection_AsciiString aParam (theArgVec[anIter]);
5794     aParam.LowerCase();
5795     if (aParam == "-rgb"
5796      || aParam == "rgb"
5797      || aParam == "-srgb"
5798      || aParam == "srgb")
5799     {
5800       aFormat     = Image_Format_RGB;
5801       aBufferType = Graphic3d_BT_RGB;
5802       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
5803     }
5804     else if (aParam == "-hls"
5805           || aParam == "hls")
5806     {
5807       aFormat     = Image_Format_RGB;
5808       aBufferType = Graphic3d_BT_RGB;
5809       toShowHls   = Standard_True;
5810     }
5811     else if (aParam == "-rgbf"
5812           || aParam == "rgbf")
5813     {
5814       aFormat     = Image_Format_RGBF;
5815       aBufferType = Graphic3d_BT_RGB;
5816     }
5817     else if (aParam == "-rgba"
5818           || aParam == "rgba"
5819           || aParam == "-srgba"
5820           || aParam == "srgba")
5821     {
5822       aFormat     = Image_Format_RGBA;
5823       aBufferType = Graphic3d_BT_RGBA;
5824       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
5825     }
5826     else if (aParam == "-rgbaf"
5827           || aParam == "rgbaf")
5828     {
5829       aFormat     = Image_Format_RGBAF;
5830       aBufferType = Graphic3d_BT_RGBA;
5831     }
5832     else if (aParam == "-depth"
5833           || aParam == "depth")
5834     {
5835       aFormat     = Image_Format_GrayF;
5836       aBufferType = Graphic3d_BT_Depth;
5837     }
5838     else if (aParam == "-name"
5839           || aParam == "name")
5840     {
5841       toShowName = Standard_True;
5842     }
5843     else if (aParam == "-hex"
5844           || aParam == "hex")
5845     {
5846       toShowHex = Standard_True;
5847     }
5848     else
5849     {
5850       Message::SendFail() << "Syntax error at '" << aParam << "'";
5851       return 1;
5852     }
5853   }
5854
5855   Image_PixMap anImage;
5856   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
5857   {
5858     Message::SendFail ("Error: image allocation failed");
5859     return 1;
5860   }
5861   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
5862   {
5863     Message::SendFail ("Error: image dump failed");
5864     return 1;
5865   }
5866
5867   // redirect possible warning messages that could have been added by ToPixMap
5868   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
5869   // contaminate result of the command
5870   Standard_CString aWarnLog = theDI.Result();
5871   if (aWarnLog != NULL && aWarnLog[0] != '\0')
5872   {
5873     std::cout << aWarnLog << std::endl;
5874   }
5875   theDI.Reset();
5876
5877   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
5878   if (toShowName)
5879   {
5880     if (aBufferType == Graphic3d_BT_RGBA)
5881     {
5882       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
5883     }
5884     else
5885     {
5886       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
5887     }
5888   }
5889   else if (toShowHex)
5890   {
5891     if (aBufferType == Graphic3d_BT_RGBA)
5892     {
5893       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
5894     }
5895     else
5896     {
5897       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
5898     }
5899   }
5900   else
5901   {
5902     switch (aBufferType)
5903     {
5904       default:
5905       case Graphic3d_BT_RGB:
5906       {
5907         if (toShowHls)
5908         {
5909           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
5910         }
5911         else if (toShow_sRGB)
5912         {
5913           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
5914           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
5915         }
5916         else
5917         {
5918           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
5919         }
5920         break;
5921       }
5922       case Graphic3d_BT_RGBA:
5923       {
5924         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
5925         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
5926         break;
5927       }
5928       case Graphic3d_BT_Depth:
5929       {
5930         theDI << aColor.GetRGB().Red();
5931         break;
5932       }
5933     }
5934   }
5935
5936   return 0;
5937 }
5938
5939 //! Auxiliary presentation for an image plane.
5940 class ViewerTest_ImagePrs : public AIS_InteractiveObject
5941 {
5942 public:
5943   //! Main constructor.
5944   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
5945                        const Standard_Real theWidth,
5946                        const Standard_Real theHeight,
5947                        const TCollection_AsciiString& theLabel)
5948   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
5949   {
5950     SetDisplayMode (0);
5951     SetHilightMode (1);
5952     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
5953     {
5954       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
5955       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
5956       Graphic3d_MaterialAspect aMat;
5957       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
5958       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
5959       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
5960       aMat.SetSpecularColor (Quantity_NOC_BLACK);
5961       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
5962       aFillAspect->SetFrontMaterial (aMat);
5963       aFillAspect->SetTextureMap (new Graphic3d_Texture2D (theImage));
5964       aFillAspect->SetTextureMapOn();
5965     }
5966     {
5967       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
5968       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
5969       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
5970       myDrawer->SetTextAspect (aTextAspect);
5971     }
5972     {
5973       const gp_Dir aNorm (0.0, 0.0, 1.0);
5974       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
5975       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
5976       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
5977       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
5978       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
5979       myTris->AddEdge (1);
5980       myTris->AddEdge (2);
5981       myTris->AddEdge (3);
5982       myTris->AddEdge (3);
5983       myTris->AddEdge (2);
5984       myTris->AddEdge (4);
5985
5986       myRect = new Graphic3d_ArrayOfPolylines (4);
5987       myRect->AddVertex (myTris->Vertice (1));
5988       myRect->AddVertex (myTris->Vertice (3));
5989       myRect->AddVertex (myTris->Vertice (4));
5990       myRect->AddVertex (myTris->Vertice (2));
5991     }
5992   }
5993
5994   //! Returns TRUE for accepted display modes.
5995   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
5996
5997   //! Compute presentation.
5998   virtual void Compute (const Handle(PrsMgr_PresentationManager)& ,
5999                         const Handle(Prs3d_Presentation)& thePrs,
6000                         const Standard_Integer theMode) Standard_OVERRIDE
6001   {
6002     switch (theMode)
6003     {
6004       case 0:
6005       {
6006         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
6007         aGroup->AddPrimitiveArray (myTris);
6008         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
6009         aGroup->AddPrimitiveArray (myRect);
6010         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
6011         return;
6012       }
6013       case 1:
6014       {
6015         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
6016         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
6017         aGroup->AddPrimitiveArray (myRect);
6018         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
6019         return;
6020       }
6021     }
6022   }
6023
6024   //! Compute selection.
6025   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
6026   {
6027     if (theMode == 0)
6028     {
6029       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
6030       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
6031       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
6032       theSel->Add (aSensitive);
6033     }
6034   }
6035
6036 private:
6037   Handle(Graphic3d_ArrayOfTriangles) myTris;
6038   Handle(Graphic3d_ArrayOfPolylines) myRect;
6039   TCollection_AsciiString myLabel;
6040   Standard_Real myWidth;
6041   Standard_Real myHeight;
6042 };
6043
6044 //==============================================================================
6045 //function : VDiffImage
6046 //purpose  : The draw-command compares two images.
6047 //==============================================================================
6048
6049 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
6050 {
6051   if (theArgNb < 3)
6052   {
6053     Message::SendFail ("Syntax error: not enough arguments");
6054     return 1;
6055   }
6056
6057   Standard_Integer anArgIter = 1;
6058   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
6059   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
6060   TCollection_AsciiString aDiffImagePath;
6061   Standard_Real    aTolColor        = -1.0;
6062   Standard_Integer toBlackWhite     = -1;
6063   Standard_Integer isBorderFilterOn = -1;
6064   Standard_Boolean isOldSyntax = Standard_False;
6065   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
6066   for (; anArgIter < theArgNb; ++anArgIter)
6067   {
6068     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6069     anArg.LowerCase();
6070     if (anArgIter + 1 < theArgNb
6071      && (anArg == "-toleranceofcolor"
6072       || anArg == "-tolerancecolor"
6073       || anArg == "-tolerance"
6074       || anArg == "-toler"))
6075     {
6076       aTolColor = Atof (theArgVec[++anArgIter]);
6077       if (aTolColor < 0.0 || aTolColor > 1.0)
6078       {
6079         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6080         return 1;
6081       }
6082     }
6083     else if (anArg == "-blackwhite")
6084     {
6085       Standard_Boolean toEnable = Standard_True;
6086       if (anArgIter + 1 < theArgNb
6087        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6088       {
6089         ++anArgIter;
6090       }
6091       toBlackWhite = toEnable ? 1 : 0;
6092     }
6093     else if (anArg == "-borderfilter")
6094     {
6095       Standard_Boolean toEnable = Standard_True;
6096       if (anArgIter + 1 < theArgNb
6097        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6098       {
6099         ++anArgIter;
6100       }
6101       isBorderFilterOn = toEnable ? 1 : 0;
6102     }
6103     else if (anArg == "-exitonclose")
6104     {
6105       ViewerTest_EventManager::ToExitOnCloseView() = true;
6106       if (anArgIter + 1 < theArgNb
6107        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
6108       {
6109         ++anArgIter;
6110       }
6111     }
6112     else if (anArg == "-closeonescape"
6113           || anArg == "-closeonesc")
6114     {
6115       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
6116       if (anArgIter + 1 < theArgNb
6117        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
6118       {
6119         ++anArgIter;
6120       }
6121     }
6122     else if (anArgIter + 3 < theArgNb
6123           && anArg == "-display")
6124     {
6125       aViewName   = theArgVec[++anArgIter];
6126       aPrsNameRef = theArgVec[++anArgIter];
6127       aPrsNameNew = theArgVec[++anArgIter];
6128       if (anArgIter + 1 < theArgNb
6129       && *theArgVec[anArgIter + 1] != '-')
6130       {
6131         aPrsNameDiff = theArgVec[++anArgIter];
6132       }
6133     }
6134     else if (aTolColor < 0.0
6135           && anArg.IsRealValue (Standard_True))
6136     {
6137       isOldSyntax = Standard_True;
6138       aTolColor = anArg.RealValue();
6139       if (aTolColor < 0.0 || aTolColor > 1.0)
6140       {
6141         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6142         return 1;
6143       }
6144     }
6145     else if (isOldSyntax
6146           && toBlackWhite == -1
6147           && (anArg == "0" || anArg == "1"))
6148     {
6149       toBlackWhite = anArg == "1" ? 1 : 0;
6150     }
6151     else if (isOldSyntax
6152           && isBorderFilterOn == -1
6153           && (anArg == "0" || anArg == "1"))
6154     {
6155       isBorderFilterOn = anArg == "1" ? 1 : 0;
6156     }
6157     else if (aDiffImagePath.IsEmpty())
6158     {
6159       aDiffImagePath = theArgVec[anArgIter];
6160     }
6161     else
6162     {
6163       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6164       return 1;
6165     }
6166   }
6167
6168   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
6169   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
6170   if (!anImgRef->Load (anImgPathRef))
6171   {
6172     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
6173     return 1;
6174   }
6175   if (!anImgNew->Load (anImgPathNew))
6176   {
6177     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
6178     return 1;
6179   }
6180
6181   // compare the images
6182   Image_Diff aComparer;
6183   Standard_Integer aDiffColorsNb = -1;
6184   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
6185   {
6186     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
6187     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
6188     aDiffColorsNb = aComparer.Compare();
6189     theDI << aDiffColorsNb << "\n";
6190   }
6191
6192   // save image of difference
6193   Handle(Image_AlienPixMap) aDiff;
6194   if (aDiffColorsNb > 0
6195   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
6196   {
6197     aDiff = new Image_AlienPixMap();
6198     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
6199     {
6200       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
6201       return 1;
6202     }
6203     aComparer.SaveDiffImage (*aDiff);
6204     if (!aDiffImagePath.IsEmpty()
6205      && !aDiff->Save (aDiffImagePath))
6206     {
6207       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
6208       return 1;
6209     }
6210   }
6211
6212   if (aViewName.IsEmpty())
6213   {
6214     return 0;
6215   }
6216
6217   ViewerTest_Names aViewNames (aViewName);
6218   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
6219   {
6220     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
6221     theDI.Eval (aCommand.ToCString());
6222   }
6223
6224   ViewerTest_VinitParams aParams;
6225   aParams.ViewName = aViewName;
6226   aParams.Size.x() = float(anImgRef->SizeX() * 2);
6227   aParams.Size.y() = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
6228                    ? float(anImgRef->SizeY() * 2)
6229                    : float(anImgRef->SizeY());
6230   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aParams);
6231
6232   Standard_Real aRatio = anImgRef->Ratio();
6233   Standard_Real aSizeX = 1.0;
6234   Standard_Real aSizeY = aSizeX / aRatio;
6235   {
6236     OSD_Path aPath (anImgPathRef);
6237     TCollection_AsciiString aLabelRef;
6238     if (!aPath.Name().IsEmpty())
6239     {
6240       aLabelRef = aPath.Name() + aPath.Extension();
6241     }
6242     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
6243
6244     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
6245     gp_Trsf aTrsfRef;
6246     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
6247     anImgRefPrs->SetLocalTransformation (aTrsfRef);
6248     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
6249   }
6250   {
6251     OSD_Path aPath (anImgPathNew);
6252     TCollection_AsciiString aLabelNew;
6253     if (!aPath.Name().IsEmpty())
6254     {
6255       aLabelNew = aPath.Name() + aPath.Extension();
6256     }
6257     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
6258
6259     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
6260     gp_Trsf aTrsfRef;
6261     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
6262     anImgNewPrs->SetLocalTransformation (aTrsfRef);
6263     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
6264   }
6265   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
6266   if (!aDiff.IsNull())
6267   {
6268     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
6269     gp_Trsf aTrsfDiff;
6270     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
6271     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
6272   }
6273   if (!aPrsNameDiff.IsEmpty())
6274   {
6275     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
6276   }
6277   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
6278   ViewerTest::CurrentView()->FitAll();
6279   return 0;
6280 }
6281
6282 //=======================================================================
6283 //function : VSelect
6284 //purpose  : Emulates different types of selection by mouse:
6285 //           1) single click selection
6286 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
6287 //           3) selection with polygon having corners at
6288 //           pixel positions (x1,y1),...,(xn,yn)
6289 //           4) any of these selections with shift button pressed
6290 //=======================================================================
6291 static Standard_Integer VSelect (Draw_Interpretor& ,
6292                                  Standard_Integer theNbArgs,
6293                                  const char** theArgVec)
6294 {
6295   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
6296   if (aCtx.IsNull())
6297   {
6298     Message::SendFail ("Error: no active viewer");
6299     return 1;
6300   }
6301
6302   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
6303   bool toAllowOverlap = false;
6304   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
6305   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6306   {
6307     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6308     anArg.LowerCase();
6309     if (anArg == "-allowoverlap")
6310     {
6311       toAllowOverlap = true;
6312       if (anArgIter + 1 < theNbArgs
6313        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
6314       {
6315         ++anArgIter;
6316       }
6317     }
6318     else if (anArg == "-replace")
6319     {
6320       aSelScheme = AIS_SelectionScheme_Replace;
6321     }
6322     else if (anArg == "-replaceextra")
6323     {
6324       aSelScheme = AIS_SelectionScheme_ReplaceExtra;
6325     }
6326     else if (anArg == "-xor"
6327           || anArg == "-shift")
6328     {
6329       aSelScheme = AIS_SelectionScheme_XOR;
6330     }
6331     else if (anArg == "-add")
6332     {
6333       aSelScheme = AIS_SelectionScheme_Add;
6334     }
6335     else if (anArg == "-remove")
6336     {
6337       aSelScheme = AIS_SelectionScheme_Remove;
6338     }
6339     else if (anArgIter + 1 < theNbArgs
6340           && anArg.IsIntegerValue()
6341           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
6342     {
6343       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
6344       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
6345     }
6346     else if (anArgIter + 1 == theNbArgs
6347           && anArg.IsIntegerValue())
6348     {
6349       if (anArg.IntegerValue() == 1)
6350       {
6351         aSelScheme = AIS_SelectionScheme_XOR;
6352       }
6353     }
6354     else
6355     {
6356       Message::SendFail() << "Syntax error at '" << anArg << "'";
6357       return 1;
6358     }
6359   }
6360
6361   if (toAllowOverlap)
6362   {
6363     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
6364   }
6365
6366   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
6367   if (aPnts.IsEmpty())
6368   {
6369     aCtx->SelectDetected (aSelScheme);
6370     aCtx->CurrentViewer()->Invalidate();
6371   }
6372   else if (aPnts.Length() == 2)
6373   {
6374     if (toAllowOverlap
6375      && aPnts.First().y() < aPnts.Last().y())
6376     {
6377       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6378     }
6379     else if (!toAllowOverlap
6380            && aPnts.First().y() > aPnts.Last().y())
6381     {
6382       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6383     }
6384
6385     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6386   }
6387   else
6388   {
6389     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6390   }
6391   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
6392   return 0;
6393 }
6394
6395 //=======================================================================
6396 //function : VMoveTo
6397 //purpose  : Emulates cursor movement to defined pixel position
6398 //=======================================================================
6399 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
6400                                 Standard_Integer theNbArgs,
6401                                 const char**     theArgVec)
6402 {
6403   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6404   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6405   if (aContext.IsNull())
6406   {
6407     Message::SendFail ("Error: no active viewer");
6408     return 1;
6409   }
6410
6411   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
6412   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6413   {
6414     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6415     anArgStr.LowerCase();
6416     if (anArgStr == "-reset"
6417      || anArgStr == "-clear")
6418     {
6419       if (anArgIter + 1 < theNbArgs)
6420       {
6421         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
6422         return 1;
6423       }
6424
6425       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
6426                                        && aContext->CurrentViewer()->GridEcho();
6427       if (toEchoGrid)
6428       {
6429         aContext->CurrentViewer()->HideGridEcho (aView);
6430       }
6431       if (aContext->ClearDetected() || toEchoGrid)
6432       {
6433         aContext->CurrentViewer()->RedrawImmediate();
6434       }
6435       return 0;
6436     }
6437     else if (aMousePos.x() == IntegerLast()
6438           && anArgStr.IsIntegerValue())
6439     {
6440       aMousePos.x() = anArgStr.IntegerValue();
6441     }
6442     else if (aMousePos.y() == IntegerLast()
6443           && anArgStr.IsIntegerValue())
6444     {
6445       aMousePos.y() = anArgStr.IntegerValue();
6446     }
6447     else
6448     {
6449       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6450       return 1;
6451     }
6452   }
6453
6454   if (aMousePos.x() == IntegerLast()
6455    || aMousePos.y() == IntegerLast())
6456   {
6457     Message::SendFail ("Syntax error: wrong number of arguments");
6458     return 1;
6459   }
6460
6461   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
6462   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
6463   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
6464
6465   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
6466   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
6467   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
6468   {
6469     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
6470     {
6471       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
6472       break;
6473     }
6474   }
6475   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
6476   return 0;
6477 }
6478
6479 //=======================================================================
6480 //function : VSelectByAxis
6481 //purpose  :
6482 //=======================================================================
6483 static Standard_Integer VSelectByAxis (Draw_Interpretor& theDI,
6484                                        Standard_Integer theNbArgs,
6485                                        const char**     theArgVec)
6486 {
6487   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6488   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6489   if (aContext.IsNull())
6490   {
6491     Message::SendFail ("Error: no active viewer");
6492     return 1;
6493   }
6494
6495   TCollection_AsciiString aName;
6496   gp_XYZ anAxisLocation(RealLast(), RealLast(), RealLast());
6497   gp_XYZ anAxisDirection(RealLast(), RealLast(), RealLast());
6498   Standard_Boolean isOnlyTop = true;
6499   Standard_Boolean toShowNormal = false;
6500   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6501   {
6502     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6503     anArgStr.LowerCase();
6504     if (anArgStr == "-display")
6505     {
6506       if (anArgIter + 1 >= theNbArgs)
6507       {
6508         Message::SendFail() << "Syntax error at argument '" << anArgStr << "'";
6509         return 1;
6510       }
6511       aName = theArgVec[++anArgIter];
6512     }
6513     else if (anArgStr == "-onlytop")
6514     {
6515       isOnlyTop = true;
6516       if (anArgIter + 1 < theNbArgs
6517         && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOnlyTop))
6518       {
6519         ++anArgIter;
6520       }
6521     }
6522     else if (anArgStr == "-shownormal")
6523     {
6524       toShowNormal = true;
6525       if (anArgIter + 1 < theNbArgs
6526         && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShowNormal))
6527       {
6528         ++anArgIter;
6529       }
6530     }
6531     else if (Precision::IsInfinite(anAxisLocation.X())
6532           && anArgStr.IsRealValue())
6533     {
6534       anAxisLocation.SetX (anArgStr.RealValue());
6535     }
6536     else if (Precision::IsInfinite(anAxisLocation.Y())
6537           && anArgStr.IsRealValue())
6538     {
6539       anAxisLocation.SetY (anArgStr.RealValue());
6540     }
6541     else if (Precision::IsInfinite(anAxisLocation.Z())
6542           && anArgStr.IsRealValue())
6543     {
6544       anAxisLocation.SetZ (anArgStr.RealValue());
6545     }
6546     else if (Precision::IsInfinite(anAxisDirection.X())
6547           && anArgStr.IsRealValue())
6548     {
6549       anAxisDirection.SetX (anArgStr.RealValue());
6550     }
6551     else if (Precision::IsInfinite(anAxisDirection.Y())
6552           && anArgStr.IsRealValue())
6553     {
6554       anAxisDirection.SetY (anArgStr.RealValue());
6555     }
6556     else if (Precision::IsInfinite(anAxisDirection.Z())
6557           && anArgStr.IsRealValue())
6558     {
6559       anAxisDirection.SetZ (anArgStr.RealValue());
6560     }
6561     else
6562     {
6563       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6564       return 1;
6565     }
6566   }
6567
6568   if (Precision::IsInfinite (anAxisLocation.X()) ||
6569       Precision::IsInfinite (anAxisLocation.Y()) ||
6570       Precision::IsInfinite (anAxisLocation.Z()) ||
6571       Precision::IsInfinite (anAxisDirection.X()) ||
6572       Precision::IsInfinite (anAxisDirection.Y()) ||
6573       Precision::IsInfinite (anAxisDirection.Z()))
6574   {
6575     Message::SendFail() << "Invalid axis location and direction";
6576     return 1;
6577   }
6578
6579   gp_Ax1 anAxis(anAxisLocation, anAxisDirection);
6580   gp_Pnt aTopPnt;
6581   if (!ViewerTest::CurrentEventManager()->PickAxis (aTopPnt, aContext, aView, anAxis))
6582   {
6583     theDI << "There are no any intersections with this axis.";
6584     return 0;
6585   }
6586   NCollection_Sequence<gp_Pnt> aPoints;
6587   NCollection_Sequence<Graphic3d_Vec3> aNormals;
6588   NCollection_Sequence<Standard_Real> aNormalLengths;
6589   for (Standard_Integer aPickIter = 1; aPickIter <= aContext->MainSelector()->NbPicked(); ++aPickIter)
6590   {
6591     const SelectMgr_SortCriterion& aPickedData = aContext->MainSelector()->PickedData (aPickIter);
6592     aPoints.Append (aPickedData.Point);
6593     aNormals.Append (aPickedData.Normal);
6594     Standard_Real aNormalLength = 1.0;
6595     if (!aPickedData.Entity.IsNull())
6596     {
6597       aNormalLength = 0.2 * aPickedData.Entity->BoundingBox().Size().maxComp();
6598     }
6599     aNormalLengths.Append (aNormalLength);
6600   }
6601   if (!aName.IsEmpty())
6602   {
6603     Standard_Boolean wasAuto = aContext->GetAutoActivateSelection();
6604     aContext->SetAutoActivateSelection (false);
6605
6606     // Display axis
6607     Quantity_Color anAxisColor = Quantity_NOC_GREEN;
6608     Handle(Geom_Axis2Placement) anAx2Axis =
6609       new Geom_Axis2Placement (gp_Ax2(anAxisLocation, anAxisDirection));
6610     Handle(AIS_Axis) anAISAxis = new AIS_Axis (gp_Ax1 (anAxisLocation, anAxisDirection));
6611     anAISAxis->SetColor (anAxisColor);
6612     ViewerTest::Display (TCollection_AsciiString (aName) + "_axis", anAISAxis, false);
6613
6614     // Display axis start point
6615     Handle(AIS_Point) anAISStartPnt = new AIS_Point (new Geom_CartesianPoint (anAxisLocation));
6616     anAISStartPnt->SetMarker (Aspect_TOM_O);
6617     anAISStartPnt->SetColor (anAxisColor);
6618     ViewerTest::Display (TCollection_AsciiString(aName) + "_start", anAISStartPnt, false);
6619
6620     Standard_Integer anIndex = 0;
6621     for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter(aPoints); aPntIter.More(); aPntIter.Next(), anIndex++)
6622     {
6623       const gp_Pnt& aPoint = aPntIter.Value();
6624
6625       // Display normals in intersection points
6626       if (toShowNormal)
6627       {
6628         const Graphic3d_Vec3& aNormal = aNormals.Value (anIndex + 1);
6629         Standard_Real aNormalLength = aNormalLengths.Value (anIndex + 1);
6630         if (aNormal.SquareModulus() > ShortRealEpsilon())
6631         {
6632           gp_Dir aNormalDir ((Standard_Real)aNormal.x(), (Standard_Real)aNormal.y(), (Standard_Real)aNormal.z());
6633           Handle(AIS_Axis) anAISNormal = new AIS_Axis (gp_Ax1 (aPoint, aNormalDir), aNormalLength);
6634           anAISNormal->SetColor (Quantity_NOC_BLUE);
6635           anAISNormal->SetInfiniteState (false);
6636           ViewerTest::Display (TCollection_AsciiString(aName) + "_normal_" + anIndex, anAISNormal, false);
6637         }
6638       }
6639
6640       // Display intersection points
6641       Handle(Geom_CartesianPoint) anIntersectPnt = new Geom_CartesianPoint (aPoint);
6642       Handle(AIS_Point) anAISIntersectPoint = new AIS_Point (anIntersectPnt);
6643       anAISIntersectPoint->SetMarker (Aspect_TOM_PLUS);
6644       anAISIntersectPoint->SetColor (Quantity_NOC_RED);
6645       ViewerTest::Display (TCollection_AsciiString(aName) + "_intersect_" + anIndex, anAISIntersectPoint, true);
6646     }
6647
6648     aContext->SetAutoActivateSelection (wasAuto);
6649   }
6650
6651   Standard_Integer anIndex = 0;
6652   for (NCollection_Sequence<gp_Pnt>::Iterator anIter(aPoints); anIter.More(); anIter.Next(), anIndex++)
6653   {
6654     const gp_Pnt& aPnt = anIter.Value();
6655     theDI << aPnt.X() << " " << aPnt.Y() << " " << aPnt.Z() << "\n";
6656   }
6657   return 0;
6658 }
6659
6660 namespace
6661 {
6662   //! Global map storing all animations registered in ViewerTest.
6663   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
6664
6665   //! The animation calling the Draw Harness command.
6666   class ViewerTest_AnimationProc : public AIS_Animation
6667   {
6668     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationProc, AIS_Animation)
6669   public:
6670
6671     //! Main constructor.
6672     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
6673                               Draw_Interpretor* theDI,
6674                               const TCollection_AsciiString& theCommand)
6675     : AIS_Animation (theAnimationName),
6676       myDrawInter(theDI),
6677       myCommand  (theCommand)
6678     {
6679       //
6680     }
6681
6682   protected:
6683
6684     //! Evaluate the command.
6685     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
6686     {
6687       TCollection_AsciiString aCmd = myCommand;
6688       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
6689       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
6690       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
6691       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
6692       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
6693       myDrawInter->Eval (aCmd.ToCString());
6694     }
6695
6696     //! Find the keyword in the command and replace it with value.
6697     //! @return the position of the keyword to pass value
6698     void replace (TCollection_AsciiString&       theCmd,
6699                   const TCollection_AsciiString& theKey,
6700                   const TCollection_AsciiString& theVal)
6701     {
6702       TCollection_AsciiString aCmd (theCmd);
6703       aCmd.LowerCase();
6704       const Standard_Integer aPos = aCmd.Search (theKey);
6705       if (aPos == -1)
6706       {
6707         return;
6708       }
6709
6710       TCollection_AsciiString aPart1, aPart2;
6711       Standard_Integer aPart1To = aPos - 1;
6712       if (aPart1To >= 1
6713        && aPart1To <= theCmd.Length())
6714       {
6715         aPart1 = theCmd.SubString (1, aPart1To);
6716       }
6717
6718       Standard_Integer aPart2From = aPos + theKey.Length();
6719       if (aPart2From >= 1
6720        && aPart2From <= theCmd.Length())
6721       {
6722         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
6723       }
6724
6725       theCmd = aPart1 + theVal + aPart2;
6726     }
6727
6728   protected:
6729
6730     Draw_Interpretor*       myDrawInter;
6731     TCollection_AsciiString myCommand;
6732
6733   };
6734
6735   //! Auxiliary animation holder.
6736   class ViewerTest_AnimationHolder : public AIS_AnimationCamera
6737   {
6738     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationHolder, AIS_AnimationCamera)
6739   public:
6740     ViewerTest_AnimationHolder (const Handle(AIS_Animation)& theAnim,
6741                                 const Handle(V3d_View)& theView,
6742                                 const Standard_Boolean theIsFreeView)
6743     : AIS_AnimationCamera ("ViewerTest_AnimationHolder", Handle(V3d_View)())
6744     {
6745       if (theAnim->Timer().IsNull())
6746       {
6747         theAnim->SetTimer (new Media_Timer());
6748       }
6749       myTimer = theAnim->Timer();
6750       myView = theView;
6751       if (theIsFreeView)
6752       {
6753         myCamStart = new Graphic3d_Camera (theView->Camera());
6754       }
6755       Add (theAnim);
6756     }
6757
6758     //! Start playback.
6759     virtual void StartTimer (const Standard_Real    theStartPts,
6760                              const Standard_Real    thePlaySpeed,
6761                              const Standard_Boolean theToUpdate,
6762                              const Standard_Boolean theToStopTimer) Standard_OVERRIDE
6763     {
6764       base_type::StartTimer (theStartPts, thePlaySpeed, theToUpdate, theToStopTimer);
6765       if (theToStopTimer)
6766       {
6767         abortPlayback();
6768       }
6769     }
6770
6771     //! Pause animation.
6772     virtual void Pause() Standard_OVERRIDE
6773     {
6774       myState = AnimationState_Paused;
6775       // default implementation would stop all children,
6776       // but we want to keep wrapped animation paused
6777       myAnimations.First()->Pause();
6778       abortPlayback();
6779     }
6780
6781     //! Stop animation.
6782     virtual void Stop() Standard_OVERRIDE
6783     {
6784       base_type::Stop();
6785       abortPlayback();
6786     }
6787
6788     //! Process one step of the animation according to the input time progress, including all children.
6789     virtual void updateWithChildren (const AIS_AnimationProgress& thePosition) Standard_OVERRIDE
6790     {
6791       Handle(V3d_View) aView = myView;
6792       if (!aView.IsNull()
6793        && !myCamStart.IsNull())
6794       {
6795         myCamStart->Copy (aView->Camera());
6796       }
6797       base_type::updateWithChildren (thePosition);
6798       if (!aView.IsNull()
6799        && !myCamStart.IsNull())
6800       {
6801         aView->Camera()->Copy (myCamStart);
6802       }
6803     }
6804   private:
6805     void abortPlayback()
6806     {
6807       if (!myView.IsNull())
6808       {
6809         myView.Nullify();
6810       }
6811     }
6812   };
6813
6814   //! Replace the animation with the new one.
6815   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
6816                                 Handle(AIS_Animation)&       theAnimation,
6817                                 const Handle(AIS_Animation)& theAnimationNew)
6818   {
6819     theAnimationNew->CopyFrom (theAnimation);
6820     if (!theParentAnimation.IsNull())
6821     {
6822       theParentAnimation->Replace (theAnimation, theAnimationNew);
6823     }
6824     else
6825     {
6826       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
6827       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
6828     }
6829     theAnimation = theAnimationNew;
6830   }
6831
6832   //! Parse the point.
6833   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
6834   {
6835     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
6836     if (!anXYZ[0].IsRealValue (Standard_True)
6837      || !anXYZ[1].IsRealValue (Standard_True)
6838      || !anXYZ[2].IsRealValue (Standard_True))
6839     {
6840       return Standard_False;
6841     }
6842
6843     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
6844     return Standard_True;
6845   }
6846
6847   //! Parse the quaternion.
6848   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
6849   {
6850     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
6851     if (!anXYZW[0].IsRealValue (Standard_True)
6852      || !anXYZW[1].IsRealValue (Standard_True)
6853      || !anXYZW[2].IsRealValue (Standard_True)
6854      || !anXYZW[3].IsRealValue (Standard_True))
6855     {
6856       return Standard_False;
6857     }
6858
6859     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
6860     return Standard_True;
6861   }
6862
6863   //! Auxiliary class for flipping image upside-down.
6864   class ImageFlipper
6865   {
6866   public:
6867
6868     //! Empty constructor.
6869     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
6870
6871     //! Perform flipping.
6872     Standard_Boolean FlipY (Image_PixMap& theImage)
6873     {
6874       if (theImage.IsEmpty()
6875        || theImage.SizeX() == 0
6876        || theImage.SizeY() == 0)
6877       {
6878         return Standard_False;
6879       }
6880
6881       const Standard_Size aRowSize = theImage.SizeRowBytes();
6882       if (myTmp.Size() < aRowSize
6883       && !myTmp.Allocate (aRowSize))
6884       {
6885         return Standard_False;
6886       }
6887
6888       // for odd height middle row should be left as is
6889       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
6890       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
6891       {
6892         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
6893         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
6894         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
6895         memcpy (aTop,               aBot,         aRowSize);
6896         memcpy (aBot,               myTmp.Data(), aRowSize);
6897       }
6898       return Standard_True;
6899     }
6900
6901   private:
6902     NCollection_Buffer myTmp;
6903   };
6904
6905 }
6906
6907 //=================================================================================================
6908 //function : VViewParams
6909 //purpose  : Gets or sets AIS View characteristics
6910 //=================================================================================================
6911 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
6912 {
6913   Handle(V3d_View) aView = ViewerTest::CurrentView();
6914   if (aView.IsNull())
6915   {
6916     Message::SendFail ("Error: no active viewer");
6917     return 1;
6918   }
6919
6920   Standard_Boolean toSetProj     = Standard_False;
6921   Standard_Boolean toSetUp       = Standard_False;
6922   Standard_Boolean toSetAt       = Standard_False;
6923   Standard_Boolean toSetEye      = Standard_False;
6924   Standard_Boolean toSetScale    = Standard_False;
6925   Standard_Boolean toSetSize     = Standard_False;
6926   Standard_Boolean toSetCenter2d = Standard_False;
6927   Standard_Real    aViewScale = aView->Scale();
6928   Standard_Real    aViewAspect = aView->Camera()->Aspect();
6929   Standard_Real    aViewSize  = 1.0;
6930   Graphic3d_Vec2i  aCenter2d;
6931   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
6932   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
6933   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
6934   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
6935   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
6936   const Graphic3d_Mat4d& anOrientMat = aView->Camera()->OrientationMatrix();
6937   const Graphic3d_Mat4d& aProjMat = aView->Camera()->ProjectionMatrix();
6938   if (theArgsNb == 1)
6939   {
6940     // print all of the available view parameters
6941     char aText[4096];
6942     Sprintf (aText,
6943              "Scale:  %g\n"
6944              "Aspect: %g\n"
6945              "Proj:   %12g %12g %12g\n"
6946              "Up:     %12g %12g %12g\n"
6947              "At:     %12g %12g %12g\n"
6948              "Eye:    %12g %12g %12g\n"
6949              "OrientMat:    %12g %12g %12g %12g\n"
6950              "              %12g %12g %12g %12g\n"
6951              "              %12g %12g %12g %12g\n"
6952              "              %12g %12g %12g %12g\n"
6953              "ProjMat:      %12g %12g %12g %12g\n"
6954              "              %12g %12g %12g %12g\n"
6955              "              %12g %12g %12g %12g\n"
6956              "              %12g %12g %12g %12g\n",
6957               aViewScale, aViewAspect,
6958               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6959               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6960               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
6961               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z(),
6962               anOrientMat.GetValue (0, 0), anOrientMat.GetValue (0, 1), anOrientMat.GetValue (0, 2), anOrientMat.GetValue (0, 3),
6963               anOrientMat.GetValue (1, 0), anOrientMat.GetValue (1, 1), anOrientMat.GetValue (1, 2), anOrientMat.GetValue (1, 3),
6964               anOrientMat.GetValue (2, 0), anOrientMat.GetValue (2, 1), anOrientMat.GetValue (2, 2), anOrientMat.GetValue (2, 3),
6965               anOrientMat.GetValue (3, 0), anOrientMat.GetValue (3, 1), anOrientMat.GetValue (3, 2), anOrientMat.GetValue (3, 3),
6966               aProjMat.GetValue (0, 0), aProjMat.GetValue (0, 1), aProjMat.GetValue (0, 2), aProjMat.GetValue (0, 3),
6967               aProjMat.GetValue (1, 0), aProjMat.GetValue (1, 1), aProjMat.GetValue (1, 2), aProjMat.GetValue (1, 3),
6968               aProjMat.GetValue (2, 0), aProjMat.GetValue (2, 1), aProjMat.GetValue (2, 2), aProjMat.GetValue (2, 3),
6969               aProjMat.GetValue (3, 0), aProjMat.GetValue (3, 1), aProjMat.GetValue (3, 2), aProjMat.GetValue (3, 3));
6970     theDi << aText;
6971     return 0;
6972   }
6973
6974   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
6975   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
6976   {
6977     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6978     anArg.LowerCase();
6979     if (anUpdateTool.parseRedrawMode (anArg))
6980     {
6981       continue;
6982     }
6983     else if (anArg == "-cmd"
6984           || anArg == "-command"
6985           || anArg == "-args")
6986     {
6987       char aText[4096];
6988       Sprintf (aText,
6989                "-scale %g "
6990                "-proj %g %g %g "
6991                "-up %g %g %g "
6992                "-at %g %g %g\n",
6993                 aViewScale,
6994                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6995                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6996                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
6997       theDi << aText;
6998     }
6999     else if (anArg == "-scale"
7000           || anArg == "-size")
7001     {
7002       if (anArgIter + 1 < theArgsNb
7003        && *theArgVec[anArgIter + 1] != '-')
7004       {
7005         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7006         if (aValueArg.IsRealValue (Standard_True))
7007         {
7008           ++anArgIter;
7009           if (anArg == "-scale")
7010           {
7011             toSetScale = Standard_True;
7012             aViewScale = aValueArg.RealValue();
7013           }
7014           else if (anArg == "-size")
7015           {
7016             toSetSize = Standard_True;
7017             aViewSize = aValueArg.RealValue();
7018           }
7019           continue;
7020         }
7021       }
7022       if (anArg == "-scale")
7023       {
7024         theDi << "Scale: " << aView->Scale() << "\n";
7025       }
7026       else if (anArg == "-size")
7027       {
7028         Graphic3d_Vec2d aSizeXY;
7029         aView->Size (aSizeXY.x(), aSizeXY.y());
7030         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
7031       }
7032     }
7033     else if (anArg == "-eye"
7034           || anArg == "-at"
7035           || anArg == "-up"
7036           || anArg == "-proj")
7037     {
7038       if (anArgIter + 3 < theArgsNb)
7039       {
7040         gp_XYZ anXYZ;
7041         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
7042         {
7043           anArgIter += 3;
7044           if (anArg == "-eye")
7045           {
7046             toSetEye = Standard_True;
7047             aViewEye = anXYZ;
7048           }
7049           else if (anArg == "-at")
7050           {
7051             toSetAt = Standard_True;
7052             aViewAt = anXYZ;
7053           }
7054           else if (anArg == "-up")
7055           {
7056             toSetUp = Standard_True;
7057             aViewUp = anXYZ;
7058           }
7059           else if (anArg == "-proj")
7060           {
7061             toSetProj = Standard_True;
7062             aViewProj = anXYZ;
7063           }
7064           continue;
7065         }
7066       }
7067
7068       if (anArg == "-eye")
7069       {
7070         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
7071       }
7072       else if (anArg == "-at")
7073       {
7074         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
7075       }
7076       else if (anArg == "-up")
7077       {
7078         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
7079       }
7080       else if (anArg == "-proj")
7081       {
7082         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
7083       }
7084     }
7085     else if (anArg == "-center")
7086     {
7087       if (anArgIter + 2 < theArgsNb)
7088       {
7089         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
7090         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
7091         if (anX.IsIntegerValue()
7092          && anY.IsIntegerValue())
7093         {
7094           toSetCenter2d = Standard_True;
7095           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
7096         }
7097       }
7098     }
7099     else
7100     {
7101       Message::SendFail() << "Syntax error at '" << anArg << "'";
7102       return 1;
7103     }
7104   }
7105
7106   // change view parameters in proper order
7107   if (toSetScale)
7108   {
7109     aView->SetScale (aViewScale);
7110   }
7111   if (toSetSize)
7112   {
7113     aView->SetSize (aViewSize);
7114   }
7115   if (toSetEye)
7116   {
7117     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
7118   }
7119   if (toSetAt)
7120   {
7121     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
7122   }
7123   if (toSetProj)
7124   {
7125     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
7126   }
7127   if (toSetUp)
7128   {
7129     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
7130   }
7131   if (toSetCenter2d)
7132   {
7133     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
7134   }
7135
7136   return 0;
7137 }
7138
7139 //==============================================================================
7140 //function : V2DMode
7141 //purpose  :
7142 //==============================================================================
7143 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
7144 {
7145   bool is2dMode = true;
7146   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
7147   if (aV3dView.IsNull())
7148   {
7149     Message::SendFail ("Error: no active viewer");
7150     return 1;
7151   }
7152   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
7153   {
7154     const TCollection_AsciiString anArg = theArgVec[anArgIt];
7155     TCollection_AsciiString anArgCase = anArg;
7156     anArgCase.LowerCase();
7157     if (anArgIt + 1 < theArgsNb
7158      && anArgCase == "-name")
7159     {
7160       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
7161       TCollection_AsciiString aViewName = aViewNames.GetViewName();
7162       if (!ViewerTest_myViews.IsBound1 (aViewName))
7163       {
7164         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
7165         return 1;
7166       }
7167       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
7168     }
7169     else if (anArgCase == "-mode")
7170     {
7171       if (anArgIt + 1 < theArgsNb
7172        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
7173       {
7174         ++anArgIt;
7175       }
7176     }
7177     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
7178     {
7179       //
7180     }
7181     else
7182     {
7183       Message::SendFail() << "Syntax error: unknown argument " << anArg;
7184       return 1;
7185     }
7186   }
7187
7188   aV3dView->SetView2DMode (is2dMode);
7189   return 0;
7190 }
7191
7192 //==============================================================================
7193 //function : VAnimation
7194 //purpose  :
7195 //==============================================================================
7196 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
7197                                     Standard_Integer  theArgNb,
7198                                     const char**      theArgVec)
7199 {
7200   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
7201   if (theArgNb < 2)
7202   {
7203     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
7204          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
7205     {
7206       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
7207     }
7208     return 0;
7209   }
7210   if (aCtx.IsNull())
7211   {
7212     Message::SendFail ("Error: no active viewer");
7213     return 1;
7214   }
7215
7216   Standard_Integer anArgIter = 1;
7217   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
7218   if (aNameArg.IsEmpty())
7219   {
7220     Message::SendFail ("Syntax error: animation name is not defined");
7221     return 1;
7222   }
7223
7224   TCollection_AsciiString aNameArgLower = aNameArg;
7225   aNameArgLower.LowerCase();
7226   if (aNameArgLower == "-reset"
7227    || aNameArgLower == "-clear")
7228   {
7229     ViewerTest_AnimationTimelineMap.Clear();
7230     return 0;
7231   }
7232   else if (aNameArg.Value (1) == '-')
7233   {
7234     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
7235     return 1;
7236   }
7237
7238   const char* aNameSplitter = "/";
7239   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
7240   if (aSplitPos == -1)
7241   {
7242     aNameSplitter = ".";
7243     aSplitPos = aNameArg.Search (aNameSplitter);
7244   }
7245
7246   // find existing or create a new animation by specified name within syntax "parent.child".
7247   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
7248   for (; !aNameArg.IsEmpty();)
7249   {
7250     TCollection_AsciiString aNameParent;
7251     if (aSplitPos != -1)
7252     {
7253       if (aSplitPos == aNameArg.Length())
7254       {
7255         Message::SendFail ("Syntax error: animation name is not defined");
7256         return 1;
7257       }
7258
7259       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
7260       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
7261
7262       aSplitPos = aNameArg.Search (aNameSplitter);
7263     }
7264     else
7265     {
7266       aNameParent = aNameArg;
7267       aNameArg.Clear();
7268     }
7269
7270     if (anAnimation.IsNull())
7271     {
7272       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
7273       {
7274         anAnimation = new AIS_Animation (aNameParent);
7275         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
7276       }
7277       aRootAnimation = anAnimation;
7278     }
7279     else
7280     {
7281       aParentAnimation = anAnimation;
7282       anAnimation = aParentAnimation->Find (aNameParent);
7283       if (anAnimation.IsNull())
7284       {
7285         anAnimation = new AIS_Animation (aNameParent);
7286         aParentAnimation->Add (anAnimation);
7287       }
7288     }
7289   }
7290   if (anAnimation.IsNull())
7291   {
7292     Message::SendFail() << "Syntax error: wrong number of arguments";
7293     return 1;
7294   }
7295
7296   if (anArgIter >= theArgNb)
7297   {
7298     // just print the list of children
7299     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
7300     {
7301       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
7302     }
7303     return 0;
7304   }
7305
7306   // animation parameters
7307   Standard_Boolean toPlay = Standard_False;
7308   Standard_Real aPlaySpeed     = 1.0;
7309   Standard_Real aPlayStartTime = anAnimation->StartPts();
7310   Standard_Real aPlayDuration  = anAnimation->Duration();
7311   Standard_Boolean isFreeCamera = Standard_False;
7312   Standard_Boolean toPauseOnClick = Standard_True;
7313   Standard_Boolean isLockLoop   = Standard_False;
7314
7315   // video recording parameters
7316   TCollection_AsciiString aRecFile;
7317   Image_VideoParams aRecParams;
7318
7319   Handle(V3d_View) aView = ViewerTest::CurrentView();
7320   for (; anArgIter < theArgNb; ++anArgIter)
7321   {
7322     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7323     anArg.LowerCase();
7324     // general options
7325     if (anArg == "-reset"
7326      || anArg == "-clear")
7327     {
7328       anAnimation->Clear();
7329     }
7330     else if (anArg == "-remove"
7331           || anArg == "-del"
7332           || anArg == "-delete")
7333     {
7334       if (aParentAnimation.IsNull())
7335       {
7336         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
7337       }
7338       else
7339       {
7340         aParentAnimation->Remove (anAnimation);
7341       }
7342     }
7343     // playback options
7344     else if (anArg == "-play")
7345     {
7346       toPlay = Standard_True;
7347       if (++anArgIter < theArgNb)
7348       {
7349         if (*theArgVec[anArgIter] == '-')
7350         {
7351           --anArgIter;
7352           continue;
7353         }
7354         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
7355
7356         if (++anArgIter < theArgNb)
7357         {
7358           if (*theArgVec[anArgIter] == '-')
7359           {
7360             --anArgIter;
7361             continue;
7362           }
7363           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7364         }
7365       }
7366     }
7367     else if (anArg == "-resume")
7368     {
7369       toPlay = Standard_True;
7370       aPlayStartTime = anAnimation->ElapsedTime();
7371       if (++anArgIter < theArgNb)
7372       {
7373         if (*theArgVec[anArgIter] == '-')
7374         {
7375           --anArgIter;
7376           continue;
7377         }
7378
7379         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7380       }
7381     }
7382     else if (anArg == "-pause")
7383     {
7384       anAnimation->Pause();
7385     }
7386     else if (anArg == "-stop")
7387     {
7388       anAnimation->Stop();
7389     }
7390     else if (anArg == "-playspeed"
7391           || anArg == "-speed")
7392     {
7393       if (++anArgIter >= theArgNb)
7394       {
7395         Message::SendFail() << "Syntax error at " << anArg << "";
7396         return 1;
7397       }
7398       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
7399     }
7400     else if (anArg == "-lock"
7401           || anArg == "-lockloop"
7402           || anArg == "-playlockloop")
7403     {
7404       isLockLoop = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
7405     }
7406     else if (anArg == "-freecamera"
7407           || anArg == "-nofreecamera"
7408           || anArg == "-playfreecamera"
7409           || anArg == "-noplayfreecamera"
7410           || anArg == "-freelook"
7411           || anArg == "-nofreelook")
7412     {
7413       isFreeCamera = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7414     }
7415     else if (anArg == "-pauseonclick"
7416           || anArg == "-nopauseonclick"
7417           || anArg == "-nopause")
7418     {
7419       toPauseOnClick = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7420     }
7421     // video recodring options
7422     else if (anArg == "-rec"
7423           || anArg == "-record")
7424     {
7425       if (++anArgIter >= theArgNb)
7426       {
7427         Message::SendFail() << "Syntax error at " << anArg;
7428         return 1;
7429       }
7430
7431       aRecFile = theArgVec[anArgIter];
7432       if (aRecParams.FpsNum <= 0)
7433       {
7434         aRecParams.FpsNum = 24;
7435       }
7436
7437       if (anArgIter + 2 < theArgNb
7438       && *theArgVec[anArgIter + 1] != '-'
7439       && *theArgVec[anArgIter + 2] != '-')
7440       {
7441         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
7442         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
7443         if (aWidthArg .IsIntegerValue()
7444          && aHeightArg.IsIntegerValue())
7445         {
7446           aRecParams.Width  = aWidthArg .IntegerValue();
7447           aRecParams.Height = aHeightArg.IntegerValue();
7448           anArgIter += 2;
7449         }
7450       }
7451     }
7452     else if (anArg == "-fps")
7453     {
7454       if (++anArgIter >= theArgNb)
7455       {
7456         Message::SendFail() << "Syntax error at " << anArg;
7457         return 1;
7458       }
7459
7460       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
7461       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
7462       if (aSplitIndex == 0)
7463       {
7464         aRecParams.FpsNum = aFpsArg.IntegerValue();
7465       }
7466       else
7467       {
7468         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
7469         aFpsArg.Split (aFpsArg.Length() - 1);
7470         const TCollection_AsciiString aNumStr = aFpsArg;
7471         aRecParams.FpsNum = aNumStr.IntegerValue();
7472         aRecParams.FpsDen = aDenStr.IntegerValue();
7473         if (aRecParams.FpsDen < 1)
7474         {
7475           Message::SendFail() << "Syntax error at " << anArg;
7476           return 1;
7477         }
7478       }
7479     }
7480     else if (anArg == "-format")
7481     {
7482       if (++anArgIter >= theArgNb)
7483       {
7484         Message::SendFail() << "Syntax error at " << anArg;
7485         return 1;
7486       }
7487       aRecParams.Format = theArgVec[anArgIter];
7488     }
7489     else if (anArg == "-pix_fmt"
7490           || anArg == "-pixfmt"
7491           || anArg == "-pixelformat")
7492     {
7493       if (++anArgIter >= theArgNb)
7494       {
7495         Message::SendFail() << "Syntax error at " << anArg;
7496         return 1;
7497       }
7498       aRecParams.PixelFormat = theArgVec[anArgIter];
7499     }
7500     else if (anArg == "-codec"
7501           || anArg == "-vcodec"
7502           || anArg == "-videocodec")
7503     {
7504       if (++anArgIter >= theArgNb)
7505       {
7506         Message::SendFail() << "Syntax error at " << anArg;
7507         return 1;
7508       }
7509       aRecParams.VideoCodec = theArgVec[anArgIter];
7510     }
7511     else if (anArg == "-crf"
7512           || anArg == "-preset"
7513           || anArg == "-qp")
7514     {
7515       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
7516       if (++anArgIter >= theArgNb)
7517       {
7518         Message::SendFail() << "Syntax error at " << anArg;
7519         return 1;
7520       }
7521
7522       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
7523     }
7524     // animation definition options
7525     else if (anArg == "-start"
7526           || anArg == "-starttime"
7527           || anArg == "-startpts")
7528     {
7529       if (++anArgIter >= theArgNb)
7530       {
7531         Message::SendFail() << "Syntax error at " << anArg;
7532         return 1;
7533       }
7534
7535       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
7536       aRootAnimation->UpdateTotalDuration();
7537     }
7538     else if (anArg == "-end"
7539           || anArg == "-endtime"
7540           || anArg == "-endpts")
7541     {
7542       if (++anArgIter >= theArgNb)
7543       {
7544         Message::SendFail() << "Syntax error at " << anArg;
7545         return 1;
7546       }
7547
7548       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
7549       aRootAnimation->UpdateTotalDuration();
7550     }
7551     else if (anArg == "-dur"
7552           || anArg == "-duration")
7553     {
7554       if (++anArgIter >= theArgNb)
7555       {
7556         Message::SendFail() << "Syntax error at " << anArg;
7557         return 1;
7558       }
7559
7560       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
7561       aRootAnimation->UpdateTotalDuration();
7562     }
7563     else if (anArg == "-command"
7564           || anArg == "-cmd"
7565           || anArg == "-invoke"
7566           || anArg == "-eval"
7567           || anArg == "-proc")
7568     {
7569       if (++anArgIter >= theArgNb)
7570       {
7571         Message::SendFail() << "Syntax error at " << anArg;
7572         return 1;
7573       }
7574
7575       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
7576       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
7577     }
7578     else if (anArg == "-objecttrsf"
7579           || anArg == "-objectransformation"
7580           || anArg == "-objtransformation"
7581           || anArg == "-objtrsf"
7582           || anArg == "-object"
7583           || anArg == "-obj")
7584     {
7585       if (++anArgIter >= theArgNb)
7586       {
7587         Message::SendFail() << "Syntax error at " << anArg;
7588         return 1;
7589       }
7590
7591       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
7592       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
7593       Handle(AIS_InteractiveObject) anObject;
7594       if (!aMapOfAIS.Find2 (anObjName, anObject))
7595       {
7596         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
7597         return 1;
7598       }
7599
7600       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
7601       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
7602       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
7603       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
7604       Standard_Boolean isTrsfSet = Standard_False;
7605       Standard_Integer aTrsfArgIter = anArgIter + 1;
7606       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
7607       {
7608         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
7609         aTrsfArg.LowerCase();
7610         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
7611         if (aTrsfArg.StartsWith ("-rotation")
7612          || aTrsfArg.StartsWith ("-rot"))
7613         {
7614           isTrsfSet = Standard_True;
7615           if (aTrsfArgIter + 4 >= theArgNb
7616           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
7617           {
7618             Message::SendFail() << "Syntax error at " << aTrsfArg;
7619             return 1;
7620           }
7621           aTrsfArgIter += 4;
7622         }
7623         else if (aTrsfArg.StartsWith ("-location")
7624               || aTrsfArg.StartsWith ("-loc"))
7625         {
7626           isTrsfSet = Standard_True;
7627           if (aTrsfArgIter + 3 >= theArgNb
7628           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
7629           {
7630             Message::SendFail() << "Syntax error at " << aTrsfArg;
7631             return 1;
7632           }
7633           aTrsfArgIter += 3;
7634         }
7635         else if (aTrsfArg.StartsWith ("-scale"))
7636         {
7637           isTrsfSet = Standard_True;
7638           if (++aTrsfArgIter >= theArgNb)
7639           {
7640             Message::SendFail() << "Syntax error at " << aTrsfArg;
7641             return 1;
7642           }
7643
7644           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
7645           if (!aScaleStr.IsRealValue (Standard_True))
7646           {
7647             Message::SendFail() << "Syntax error at " << aTrsfArg;
7648             return 1;
7649           }
7650           aScales[anIndex] = aScaleStr.RealValue();
7651         }
7652         else
7653         {
7654           anArgIter = aTrsfArgIter - 1;
7655           break;
7656         }
7657       }
7658       if (!isTrsfSet)
7659       {
7660         Message::SendFail() << "Syntax error at " << anArg;
7661         return 1;
7662       }
7663       else if (aTrsfArgIter >= theArgNb)
7664       {
7665         anArgIter = theArgNb;
7666       }
7667
7668       aTrsfs[0].SetRotation        (aRotQuats[0]);
7669       aTrsfs[1].SetRotation        (aRotQuats[1]);
7670       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
7671       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
7672       aTrsfs[0].SetScaleFactor     (aScales[0]);
7673       aTrsfs[1].SetScaleFactor     (aScales[1]);
7674
7675       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
7676       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
7677     }
7678     else if (anArg == "-viewtrsf"
7679           || anArg == "-view")
7680     {
7681       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
7682       if (aCamAnimation.IsNull())
7683       {
7684         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
7685         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
7686       }
7687
7688       Handle(Graphic3d_Camera) aCams[2] =
7689       {
7690         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
7691         new Graphic3d_Camera (aCamAnimation->View()->Camera())
7692       };
7693
7694       Standard_Boolean isTrsfSet = Standard_False;
7695       Standard_Integer aViewArgIter = anArgIter + 1;
7696       for (; aViewArgIter < theArgNb; ++aViewArgIter)
7697       {
7698         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
7699         aViewArg.LowerCase();
7700         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
7701         if (aViewArg.StartsWith ("-scale"))
7702         {
7703           isTrsfSet = Standard_True;
7704           if (++aViewArgIter >= theArgNb)
7705           {
7706             Message::SendFail() << "Syntax error at " << anArg;
7707             return 1;
7708           }
7709
7710           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
7711           if (!aScaleStr.IsRealValue (Standard_True))
7712           {
7713             Message::SendFail() << "Syntax error at " << aViewArg;
7714             return 1;
7715           }
7716           Standard_Real aScale = aScaleStr.RealValue();
7717           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
7718           aCams[anIndex]->SetScale (aScale);
7719         }
7720         else if (aViewArg.StartsWith ("-eye")
7721               || aViewArg.StartsWith ("-center")
7722               || aViewArg.StartsWith ("-at")
7723               || aViewArg.StartsWith ("-up"))
7724         {
7725           isTrsfSet = Standard_True;
7726           gp_XYZ anXYZ;
7727           if (aViewArgIter + 3 >= theArgNb
7728           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
7729           {
7730             Message::SendFail() << "Syntax error at " << aViewArg;
7731             return 1;
7732           }
7733           aViewArgIter += 3;
7734
7735           if (aViewArg.StartsWith ("-eye"))
7736           {
7737             aCams[anIndex]->SetEye (anXYZ);
7738           }
7739           else if (aViewArg.StartsWith ("-center")
7740                 || aViewArg.StartsWith ("-at"))
7741           {
7742             aCams[anIndex]->SetCenter (anXYZ);
7743           }
7744           else if (aViewArg.StartsWith ("-up"))
7745           {
7746             aCams[anIndex]->SetUp (anXYZ);
7747           }
7748         }
7749         else
7750         {
7751           anArgIter = aViewArgIter - 1;
7752           break;
7753         }
7754       }
7755       if (!isTrsfSet)
7756       {
7757         Message::SendFail() << "Syntax error at " << anArg;
7758         return 1;
7759       }
7760       else if (aViewArgIter >= theArgNb)
7761       {
7762         anArgIter = theArgNb;
7763       }
7764
7765       aCamAnimation->SetCameraStart(aCams[0]);
7766       aCamAnimation->SetCameraEnd  (aCams[1]);
7767     }
7768     else
7769     {
7770       Message::SendFail() << "Syntax error at " << anArg;
7771       return 1;
7772     }
7773   }
7774
7775   ViewerTest::CurrentEventManager()->AbortViewAnimation();
7776   ViewerTest::CurrentEventManager()->SetObjectsAnimation (Handle(AIS_Animation)());
7777   if (!toPlay && aRecFile.IsEmpty())
7778   {
7779     return 0;
7780   }
7781
7782   // Start animation timeline and process frame updating.
7783   if (aRecParams.FpsNum <= 0
7784   && !isLockLoop)
7785   {
7786     Handle(ViewerTest_AnimationHolder) aHolder = new ViewerTest_AnimationHolder (anAnimation, aView, isFreeCamera);
7787     aHolder->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7788     ViewerTest::CurrentEventManager()->SetPauseObjectsAnimation (toPauseOnClick);
7789     ViewerTest::CurrentEventManager()->SetObjectsAnimation (aHolder);
7790     ViewerTest::CurrentEventManager()->ProcessExpose();
7791     return 0;
7792   }
7793
7794   // Perform video recording
7795   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
7796   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
7797   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7798
7799   OSD_Timer aPerfTimer;
7800   aPerfTimer.Start();
7801
7802   Handle(Image_VideoRecorder) aRecorder;
7803   ImageFlipper aFlipper;
7804   Handle(Draw_ProgressIndicator) aProgress;
7805   if (!aRecFile.IsEmpty())
7806   {
7807     if (aRecParams.Width  <= 0
7808      || aRecParams.Height <= 0)
7809     {
7810       aView->Window()->Size (aRecParams.Width, aRecParams.Height);
7811     }
7812
7813     aRecorder = new Image_VideoRecorder();
7814     if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
7815     {
7816       Message::SendFail ("Error: failed to open video file for recording");
7817       return 0;
7818     }
7819
7820     aProgress = new Draw_ProgressIndicator (theDI, 1);
7821   }
7822
7823   // Manage frame-rated animation here
7824   Standard_Real aPts = aPlayStartTime;
7825   int64_t aNbFrames = 0;
7826   Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
7827                             "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
7828   Standard_Integer aSecondsProgress = 0;
7829   for (; aPts <= anUpperPts && aPS.More();)
7830   {
7831     Standard_Real aRecPts = 0.0;
7832     if (aRecParams.FpsNum > 0)
7833     {
7834       aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
7835     }
7836     else
7837     {
7838       aRecPts = aPlaySpeed * aPerfTimer.ElapsedTime();
7839     }
7840
7841     aPts = aPlayStartTime + aRecPts;
7842     ++aNbFrames;
7843     if (!anAnimation->Update (aPts))
7844     {
7845       break;
7846     }
7847
7848     if (!aRecorder.IsNull())
7849     {
7850       V3d_ImageDumpOptions aDumpParams;
7851       aDumpParams.Width          = aRecParams.Width;
7852       aDumpParams.Height         = aRecParams.Height;
7853       aDumpParams.BufferType     = Graphic3d_BT_RGBA;
7854       aDumpParams.StereoOptions  = V3d_SDO_MONO;
7855       aDumpParams.ToAdjustAspect = Standard_True;
7856       if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
7857       {
7858         Message::SendFail ("Error: view dump is failed");
7859         return 0;
7860       }
7861       aFlipper.FlipY (aRecorder->ChangeFrame());
7862       if (!aRecorder->PushFrame())
7863       {
7864         return 0;
7865       }
7866     }
7867     else
7868     {
7869       aView->Redraw();
7870     }
7871
7872     while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
7873     {
7874       aPS.Next();
7875       ++aSecondsProgress;
7876     }
7877   }
7878
7879   aPerfTimer.Stop();
7880   anAnimation->Stop();
7881   const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
7882   theDI << "Average FPS: " << aRecFps << "\n"
7883         << "Nb. Frames: "  << Standard_Real(aNbFrames);
7884
7885   aView->Redraw();
7886   aView->SetImmediateUpdate (wasImmediateUpdate);
7887   return 0;
7888 }
7889
7890
7891 //=======================================================================
7892 //function : VChangeSelected
7893 //purpose  : Adds the shape to selection or remove one from it
7894 //=======================================================================
7895 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
7896                                 Standard_Integer argc,
7897                                 const char ** argv)
7898 {
7899   if(argc != 2)
7900   {
7901     di<<"Usage : " << argv[0] << " shape \n";
7902     return 1;
7903   }
7904   //get AIS_Shape:
7905   TCollection_AsciiString aName(argv[1]);
7906   Handle(AIS_InteractiveObject) anAISObject;
7907   if (!GetMapOfAIS().Find2 (aName, anAISObject)
7908     || anAISObject.IsNull())
7909   {
7910     di<<"Use 'vdisplay' before";
7911     return 1;
7912   }
7913
7914   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
7915   return 0;
7916 }
7917
7918 //=======================================================================
7919 //function : VNbSelected
7920 //purpose  : Returns number of selected objects
7921 //=======================================================================
7922 static Standard_Integer VNbSelected (Draw_Interpretor& di,
7923                                 Standard_Integer argc,
7924                                 const char ** argv)
7925 {
7926   if(argc != 1)
7927   {
7928     di << "Usage : " << argv[0] << "\n";
7929     return 1;
7930   }
7931   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7932   if(aContext.IsNull())
7933   {
7934     di << "use 'vinit' command before " << argv[0] << "\n";
7935     return 1;
7936   }
7937   di << aContext->NbSelected() << "\n";
7938   return 0;
7939 }
7940
7941 //=======================================================================
7942 //function : VSetViewSize
7943 //purpose  :
7944 //=======================================================================
7945 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
7946                                 Standard_Integer argc,
7947                                 const char ** argv)
7948 {
7949   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7950   if(aContext.IsNull())
7951   {
7952     di << "use 'vinit' command before " << argv[0] << "\n";
7953     return 1;
7954   }
7955   if(argc != 2)
7956   {
7957     di<<"Usage : " << argv[0] << " Size\n";
7958     return 1;
7959   }
7960   Standard_Real aSize = Draw::Atof (argv[1]);
7961   if (aSize <= 0.)
7962   {
7963     di<<"Bad Size value  : " << aSize << "\n";
7964     return 1;
7965   }
7966
7967   Handle(V3d_View) aView = ViewerTest::CurrentView();
7968   aView->SetSize(aSize);
7969   return 0;
7970 }
7971
7972 //=======================================================================
7973 //function : VMoveView
7974 //purpose  :
7975 //=======================================================================
7976 static Standard_Integer VMoveView (Draw_Interpretor& di,
7977                                 Standard_Integer argc,
7978                                 const char ** argv)
7979 {
7980   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7981   if(aContext.IsNull())
7982   {
7983     di << "use 'vinit' command before " << argv[0] << "\n";
7984     return 1;
7985   }
7986   if(argc < 4 || argc > 5)
7987   {
7988     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
7989     return 1;
7990   }
7991   Standard_Real Dx = Draw::Atof (argv[1]);
7992   Standard_Real Dy = Draw::Atof (argv[2]);
7993   Standard_Real Dz = Draw::Atof (argv[3]);
7994   Standard_Boolean aStart = Standard_True;
7995   if (argc == 5)
7996   {
7997       aStart = (Draw::Atoi (argv[4]) > 0);
7998   }
7999
8000   Handle(V3d_View) aView = ViewerTest::CurrentView();
8001   aView->Move(Dx,Dy,Dz,aStart);
8002   return 0;
8003 }
8004
8005 //=======================================================================
8006 //function : VTranslateView
8007 //purpose  :
8008 //=======================================================================
8009 static Standard_Integer VTranslateView (Draw_Interpretor& di,
8010                                 Standard_Integer argc,
8011                                 const char ** argv)
8012 {
8013   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8014   if(aContext.IsNull())
8015   {
8016     di << "use 'vinit' command before " << argv[0] << "\n";
8017     return 1;
8018   }
8019   if(argc < 4 || argc > 5)
8020   {
8021     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8022     return 1;
8023   }
8024   Standard_Real Dx = Draw::Atof (argv[1]);
8025   Standard_Real Dy = Draw::Atof (argv[2]);
8026   Standard_Real Dz = Draw::Atof (argv[3]);
8027   Standard_Boolean aStart = Standard_True;
8028   if (argc == 5)
8029   {
8030       aStart = (Draw::Atoi (argv[4]) > 0);
8031   }
8032
8033   Handle(V3d_View) aView = ViewerTest::CurrentView();
8034   aView->Translate(Dx,Dy,Dz,aStart);
8035   return 0;
8036 }
8037
8038 //=======================================================================
8039 //function : VTurnView
8040 //purpose  :
8041 //=======================================================================
8042 static Standard_Integer VTurnView (Draw_Interpretor& di,
8043                                 Standard_Integer argc,
8044                                 const char ** argv)
8045 {
8046   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8047   if(aContext.IsNull()) {
8048     di << "use 'vinit' command before " << argv[0] << "\n";
8049     return 1;
8050   }
8051   if(argc < 4 || argc > 5){
8052     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
8053     return 1;
8054   }
8055   Standard_Real Ax = Draw::Atof (argv[1]);
8056   Standard_Real Ay = Draw::Atof (argv[2]);
8057   Standard_Real Az = Draw::Atof (argv[3]);
8058   Standard_Boolean aStart = Standard_True;
8059   if (argc == 5)
8060   {
8061       aStart = (Draw::Atoi (argv[4]) > 0);
8062   }
8063
8064   Handle(V3d_View) aView = ViewerTest::CurrentView();
8065   aView->Turn(Ax,Ay,Az,aStart);
8066   return 0;
8067 }
8068
8069 //==============================================================================
8070 //function : VTextureEnv
8071 //purpose  : ENables or disables environment mapping
8072 //==============================================================================
8073 class OCC_TextureEnv : public Graphic3d_TextureEnv
8074 {
8075 public:
8076   OCC_TextureEnv(const Standard_CString FileName);
8077   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
8078   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
8079                             const Standard_Boolean theModulateFlag,
8080                             const Graphic3d_TypeOfTextureFilter theFilter,
8081                             const Standard_ShortReal theXScale,
8082                             const Standard_ShortReal theYScale,
8083                             const Standard_ShortReal theXShift,
8084                             const Standard_ShortReal theYShift,
8085                             const Standard_ShortReal theAngle);
8086   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
8087 };
8088 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
8089
8090 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
8091   : Graphic3d_TextureEnv(theFileName)
8092 {
8093 }
8094
8095 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
8096   : Graphic3d_TextureEnv(theTexId)
8097 {
8098 }
8099
8100 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
8101                                           const Standard_Boolean theModulateFlag,
8102                                           const Graphic3d_TypeOfTextureFilter theFilter,
8103                                           const Standard_ShortReal theXScale,
8104                                           const Standard_ShortReal theYScale,
8105                                           const Standard_ShortReal theXShift,
8106                                           const Standard_ShortReal theYShift,
8107                                           const Standard_ShortReal theAngle)
8108 {
8109   myParams->SetRepeat     (theRepeatFlag);
8110   myParams->SetModulate   (theModulateFlag);
8111   myParams->SetFilter     (theFilter);
8112   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
8113   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
8114   myParams->SetRotation   (theAngle);
8115 }
8116
8117 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
8118 {
8119   // get the active view
8120   Handle(V3d_View) aView = ViewerTest::CurrentView();
8121   if (aView.IsNull())
8122   {
8123     Message::SendFail ("Error: no active viewer");
8124     return 1;
8125   }
8126
8127   // Checking the input arguments
8128   Standard_Boolean anEnableFlag = Standard_False;
8129   Standard_Boolean isOk         = theArgNb >= 2;
8130   if (isOk)
8131   {
8132     TCollection_AsciiString anEnableOpt(theArgVec[1]);
8133     anEnableFlag = anEnableOpt.IsEqual("on");
8134     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
8135   }
8136   if (anEnableFlag)
8137   {
8138     isOk = (theArgNb == 3 || theArgNb == 11);
8139     if (isOk)
8140     {
8141       TCollection_AsciiString aTextureOpt(theArgVec[2]);
8142       isOk = (!aTextureOpt.IsIntegerValue() ||
8143              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
8144
8145       if (isOk && theArgNb == 11)
8146       {
8147         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
8148                                 aModulateOpt(theArgVec[4]),
8149                                 aFilterOpt  (theArgVec[5]),
8150                                 aSScaleOpt  (theArgVec[6]),
8151                                 aTScaleOpt  (theArgVec[7]),
8152                                 aSTransOpt  (theArgVec[8]),
8153                                 aTTransOpt  (theArgVec[9]),
8154                                 anAngleOpt  (theArgVec[10]);
8155         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
8156                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
8157                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
8158                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
8159                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
8160                 anAngleOpt.IsRealValue (Standard_True));
8161       }
8162     }
8163   }
8164
8165   if (!isOk)
8166   {
8167     Message::SendFail() << "Usage:\n"
8168                         << theArgVec[0] << " off\n"
8169                         << 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]";
8170     return 1;
8171   }
8172
8173   if (anEnableFlag)
8174   {
8175     TCollection_AsciiString aTextureOpt(theArgVec[2]);
8176     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
8177                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
8178                                      new OCC_TextureEnv(theArgVec[2]);
8179
8180     if (theArgNb == 11)
8181     {
8182       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
8183       aTexEnv->SetTextureParameters(
8184         aRepeatOpt.  IsEqual("repeat"),
8185         aModulateOpt.IsEqual("modulate"),
8186         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
8187                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
8188                                                                            Graphic3d_TOTF_TRILINEAR,
8189         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
8190         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
8191         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
8192         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
8193         (Standard_ShortReal)Draw::Atof(theArgVec[10])
8194         );
8195     }
8196     aView->SetTextureEnv(aTexEnv);
8197   }
8198   else // Disabling environment mapping
8199   {
8200     Handle(Graphic3d_TextureEnv) aTexture;
8201     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
8202   }
8203
8204   aView->Redraw();
8205   return 0;
8206 }
8207
8208 namespace
8209 {
8210   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
8211
8212   //! Remove registered clipping plane from all views and objects.
8213   static void removePlane (MapOfPlanes& theRegPlanes,
8214                            const TCollection_AsciiString& theName)
8215   {
8216     Handle(Graphic3d_ClipPlane) aClipPlane;
8217     if (!theRegPlanes.Find (theName, aClipPlane))
8218     {
8219       Message::SendWarning ("Warning: no such plane");
8220       return;
8221     }
8222
8223     theRegPlanes.UnBind (theName);
8224     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
8225          anIObjIt.More(); anIObjIt.Next())
8226     {
8227       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
8228       aPrs->RemoveClipPlane (aClipPlane);
8229     }
8230
8231     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
8232          aViewIt.More(); aViewIt.Next())
8233     {
8234       const Handle(V3d_View)& aView = aViewIt.Key2();
8235       aView->RemoveClipPlane(aClipPlane);
8236     }
8237
8238     ViewerTest::RedrawAllViews();
8239   }
8240 }
8241
8242 //===============================================================================================
8243 //function : VClipPlane
8244 //purpose  :
8245 //===============================================================================================
8246 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8247 {
8248   // use short-cut for created clip planes map of created (or "registered by name") clip planes
8249   static MapOfPlanes aRegPlanes;
8250
8251   if (theArgsNb < 2)
8252   {
8253     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
8254     {
8255       theDi << aPlaneIter.Key() << " ";
8256     }
8257     return 0;
8258   }
8259
8260   TCollection_AsciiString aCommand (theArgVec[1]);
8261   aCommand.LowerCase();
8262   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
8263   if (anActiveView.IsNull())
8264   {
8265     Message::SendFail ("Error: no active viewer");
8266     return 1;
8267   }
8268
8269   // print maximum number of planes for current viewer
8270   if (aCommand == "-maxplanes"
8271    || aCommand == "maxplanes")
8272   {
8273     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
8274           << " plane slots provided by driver.\n";
8275     return 0;
8276   }
8277
8278   // create / delete plane instance
8279   if (aCommand == "-create"
8280    || aCommand == "create"
8281    || aCommand == "-delete"
8282    || aCommand == "delete"
8283    || aCommand == "-clone"
8284    || aCommand == "clone")
8285   {
8286     if (theArgsNb < 3)
8287     {
8288       Message::SendFail ("Syntax error: plane name is required");
8289       return 1;
8290     }
8291
8292     Standard_Boolean toCreate = aCommand == "-create"
8293                              || aCommand == "create";
8294     Standard_Boolean toClone  = aCommand == "-clone"
8295                              || aCommand == "clone";
8296     Standard_Boolean toDelete = aCommand == "-delete"
8297                              || aCommand == "delete";
8298     TCollection_AsciiString aPlane (theArgVec[2]);
8299
8300     if (toCreate)
8301     {
8302       if (aRegPlanes.IsBound (aPlane))
8303       {
8304         std::cout << "Warning: existing plane has been overridden.\n";
8305         toDelete = true;
8306       }
8307       else
8308       {
8309         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8310         return 0;
8311       }
8312     }
8313     else if (toClone) // toClone
8314     {
8315       if (!aRegPlanes.IsBound (aPlane))
8316       {
8317         Message::SendFail ("Error: no such plane");
8318         return 1;
8319       }
8320       else if (theArgsNb < 4)
8321       {
8322         Message::SendFail ("Syntax error: enter name for new plane");
8323         return 1;
8324       }
8325
8326       TCollection_AsciiString aClone (theArgVec[3]);
8327       if (aRegPlanes.IsBound (aClone))
8328       {
8329         Message::SendFail ("Error: plane name is in use");
8330         return 1;
8331       }
8332
8333       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
8334
8335       aRegPlanes.Bind (aClone, aClipPlane->Clone());
8336       return 0;
8337     }
8338
8339     if (toDelete)
8340     {
8341       if (aPlane == "ALL"
8342        || aPlane == "all"
8343        || aPlane == "*")
8344       {
8345         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
8346         {
8347           aPlane = aPlaneIter.Key();
8348           removePlane (aRegPlanes, aPlane);
8349           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
8350         }
8351       }
8352       else
8353       {
8354         removePlane (aRegPlanes, aPlane);
8355       }
8356     }
8357
8358     if (toCreate)
8359     {
8360       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8361     }
8362     return 0;
8363   }
8364
8365   // set / unset plane command
8366   if (aCommand == "set"
8367    || aCommand == "unset")
8368   {
8369     if (theArgsNb < 5)
8370     {
8371       Message::SendFail ("Syntax error: need more arguments");
8372       return 1;
8373     }
8374
8375     // redirect to new syntax
8376     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
8377     anArgVec.SetValue (1, theArgVec[0]);
8378     anArgVec.SetValue (2, theArgVec[2]);
8379     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
8380     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
8381     {
8382       anArgVec.SetValue (anIt, theArgVec[anIt]);
8383     }
8384
8385     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
8386   }
8387
8388   // change plane command
8389   TCollection_AsciiString aPlaneName;
8390   Handle(Graphic3d_ClipPlane) aClipPlane;
8391   Standard_Integer anArgIter = 0;
8392   if (aCommand == "-change"
8393    || aCommand == "change")
8394   {
8395     // old syntax support
8396     if (theArgsNb < 3)
8397     {
8398       Message::SendFail ("Syntax error: need more arguments");
8399       return 1;
8400     }
8401
8402     anArgIter  = 3;
8403     aPlaneName = theArgVec[2];
8404     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
8405     {
8406       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
8407       return 1;
8408     }
8409   }
8410   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
8411   {
8412     anArgIter  = 2;
8413     aPlaneName = theArgVec[1];
8414   }
8415   else
8416   {
8417     anArgIter  = 2;
8418     aPlaneName = theArgVec[1];
8419     aClipPlane = new Graphic3d_ClipPlane();
8420     aRegPlanes.Bind (aPlaneName, aClipPlane);
8421     theDi << "Created new plane " << aPlaneName << ".\n";
8422   }
8423
8424   if (theArgsNb - anArgIter < 1)
8425   {
8426     Message::SendFail ("Syntax error: need more arguments");
8427     return 1;
8428   }
8429
8430   for (; anArgIter < theArgsNb; ++anArgIter)
8431   {
8432     const char**     aChangeArgs   = theArgVec + anArgIter;
8433     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
8434     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
8435     aChangeArg.LowerCase();
8436
8437     Standard_Boolean toEnable = Standard_True;
8438     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
8439     {
8440       aClipPlane->SetOn (toEnable);
8441     }
8442     else if (aChangeArg.StartsWith ("-equation")
8443           || aChangeArg.StartsWith ("equation"))
8444     {
8445       if (aNbChangeArgs < 5)
8446       {
8447         Message::SendFail ("Syntax error: need more arguments");
8448         return 1;
8449       }
8450
8451       Standard_Integer aSubIndex = 1;
8452       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
8453       if (aPrefixLen < aChangeArg.Length())
8454       {
8455         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
8456         if (!aSubStr.IsIntegerValue()
8457           || aSubStr.IntegerValue() <= 0)
8458         {
8459           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8460           return 1;
8461         }
8462         aSubIndex = aSubStr.IntegerValue();
8463       }
8464
8465       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
8466       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
8467       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
8468       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
8469       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8470       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
8471       {
8472         if (aSubPln->ChainNextPlane().IsNull())
8473         {
8474           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8475         }
8476         aSubPln = aSubPln->ChainNextPlane();
8477       }
8478       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8479       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
8480       anArgIter += 4;
8481     }
8482     else if ((aChangeArg == "-boxinterior"
8483            || aChangeArg == "-boxint"
8484            || aChangeArg == "-box")
8485             && aNbChangeArgs >= 7)
8486     {
8487       Graphic3d_BndBox3d aBndBox;
8488       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
8489       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
8490       anArgIter += 6;
8491
8492       Standard_Integer aNbSubPlanes = 6;
8493       const Graphic3d_Vec3d aDirArray[6] =
8494       {
8495         Graphic3d_Vec3d (-1, 0, 0),
8496         Graphic3d_Vec3d ( 1, 0, 0),
8497         Graphic3d_Vec3d ( 0,-1, 0),
8498         Graphic3d_Vec3d ( 0, 1, 0),
8499         Graphic3d_Vec3d ( 0, 0,-1),
8500         Graphic3d_Vec3d ( 0, 0, 1),
8501       };
8502       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8503       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
8504       {
8505         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
8506         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
8507         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
8508         if (aSubPlaneIter + 1 == aNbSubPlanes)
8509         {
8510           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8511         }
8512         else
8513         {
8514           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8515         }
8516         aSubPln = aSubPln->ChainNextPlane();
8517       }
8518     }
8519     else if (aChangeArg == "-capping"
8520           || aChangeArg == "capping")
8521     {
8522       if (aNbChangeArgs < 2)
8523       {
8524         Message::SendFail ("Syntax error: need more arguments");
8525         return 1;
8526       }
8527
8528       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8529       {
8530         aClipPlane->SetCapping (toEnable);
8531         anArgIter += 1;
8532       }
8533       else
8534       {
8535         // just skip otherwise (old syntax)
8536       }
8537     }
8538     else if (aChangeArg == "-useobjectmaterial"
8539           || aChangeArg == "-useobjectmat"
8540           || aChangeArg == "-useobjmat"
8541           || aChangeArg == "-useobjmaterial")
8542     {
8543       if (aNbChangeArgs < 2)
8544       {
8545         Message::SendFail ("Syntax error: need more arguments");
8546         return 1;
8547       }
8548
8549       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8550       {
8551         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
8552         anArgIter += 1;
8553       }
8554     }
8555     else if (aChangeArg == "-useobjecttexture"
8556           || aChangeArg == "-useobjecttex"
8557           || aChangeArg == "-useobjtexture"
8558           || aChangeArg == "-useobjtex")
8559     {
8560       if (aNbChangeArgs < 2)
8561       {
8562         Message::SendFail ("Syntax error: need more arguments");
8563         return 1;
8564       }
8565
8566       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8567       {
8568         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
8569         anArgIter += 1;
8570       }
8571     }
8572     else if (aChangeArg == "-useobjectshader"
8573           || aChangeArg == "-useobjshader")
8574     {
8575       if (aNbChangeArgs < 2)
8576       {
8577         Message::SendFail ("Syntax error: need more arguments");
8578         return 1;
8579       }
8580
8581       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8582       {
8583         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
8584         anArgIter += 1;
8585       }
8586     }
8587     else if (aChangeArg == "-color"
8588           || aChangeArg == "color")
8589     {
8590       Quantity_Color aColor;
8591       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
8592                                                      aChangeArgs + 1,
8593                                                      aColor);
8594       if (aNbParsed == 0)
8595       {
8596         Message::SendFail ("Syntax error: need more arguments");
8597         return 1;
8598       }
8599       aClipPlane->SetCappingColor (aColor);
8600       anArgIter += aNbParsed;
8601     }
8602     else if (aNbChangeArgs >= 1
8603           && (aChangeArg == "-material"
8604            || aChangeArg == "material"))
8605     {
8606       ++anArgIter;
8607       Graphic3d_NameOfMaterial aMatName;
8608       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
8609       {
8610         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
8611         return 1;
8612       }
8613       aClipPlane->SetCappingMaterial (aMatName);
8614     }
8615     else if ((aChangeArg == "-transparency"
8616            || aChangeArg == "-transp")
8617           && aNbChangeArgs >= 2)
8618     {
8619       TCollection_AsciiString aValStr (aChangeArgs[1]);
8620       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
8621       if (aValStr.IsRealValue (Standard_True))
8622       {
8623         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
8624         aMat.SetTransparency ((float )aValStr.RealValue());
8625         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
8626         aClipPlane->SetCappingMaterial (aMat);
8627       }
8628       else
8629       {
8630         aValStr.LowerCase();
8631         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
8632         if (aValStr == "opaque")
8633         {
8634           aMode = Graphic3d_AlphaMode_Opaque;
8635         }
8636         else if (aValStr == "mask")
8637         {
8638           aMode = Graphic3d_AlphaMode_Mask;
8639         }
8640         else if (aValStr == "blend")
8641         {
8642           aMode = Graphic3d_AlphaMode_Blend;
8643         }
8644         else if (aValStr == "maskblend"
8645               || aValStr == "blendmask")
8646         {
8647           aMode = Graphic3d_AlphaMode_MaskBlend;
8648         }
8649         else if (aValStr == "blendauto")
8650         {
8651           aMode = Graphic3d_AlphaMode_BlendAuto;
8652         }
8653         else
8654         {
8655           Message::SendFail() << "Syntax error at '" << aValStr << "'";
8656           return 1;
8657         }
8658         anAspect->SetAlphaMode (aMode);
8659         aClipPlane->SetCappingAspect (anAspect);
8660       }
8661       anArgIter += 1;
8662     }
8663     else if (aChangeArg == "-texname"
8664           || aChangeArg == "texname")
8665     {
8666       if (aNbChangeArgs < 2)
8667       {
8668         Message::SendFail ("Syntax error: need more arguments");
8669         return 1;
8670       }
8671
8672       TCollection_AsciiString aTextureName (aChangeArgs[1]);
8673       Handle(Graphic3d_Texture2D) aTexture = new Graphic3d_Texture2D (aTextureName);
8674       if (!aTexture->IsDone())
8675       {
8676         aClipPlane->SetCappingTexture (NULL);
8677       }
8678       else
8679       {
8680         aTexture->EnableModulate();
8681         aTexture->EnableRepeat();
8682         aClipPlane->SetCappingTexture (aTexture);
8683       }
8684       anArgIter += 1;
8685     }
8686     else if (aChangeArg == "-texscale"
8687           || aChangeArg == "texscale")
8688     {
8689       if (aClipPlane->CappingTexture().IsNull())
8690       {
8691         Message::SendFail ("Error: no texture is set");
8692         return 1;
8693       }
8694
8695       if (aNbChangeArgs < 3)
8696       {
8697         Message::SendFail ("Syntax error: need more arguments");
8698         return 1;
8699       }
8700
8701       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8702       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8703       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
8704       anArgIter += 2;
8705     }
8706     else if (aChangeArg == "-texorigin"
8707           || aChangeArg == "texorigin") // texture origin
8708     {
8709       if (aClipPlane->CappingTexture().IsNull())
8710       {
8711         Message::SendFail ("Error: no texture is set");
8712         return 1;
8713       }
8714
8715       if (aNbChangeArgs < 3)
8716       {
8717         Message::SendFail ("Syntax error: need more arguments");
8718         return 1;
8719       }
8720
8721       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8722       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8723
8724       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
8725       anArgIter += 2;
8726     }
8727     else if (aChangeArg == "-texrotate"
8728           || aChangeArg == "texrotate") // texture rotation
8729     {
8730       if (aClipPlane->CappingTexture().IsNull())
8731       {
8732         Message::SendFail ("Error: no texture is set");
8733         return 1;
8734       }
8735
8736       if (aNbChangeArgs < 2)
8737       {
8738         Message::SendFail ("Syntax error: need more arguments");
8739         return 1;
8740       }
8741
8742       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8743       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
8744       anArgIter += 1;
8745     }
8746     else if (aChangeArg == "-hatch"
8747           || aChangeArg == "hatch")
8748     {
8749       if (aNbChangeArgs < 2)
8750       {
8751         Message::SendFail ("Syntax error: need more arguments");
8752         return 1;
8753       }
8754
8755       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
8756       aHatchStr.LowerCase();
8757       if (aHatchStr == "on")
8758       {
8759         aClipPlane->SetCappingHatchOn();
8760       }
8761       else if (aHatchStr == "off")
8762       {
8763         aClipPlane->SetCappingHatchOff();
8764       }
8765       else
8766       {
8767         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
8768       }
8769       anArgIter += 1;
8770     }
8771     else if (aChangeArg == "-delete"
8772           || aChangeArg == "delete")
8773     {
8774       removePlane (aRegPlanes, aPlaneName);
8775       return 0;
8776     }
8777     else if (aChangeArg == "-set"
8778           || aChangeArg == "-unset"
8779           || aChangeArg == "-setoverrideglobal")
8780     {
8781       // set / unset plane command
8782       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
8783       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
8784       Standard_Integer anIt = 1;
8785       for (; anIt < aNbChangeArgs; ++anIt)
8786       {
8787         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
8788         if (anEntityName.IsEmpty()
8789          || anEntityName.Value (1) == '-')
8790         {
8791           break;
8792         }
8793         else if (!toOverrideGlobal
8794                && ViewerTest_myViews.IsBound1 (anEntityName))
8795         {
8796           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
8797           if (toSet)
8798           {
8799             aView->AddClipPlane (aClipPlane);
8800           }
8801           else
8802           {
8803             aView->RemoveClipPlane (aClipPlane);
8804           }
8805           continue;
8806         }
8807         else if (GetMapOfAIS().IsBound2 (anEntityName))
8808         {
8809           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
8810           if (toSet)
8811           {
8812             aIObj->AddClipPlane (aClipPlane);
8813           }
8814           else
8815           {
8816             aIObj->RemoveClipPlane (aClipPlane);
8817           }
8818           if (!aIObj->ClipPlanes().IsNull())
8819           {
8820             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
8821           }
8822         }
8823         else
8824         {
8825           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
8826           return 1;
8827         }
8828       }
8829
8830       if (anIt == 1)
8831       {
8832         // apply to active view
8833         if (toSet)
8834         {
8835           anActiveView->AddClipPlane (aClipPlane);
8836         }
8837         else
8838         {
8839           anActiveView->RemoveClipPlane (aClipPlane);
8840         }
8841       }
8842       else
8843       {
8844         anArgIter = anArgIter + anIt - 1;
8845       }
8846     }
8847     else
8848     {
8849       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8850       return 1;
8851     }
8852   }
8853
8854   ViewerTest::RedrawAllViews();
8855   return 0;
8856 }
8857
8858 //===============================================================================================
8859 //function : VZRange
8860 //purpose  :
8861 //===============================================================================================
8862 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8863 {
8864   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8865
8866   if (aCurrentView.IsNull())
8867   {
8868     Message::SendFail ("Error: no active viewer");
8869     return 1;
8870   }
8871
8872   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
8873
8874   if (theArgsNb < 2)
8875   {
8876     theDi << "ZNear: " << aCamera->ZNear() << "\n";
8877     theDi << "ZFar: " << aCamera->ZFar() << "\n";
8878     return 0;
8879   }
8880
8881   if (theArgsNb == 3)
8882   {
8883     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
8884     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
8885
8886     if (aNewZNear >= aNewZFar)
8887     {
8888       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
8889       return 1;
8890     }
8891
8892     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
8893     {
8894       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
8895       return 1;
8896     }
8897
8898     aCamera->SetZRange (aNewZNear, aNewZFar);
8899   }
8900   else
8901   {
8902     Message::SendFail ("Syntax error: wrong command arguments");
8903     return 1;
8904   }
8905
8906   aCurrentView->Redraw();
8907
8908   return 0;
8909 }
8910
8911 //===============================================================================================
8912 //function : VAutoZFit
8913 //purpose  :
8914 //===============================================================================================
8915 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8916 {
8917   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8918
8919   if (aCurrentView.IsNull())
8920   {
8921     Message::SendFail ("Error: no active viewer");
8922     return 1;
8923   }
8924
8925   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
8926
8927   if (theArgsNb > 3)
8928   {
8929     Message::SendFail ("Syntax error: wrong command arguments");
8930     return 1;
8931   }
8932
8933   if (theArgsNb < 2)
8934   {
8935     theDi << "Auto z-fit mode: \n"
8936           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
8937           << "Scale: " << aScale << "\n";
8938     return 0;
8939   }
8940
8941   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
8942
8943   if (theArgsNb >= 3)
8944   {
8945     aScale = Draw::Atoi (theArgVec[2]);
8946   }
8947
8948   aCurrentView->SetAutoZFitMode (isOn, aScale);
8949   aCurrentView->Redraw();
8950   return 0;
8951 }
8952
8953 //! Auxiliary function to print projection type
8954 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
8955 {
8956   switch (theProjType)
8957   {
8958     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
8959     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
8960     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
8961     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
8962     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
8963   }
8964   return "UNKNOWN";
8965 }
8966
8967 //===============================================================================================
8968 //function : VCamera
8969 //purpose  :
8970 //===============================================================================================
8971 static int VCamera (Draw_Interpretor& theDI,
8972                     Standard_Integer  theArgsNb,
8973                     const char**      theArgVec)
8974 {
8975   Handle(V3d_View) aView = ViewerTest::CurrentView();
8976   if (aView.IsNull())
8977   {
8978     Message::SendFail ("Error: no active viewer");
8979     return 1;
8980   }
8981
8982   Handle(Graphic3d_Camera) aCamera = aView->Camera();
8983   if (theArgsNb < 2)
8984   {
8985     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
8986     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
8987     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
8988     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
8989     theDI << "Distance:   " << aCamera->Distance() << "\n";
8990     theDI << "IOD:        " << aCamera->IOD() << "\n";
8991     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
8992     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
8993     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
8994     theDI << "ZNear:      " << aCamera->ZNear() << "\n";
8995     theDI << "ZFar:       " << aCamera->ZFar() << "\n";
8996     return 0;
8997   }
8998
8999   TCollection_AsciiString aPrsName;
9000   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9001   {
9002     Standard_CString        anArg = theArgVec[anArgIter];
9003     TCollection_AsciiString anArgCase (anArg);
9004     anArgCase.LowerCase();
9005     if (anArgCase == "-proj"
9006      || anArgCase == "-projection"
9007      || anArgCase == "-projtype"
9008      || anArgCase == "-projectiontype")
9009     {
9010       theDI << projTypeName (aCamera->ProjectionType()) << " ";
9011     }
9012     else if (anArgCase == "-ortho"
9013           || anArgCase == "-orthographic")
9014     {
9015       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
9016     }
9017     else if (anArgCase == "-persp"
9018           || anArgCase == "-perspective"
9019           || anArgCase == "-perspmono"
9020           || anArgCase == "-perspectivemono"
9021           || anArgCase == "-mono")
9022     {
9023       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9024     }
9025     else if (anArgCase == "-stereo"
9026           || anArgCase == "-stereoscopic"
9027           || anArgCase == "-perspstereo"
9028           || anArgCase == "-perspectivestereo")
9029     {
9030       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9031     }
9032     else if (anArgCase == "-left"
9033           || anArgCase == "-lefteye"
9034           || anArgCase == "-monoleft"
9035           || anArgCase == "-monolefteye"
9036           || anArgCase == "-perpsleft"
9037           || anArgCase == "-perpslefteye")
9038     {
9039       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
9040     }
9041     else if (anArgCase == "-right"
9042           || anArgCase == "-righteye"
9043           || anArgCase == "-monoright"
9044           || anArgCase == "-monorighteye"
9045           || anArgCase == "-perpsright")
9046     {
9047       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
9048     }
9049     else if (anArgCase == "-dist"
9050           || anArgCase == "-distance")
9051     {
9052       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9053       if (anArgValue != NULL
9054       && *anArgValue != '-')
9055       {
9056         ++anArgIter;
9057         aCamera->SetDistance (Draw::Atof (anArgValue));
9058         continue;
9059       }
9060       theDI << aCamera->Distance() << " ";
9061     }
9062     else if (anArgCase == "-iod")
9063     {
9064       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9065       if (anArgValue != NULL
9066       && *anArgValue != '-')
9067       {
9068         ++anArgIter;
9069         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
9070         continue;
9071       }
9072       theDI << aCamera->IOD() << " ";
9073     }
9074     else if (anArgCase == "-iodtype")
9075     {
9076       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9077       TCollection_AsciiString anValueCase (anArgValue);
9078       anValueCase.LowerCase();
9079       if (anValueCase == "abs"
9080        || anValueCase == "absolute")
9081       {
9082         ++anArgIter;
9083         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
9084         continue;
9085       }
9086       else if (anValueCase == "rel"
9087             || anValueCase == "relative")
9088       {
9089         ++anArgIter;
9090         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
9091         continue;
9092       }
9093       else if (*anArgValue != '-')
9094       {
9095         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
9096         return 1;
9097       }
9098       switch (aCamera->GetIODType())
9099       {
9100         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
9101         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
9102       }
9103     }
9104     else if (anArgCase == "-zfocus")
9105     {
9106       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9107       if (anArgValue != NULL
9108       && *anArgValue != '-')
9109       {
9110         ++anArgIter;
9111         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
9112         continue;
9113       }
9114       theDI << aCamera->ZFocus() << " ";
9115     }
9116     else if (anArgCase == "-zfocustype")
9117     {
9118       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9119       TCollection_AsciiString anValueCase (anArgValue);
9120       anValueCase.LowerCase();
9121       if (anValueCase == "abs"
9122        || anValueCase == "absolute")
9123       {
9124         ++anArgIter;
9125         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
9126         continue;
9127       }
9128       else if (anValueCase == "rel"
9129             || anValueCase == "relative")
9130       {
9131         ++anArgIter;
9132         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
9133         continue;
9134       }
9135       else if (*anArgValue != '-')
9136       {
9137         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
9138         return 1;
9139       }
9140       switch (aCamera->ZFocusType())
9141       {
9142         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
9143         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
9144       }
9145     }
9146     else if (anArgCase == "-lockzup"
9147           || anArgCase == "-turntable")
9148     {
9149       bool toLockUp = true;
9150       if (++anArgIter < theArgsNb
9151       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
9152       {
9153         --anArgIter;
9154       }
9155       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
9156     }
9157     else if (anArgCase == "-rotationmode"
9158           || anArgCase == "-rotmode")
9159     {
9160       AIS_RotationMode aRotMode = AIS_RotationMode_BndBoxActive;
9161       TCollection_AsciiString aRotStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9162       aRotStr.LowerCase();
9163       if (aRotStr == "bndboxactive"
9164        || aRotStr == "active")
9165       {
9166         aRotMode = AIS_RotationMode_BndBoxActive;
9167       }
9168       else if (aRotStr == "picklast"
9169             || aRotStr == "pick")
9170       {
9171         aRotMode = AIS_RotationMode_PickLast;
9172       }
9173       else if (aRotStr == "pickcenter")
9174       {
9175         aRotMode = AIS_RotationMode_PickCenter;
9176       }
9177       else if (aRotStr == "cameraat"
9178             || aRotStr == "cameracenter")
9179       {
9180         aRotMode = AIS_RotationMode_CameraAt;
9181       }
9182       else if (aRotStr == "bndboxscene"
9183             || aRotStr == "boxscene")
9184       {
9185         aRotMode = AIS_RotationMode_BndBoxScene;
9186       }
9187       else
9188       {
9189         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9190         return 1;
9191       }
9192
9193       ViewerTest::CurrentEventManager()->SetRotationMode (aRotMode);
9194       ++anArgIter;
9195     }
9196     else if (anArgCase == "-navigationmode"
9197           || anArgCase == "-navmode")
9198     {
9199       AIS_NavigationMode aNavMode = AIS_NavigationMode_Orbit;
9200       TCollection_AsciiString aNavStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9201       aNavStr.LowerCase();
9202       if (aNavStr == "orbit")
9203       {
9204         aNavMode = AIS_NavigationMode_Orbit;
9205       }
9206       else if (aNavStr == "flight"
9207             || aNavStr == "fly"
9208             || aNavStr == "copter"
9209             || aNavStr == "helicopter")
9210       {
9211         aNavMode = AIS_NavigationMode_FirstPersonFlight;
9212       }
9213       else if (aNavStr == "walk"
9214             || aNavStr == "shooter")
9215       {
9216         aNavMode = AIS_NavigationMode_FirstPersonWalk;
9217       }
9218       else
9219       {
9220         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9221         return 1;
9222       }
9223
9224       Handle(ViewerTest_EventManager) aViewMgr = ViewerTest::CurrentEventManager();
9225       aViewMgr->SetNavigationMode (aNavMode);
9226       if (aNavMode == AIS_NavigationMode_Orbit)
9227       {
9228         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
9229       }
9230       else
9231       {
9232         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateView);
9233       }
9234       ++anArgIter;
9235     }
9236     else if (anArgCase == "-fov"
9237           || anArgCase == "-fovy"
9238           || anArgCase == "-fovx"
9239           || anArgCase == "-fov2d")
9240     {
9241       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9242       if (anArgValue != NULL
9243       && *anArgValue != '-')
9244       {
9245         ++anArgIter;
9246         if (anArgCase == "-fov2d")
9247         {
9248           aCamera->SetFOV2d (Draw::Atof (anArgValue));
9249         }
9250         else if (anArgCase == "-fovx")
9251         {
9252           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
9253         }
9254         else
9255         {
9256           aCamera->SetFOVy (Draw::Atof (anArgValue));
9257         }
9258         continue;
9259       }
9260       if (anArgCase == "-fov2d")
9261       {
9262         theDI << aCamera->FOV2d() << " ";
9263       }
9264       else if (anArgCase == "-fovx")
9265       {
9266         theDI << aCamera->FOVx() << " ";
9267       }
9268       else
9269       {
9270         theDI << aCamera->FOVy() << " ";
9271       }
9272     }
9273     else if (anArgIter + 1 < theArgsNb
9274           && anArgCase == "-xrpose")
9275     {
9276       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
9277       anXRArg.LowerCase();
9278       if (anXRArg == "base")
9279       {
9280         aCamera = aView->View()->BaseXRCamera();
9281       }
9282       else if (anXRArg == "head")
9283       {
9284         aCamera = aView->View()->PosedXRCamera();
9285       }
9286       else
9287       {
9288         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
9289         return 1;
9290       }
9291       if (aCamera.IsNull())
9292       {
9293         Message::SendFail() << "Error: undefined XR pose";
9294         return 0;
9295       }
9296       if (aView->AutoZFitMode())
9297       {
9298         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
9299         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
9300         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
9301       }
9302     }
9303     else if (aPrsName.IsEmpty()
9304          && !anArgCase.StartsWith ("-"))
9305     {
9306       aPrsName = anArg;
9307     }
9308     else
9309     {
9310       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
9311       return 1;
9312     }
9313   }
9314
9315   if (aPrsName.IsEmpty()
9316    || theArgsNb > 2)
9317   {
9318     aView->Redraw();
9319   }
9320
9321   if (!aPrsName.IsEmpty())
9322   {
9323     Handle(AIS_CameraFrustum) aCameraFrustum;
9324     if (GetMapOfAIS().IsBound2 (aPrsName))
9325     {
9326       // find existing object
9327       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
9328       if (aCameraFrustum.IsNull())
9329       {
9330         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
9331         return 1;
9332       }
9333     }
9334
9335     if (aCameraFrustum.IsNull())
9336     {
9337       aCameraFrustum = new AIS_CameraFrustum();
9338     }
9339     else
9340     {
9341       // not include displayed object of old camera frustum in the new one.
9342       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
9343       aView->ZFitAll();
9344     }
9345     aCameraFrustum->SetCameraFrustum (aCamera);
9346
9347     ViewerTest::Display (aPrsName, aCameraFrustum);
9348   }
9349
9350   return 0;
9351 }
9352
9353 //! Parse stereo output mode
9354 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
9355                                          Graphic3d_StereoMode& theMode)
9356 {
9357   TCollection_AsciiString aFlag (theArg);
9358   aFlag.LowerCase();
9359   if (aFlag == "quadbuffer")
9360   {
9361     theMode = Graphic3d_StereoMode_QuadBuffer;
9362   }
9363   else if (aFlag == "anaglyph")
9364   {
9365     theMode = Graphic3d_StereoMode_Anaglyph;
9366   }
9367   else if (aFlag == "row"
9368         || aFlag == "rowinterlaced")
9369   {
9370     theMode = Graphic3d_StereoMode_RowInterlaced;
9371   }
9372   else if (aFlag == "col"
9373         || aFlag == "colinterlaced"
9374         || aFlag == "columninterlaced")
9375   {
9376     theMode = Graphic3d_StereoMode_ColumnInterlaced;
9377   }
9378   else if (aFlag == "chess"
9379         || aFlag == "chessboard")
9380   {
9381     theMode = Graphic3d_StereoMode_ChessBoard;
9382   }
9383   else if (aFlag == "sbs"
9384         || aFlag == "sidebyside")
9385   {
9386     theMode = Graphic3d_StereoMode_SideBySide;
9387   }
9388   else if (aFlag == "ou"
9389         || aFlag == "overunder")
9390   {
9391     theMode = Graphic3d_StereoMode_OverUnder;
9392   }
9393   else if (aFlag == "pageflip"
9394         || aFlag == "softpageflip")
9395   {
9396     theMode = Graphic3d_StereoMode_SoftPageFlip;
9397   }
9398   else if (aFlag == "openvr"
9399         || aFlag == "vr")
9400   {
9401     theMode = Graphic3d_StereoMode_OpenVR;
9402   }
9403   else
9404   {
9405     return Standard_False;
9406   }
9407   return Standard_True;
9408 }
9409
9410 //! Parse anaglyph filter
9411 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
9412                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
9413 {
9414   TCollection_AsciiString aFlag (theArg);
9415   aFlag.LowerCase();
9416   if (aFlag == "redcyansimple")
9417   {
9418     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9419   }
9420   else if (aFlag == "redcyan"
9421         || aFlag == "redcyanoptimized")
9422   {
9423     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
9424   }
9425   else if (aFlag == "yellowbluesimple")
9426   {
9427     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
9428   }
9429   else if (aFlag == "yellowblue"
9430         || aFlag == "yellowblueoptimized")
9431   {
9432     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
9433   }
9434   else if (aFlag == "greenmagenta"
9435         || aFlag == "greenmagentasimple")
9436   {
9437     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
9438   }
9439   else
9440   {
9441     return Standard_False;
9442   }
9443   return Standard_True;
9444 }
9445
9446 //==============================================================================
9447 //function : VStereo
9448 //purpose  :
9449 //==============================================================================
9450
9451 static int VStereo (Draw_Interpretor& theDI,
9452                     Standard_Integer  theArgNb,
9453                     const char**      theArgVec)
9454 {
9455   Handle(V3d_View) aView = ViewerTest::CurrentView();
9456   if (aView.IsNull())
9457   {
9458     Message::SendFail ("Error: no active viewer");
9459     return 0;
9460   }
9461
9462   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9463   Graphic3d_RenderingParams* aParams = &aView->ChangeRenderingParams();
9464   if (theArgNb < 2)
9465   {
9466     Standard_Boolean isActive = aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo;
9467     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
9468     if (isActive)
9469     {
9470       TCollection_AsciiString aMode;
9471       switch (aView->RenderingParams().StereoMode)
9472       {
9473         case Graphic3d_StereoMode_QuadBuffer:
9474         {
9475           aMode = "quadBuffer";
9476           break;
9477         }
9478         case Graphic3d_StereoMode_RowInterlaced:
9479         {
9480           aMode = "rowInterlaced";
9481           if (aView->RenderingParams().ToSmoothInterlacing)
9482           {
9483             aMode.AssignCat (" (smoothed)");
9484           }
9485           break;
9486         }
9487         case Graphic3d_StereoMode_ColumnInterlaced:
9488         {
9489           aMode = "columnInterlaced";
9490           if (aView->RenderingParams().ToSmoothInterlacing)
9491           {
9492             aMode.AssignCat (" (smoothed)");
9493           }
9494           break;
9495         }
9496         case Graphic3d_StereoMode_ChessBoard:
9497         {
9498           aMode = "chessBoard";
9499           if (aView->RenderingParams().ToSmoothInterlacing)
9500           {
9501             aMode.AssignCat (" (smoothed)");
9502           }
9503           break;
9504         }
9505         case Graphic3d_StereoMode_SideBySide:
9506         {
9507           aMode = "sideBySide";
9508           break;
9509         }
9510         case Graphic3d_StereoMode_OverUnder:
9511         {
9512           aMode = "overUnder";
9513           break;
9514         }
9515         case Graphic3d_StereoMode_SoftPageFlip:
9516         {
9517           aMode = "softPageFlip";
9518           break;
9519         }
9520         case Graphic3d_StereoMode_OpenVR:
9521         {
9522           aMode = "openVR";
9523           break;
9524         }
9525         case Graphic3d_StereoMode_Anaglyph:
9526         {
9527           aMode = "anaglyph";
9528           switch (aView->RenderingParams().AnaglyphFilter)
9529           {
9530             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
9531             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
9532             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
9533             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
9534             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
9535             case Graphic3d_RenderingParams::Anaglyph_UserDefined         : aMode.AssignCat (" (userDefined)");        break;
9536           }
9537         }
9538       }
9539       theDI << "Mode " << aMode << "\n";
9540     }
9541     return 0;
9542   }
9543
9544   Graphic3d_StereoMode aMode = aParams->StereoMode;
9545   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
9546   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
9547   {
9548     Standard_CString        anArg = theArgVec[anArgIter];
9549     TCollection_AsciiString aFlag (anArg);
9550     aFlag.LowerCase();
9551     if (anUpdateTool.parseRedrawMode (aFlag))
9552     {
9553       continue;
9554     }
9555     else if (aFlag == "0"
9556           || aFlag == "off")
9557     {
9558       if (++anArgIter < theArgNb)
9559       {
9560         Message::SendFail ("Error: wrong number of arguments");
9561         return 1;
9562       }
9563
9564       if (aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
9565       {
9566         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9567       }
9568       return 0;
9569     }
9570     else if (aFlag == "1"
9571           || aFlag == "on")
9572     {
9573       if (++anArgIter < theArgNb)
9574       {
9575         Message::SendFail ("Error: wrong number of arguments");
9576         return 1;
9577       }
9578
9579       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9580       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
9581       {
9582         return 0;
9583       }
9584     }
9585     else if (aFlag == "-reverse"
9586           || aFlag == "-noreverse"
9587           || aFlag == "-reversed"
9588           || aFlag == "-swap"
9589           || aFlag == "-noswap")
9590     {
9591       aParams->ToReverseStereo = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
9592     }
9593     else if (aFlag == "-mode"
9594           || aFlag == "-stereomode")
9595     {
9596       if (++anArgIter >= theArgNb
9597       || !parseStereoMode (theArgVec[anArgIter], aMode))
9598       {
9599         Message::SendFail() << "Syntax error at '" << anArg << "'";
9600         return 1;
9601       }
9602
9603       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9604       {
9605         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9606       }
9607     }
9608     else if (aFlag == "-anaglyph"
9609           || aFlag == "-anaglyphfilter")
9610     {
9611       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9612       if (++anArgIter >= theArgNb
9613       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
9614       {
9615         Message::SendFail() << "Syntax error at '" << anArg << "'";
9616         return 1;
9617       }
9618
9619       aMode = Graphic3d_StereoMode_Anaglyph;
9620       aParams->AnaglyphFilter = aFilter;
9621     }
9622     else if (parseStereoMode (anArg, aMode)) // short syntax
9623     {
9624       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9625       {
9626         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9627       }
9628     }
9629     else if (anArgIter + 1 < theArgNb
9630           && aFlag == "-hmdfov2d")
9631     {
9632       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
9633       if (aParams->HmdFov2d < 10.0f
9634        || aParams->HmdFov2d > 180.0f)
9635       {
9636         Message::SendFail() << "Error: FOV is out of range";
9637         return 1;
9638       }
9639     }
9640     else if (aFlag == "-mirror"
9641           || aFlag == "-mirrorcomposer")
9642     {
9643       aParams->ToMirrorComposer = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);;
9644     }
9645     else if (aFlag == "-smooth"
9646           || aFlag == "-nosmooth"
9647           || aFlag == "-smoothinterlacing"
9648           || aFlag == "-nosmoothinterlacing")
9649     {
9650       aParams->ToSmoothInterlacing = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
9651     }
9652     else if (anArgIter + 1 < theArgNb
9653           && (aFlag == "-unitfactor"
9654            || aFlag == "-unitscale"))
9655     {
9656       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
9657     }
9658     else
9659     {
9660       Message::SendFail() << "Syntax error at '" << anArg << "'";
9661       return 1;
9662     }
9663   }
9664
9665   aParams->StereoMode = aMode;
9666   aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9667   if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
9668   {
9669     // initiate implicit continuous rendering
9670     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
9671   }
9672   return 0;
9673 }
9674
9675 //===============================================================================================
9676 //function : VDefaults
9677 //purpose  :
9678 //===============================================================================================
9679 static int VDefaults (Draw_Interpretor& theDi,
9680                       Standard_Integer  theArgsNb,
9681                       const char**      theArgVec)
9682 {
9683   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9684   if (aCtx.IsNull())
9685   {
9686     Message::SendFail ("Error: no active viewer");
9687     return 1;
9688   }
9689
9690   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
9691   if (theArgsNb < 2)
9692   {
9693     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
9694     {
9695       theDi << "DeflType:           relative\n"
9696             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
9697     }
9698     else
9699     {
9700       theDi << "DeflType:           absolute\n"
9701             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
9702     }
9703     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
9704     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
9705     return 0;
9706   }
9707
9708   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9709   {
9710     TCollection_AsciiString anArg (theArgVec[anArgIter]);
9711     anArg.UpperCase();
9712     if (anArg == "-ABSDEFL"
9713      || anArg == "-ABSOLUTEDEFLECTION"
9714      || anArg == "-DEFL"
9715      || anArg == "-DEFLECTION")
9716     {
9717       if (++anArgIter >= theArgsNb)
9718       {
9719         Message::SendFail() << "Syntax error at " << anArg;
9720         return 1;
9721       }
9722       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
9723       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
9724     }
9725     else if (anArg == "-RELDEFL"
9726           || anArg == "-RELATIVEDEFLECTION"
9727           || anArg == "-DEVCOEFF"
9728           || anArg == "-DEVIATIONCOEFF"
9729           || anArg == "-DEVIATIONCOEFFICIENT")
9730     {
9731       if (++anArgIter >= theArgsNb)
9732       {
9733         Message::SendFail() << "Syntax error at " << anArg;
9734         return 1;
9735       }
9736       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
9737       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
9738     }
9739     else if (anArg == "-ANGDEFL"
9740           || anArg == "-ANGULARDEFL"
9741           || anArg == "-ANGULARDEFLECTION")
9742     {
9743       if (++anArgIter >= theArgsNb)
9744       {
9745         Message::SendFail() << "Syntax error at " << anArg;
9746         return 1;
9747       }
9748       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
9749     }
9750     else if (anArg == "-AUTOTR"
9751           || anArg == "-AUTOTRIANG"
9752           || anArg == "-AUTOTRIANGULATION")
9753     {
9754       ++anArgIter;
9755       bool toTurnOn = true;
9756       if (anArgIter >= theArgsNb
9757       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
9758       {
9759         Message::SendFail() << "Syntax error at '" << anArg << "'";
9760         return 1;
9761       }
9762       aDefParams->SetAutoTriangulation (toTurnOn);
9763     }
9764     else
9765     {
9766       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
9767       return 1;
9768     }
9769   }
9770
9771   return 0;
9772 }
9773
9774 //! Parse light source type from string.
9775 static bool parseLightSourceType (const TCollection_AsciiString& theTypeName,
9776                                   Graphic3d_TypeOfLightSource& theType)
9777 {
9778   TCollection_AsciiString aType (theTypeName);
9779   aType.LowerCase();
9780   if (aType == "amb"
9781    || aType == "ambient"
9782    || aType == "amblight")
9783   {
9784     theType = Graphic3d_TypeOfLightSource_Ambient;
9785   }
9786   else if (aType == "directional"
9787         || aType == "dirlight")
9788   {
9789     theType = Graphic3d_TypeOfLightSource_Directional;
9790   }
9791   else if (aType == "spot"
9792         || aType == "spotlight")
9793   {
9794     theType = Graphic3d_TypeOfLightSource_Spot;
9795   }
9796   else if (aType == "poslight"
9797         || aType == "positional"
9798         || aType == "point"
9799         || aType == "pnt")
9800   {
9801     theType = Graphic3d_TypeOfLightSource_Positional;
9802   }
9803   else
9804   {
9805     return false;
9806   }
9807   return true;
9808 }
9809
9810 //! Find existing light by name or index.
9811 static Handle(V3d_Light) findLightSource (const TCollection_AsciiString& theName)
9812 {
9813   Handle(V3d_Light) aLight;
9814   Standard_Integer aLightIndex = -1;
9815   Draw::ParseInteger (theName.ToCString(), aLightIndex);
9816   Standard_Integer aLightIt = 0;
9817   Handle(V3d_View) aView = ViewerTest::CurrentView();
9818   for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
9819   {
9820     if (aLightIndex != -1)
9821     {
9822       if (aLightIt == aLightIndex)
9823       {
9824         return aLightIter.Value();
9825       }
9826     }
9827     else if (aLightIter.Value()->GetId() == theName
9828           || aLightIter.Value()->Name()  == theName)
9829     {
9830       if (!aLight.IsNull())
9831       {
9832         Message::SendWarning() << "Warning: ambiguous light name '" << theName << "'";
9833         break;
9834       }
9835       aLight = aLightIter.Value();
9836     }
9837   }
9838   return aLight;
9839 }
9840
9841 //===============================================================================================
9842 //function : VLight
9843 //purpose  :
9844 //===============================================================================================
9845 static int VLight (Draw_Interpretor& theDi,
9846                    Standard_Integer  theArgsNb,
9847                    const char**      theArgVec)
9848 {
9849   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
9850   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
9851   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9852   if (aView.IsNull()
9853    || aViewer.IsNull())
9854   {
9855     Message::SendFail ("Error: no active viewer");
9856     return 1;
9857   }
9858
9859   if (theArgsNb < 2)
9860   {
9861     // print lights info
9862     Standard_Integer aLightId = 0;
9863     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
9864     {
9865       Handle(V3d_Light) aLight = aLightIter.Value();
9866       const Quantity_Color aColor = aLight->Color();
9867       theDi << "Light #" << aLightId
9868             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
9869             << " [" << aLight->GetId() << "] "
9870             << (aLight->IsEnabled() ? "ON" : "OFF") << "\n";
9871       switch (aLight->Type())
9872       {
9873         case V3d_AMBIENT:
9874         {
9875           theDi << "  Type:       Ambient\n"
9876                 << "  Intensity:  " << aLight->Intensity() << "\n";
9877           break;
9878         }
9879         case V3d_DIRECTIONAL:
9880         {
9881           theDi << "  Type:       Directional\n"
9882                 << "  Intensity:  " << aLight->Intensity() << "\n"
9883                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9884                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9885                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9886                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n";
9887           break;
9888         }
9889         case V3d_POSITIONAL:
9890         {
9891           theDi << "  Type:       Positional\n"
9892                 << "  Intensity:  " << aLight->Intensity() << "\n"
9893                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9894                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9895                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9896                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9897                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9898                 << "  Range:      " << aLight->Range() << "\n";
9899           break;
9900         }
9901         case V3d_SPOT:
9902         {
9903           theDi << "  Type:       Spot\n"
9904                 << "  Intensity:  " << aLight->Intensity() << "\n"
9905                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9906                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9907                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9908                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n"
9909                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9910                 << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n"
9911                 << "  Exponent:   " << aLight->Concentration() << "\n"
9912                 << "  Range:      " << aLight->Range() << "\n";
9913           break;
9914         }
9915         default:
9916         {
9917           theDi << "  Type:       UNKNOWN\n";
9918           break;
9919         }
9920       }
9921       theDi << "  Color:      " << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
9922     }
9923   }
9924
9925   Handle(V3d_Light) aLightOld, aLightNew;
9926   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
9927   bool isGlobal = true;
9928   ViewerTest_AutoUpdater anUpdateTool (aCtx, aView);
9929   Handle(AIS_LightSource) aLightPrs;
9930   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
9931   {
9932     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
9933     TCollection_AsciiString anArgCase (anArg);
9934     anArgCase.LowerCase();
9935     if (anUpdateTool.parseRedrawMode (anArg))
9936     {
9937       continue;
9938     }
9939     else if (anArgCase == "-new"
9940           || anArgCase == "-add"
9941           || anArgCase == "-create"
9942           || anArgCase == "-type"
9943           || (anArgCase == "-reset"
9944           && !aLightNew.IsNull())
9945           || (anArgCase == "-defaults"
9946           && !aLightNew.IsNull())
9947           || anArgCase == "add"
9948           || anArgCase == "new"
9949           || anArgCase == "create")
9950     {
9951       Graphic3d_TypeOfLightSource aType = Graphic3d_TypeOfLightSource_Ambient;
9952       if (anArgCase == "-reset")
9953       {
9954         aType = aLightNew->Type();
9955       }
9956       else if (anArgIt + 1 >= theArgsNb
9957            || !parseLightSourceType (theArgVec[++anArgIt], aType))
9958       {
9959         theDi << "Syntax error at '" << theArgVec[anArgIt] << "'\n";
9960         return 1;
9961       }
9962
9963       TCollection_AsciiString aName;
9964       if (!aLightNew.IsNull())
9965       {
9966         aName = aLightNew->Name();
9967       }
9968       switch (aType)
9969       {
9970         case Graphic3d_TypeOfLightSource_Ambient:
9971         {
9972           aLightNew = new V3d_AmbientLight();
9973           break;
9974         }
9975         case Graphic3d_TypeOfLightSource_Directional:
9976         {
9977           aLightNew = new V3d_DirectionalLight();
9978           break;
9979         }
9980         case Graphic3d_TypeOfLightSource_Spot:
9981         {
9982           aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
9983           break;
9984         }
9985         case Graphic3d_TypeOfLightSource_Positional:
9986         {
9987           aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
9988           break;
9989         }
9990       }
9991
9992       if (anArgCase == "-type"
9993       && !aLightOld.IsNull())
9994       {
9995         aLightNew->CopyFrom (aLightOld);
9996       }
9997       aLightNew->SetName (aName);
9998     }
9999     else if ((anArgCase == "-layer"
10000            || anArgCase == "-zlayer")
10001           && anArgIt + 1 < theArgsNb)
10002     {
10003       if (!ViewerTest::ParseZLayer (theArgVec[++anArgIt], aLayer)
10004       ||  aLayer == Graphic3d_ZLayerId_UNKNOWN)
10005       {
10006         Message::SendFail() << "Error: wrong syntax at '" << theArgVec[anArgIt] << "'";
10007         return 1;
10008       }
10009     }
10010     else if (anArgCase == "-glob"
10011           || anArgCase == "-global"
10012           || anArgCase == "-loc"
10013           || anArgCase == "-local")
10014     {
10015       isGlobal = anArgCase.StartsWith ("-glob");
10016     }
10017     else if (anArgCase == "-def"
10018           || anArgCase == "-defaults"
10019           || anArgCase == "-reset")
10020     {
10021       aViewer->SetDefaultLights();
10022       aLightOld.Nullify();
10023       aLightNew.Nullify();
10024       aLightPrs.Nullify();
10025     }
10026     else if (anArgCase == "-clr"
10027           || anArgCase == "-clear"
10028           || anArgCase == "clear")
10029     {
10030       TColStd_SequenceOfInteger aLayers;
10031       aViewer->GetAllZLayers (aLayers);
10032       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10033       {
10034         if (aLayeriter.Value() == aLayer
10035          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10036         {
10037           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10038           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10039           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10040           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10041           {
10042             break;
10043           }
10044         }
10045       }
10046
10047       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10048       {
10049         ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
10050         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10051         {
10052           Handle(V3d_Light) aLight = aLightIter.Value();
10053           Handle(AIS_InteractiveObject) aPrsObject;
10054           GetMapOfAIS().Find2 (aLight->Name(), aPrsObject);
10055           if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10056           {
10057             aCtx->Remove (aLightSourceDel, false);
10058             aMap.UnBind1 (aLightSourceDel);
10059           }
10060           aViewer->DelLight (aLight);
10061           aLightIter = aView->ActiveLightIterator();
10062         }
10063       }
10064
10065       aLightOld.Nullify();
10066       aLightNew.Nullify();
10067       aLightPrs.Nullify();
10068     }
10069     else if (!aLightNew.IsNull()
10070           && (anArgCase == "-display"
10071            || anArgCase == "-disp"
10072            || anArgCase == "-presentation"
10073            || anArgCase == "-prs"))
10074     {
10075       TCollection_AsciiString aLightName = aLightNew->Name();
10076       if (anArgIt + 1 < theArgsNb
10077        && theArgVec[anArgIt + 1][0] != '-')
10078       {
10079         // old syntax
10080         aLightName = theArgVec[++anArgIt];
10081         if (aLightNew->Name() != aLightName)
10082         {
10083           if (Handle(V3d_Light) anOtherLight = findLightSource (aLightName))
10084           {
10085             theDi << "Syntax error: light with name '" << aLightName << "' is already defined";
10086             return 1;
10087           }
10088           aLightNew->SetName (aLightName);
10089         }
10090       }
10091       if (aLightName.IsEmpty())
10092       {
10093         Message::SendFail() << "Error: nameless light source cannot be displayed";
10094         return 1;
10095       }
10096       if (aLightPrs.IsNull())
10097       {
10098         aLightPrs = new AIS_LightSource (aLightNew);
10099       }
10100       theDi << aLightName << " ";
10101     }
10102     else if (!aLightNew.IsNull()
10103           && (anArgCase == "-disable"
10104            || anArgCase == "-disabled"
10105            || anArgCase == "-enable"
10106            || anArgCase == "-enabled"))
10107     {
10108       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10109       if (anArgCase == "-disable"
10110        || anArgCase == "-disabled")
10111       {
10112         toEnable = !toEnable;
10113       }
10114       aLightNew->SetEnabled (toEnable);
10115     }
10116     else if (!aLightNew.IsNull()
10117           && (anArgCase == "-color"
10118            || anArgCase == "-colour"
10119            || anArgCase == "color"))
10120     {
10121       Quantity_Color aColor;
10122       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
10123                                                      theArgVec + anArgIt + 1,
10124                                                      aColor);
10125       anArgIt += aNbParsed;
10126       if (aNbParsed == 0)
10127       {
10128         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10129         return 1;
10130       }
10131       aLightNew->SetColor (aColor);
10132     }
10133     else if (!aLightNew.IsNull()
10134           && (anArgCase == "-pos"
10135            || anArgCase == "-position"
10136            || anArgCase == "-prsposition"
10137            || anArgCase == "-prspos"
10138            || anArgCase == "pos"
10139            || anArgCase == "position")
10140           && (anArgIt + 3) < theArgsNb)
10141     {
10142       gp_XYZ aPosXYZ;
10143       if (!parseXYZ (theArgVec + anArgIt + 1, aPosXYZ))
10144       {
10145         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10146         return 1;
10147       }
10148
10149       anArgIt += 3;
10150       if (anArgCase == "-prsposition"
10151        || anArgCase == "-prspos")
10152       {
10153         aLightNew->SetDisplayPosition (aPosXYZ);
10154       }
10155       else
10156       {
10157         if (aLightNew->Type() != Graphic3d_TypeOfLightSource_Positional
10158          && aLightNew->Type() != Graphic3d_TypeOfLightSource_Spot)
10159         {
10160           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10161           return 1;
10162         }
10163
10164         aLightNew->SetPosition (aPosXYZ);
10165       }
10166     }
10167     else if (!aLightNew.IsNull()
10168           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional
10169            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10170           && (anArgCase == "-dir"
10171            || anArgCase == "-direction")
10172           && (anArgIt + 3) < theArgsNb)
10173     {
10174       gp_XYZ aDirXYZ;
10175       if (!parseXYZ (theArgVec + anArgIt + 1, aDirXYZ))
10176       {
10177         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10178         return 1;
10179       }
10180
10181       anArgIt += 3;
10182       aLightNew->SetDirection (gp_Dir (aDirXYZ));
10183     }
10184     else if (!aLightNew.IsNull()
10185           && (anArgCase == "-smoothangle"
10186            || anArgCase == "-smoothradius"
10187            || anArgCase == "-sm"
10188            || anArgCase == "-smoothness")
10189           && anArgIt + 1 < theArgsNb)
10190     {
10191       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10192       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10193       {
10194         aSmoothness = Standard_ShortReal(aSmoothness * M_PI / 180.0);
10195       }
10196       if (Abs (aSmoothness) <= ShortRealEpsilon())
10197       {
10198         aLightNew->SetIntensity (1.f);
10199       }
10200       else if (Abs (aLightNew->Smoothness()) <= ShortRealEpsilon())
10201       {
10202         aLightNew->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
10203       }
10204       else
10205       {
10206         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightNew->Smoothness());
10207         aLightNew->SetIntensity (aLightNew->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
10208       }
10209
10210       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10211       {
10212         aLightNew->SetSmoothRadius (aSmoothness);
10213       }
10214       else if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10215       {
10216         aLightNew->SetSmoothAngle (aSmoothness);
10217       }
10218     }
10219     else if (!aLightNew.IsNull()
10220           && (anArgCase == "-int"
10221            || anArgCase == "-intensity")
10222           && anArgIt + 1 < theArgsNb)
10223     {
10224       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10225       aLightNew->SetIntensity (aIntensity);
10226     }
10227     else if (!aLightNew.IsNull()
10228           &&  aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10229           && (anArgCase == "-spotangle"
10230            || anArgCase == "-ang"
10231            || anArgCase == "-angle")
10232           && anArgIt + 1 < theArgsNb)
10233     {
10234       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10235       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
10236       aLightNew->SetAngle (anAngle);
10237     }
10238     else if (!aLightNew.IsNull()
10239           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10240            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10241           && (anArgCase == "-constatten"
10242            || anArgCase == "-constattenuation")
10243           && anArgIt + 1 < theArgsNb)
10244     {
10245       const Standard_ShortReal aConstAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10246       aLightNew->SetAttenuation (aConstAtten, aLightNew->LinearAttenuation());
10247     }
10248     else if (!aLightNew.IsNull()
10249           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10250            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10251           && (anArgCase == "-linatten"
10252            || anArgCase == "-linearatten"
10253            || anArgCase == "-linearattenuation")
10254           && anArgIt + 1 < theArgsNb)
10255     {
10256       const Standard_ShortReal aLinAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10257       aLightNew->SetAttenuation (aLightNew->ConstAttenuation(), aLinAtten);
10258     }
10259     else if (!aLightNew.IsNull()
10260           && aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10261           && (anArgCase == "-spotexp"
10262            || anArgCase == "-spotexponent"
10263            || anArgCase == "-exp"
10264            || anArgCase == "-exponent")
10265           && anArgIt + 1 < theArgsNb)
10266     {
10267       aLightNew->SetConcentration ((Standard_ShortReal )Atof (theArgVec[++anArgIt]));
10268     }
10269     else if (!aLightNew.IsNull()
10270            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10271            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Directional
10272            && anArgCase == "-range"
10273            && anArgIt + 1 < theArgsNb)
10274     {
10275       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[++anArgIt]));
10276       aLightNew->SetRange (aRange);
10277     }
10278     else if (!aLightNew.IsNull()
10279           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10280           && (anArgCase == "-head"
10281            || anArgCase == "-headlight"))
10282     {
10283       Standard_Boolean isHeadLight = Standard_True;
10284       if (anArgIt + 1 < theArgsNb
10285        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
10286       {
10287         ++anArgIt;
10288       }
10289       aLightNew->SetHeadlight (isHeadLight);
10290     }
10291     else if (!aLightNew.IsNull()
10292            && anArgCase == "-name"
10293            && anArgIt + 1 < theArgsNb)
10294     {
10295       const TCollection_AsciiString aName = theArgVec[++anArgIt];
10296       if (aLightNew->Name() == aName)
10297       {
10298         continue;
10299       }
10300
10301       if (Handle(V3d_Light) anOtherLight = findLightSource (aName))
10302       {
10303         theDi << "Syntax error: light with name '" << aName << "' is already defined";
10304         return 1;
10305       }
10306       aLightNew->SetName (aName);
10307     }
10308     else if (!aLightPrs.IsNull()
10309           && (anArgCase == "-showzoomable"
10310            || anArgCase == "-prszoomable"
10311            || anArgCase == "-zoomable"))
10312     {
10313       const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10314       aLightPrs->SetZoomable (isZoomable);
10315     }
10316     else if (!aLightPrs.IsNull()
10317          && (anArgCase == "-showdraggable"
10318           || anArgCase == "-prsdraggable"
10319           || anArgCase == "-draggable"))
10320     {
10321       const bool isDraggable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10322       aLightPrs->SetDraggable (isDraggable);
10323     }
10324     else if (!aLightPrs.IsNull()
10325           && (anArgCase == "-showname"
10326            || anArgCase == "-prsname"))
10327     {
10328       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10329       aLightPrs->SetDisplayName (toDisplay);
10330     }
10331     else if (!aLightPrs.IsNull()
10332           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10333            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10334           && (anArgCase == "-showrange"
10335            || anArgCase == "-prsrange"))
10336     {
10337       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10338       aLightPrs->SetDisplayRange (toDisplay);
10339     }
10340     else if (!aLightPrs.IsNull()
10341           && (anArgCase == "-showsize"
10342            || anArgCase == "-prssize")
10343           && anArgIt + 1 < theArgsNb)
10344     {
10345       Standard_Real aSize = 0.0;
10346       if (!Draw::ParseReal (theArgVec[++anArgIt], aSize)
10347        || aSize <= 0.0
10348        || aLightPrs.IsNull())
10349       {
10350         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10351         return 1;
10352       }
10353
10354       aLightPrs->SetSize (aSize);
10355     }
10356     else if (!aLightPrs.IsNull()
10357           && (anArgCase == "-dirarcsize"
10358            || anArgCase == "-arcsize"
10359            || anArgCase == "-arc")
10360           && anArgIt + 1 < theArgsNb)
10361     {
10362       Standard_Integer aSize = 0;
10363       if (!Draw::ParseInteger (theArgVec[anArgIt + 1], aSize)
10364        || aSize <= 0
10365        || aLightPrs->Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
10366       {
10367         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10368         return 1;
10369       }
10370       ++anArgIt;
10371       aLightPrs->SetArcSize (aSize);
10372     }
10373     else if (!aLightNew.IsNull()
10374           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10375           && (anArgCase == "-castshadow"
10376            || anArgCase == "-castshadows"
10377            || anArgCase == "-shadows"))
10378     {
10379       bool toCastShadows = true;
10380       if (anArgIt + 1 < theArgsNb
10381        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
10382       {
10383         ++anArgIt;
10384       }
10385       aLightNew->SetCastShadows (toCastShadows);
10386     }
10387     else if (anArgCase == "-del"
10388           || anArgCase == "-delete"
10389           || anArgCase == "-remove"
10390           || anArgCase == "del"
10391           || anArgCase == "delete"
10392           || anArgCase == "remove")
10393     {
10394       if (aLightOld.IsNull())
10395       {
10396         if (!aLightNew.IsNull())
10397         {
10398           aLightNew.Nullify();
10399           continue;
10400         }
10401
10402         if (++anArgIt >= theArgsNb)
10403         {
10404           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10405           return 1;
10406         }
10407
10408         const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10409         aLightOld = findLightSource (anOldName);
10410         if (aLightOld.IsNull())
10411         {
10412           Message::SendWarning() << "Warning: light '" << anOldName << "' not found";
10413           continue;
10414         }
10415       }
10416
10417       aLightNew.Nullify();
10418       aLightPrs.Nullify();
10419     }
10420     else if (anArgCase == "-change"
10421           || anArgCase == "change")
10422     {
10423       // just skip old syntax
10424     }
10425     else if (aLightNew.IsNull()
10426          && !anArgCase.StartsWith ("-"))
10427     {
10428       if (!aLightNew.IsNull())
10429       {
10430         continue;
10431       }
10432
10433       const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10434       aLightOld = findLightSource (anOldName);
10435       if (!aLightOld.IsNull())
10436       {
10437         aLightNew = aLightOld;
10438
10439         Handle(AIS_InteractiveObject) aPrsObject;
10440         GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10441         aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsObject);
10442       }
10443       else
10444       {
10445         Standard_Integer aLightIndex = -1;
10446         Draw::ParseInteger (anOldName.ToCString(), aLightIndex);
10447         if (aLightIndex != -1)
10448         {
10449           Message::SendFail() << "Syntax error: light source with index '" << aLightIndex << "' is not found";
10450           return 1;
10451         }
10452
10453         aLightNew = new V3d_AmbientLight();
10454         aLightNew->SetName (anOldName);
10455       }
10456     }
10457     else
10458     {
10459       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
10460       return 1;
10461     }
10462   }
10463
10464   // delete old light source
10465   if (!aLightOld.IsNull()
10466     && aLightOld != aLightNew)
10467   {
10468     TColStd_SequenceOfInteger aLayers;
10469     aViewer->GetAllZLayers (aLayers);
10470     for (TColStd_SequenceOfInteger::Iterator aLayerIter (aLayers); aLayerIter.More(); aLayerIter.Next())
10471     {
10472       if (aLayerIter.Value() == aLayer
10473        || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10474       {
10475         Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerIter.Value());
10476         if (!aSettings.Lights().IsNull())
10477         {
10478           aSettings.Lights()->Remove (aLightOld);
10479           if (aSettings.Lights()->IsEmpty())
10480           {
10481             aSettings.SetLights (Handle(Graphic3d_LightSet)());
10482           }
10483         }
10484         aViewer->SetZLayerSettings (aLayerIter.Value(), aSettings);
10485         if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10486         {
10487           break;
10488         }
10489       }
10490     }
10491
10492     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10493     {
10494       Handle(AIS_InteractiveObject) aPrsObject;
10495       GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10496       if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10497       {
10498         aCtx->Remove (aLightSourceDel, false);
10499         GetMapOfAIS().UnBind1 (aLightSourceDel);
10500       }
10501       aViewer->DelLight (aLightOld);
10502     }
10503     aLightOld.Nullify();
10504   }
10505
10506   // add new light source
10507   if (!aLightNew.IsNull())
10508   {
10509     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10510     {
10511       aViewer->AddLight (aLightNew);
10512       if (isGlobal)
10513       {
10514         aViewer->SetLightOn (aLightNew);
10515       }
10516       else
10517       {
10518         aView->SetLightOn (aLightNew);
10519       }
10520     }
10521     else
10522     {
10523       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayer);
10524       if (aSettings.Lights().IsNull())
10525       {
10526         aSettings.SetLights (new Graphic3d_LightSet());
10527       }
10528       aSettings.Lights()->Add (aLightNew);
10529       aViewer->SetZLayerSettings (aLayer, aSettings);
10530     }
10531
10532     if (!aLightPrs.IsNull())
10533     {
10534       aLightPrs->SetLight (aLightNew);
10535       ViewerTest::Display (aLightNew->Name(), aLightPrs, false);
10536     }
10537   }
10538
10539   // manage presentations
10540   struct LightPrsSort
10541   {
10542     bool operator() (const Handle(AIS_LightSource)& theLeft,
10543                      const Handle(AIS_LightSource)& theRight)
10544     {
10545       return theLeft->Light()->GetId() < theRight->Light()->GetId();
10546     }
10547   };
10548
10549   AIS_ListOfInteractive aPrsList;
10550   aCtx->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
10551   if (!aPrsList.IsEmpty())
10552   {
10553     // update light source presentations
10554     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
10555     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
10556     {
10557       if (Handle(AIS_LightSource) aLightPrs2 = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
10558       {
10559         aLightPrsVec.push_back (aLightPrs2);
10560       }
10561     }
10562
10563     // sort objects by id as AIS_InteractiveContext stores them in unordered map
10564     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
10565
10566     Standard_Integer aTopStack = 0;
10567     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
10568     {
10569       Handle(AIS_LightSource) aLightPrs2 = *aPrsIter;
10570       if (!aLightPrs2->TransformPersistence().IsNull()
10571         && aLightPrs2->TransformPersistence()->IsTrihedronOr2d())
10572       {
10573         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs2->Size();
10574         aLightPrs2->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
10575         aTopStack += aPrsSize + aPrsSize / 2;
10576       }
10577       aCtx->Redisplay (aLightPrs2, false);
10578       aCtx->SetTransformPersistence (aLightPrs2, aLightPrs2->TransformPersistence());
10579     }
10580   }
10581   return 0;
10582 }
10583
10584 //===============================================================================================
10585 //function : VPBREnvironment
10586 //purpose  :
10587 //===============================================================================================
10588 static int VPBREnvironment (Draw_Interpretor&,
10589                             Standard_Integer theArgsNb,
10590                             const char**     theArgVec)
10591 {
10592   if (theArgsNb > 2)
10593   {
10594     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
10595     return 1;
10596   }
10597
10598   Handle(V3d_View) aView = ViewerTest::CurrentView();
10599   if (aView.IsNull())
10600   {
10601     Message::SendFail ("Error: no active viewer");
10602     return 1;
10603   }
10604
10605   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
10606   anArg.LowerCase();
10607
10608   if (anArg == "-generate"
10609    || anArg == "-gen")
10610   {
10611     aView->GeneratePBREnvironment (Standard_True);
10612   }
10613   else if (anArg == "-clear")
10614   {
10615     aView->ClearPBREnvironment (Standard_True);
10616   }
10617   else
10618   {
10619     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
10620     return 1;
10621   }
10622
10623   return 0;
10624 }
10625
10626 //! Read Graphic3d_RenderingParams::PerfCounters flag.
10627 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
10628                                             Standard_Boolean& theToReset,
10629                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
10630                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
10631 {
10632   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
10633   TCollection_AsciiString aVal = theValue;
10634   Standard_Boolean toReverse = Standard_False;
10635   if (aVal == "none")
10636   {
10637     theToReset = Standard_True;
10638     return Standard_True;
10639   }
10640   else if (aVal.StartsWith ("-"))
10641   {
10642     toReverse = Standard_True;
10643     aVal = aVal.SubString (2, aVal.Length());
10644   }
10645   else if (aVal.StartsWith ("no"))
10646   {
10647     toReverse = Standard_True;
10648     aVal = aVal.SubString (3, aVal.Length());
10649   }
10650   else if (aVal.StartsWith ("+"))
10651   {
10652     aVal = aVal.SubString (2, aVal.Length());
10653   }
10654   else
10655   {
10656     theToReset = Standard_True;
10657   }
10658
10659   if (     aVal == "fps"
10660         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
10661   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
10662   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
10663   else if (aVal == "structs"
10664         || aVal == "structures"
10665         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
10666   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
10667   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
10668   else if (aVal == "tris"
10669         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
10670   else if (aVal == "pnts"
10671         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
10672   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
10673   else if (aVal == "mem"
10674         || aVal == "gpumem"
10675         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
10676   else if (aVal == "skipimmediate"
10677         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
10678   else if (aVal == "frametime"
10679         || aVal == "frametimers"
10680         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
10681   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
10682   else if (aVal == "extended"
10683         || aVal == "verbose"
10684         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
10685   else if (aVal == "full"
10686         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
10687   else
10688   {
10689     return Standard_False;
10690   }
10691
10692   if (toReverse)
10693   {
10694     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
10695   }
10696   else
10697   {
10698     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
10699   }
10700   return Standard_True;
10701 }
10702
10703 //! Read Graphic3d_RenderingParams::PerfCounters flags.
10704 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
10705                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
10706 {
10707   TCollection_AsciiString aValue = theValue;
10708   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
10709   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
10710   Standard_Boolean toReset = Standard_False;
10711   for (;;)
10712   {
10713     Standard_Integer aSplitPos = aValue.Search ("|");
10714     if (aSplitPos <= 0)
10715     {
10716       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
10717       {
10718         return Standard_False;
10719       }
10720       if (toReset)
10721       {
10722         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
10723       }
10724       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
10725       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
10726       return Standard_True;
10727     }
10728
10729     if (aSplitPos > 1)
10730     {
10731       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
10732       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
10733       {
10734         return Standard_False;
10735       }
10736     }
10737     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
10738   }
10739 }
10740
10741 //=======================================================================
10742 //function : VRenderParams
10743 //purpose  : Enables/disables rendering features
10744 //=======================================================================
10745
10746 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
10747                                        Standard_Integer  theArgNb,
10748                                        const char**      theArgVec)
10749 {
10750   Handle(V3d_View) aView = ViewerTest::CurrentView();
10751   if (aView.IsNull())
10752   {
10753     Message::SendFail ("Error: no active viewer");
10754     return 1;
10755   }
10756
10757   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
10758   TCollection_AsciiString aCmdName (theArgVec[0]);
10759   aCmdName.LowerCase();
10760   if (aCmdName == "vraytrace")
10761   {
10762     if (theArgNb == 1)
10763     {
10764       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
10765       return 0;
10766     }
10767     else if (theArgNb == 2)
10768     {
10769       TCollection_AsciiString aValue (theArgVec[1]);
10770       aValue.LowerCase();
10771       if (aValue == "on"
10772        || aValue == "1")
10773       {
10774         aParams.Method = Graphic3d_RM_RAYTRACING;
10775         aView->Redraw();
10776         return 0;
10777       }
10778       else if (aValue == "off"
10779             || aValue == "0")
10780       {
10781         aParams.Method = Graphic3d_RM_RASTERIZATION;
10782         aView->Redraw();
10783         return 0;
10784       }
10785       else
10786       {
10787         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
10788         return 1;
10789       }
10790     }
10791     else
10792     {
10793       Message::SendFail ("Syntax error: wrong number of arguments");
10794       return 1;
10795     }
10796   }
10797
10798   if (theArgNb < 2)
10799   {
10800     theDI << "renderMode:  ";
10801     switch (aParams.Method)
10802     {
10803       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10804       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
10805     }
10806     theDI << "\n";
10807     theDI << "transparency:  ";
10808     switch (aParams.TransparencyMethod)
10809     {
10810       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
10811       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
10812                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
10813       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
10814                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
10815     }
10816     theDI << "\n";
10817     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
10818     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
10819     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
10820     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
10821     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
10822     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
10823     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
10824     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
10825     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
10826     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
10827     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
10828     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
10829     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
10830     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
10831     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
10832     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
10833     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
10834     theDI << "shadingModel: ";
10835     switch (aView->ShadingModel())
10836     {
10837       case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
10838       case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit";     break;
10839       case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat";      break;
10840       case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud";   break;
10841       case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong";     break;
10842       case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
10843       case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
10844     }
10845     theDI << "\n";
10846     {
10847       theDI << "perfCounters:";
10848       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
10849       {
10850         theDI << " fps";
10851       }
10852       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
10853       {
10854         theDI << " cpu";
10855       }
10856       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
10857       {
10858         theDI << " structs";
10859       }
10860       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
10861       {
10862         theDI << " groups";
10863       }
10864       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
10865       {
10866         theDI << " arrays";
10867       }
10868       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
10869       {
10870         theDI << " tris";
10871       }
10872       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
10873       {
10874         theDI << " lines";
10875       }
10876       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
10877       {
10878         theDI << " pnts";
10879       }
10880       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
10881       {
10882         theDI << " gpumem";
10883       }
10884       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
10885       {
10886         theDI << " frameTime";
10887       }
10888       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
10889       {
10890         theDI << " skipimmediate";
10891       }
10892       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
10893       {
10894         theDI << " none";
10895       }
10896       theDI << "\n";
10897     }
10898     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
10899     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
10900     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
10901                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
10902                                                                                                                     "noUpdate") << "\n";
10903     theDI << "\n";
10904     return 0;
10905   }
10906
10907   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
10908   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10909   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10910   {
10911     Standard_CString        anArg (theArgVec[anArgIter]);
10912     TCollection_AsciiString aFlag (anArg);
10913     aFlag.LowerCase();
10914     if (anUpdateTool.parseRedrawMode (aFlag))
10915     {
10916       continue;
10917     }
10918     else if (aFlag == "-echo"
10919           || aFlag == "-print")
10920     {
10921       toPrint = Standard_True;
10922       anUpdateTool.Invalidate();
10923     }
10924     else if (aFlag == "-reset")
10925     {
10926       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
10927     }
10928     else if (aFlag == "-sync"
10929           && (anArgIter + 1 < theArgNb))
10930     {
10931       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
10932       aSyncFlag.LowerCase();
10933       if (aSyncFlag == "default"
10934        || aSyncFlag == "defaults"
10935        || aSyncFlag == "viewer")
10936       {
10937         toSyncDefaults = true;
10938       }
10939       else if (aSyncFlag == "allviews"
10940             || aSyncFlag == "views")
10941       {
10942         toSyncAllViews = true;
10943       }
10944       else
10945       {
10946         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
10947         return 1;
10948       }
10949     }
10950     else if (aFlag == "-mode"
10951           || aFlag == "-rendermode"
10952           || aFlag == "-render_mode")
10953     {
10954       if (toPrint)
10955       {
10956         switch (aParams.Method)
10957         {
10958           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10959           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
10960         }
10961         continue;
10962       }
10963       else
10964       {
10965         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10966         return 1;
10967       }
10968     }
10969     else if (aFlag == "-ray"
10970           || aFlag == "-raytrace")
10971     {
10972       if (toPrint)
10973       {
10974         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
10975         continue;
10976       }
10977
10978       bool isRayTrace = true;
10979       if (anArgIter + 1 < theArgNb
10980        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
10981       {
10982         ++anArgIter;
10983       }
10984       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
10985     }
10986     else if (aFlag == "-rast"
10987           || aFlag == "-raster"
10988           || aFlag == "-rasterization")
10989     {
10990       if (toPrint)
10991       {
10992         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
10993         continue;
10994       }
10995
10996       bool isRaster = true;
10997       if (anArgIter + 1 < theArgNb
10998        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
10999       {
11000         ++anArgIter;
11001       }
11002       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
11003     }
11004     else if (aFlag == "-msaa")
11005     {
11006       if (toPrint)
11007       {
11008         theDI << aParams.NbMsaaSamples << " ";
11009         continue;
11010       }
11011       else if (++anArgIter >= theArgNb)
11012       {
11013         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11014         return 1;
11015       }
11016
11017       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11018       if (aNbSamples < 0)
11019       {
11020         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11021         return 1;
11022       }
11023       else
11024       {
11025         aParams.NbMsaaSamples = aNbSamples;
11026       }
11027     }
11028     else if (aFlag == "-linefeather"
11029           || aFlag == "-edgefeather"
11030           || aFlag == "-feather")
11031     {
11032       if (toPrint)
11033       {
11034         theDI << " " << aParams.LineFeather << " ";
11035         continue;
11036       }
11037       else if (++anArgIter >= theArgNb)
11038       {
11039         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11040         return 1;
11041       }
11042
11043       TCollection_AsciiString aParam = theArgVec[anArgIter];
11044       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11045       if (aFeather <= 0.0f)
11046       {
11047         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
11048         return 1;
11049       }
11050       aParams.LineFeather = aFeather;
11051     }
11052     else if (aFlag == "-oit")
11053     {
11054       if (toPrint)
11055       {
11056         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
11057         {
11058           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
11059         }
11060         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
11061         {
11062           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
11063         }
11064         else
11065         {
11066           theDI << "off" << " ";
11067         }
11068         continue;
11069       }
11070       else if (++anArgIter >= theArgNb)
11071       {
11072         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11073         return 1;
11074       }
11075
11076       TCollection_AsciiString aParam = theArgVec[anArgIter];
11077       aParam.LowerCase();
11078       if (aParam == "peeling"
11079        || aParam == "peel")
11080       {
11081         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
11082         if (anArgIter + 1 < theArgNb
11083          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
11084         {
11085           ++anArgIter;
11086           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11087           if (aNbLayers < 2)
11088           {
11089             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
11090             return 1;
11091           }
11092           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11093         }
11094       }
11095       else if (aParam == "weighted"
11096             || aParam == "weight")
11097       {
11098         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11099         if (anArgIter + 1 < theArgNb
11100          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
11101         {
11102           ++anArgIter;
11103           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
11104           if (aWeight < 0.f || aWeight > 1.f)
11105           {
11106             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11107             return 1;
11108           }
11109           aParams.OitDepthFactor = aWeight;
11110         }
11111       }
11112       else if (aParam.IsRealValue())
11113       {
11114         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11115         if (aWeight < 0.f || aWeight > 1.f)
11116         {
11117           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11118           return 1;
11119         }
11120
11121         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11122         aParams.OitDepthFactor     = aWeight;
11123       }
11124       else if (aParam == "off")
11125       {
11126         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
11127       }
11128       else
11129       {
11130         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11131         return 1;
11132       }
11133     }
11134     else if (aFlag == "-fonthinting"
11135           || aFlag == "-fonthint")
11136     {
11137       if (toPrint)
11138       {
11139         if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11140         {
11141           theDI << "normal" << " ";
11142         }
11143         else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11144         {
11145           theDI << "light" << " ";
11146         }
11147         else
11148         {
11149           theDI << "off" << " ";
11150         }
11151         continue;
11152       }
11153       else if (anArgIter + 1 >= theArgNb)
11154       {
11155         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11156         return 1;
11157       }
11158
11159       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11160       aHintStyle.LowerCase();
11161       if (aHintStyle == "normal"
11162        || aHintStyle == "on"
11163        || aHintStyle == "1")
11164       {
11165         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11166         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Normal);
11167       }
11168       else if (aHintStyle == "light")
11169       {
11170         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11171         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Light);
11172       }
11173       else if (aHintStyle == "no"
11174             || aHintStyle == "off"
11175             || aHintStyle == "0")
11176       {
11177         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11178         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11179       }
11180       else
11181       {
11182         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11183         return 1;
11184       }
11185     }
11186     else if (aFlag == "-fontautohinting"
11187           || aFlag == "-fontautohint")
11188     {
11189       if (toPrint)
11190       {
11191         if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
11192         {
11193           theDI << "force" << " ";
11194         }
11195         else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
11196         {
11197           theDI << "disallow" << " ";
11198         }
11199         else
11200         {
11201           theDI << "auto" << " ";
11202         }
11203         continue;
11204       }
11205       else if (anArgIter + 1 >= theArgNb)
11206       {
11207         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11208         return 1;
11209       }
11210
11211       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11212       aHintStyle.LowerCase();
11213       if (aHintStyle == "force")
11214       {
11215         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11216         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_ForceAutohint);
11217       }
11218       else if (aHintStyle == "disallow"
11219             || aHintStyle == "no")
11220       {
11221         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11222         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_NoAutohint);
11223       }
11224       else if (aHintStyle == "auto")
11225       {
11226         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11227         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11228       }
11229       else
11230       {
11231         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11232         return 1;
11233       }
11234     }
11235     else if (aFlag == "-depthprepass")
11236     {
11237       if (toPrint)
11238       {
11239         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11240         continue;
11241       }
11242       aParams.ToEnableDepthPrepass = Standard_True;
11243       if (anArgIter + 1 < theArgNb
11244        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11245       {
11246         ++anArgIter;
11247       }
11248     }
11249     else if (aFlag == "-samplealphatocoverage"
11250           || aFlag == "-alphatocoverage")
11251     {
11252       if (toPrint)
11253       {
11254         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11255         continue;
11256       }
11257       aParams.ToEnableAlphaToCoverage = Standard_True;
11258       if (anArgIter + 1 < theArgNb
11259        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11260       {
11261         ++anArgIter;
11262       }
11263     }
11264     else if (aFlag == "-rendscale"
11265           || aFlag == "-renderscale"
11266           || aFlag == "-renderresolutionscale")
11267     {
11268       if (toPrint)
11269       {
11270         theDI << aParams.RenderResolutionScale << " ";
11271         continue;
11272       }
11273       else if (++anArgIter >= theArgNb)
11274       {
11275         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11276         return 1;
11277       }
11278
11279       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11280       if (aScale < 0.01)
11281       {
11282         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11283         return 1;
11284       }
11285       else
11286       {
11287         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11288       }
11289     }
11290     else if (aFlag == "-raydepth"
11291           || aFlag == "-ray_depth")
11292     {
11293       if (toPrint)
11294       {
11295         theDI << aParams.RaytracingDepth << " ";
11296         continue;
11297       }
11298       else if (++anArgIter >= theArgNb)
11299       {
11300         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11301         return 1;
11302       }
11303
11304       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11305
11306       // We allow RaytracingDepth be more than 10 in case of GI enabled
11307       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11308       {
11309         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11310         return 1;
11311       }
11312       else
11313       {
11314         aParams.RaytracingDepth = aDepth;
11315       }
11316     }
11317     else if (aFlag == "-shad"
11318           || aFlag == "-shadows")
11319     {
11320       if (toPrint)
11321       {
11322         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11323         continue;
11324       }
11325
11326       Standard_Boolean toEnable = Standard_True;
11327       if (++anArgIter < theArgNb
11328       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11329       {
11330         --anArgIter;
11331       }
11332       aParams.IsShadowEnabled = toEnable;
11333     }
11334     else if (aFlag == "-shadowmapresolution"
11335           || aFlag == "-shadowmap")
11336     {
11337       if (toPrint)
11338       {
11339         theDI << aParams.ShadowMapResolution << " ";
11340         continue;
11341       }
11342       else if (++anArgIter >= theArgNb)
11343       {
11344         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11345         return 1;
11346       }
11347
11348       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
11349     }
11350     else if (aFlag == "-shadowmapbias")
11351     {
11352       if (toPrint)
11353       {
11354         theDI << aParams.ShadowMapBias << " ";
11355         continue;
11356       }
11357       else if (++anArgIter >= theArgNb)
11358       {
11359         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11360         return 1;
11361       }
11362
11363       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
11364     }
11365     else if (aFlag == "-refl"
11366           || aFlag == "-reflections")
11367     {
11368       if (toPrint)
11369       {
11370         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11371         continue;
11372       }
11373
11374       Standard_Boolean toEnable = Standard_True;
11375       if (++anArgIter < theArgNb
11376       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11377       {
11378         --anArgIter;
11379       }
11380       aParams.IsReflectionEnabled = toEnable;
11381     }
11382     else if (aFlag == "-fsaa")
11383     {
11384       if (toPrint)
11385       {
11386         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11387         continue;
11388       }
11389
11390       Standard_Boolean toEnable = Standard_True;
11391       if (++anArgIter < theArgNb
11392       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11393       {
11394         --anArgIter;
11395       }
11396       aParams.IsAntialiasingEnabled = toEnable;
11397     }
11398     else if (aFlag == "-gleam")
11399     {
11400       if (toPrint)
11401       {
11402         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11403         continue;
11404       }
11405
11406       Standard_Boolean toEnable = Standard_True;
11407       if (++anArgIter < theArgNb
11408       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11409       {
11410         --anArgIter;
11411       }
11412       aParams.IsTransparentShadowEnabled = toEnable;
11413     }
11414     else if (aFlag == "-gi")
11415     {
11416       if (toPrint)
11417       {
11418         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11419         continue;
11420       }
11421
11422       Standard_Boolean toEnable = Standard_True;
11423       if (++anArgIter < theArgNb
11424       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11425       {
11426         --anArgIter;
11427       }
11428       aParams.IsGlobalIlluminationEnabled = toEnable;
11429       if (!toEnable)
11430       {
11431         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11432       }
11433     }
11434     else if (aFlag == "-blockedrng"
11435           || aFlag == "-brng")
11436     {
11437       if (toPrint)
11438       {
11439         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
11440         continue;
11441       }
11442
11443       Standard_Boolean toEnable = Standard_True;
11444       if (++anArgIter < theArgNb
11445         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11446       {
11447         --anArgIter;
11448       }
11449       aParams.CoherentPathTracingMode = toEnable;
11450     }
11451     else if (aFlag == "-maxrad")
11452     {
11453       if (toPrint)
11454       {
11455         theDI << aParams.RadianceClampingValue << " ";
11456         continue;
11457       }
11458       else if (++anArgIter >= theArgNb)
11459       {
11460         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11461         return 1;
11462       }
11463
11464       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11465       if (!aMaxRadStr.IsRealValue (Standard_True))
11466       {
11467         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11468         return 1;
11469       }
11470
11471       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11472       if (aMaxRadiance <= 0.0)
11473       {
11474         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
11475         return 1;
11476       }
11477       else
11478       {
11479         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
11480       }
11481     }
11482     else if (aFlag == "-iss")
11483     {
11484       if (toPrint)
11485       {
11486         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
11487         continue;
11488       }
11489
11490       Standard_Boolean toEnable = Standard_True;
11491       if (++anArgIter < theArgNb
11492         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11493       {
11494         --anArgIter;
11495       }
11496       aParams.AdaptiveScreenSampling = toEnable;
11497     }
11498     else if (aFlag == "-issatomic")
11499     {
11500       if (toPrint)
11501       {
11502         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
11503         continue;
11504       }
11505
11506       Standard_Boolean toEnable = Standard_True;
11507       if (++anArgIter < theArgNb
11508       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11509       {
11510         --anArgIter;
11511       }
11512       aParams.AdaptiveScreenSamplingAtomic = toEnable;
11513     }
11514     else if (aFlag == "-issd")
11515     {
11516       if (toPrint)
11517       {
11518         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
11519         continue;
11520       }
11521
11522       Standard_Boolean toEnable = Standard_True;
11523       if (++anArgIter < theArgNb
11524         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11525       {
11526         --anArgIter;
11527       }
11528       aParams.ShowSamplingTiles = toEnable;
11529     }
11530     else if (aFlag == "-tilesize")
11531     {
11532       if (toPrint)
11533       {
11534         theDI << aParams.RayTracingTileSize << " ";
11535         continue;
11536       }
11537       else if (++anArgIter >= theArgNb)
11538       {
11539         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11540         return 1;
11541       }
11542
11543       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
11544       if (aTileSize < 1)
11545       {
11546         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
11547         return 1;
11548       }
11549       aParams.RayTracingTileSize = aTileSize;
11550     }
11551     else if (aFlag == "-nbtiles")
11552     {
11553       if (toPrint)
11554       {
11555         theDI << aParams.NbRayTracingTiles << " ";
11556         continue;
11557       }
11558       else if (++anArgIter >= theArgNb)
11559       {
11560         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11561         return 1;
11562       }
11563
11564       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
11565       if (aNbTiles < -1)
11566       {
11567         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
11568         return 1;
11569       }
11570       else if (aNbTiles > 0
11571             && (aNbTiles < 64
11572              || aNbTiles > 1024))
11573       {
11574         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
11575       }
11576       aParams.NbRayTracingTiles = aNbTiles;
11577     }
11578     else if (aFlag == "-env")
11579     {
11580       if (toPrint)
11581       {
11582         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
11583         continue;
11584       }
11585
11586       Standard_Boolean toEnable = Standard_True;
11587       if (++anArgIter < theArgNb
11588         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11589       {
11590         --anArgIter;
11591       }
11592       aParams.UseEnvironmentMapBackground = toEnable;
11593     }
11594     else if (aFlag == "-ignorenormalmap")
11595     {
11596       if (toPrint)
11597       {
11598         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
11599         continue;
11600       }
11601
11602       Standard_Boolean toEnable = Standard_True;
11603       if (++anArgIter < theArgNb
11604         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11605       {
11606         --anArgIter;
11607       }
11608       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
11609     }
11610     else if (aFlag == "-twoside")
11611     {
11612       if (toPrint)
11613       {
11614         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
11615         continue;
11616       }
11617
11618       Standard_Boolean toEnable = Standard_True;
11619       if (++anArgIter < theArgNb
11620         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11621       {
11622         --anArgIter;
11623       }
11624       aParams.TwoSidedBsdfModels = toEnable;
11625     }
11626     else if (aFlag == "-shademodel"
11627           || aFlag == "-shadingmodel"
11628           || aFlag == "-shading")
11629     {
11630       if (toPrint)
11631       {
11632         switch (aView->ShadingModel())
11633         {
11634           case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
11635           case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit ";    break;
11636           case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat ";     break;
11637           case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud ";  break;
11638           case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong ";    break;
11639           case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
11640           case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
11641         }
11642         continue;
11643       }
11644
11645       if (++anArgIter >= theArgNb)
11646       {
11647         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11648       }
11649
11650       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TypeOfShadingModel_DEFAULT;
11651       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
11652        && aModel != Graphic3d_TypeOfShadingModel_DEFAULT)
11653       {
11654         aView->SetShadingModel (aModel);
11655       }
11656       else
11657       {
11658         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
11659         return 1;
11660       }
11661     }
11662     else if (aFlag == "-pbrenvpow2size"
11663           || aFlag == "-pbrenvp2s"
11664           || aFlag == "-pep2s")
11665     {
11666       if (++anArgIter >= theArgNb)
11667       {
11668         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11669         return 1;
11670       }
11671
11672       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
11673       if (aPbrEnvPow2Size < 1)
11674       {
11675         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
11676         return 1;
11677       }
11678       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
11679     }
11680     else if (aFlag == "-pbrenvspecmaplevelsnumber"
11681           || aFlag == "-pbrenvspecmapnblevels"
11682           || aFlag == "-pbrenvspecmaplevels"
11683           || aFlag == "-pbrenvsmln"
11684           || aFlag == "-pesmln")
11685     {
11686       if (++anArgIter >= theArgNb)
11687       {
11688         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11689         return 1;
11690       }
11691
11692       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
11693       if (aPbrEnvSpecMapNbLevels < 2)
11694       {
11695         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
11696         return 1;
11697       }
11698       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
11699     }
11700     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
11701           || aFlag == "-pbrenvbakingdiffsamples"
11702           || aFlag == "-pbrenvbdsn")
11703     {
11704       if (++anArgIter >= theArgNb)
11705       {
11706         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11707         return 1;
11708       }
11709
11710       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11711       if (aPbrEnvBakingDiffNbSamples < 1)
11712       {
11713         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
11714         return 1;
11715       }
11716       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
11717     }
11718     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
11719           || aFlag == "-pbrenvbakingspecsamples"
11720           || aFlag == "-pbrenvbssn")
11721     {
11722     if (++anArgIter >= theArgNb)
11723     {
11724       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11725       return 1;
11726     }
11727
11728     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
11729     if (aPbrEnvBakingSpecNbSamples < 1)
11730     {
11731       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
11732       return 1;
11733     }
11734     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
11735     }
11736     else if (aFlag == "-pbrenvbakingprobability"
11737           || aFlag == "-pbrenvbp")
11738     {
11739       if (++anArgIter >= theArgNb)
11740       {
11741         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11742         return 1;
11743       }
11744       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
11745       if (aPbrEnvBakingProbability < 0.f
11746        || aPbrEnvBakingProbability > 1.f)
11747       {
11748         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
11749         return 1;
11750       }
11751       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
11752     }
11753     else if (aFlag == "-resolution")
11754     {
11755       if (++anArgIter >= theArgNb)
11756       {
11757         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11758         return 1;
11759       }
11760
11761       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
11762       if (aResolution.IsIntegerValue())
11763       {
11764         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
11765       }
11766       else
11767       {
11768         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
11769         return 1;
11770       }
11771     }
11772     else if (aFlag == "-rebuildglsl"
11773           || aFlag == "-rebuild")
11774     {
11775       if (toPrint)
11776       {
11777         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
11778         continue;
11779       }
11780
11781       Standard_Boolean toEnable = Standard_True;
11782       if (++anArgIter < theArgNb
11783           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11784       {
11785         --anArgIter;
11786       }
11787       aParams.RebuildRayTracingShaders = toEnable;
11788     }
11789     else if (aFlag == "-focal")
11790     {
11791       if (++anArgIter >= theArgNb)
11792       {
11793         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11794         return 1;
11795       }
11796
11797       TCollection_AsciiString aParam (theArgVec[anArgIter]);
11798       if (aParam.IsRealValue (Standard_True))
11799       {
11800         float aFocalDist = static_cast<float> (aParam.RealValue());
11801         if (aFocalDist < 0)
11802         {
11803           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11804           return 1;
11805         }
11806         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
11807       }
11808       else
11809       {
11810         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11811         return 1;
11812       }
11813     }
11814     else if (aFlag == "-aperture")
11815     {
11816       if (++anArgIter >= theArgNb)
11817       {
11818         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11819         return 1;
11820       }
11821
11822       TCollection_AsciiString aParam(theArgVec[anArgIter]);
11823       if (aParam.IsRealValue (Standard_True))
11824       {
11825         float aApertureSize = static_cast<float> (aParam.RealValue());
11826         if (aApertureSize < 0)
11827         {
11828           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11829           return 1;
11830         }
11831         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
11832       }
11833       else
11834       {
11835         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11836         return 1;
11837       }
11838     }
11839     else if (aFlag == "-exposure")
11840     {
11841       if (++anArgIter >= theArgNb)
11842       {
11843         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11844         return 1;
11845       }
11846
11847       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
11848       if (anExposure.IsRealValue (Standard_True))
11849       {
11850         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
11851       }
11852       else
11853       {
11854         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11855         return 1;
11856       }
11857     }
11858     else if (aFlag == "-whitepoint")
11859     {
11860       if (++anArgIter >= theArgNb)
11861       {
11862         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11863         return 1;
11864       }
11865
11866       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
11867       if (aWhitePoint.IsRealValue (Standard_True))
11868       {
11869         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
11870       }
11871       else
11872       {
11873         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11874         return 1;
11875       }
11876     }
11877     else if (aFlag == "-tonemapping")
11878     {
11879       if (++anArgIter >= theArgNb)
11880       {
11881         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11882         return 1;
11883       }
11884
11885       TCollection_AsciiString aMode (theArgVec[anArgIter]);
11886       aMode.LowerCase();
11887
11888       if (aMode == "disabled")
11889       {
11890         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
11891       }
11892       else if (aMode == "filmic")
11893       {
11894         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
11895       }
11896       else
11897       {
11898         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11899         return 1;
11900       }
11901     }
11902     else if (aFlag == "-performancestats"
11903           || aFlag == "-performancecounters"
11904           || aFlag == "-perfstats"
11905           || aFlag == "-perfcounters"
11906           || aFlag == "-stats")
11907     {
11908       if (++anArgIter >= theArgNb)
11909       {
11910         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11911         return 1;
11912       }
11913
11914       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
11915       aFlagsStr.LowerCase();
11916       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
11917       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
11918       {
11919         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11920         return 1;
11921       }
11922       aView->ChangeRenderingParams().CollectedStats = aFlags;
11923       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
11924     }
11925     else if (aFlag == "-perfupdateinterval"
11926           || aFlag == "-statsupdateinterval")
11927     {
11928       if (++anArgIter >= theArgNb)
11929       {
11930         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11931         return 1;
11932       }
11933       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11934     }
11935     else if (aFlag == "-perfchart"
11936           || aFlag == "-statschart")
11937     {
11938       if (++anArgIter >= theArgNb)
11939       {
11940         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11941         return 1;
11942       }
11943       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
11944     }
11945     else if (aFlag == "-perfchartmax"
11946           || aFlag == "-statschartmax")
11947     {
11948       if (++anArgIter >= theArgNb)
11949       {
11950         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11951         return 1;
11952       }
11953       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11954     }
11955     else if (aFlag == "-frustumculling"
11956           || aFlag == "-culling")
11957     {
11958       if (toPrint)
11959       {
11960         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
11961                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
11962                                                                                                    "noUpdate") << " ";
11963         continue;
11964       }
11965
11966       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
11967       if (++anArgIter < theArgNb)
11968       {
11969         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
11970         aStateStr.LowerCase();
11971         bool toEnable = true;
11972         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
11973         {
11974           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
11975         }
11976         else if (aStateStr == "noupdate"
11977               || aStateStr == "freeze")
11978         {
11979           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
11980         }
11981         else
11982         {
11983           --anArgIter;
11984         }
11985       }
11986       aParams.FrustumCullingState = aState;
11987     }
11988     else
11989     {
11990       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
11991       return 1;
11992     }
11993   }
11994
11995   // set current view parameters as defaults
11996   if (toSyncDefaults)
11997   {
11998     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
11999   }
12000   if (toSyncAllViews)
12001   {
12002     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
12003     {
12004       aViewIter.Value()->ChangeRenderingParams() = aParams;
12005     }
12006   }
12007   return 0;
12008 }
12009
12010 //=======================================================================
12011 //function : searchInfo
12012 //purpose  :
12013 //=======================================================================
12014 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12015                                            const TCollection_AsciiString&              theKey)
12016 {
12017   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12018   {
12019     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12020     {
12021       return anIter.Value();
12022     }
12023   }
12024   return TCollection_AsciiString();
12025 }
12026
12027 //=======================================================================
12028 //function : VStatProfiler
12029 //purpose  :
12030 //=======================================================================
12031 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12032                                        Standard_Integer  theArgNb,
12033                                        const char**      theArgVec)
12034 {
12035   Handle(V3d_View) aView = ViewerTest::CurrentView();
12036   if (aView.IsNull())
12037   {
12038     Message::SendFail ("Error: no active viewer");
12039     return 1;
12040   }
12041
12042   Standard_Boolean toRedraw = Standard_True;
12043   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12044   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12045   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12046   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12047   {
12048     Standard_CString        anArg (theArgVec[anArgIter]);
12049     TCollection_AsciiString aFlag (anArg);
12050     aFlag.LowerCase();
12051     if (aFlag == "-noredraw")
12052     {
12053       toRedraw = Standard_False;
12054     }
12055     else
12056     {
12057       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12058       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12059       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12060       else if (aFlag == "alllayers"
12061             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12062       else if (aFlag == "allstructs"
12063             || aFlag == "allstructures"
12064             || aFlag == "structs"
12065             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12066       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12067       else if (aFlag == "allarrays"
12068             || aFlag == "fillarrays"
12069             || aFlag == "linearrays"
12070             || aFlag == "pointarrays"
12071             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12072       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12073       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12074       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12075       else if (aFlag == "geommem"
12076             || aFlag == "texturemem"
12077             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12078       else if (aFlag == "elapsedframe"
12079             || aFlag == "cpuframeaverage"
12080             || aFlag == "cpupickingaverage"
12081             || aFlag == "cpucullingaverage"
12082             || aFlag == "cpudynaverage"
12083             || aFlag == "cpuframemax"
12084             || aFlag == "cpupickingmax"
12085             || aFlag == "cpucullingmax"
12086             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12087       else
12088       {
12089         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12090         continue;
12091       }
12092
12093       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12094     }
12095   }
12096
12097   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12098   {
12099     aView->ChangeRenderingParams().CollectedStats =
12100       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12101
12102     if (toRedraw)
12103     {
12104       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12105       aView->Redraw();
12106       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12107     }
12108
12109     TColStd_IndexedDataMapOfStringString aDict;
12110     aView->StatisticInformation (aDict);
12111
12112     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12113
12114     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12115     {
12116       Standard_CString        anArg(theArgVec[anArgIter]);
12117       TCollection_AsciiString aFlag(anArg);
12118       aFlag.LowerCase();
12119       if (aFlag == "fps")
12120       {
12121         theDI << searchInfo (aDict, "FPS") << " ";
12122       }
12123       else if (aFlag == "cpu")
12124       {
12125         theDI << searchInfo (aDict, "CPU FPS") << " ";
12126       }
12127       else if (aFlag == "alllayers")
12128       {
12129         theDI << searchInfo (aDict, "Layers") << " ";
12130       }
12131       else if (aFlag == "layers")
12132       {
12133         theDI << searchInfo (aDict, "Rendered layers") << " ";
12134       }
12135       else if (aFlag == "allstructs"
12136             || aFlag == "allstructures")
12137       {
12138         theDI << searchInfo (aDict, "Structs") << " ";
12139       }
12140       else if (aFlag == "structs"
12141             || aFlag == "structures")
12142       {
12143         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
12144         if (aRend.IsEmpty()) // all structures rendered
12145         {
12146           aRend = searchInfo (aDict, "Structs");
12147         }
12148         theDI << aRend << " ";
12149       }
12150       else if (aFlag == "groups")
12151       {
12152         theDI << searchInfo (aDict, "Rendered groups") << " ";
12153       }
12154       else if (aFlag == "allarrays")
12155       {
12156         theDI << searchInfo (aDict, "Rendered arrays") << " ";
12157       }
12158       else if (aFlag == "fillarrays")
12159       {
12160         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
12161       }
12162       else if (aFlag == "linearrays")
12163       {
12164         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
12165       }
12166       else if (aFlag == "pointarrays")
12167       {
12168         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
12169       }
12170       else if (aFlag == "textarrays")
12171       {
12172         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
12173       }
12174       else if (aFlag == "triangles")
12175       {
12176         theDI << searchInfo (aDict, "Rendered triangles") << " ";
12177       }
12178       else if (aFlag == "points")
12179       {
12180         theDI << searchInfo (aDict, "Rendered points") << " ";
12181       }
12182       else if (aFlag == "geommem")
12183       {
12184         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12185       }
12186       else if (aFlag == "texturemem")
12187       {
12188         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12189       }
12190       else if (aFlag == "framemem")
12191       {
12192         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12193       }
12194       else if (aFlag == "elapsedframe")
12195       {
12196         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12197       }
12198       else if (aFlag == "cpuframe_average")
12199       {
12200         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12201       }
12202       else if (aFlag == "cpupicking_average")
12203       {
12204         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12205       }
12206       else if (aFlag == "cpuculling_average")
12207       {
12208         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12209       }
12210       else if (aFlag == "cpudyn_average")
12211       {
12212         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12213       }
12214       else if (aFlag == "cpuframe_max")
12215       {
12216         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12217       }
12218       else if (aFlag == "cpupicking_max")
12219       {
12220         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12221       }
12222       else if (aFlag == "cpuculling_max")
12223       {
12224         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12225       }
12226       else if (aFlag == "cpudyn_max")
12227       {
12228         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12229       }
12230     }
12231   }
12232   else
12233   {
12234     if (toRedraw)
12235     {
12236       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12237       aView->Redraw();
12238       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12239     }
12240     theDI << "Statistic info:\n" << aView->StatisticInformation();
12241   }
12242   return 0;
12243 }
12244
12245 //=======================================================================
12246 //function : VXRotate
12247 //purpose  :
12248 //=======================================================================
12249 static Standard_Integer VXRotate (Draw_Interpretor& di,
12250                                    Standard_Integer argc,
12251                                    const char ** argv)
12252 {
12253   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12254   if (aContext.IsNull())
12255   {
12256     di << argv[0] << "ERROR : use 'vinit' command before \n";
12257     return 1;
12258   }
12259
12260   if (argc != 3)
12261   {
12262     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12263     return 1;
12264   }
12265
12266   TCollection_AsciiString aName (argv[1]);
12267   Standard_Real anAngle = Draw::Atof (argv[2]);
12268
12269   // find object
12270   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12271   Handle(AIS_InteractiveObject) anIObj;
12272   if (!aMap.Find2 (aName, anIObj))
12273   {
12274     di << "Use 'vdisplay' before\n";
12275     return 1;
12276   }
12277
12278   gp_Trsf aTransform;
12279   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12280   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12281
12282   aContext->SetLocation (anIObj, aTransform);
12283   aContext->UpdateCurrentViewer();
12284   return 0;
12285 }
12286
12287 namespace
12288 {
12289   //! Structure for setting AIS_Manipulator::SetPart() property.
12290   struct ManipAxisModeOnOff
12291   {
12292     Standard_Integer    Axis;
12293     AIS_ManipulatorMode Mode;
12294     Standard_Boolean    ToEnable;
12295
12296     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
12297   };
12298
12299   enum ManipAjustPosition
12300   {
12301     ManipAjustPosition_Off,
12302     ManipAjustPosition_Center,
12303     ManipAjustPosition_Location,
12304     ManipAjustPosition_ShapeLocation,
12305   };
12306 }
12307
12308 //===============================================================================================
12309 //function : VManipulator
12310 //purpose  :
12311 //===============================================================================================
12312 static int VManipulator (Draw_Interpretor& theDi,
12313                          Standard_Integer  theArgsNb,
12314                          const char**      theArgVec)
12315 {
12316   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12317   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12318   if (aCurrentView.IsNull()
12319    || aViewer.IsNull())
12320   {
12321     Message::SendFail ("Error: no active viewer");
12322     return 1;
12323   }
12324
12325   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12326   Standard_Integer anArgIter = 1;
12327   Handle(AIS_Manipulator) aManipulator;
12328   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12329   TCollection_AsciiString aName;
12330   // parameters
12331   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
12332   Standard_Real aGap = -1.0, aSize = -1.0;
12333   NCollection_Sequence<ManipAxisModeOnOff> aParts;
12334   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
12335   //
12336   bool toDetach = false;
12337   AIS_Manipulator::OptionsForAttach anAttachOptions;
12338   Handle(AIS_InteractiveObject) anAttachObject;
12339   Handle(V3d_View) aViewAffinity;
12340   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
12341   //
12342   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
12343   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
12344   Standard_Integer toStopMouseTransform = -1;
12345   // explicit transformation
12346   gp_Trsf aTrsf;
12347   gp_XYZ aTmpXYZ;
12348   Standard_Real aTmpReal = 0.0;
12349   gp_XYZ aRotPnt, aRotAxis;
12350   for (; anArgIter < theArgsNb; ++anArgIter)
12351   {
12352     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12353     anArg.LowerCase();
12354     if (anUpdateTool.parseRedrawMode (anArg))
12355     {
12356       continue;
12357     }
12358     else if (anArg == "-help")
12359     {
12360       theDi.PrintHelp (theArgVec[0]);
12361       return 0;
12362     }
12363     //
12364     else if (anArg == "-autoactivate"
12365           || anArg == "-noautoactivate")
12366     {
12367       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12368     }
12369     else if (anArg == "-followtranslation"
12370           || anArg == "-nofollowtranslation")
12371     {
12372       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12373     }
12374     else if (anArg == "-followrotation"
12375           || anArg == "-nofollowrotation")
12376     {
12377       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12378     }
12379     else if (anArg == "-followdragging"
12380           || anArg == "-nofollowdragging")
12381     {
12382       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12383     }
12384     else if (anArg == "-gap"
12385           && anArgIter + 1 < theArgsNb
12386           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
12387           && aGap >= 0.0)
12388     {
12389       ++anArgIter;
12390     }
12391     else if (anArg == "-size"
12392           && anArgIter + 1 < theArgsNb
12393           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
12394           && aSize > 0.0)
12395     {
12396       ++anArgIter;
12397     }
12398     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
12399           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
12400     {
12401       ManipAxisModeOnOff aPart;
12402       Standard_Integer aMode = 0;
12403       if (anArg == "-part")
12404       {
12405         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
12406           || aPart.Axis < 0 || aPart.Axis > 3)
12407         {
12408           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
12409           return 1;
12410         }
12411       }
12412       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
12413         || aMode < 1 || aMode > 4)
12414       {
12415         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
12416         return 1;
12417       }
12418       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
12419       {
12420         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
12421         return 1;
12422       }
12423       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
12424       aParts.Append (aPart);
12425     }
12426     else if (anArg == "-pos"
12427           && anArgIter + 3 < theArgsNb
12428           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
12429     {
12430       anArgIter += 3;
12431       if (anArgIter + 3 < theArgsNb
12432        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
12433        && aVDir.Modulus() > Precision::Confusion())
12434       {
12435         anArgIter += 3;
12436       }
12437       if (anArgIter + 3 < theArgsNb
12438        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
12439        && anXDir.Modulus() > Precision::Confusion())
12440       {
12441         anArgIter += 3;
12442       }
12443     }
12444     else if (anArg == "-zoomable"
12445           || anArg == "-notzoomable")
12446     {
12447       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12448     }
12449     //
12450     else if (anArg == "-adjustposition"
12451           || anArg == "-noadjustposition")
12452     {
12453       anAttachPos = ManipAjustPosition_Center;
12454       if (anArgIter + 1 < theArgsNb)
12455       {
12456         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
12457         aPosName.LowerCase();
12458         if (aPosName == "0")
12459         {
12460           anAttachPos = ManipAjustPosition_Off;
12461         }
12462         else if (aPosName == "1"
12463               || aPosName == "center")
12464         {
12465           anAttachPos = ManipAjustPosition_Center;
12466         }
12467         else if (aPosName == "transformation"
12468               || aPosName == "trsf"
12469               || aPosName == "location"
12470               || aPosName == "loc")
12471         {
12472           anAttachPos = ManipAjustPosition_Location;
12473         }
12474         else if (aPosName == "shapelocation"
12475               || aPosName == "shapeloc")
12476         {
12477           anAttachPos = ManipAjustPosition_ShapeLocation;
12478         }
12479         else
12480         {
12481           --anArgIter;
12482         }
12483       }
12484       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
12485     }
12486     else if (anArg == "-adjustsize"
12487           || anArg == "-noadjustsize")
12488     {
12489       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12490     }
12491     else if (anArg == "-enablemodes"
12492           || anArg == "-enablemodes")
12493     {
12494       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12495     }
12496     //
12497     else if (anArg == "-starttransform"
12498           && anArgIter + 2 < theArgsNb
12499           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
12500           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
12501     {
12502       anArgIter += 2;
12503     }
12504     else if (anArg == "-transform"
12505           && anArgIter + 2 < theArgsNb
12506           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
12507           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
12508     {
12509       anArgIter += 2;
12510     }
12511     else if (anArg == "-stoptransform")
12512     {
12513       toStopMouseTransform = 1;
12514       if (anArgIter + 1 < theArgsNb
12515        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
12516       {
12517         ++anArgIter;
12518         toStopMouseTransform = 0;
12519       }
12520     }
12521     //
12522     else if (anArg == "-move"
12523           && anArgIter + 3 < theArgsNb
12524           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
12525     {
12526       anArgIter += 3;
12527       aTrsf.SetTranslationPart (aTmpXYZ);
12528     }
12529     else if (anArg == "-scale"
12530           && anArgIter + 1 < theArgsNb
12531           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
12532     {
12533       ++anArgIter;
12534       aTrsf.SetScale (gp_Pnt(), aTmpReal);
12535     }
12536     else if (anArg == "-rotate"
12537           && anArgIter + 7 < theArgsNb
12538           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
12539           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
12540           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
12541     {
12542       anArgIter += 7;
12543       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
12544     }
12545     //
12546     else if (anArg == "-detach")
12547     {
12548       toDetach = true;
12549     }
12550     else if (anArg == "-attach"
12551           && anArgIter + 1 < theArgsNb)
12552     {
12553       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
12554       if (!aMapAIS.Find2 (anObjName, anAttachObject))
12555       {
12556         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
12557         return 1;
12558       }
12559
12560       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
12561       {
12562         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
12563         if (!aManip.IsNull()
12564           && aManip->IsAttached()
12565           && aManip->Object() == anAttachObject)
12566         {
12567           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
12568           return 1;
12569         }
12570       }
12571     }
12572     else if (anArg == "-view"
12573           && anArgIter + 1 < theArgsNb
12574           && aViewAffinity.IsNull())
12575     {
12576       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
12577       if (aViewString == "active")
12578       {
12579         aViewAffinity = ViewerTest::CurrentView();
12580       }
12581       else // Check view name
12582       {
12583         ViewerTest_Names aViewNames (aViewString);
12584         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
12585         {
12586           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
12587           return 1;
12588         }
12589         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
12590         if (aViewAffinity.IsNull())
12591         {
12592           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
12593           return 1;
12594         }
12595       }
12596     }
12597     else if (aName.IsEmpty())
12598     {
12599       aName = theArgVec[anArgIter];
12600       if (!aMapAIS.IsBound2 (aName))
12601       {
12602         aManipulator = new AIS_Manipulator();
12603         aManipulator->SetModeActivationOnDetection (true);
12604         aMapAIS.Bind (aManipulator, aName);
12605       }
12606       else
12607       {
12608         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12609         if (aManipulator.IsNull())
12610         {
12611           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12612           return 1;
12613         }
12614       }
12615     }
12616     else
12617     {
12618       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
12619     }
12620   }
12621
12622   if (aName.IsEmpty())
12623   {
12624     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
12625     return 1;
12626   }
12627   if (!toDetach
12628     && aManipulator.IsNull())
12629   {
12630     aManipulator = new AIS_Manipulator();
12631     aManipulator->SetModeActivationOnDetection (true);
12632     aMapAIS.Bind (aManipulator, aName);
12633   }
12634
12635   // -----------------------------------------
12636   // change properties of manipulator instance
12637   // -----------------------------------------
12638
12639   if (toAutoActivate != -1)
12640   {
12641     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
12642   }
12643   if (toFollowTranslation != -1)
12644   {
12645     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
12646   }
12647   if (toFollowRotation != -1)
12648   {
12649     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
12650   }
12651   if (toFollowDragging != -1)
12652   {
12653     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
12654   }
12655   if (aGap >= 0.0f)
12656   {
12657     aManipulator->SetGap ((float )aGap);
12658   }
12659
12660   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
12661   {
12662     const ManipAxisModeOnOff& aPart = aPartIter.Value();
12663     if (aPart.Axis == -1)
12664     {
12665       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
12666     }
12667     else
12668     {
12669       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
12670     }
12671   }
12672
12673   if (aSize > 0.0)
12674   {
12675     aManipulator->SetSize ((float )aSize);
12676   }
12677   if (isZoomable != -1)
12678   {
12679     aManipulator->SetZoomPersistence (isZoomable == 0);
12680
12681     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12682     {
12683       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
12684       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
12685     }
12686   }
12687
12688   // ----------------------------------
12689   // detach existing manipulator object
12690   // ----------------------------------
12691
12692   if (toDetach)
12693   {
12694     aManipulator->Detach();
12695     aMapAIS.UnBind2 (aName);
12696     ViewerTest::GetAISContext()->Remove (aManipulator, false);
12697   }
12698
12699   // ---------------------------------------------------
12700   // attach, detach or access manipulator from an object
12701   // ---------------------------------------------------
12702
12703   if (!anAttachObject.IsNull())
12704   {
12705     aManipulator->Attach (anAttachObject, anAttachOptions);
12706   }
12707   if (!aViewAffinity.IsNull())
12708   {
12709     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
12710          anIter.More(); anIter.Next())
12711     {
12712       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
12713     }
12714     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
12715   }
12716
12717   if (anAttachPos != ManipAjustPosition_Off
12718    && aManipulator->IsAttached()
12719    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
12720   {
12721     gp_Ax2 aPosition = gp::XOY();
12722     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
12723     switch (anAttachPos)
12724     {
12725       case ManipAjustPosition_Off:
12726       {
12727         break;
12728       }
12729       case ManipAjustPosition_Location:
12730       {
12731         aPosition = gp::XOY().Transformed (aBaseTrsf);
12732         break;
12733       }
12734       case ManipAjustPosition_ShapeLocation:
12735       {
12736         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
12737         {
12738           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
12739         }
12740         else
12741         {
12742           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
12743           return 1;
12744         }
12745         break;
12746       }
12747       case ManipAjustPosition_Center:
12748       {
12749         Bnd_Box aBox;
12750         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
12751         {
12752           Bnd_Box anObjBox;
12753           anObjIter.Value()->BoundingBox (anObjBox);
12754           aBox.Add (anObjBox);
12755         }
12756         aBox = aBox.FinitePart();
12757         if (!aBox.IsVoid())
12758         {
12759           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
12760           aPosition.SetLocation (aCenter);
12761         }
12762         break;
12763       }
12764     }
12765     aManipulator->SetPosition (aPosition);
12766   }
12767   if (!Precision::IsInfinite (aLocation.X()))
12768   {
12769     if (aVDir.Modulus() <= Precision::Confusion())
12770     {
12771       aVDir = aManipulator->Position().Direction().XYZ();
12772     }
12773     if (anXDir.Modulus() <= Precision::Confusion())
12774     {
12775       anXDir = aManipulator->Position().XDirection().XYZ();
12776     }
12777     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
12778   }
12779
12780   // --------------------------------------
12781   // apply transformation using manipulator
12782   // --------------------------------------
12783
12784   if (aMousePosFrom.x() != IntegerLast())
12785   {
12786     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
12787   }
12788   if (aMousePosTo.x() != IntegerLast())
12789   {
12790     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
12791   }
12792   if (toStopMouseTransform != -1)
12793   {
12794     aManipulator->StopTransform (toStopMouseTransform == 1);
12795   }
12796
12797   if (aTrsf.Form() != gp_Identity)
12798   {
12799     aManipulator->Transform (aTrsf);
12800   }
12801
12802   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12803   {
12804     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
12805   }
12806   return 0;
12807 }
12808
12809 //===============================================================================================
12810 //function : VSelectionProperties
12811 //purpose  :
12812 //===============================================================================================
12813 static int VSelectionProperties (Draw_Interpretor& theDi,
12814                                  Standard_Integer  theArgsNb,
12815                                  const char**      theArgVec)
12816 {
12817   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
12818   if (aCtx.IsNull())
12819   {
12820     Message::SendFail ("Error: no active viewer");
12821     return 1;
12822   }
12823
12824   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
12825   {
12826     // handle obsolete alias
12827     bool toEnable = true;
12828     if (theArgsNb < 2)
12829     {
12830       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
12831       return 0;
12832     }
12833     else if (theArgsNb != 2
12834          || !Draw::ParseOnOff (theArgVec[1], toEnable))
12835     {
12836       Message::SendFail ("Syntax error: wrong number of parameters");
12837       return 1;
12838     }
12839     if (toEnable != aCtx->ToHilightSelected())
12840     {
12841       aCtx->ClearDetected();
12842       aCtx->SetToHilightSelected (toEnable);
12843     }
12844     return 0;
12845   }
12846
12847   Standard_Boolean toPrint  = theArgsNb == 1;
12848   Standard_Boolean toRedraw = Standard_False;
12849   Standard_Integer anArgIter = 1;
12850   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
12851   if (anArgIter < theArgsNb)
12852   {
12853     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
12854     anArgFirst.LowerCase();
12855     ++anArgIter;
12856     if (anArgFirst == "dynhighlight"
12857      || anArgFirst == "dynhilight"
12858      || anArgFirst == "dynamichighlight"
12859      || anArgFirst == "dynamichilight")
12860     {
12861       aType = Prs3d_TypeOfHighlight_Dynamic;
12862     }
12863     else if (anArgFirst == "localdynhighlight"
12864           || anArgFirst == "localdynhilight"
12865           || anArgFirst == "localdynamichighlight"
12866           || anArgFirst == "localdynamichilight")
12867     {
12868       aType = Prs3d_TypeOfHighlight_LocalDynamic;
12869     }
12870     else if (anArgFirst == "selhighlight"
12871           || anArgFirst == "selhilight"
12872           || anArgFirst == "selectedhighlight"
12873           || anArgFirst == "selectedhilight")
12874     {
12875       aType = Prs3d_TypeOfHighlight_Selected;
12876     }
12877     else if (anArgFirst == "localselhighlight"
12878           || anArgFirst == "localselhilight"
12879           || anArgFirst == "localselectedhighlight"
12880           || anArgFirst == "localselectedhilight")
12881     {
12882       aType = Prs3d_TypeOfHighlight_LocalSelected;
12883     }
12884     else
12885     {
12886       --anArgIter;
12887     }
12888   }
12889   for (; anArgIter < theArgsNb; ++anArgIter)
12890   {
12891     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12892     anArg.LowerCase();
12893     if (anArg == "-help")
12894     {
12895       theDi.PrintHelp (theArgVec[0]);
12896       return 0;
12897     }
12898     else if (anArg == "-print")
12899     {
12900       toPrint = Standard_True;
12901     }
12902     else if (anArg == "-autoactivate")
12903     {
12904       Standard_Boolean toEnable = Standard_True;
12905       if (anArgIter + 1 < theArgsNb
12906        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12907       {
12908         ++anArgIter;
12909       }
12910       aCtx->SetAutoActivateSelection (toEnable);
12911     }
12912     else if (anArg == "-automatichighlight"
12913           || anArg == "-automatichilight"
12914           || anArg == "-autohighlight"
12915           || anArg == "-autohilight")
12916     {
12917       Standard_Boolean toEnable = Standard_True;
12918       if (anArgIter + 1 < theArgsNb
12919        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12920       {
12921         ++anArgIter;
12922       }
12923       aCtx->ClearSelected (false);
12924       aCtx->ClearDetected();
12925       aCtx->SetAutomaticHilight (toEnable);
12926       toRedraw = true;
12927     }
12928     else if (anArg == "-highlightselected"
12929           || anArg == "-hilightselected")
12930     {
12931       Standard_Boolean toEnable = Standard_True;
12932       if (anArgIter + 1 < theArgsNb
12933        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12934       {
12935         ++anArgIter;
12936       }
12937       aCtx->ClearDetected();
12938       aCtx->SetToHilightSelected (toEnable);
12939       toRedraw = true;
12940     }
12941     else if (anArg == "-pickstrategy"
12942           || anArg == "-pickingstrategy")
12943     {
12944       if (++anArgIter >= theArgsNb)
12945       {
12946         Message::SendFail ("Syntax error: type of highlighting is undefined");
12947         return 1;
12948       }
12949
12950       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
12951       TCollection_AsciiString aVal (theArgVec[anArgIter]);
12952       aVal.LowerCase();
12953       if (aVal == "first"
12954        || aVal == "firstaccepted"
12955        || aVal == "firstacceptable")
12956       {
12957         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
12958       }
12959       else if (aVal == "topmost"
12960             || aVal == "onlyTopmost")
12961       {
12962         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
12963       }
12964       else
12965       {
12966         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
12967         return 1;
12968       }
12969
12970       aCtx->SetPickingStrategy (aStrategy);
12971     }
12972     else if (anArg == "-pixtol"
12973           && anArgIter + 1 < theArgsNb)
12974     {
12975       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
12976     }
12977     else if (anArg == "-preferclosest")
12978     {
12979       bool toPreferClosest = true;
12980       if (anArgIter + 1 < theArgsNb
12981        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
12982       {
12983         ++anArgIter;
12984       }
12985       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
12986     }
12987     else if ((anArg == "-depthtol"
12988            || anArg == "-depthtolerance")
12989           && anArgIter + 1 < theArgsNb)
12990     {
12991       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
12992       aTolType.LowerCase();
12993       if (aTolType == "uniform")
12994       {
12995         if (anArgIter + 1 >= theArgsNb)
12996         {
12997           Message::SendFail() << "Syntax error: wrong number of arguments";
12998           return 1;
12999         }
13000         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
13001                                                  Draw::Atof (theArgVec[++anArgIter]));
13002       }
13003       else if (aTolType == "uniformpx")
13004       {
13005         if (anArgIter + 1 >= theArgsNb)
13006         {
13007           Message::SendFail() << "Syntax error: wrong number of arguments";
13008           return 1;
13009         }
13010         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
13011                                                  Draw::Atof (theArgVec[++anArgIter]));
13012       }
13013       else if (aTolType == "sensfactor")
13014       {
13015         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
13016       }
13017       else
13018       {
13019         Message::SendFail() << "Syntax error at '" << aTolType << "'";
13020         return 1;
13021       }
13022     }
13023     else if ((anArg == "-mode"
13024            || anArg == "-dispmode")
13025           && anArgIter + 1 < theArgsNb)
13026     {
13027       if (aType == Prs3d_TypeOfHighlight_None)
13028       {
13029         Message::SendFail ("Syntax error: type of highlighting is undefined");
13030         return 1;
13031       }
13032
13033       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13034       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13035       aStyle->SetDisplayMode (aDispMode);
13036       toRedraw = Standard_True;
13037     }
13038     else if (anArg == "-layer"
13039           && anArgIter + 1 < theArgsNb)
13040     {
13041       if (aType == Prs3d_TypeOfHighlight_None)
13042       {
13043         Message::SendFail ("Syntax error: type of highlighting is undefined");
13044         return 1;
13045       }
13046
13047       ++anArgIter;
13048       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13049       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13050       {
13051         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13052         return 1;
13053       }
13054
13055       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13056       aStyle->SetZLayer (aNewLayer);
13057       toRedraw = Standard_True;
13058     }
13059     else if (anArg == "-hicolor"
13060           || anArg == "-selcolor"
13061           || anArg == "-color")
13062     {
13063       if (anArg.StartsWith ("-hi"))
13064       {
13065         aType = Prs3d_TypeOfHighlight_Dynamic;
13066       }
13067       else if (anArg.StartsWith ("-sel"))
13068       {
13069         aType = Prs3d_TypeOfHighlight_Selected;
13070       }
13071       else if (aType == Prs3d_TypeOfHighlight_None)
13072       {
13073         Message::SendFail ("Syntax error: type of highlighting is undefined");
13074         return 1;
13075       }
13076
13077       Quantity_Color aColor;
13078       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13079                                                      theArgVec + anArgIter + 1,
13080                                                      aColor);
13081       if (aNbParsed == 0)
13082       {
13083         Message::SendFail ("Syntax error: need more arguments");
13084         return 1;
13085       }
13086       anArgIter += aNbParsed;
13087
13088       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13089       aStyle->SetColor (aColor);
13090       toRedraw = Standard_True;
13091     }
13092     else if ((anArg == "-transp"
13093            || anArg == "-transparency"
13094            || anArg == "-hitransp"
13095            || anArg == "-seltransp"
13096            || anArg == "-hitransplocal"
13097            || anArg == "-seltransplocal")
13098           && anArgIter + 1 < theArgsNb)
13099     {
13100       if (anArg.StartsWith ("-hi"))
13101       {
13102         aType = Prs3d_TypeOfHighlight_Dynamic;
13103       }
13104       else if (anArg.StartsWith ("-sel"))
13105       {
13106         aType = Prs3d_TypeOfHighlight_Selected;
13107       }
13108       else if (aType == Prs3d_TypeOfHighlight_None)
13109       {
13110         Message::SendFail ("Syntax error: type of highlighting is undefined");
13111         return 1;
13112       }
13113
13114       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13115       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13116       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13117       toRedraw = Standard_True;
13118     }
13119     else if ((anArg == "-mat"
13120            || anArg == "-material")
13121           && anArgIter + 1 < theArgsNb)
13122     {
13123       if (aType == Prs3d_TypeOfHighlight_None)
13124       {
13125         Message::SendFail ("Syntax error: type of highlighting is undefined");
13126         return 1;
13127       }
13128
13129       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13130       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13131       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
13132       {
13133         ++anArgIter;
13134         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13135         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13136         Graphic3d_MaterialAspect aMat (aMatName);
13137         aMat.SetColor (aStyle->Color());
13138         aMat.SetTransparency (aStyle->Transparency());
13139         anAspect->SetFrontMaterial (aMat);
13140         anAspect->SetInteriorColor (aStyle->Color());
13141         aStyle->SetBasicFillAreaAspect (anAspect);
13142       }
13143       else
13144       {
13145         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
13146       }
13147       toRedraw = Standard_True;
13148     }
13149     else
13150     {
13151       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
13152       return 1;
13153     }
13154   }
13155
13156   if (toPrint)
13157   {
13158     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
13159     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
13160     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
13161     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
13162     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
13163     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
13164     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
13165     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
13166     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
13167     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
13168     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
13169     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
13170     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
13171     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
13172   }
13173
13174   if (aCtx->NbSelected() != 0 && toRedraw)
13175   {
13176     aCtx->HilightSelected (Standard_True);
13177   }
13178
13179   return 0;
13180 }
13181
13182 //===============================================================================================
13183 //function : VDumpSelectionImage
13184 //purpose  :
13185 //===============================================================================================
13186 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13187                                 Standard_Integer  theArgsNb,
13188                                 const char**      theArgVec)
13189 {
13190   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13191   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13192   if (aContext.IsNull())
13193   {
13194     Message::SendFail ("Error: no active viewer");
13195     return 1;
13196   }
13197
13198   TCollection_AsciiString aFile;
13199   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13200   Handle(Graphic3d_Camera) aCustomCam;
13201   Image_Format anImgFormat = Image_Format_BGR;
13202   Standard_Integer aPickedIndex = 1;
13203   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13204   {
13205     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13206     aParam.LowerCase();
13207     if (aParam == "-type")
13208     {
13209       if (++anArgIter >= theArgsNb)
13210       {
13211         Message::SendFail ("Syntax error: wrong number parameters of flag '-type'");
13212         return 1;
13213       }
13214
13215       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13216       aValue.LowerCase();
13217       if (aValue == "depth"
13218        || aValue == "normdepth"
13219        || aValue == "normalizeddepth")
13220       {
13221         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13222         anImgFormat = Image_Format_GrayF;
13223       }
13224       else if (aValue == "depthinverted"
13225             || aValue == "normdepthinverted"
13226             || aValue == "normalizeddepthinverted"
13227             || aValue == "inverted")
13228       {
13229         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13230         anImgFormat = Image_Format_GrayF;
13231       }
13232       else if (aValue == "unnormdepth"
13233             || aValue == "unnormalizeddepth")
13234       {
13235         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13236         anImgFormat = Image_Format_GrayF;
13237       }
13238       else if (aValue == "objectcolor"
13239             || aValue == "object"
13240             || aValue == "color")
13241       {
13242         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13243       }
13244       else if (aValue == "entitycolor"
13245             || aValue == "entity")
13246       {
13247         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13248       }
13249       else if (aValue == "entitytypecolor"
13250             || aValue == "entitytype")
13251       {
13252         aType = StdSelect_TypeOfSelectionImage_ColoredEntityType;
13253       }
13254       else if (aValue == "ownercolor"
13255             || aValue == "owner")
13256       {
13257         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13258       }
13259       else if (aValue == "selectionmodecolor"
13260             || aValue == "selectionmode"
13261             || aValue == "selmodecolor"
13262             || aValue == "selmode")
13263       {
13264         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13265       }
13266       else if (aValue == "surfnormal"
13267             || aValue == "surfacenormal"
13268             || aValue == "normal")
13269       {
13270         aType = StdSelect_TypeOfSelectionImage_SurfaceNormal;
13271       }
13272       else
13273       {
13274         Message::SendFail() << "Syntax error: unknown type '" << aValue << "'";
13275         return 1;
13276       }
13277     }
13278     else if (aParam == "-picked"
13279           || aParam == "-pickeddepth"
13280           || aParam == "-pickedindex")
13281     {
13282       if (++anArgIter >= theArgsNb)
13283       {
13284         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13285         return 1;
13286       }
13287
13288       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13289     }
13290     else if (anArgIter + 1 < theArgsNb
13291           && aParam == "-xrpose")
13292     {
13293       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13294       anXRArg.LowerCase();
13295       if (anXRArg == "base")
13296       {
13297         aCustomCam = aView->View()->BaseXRCamera();
13298       }
13299       else if (anXRArg == "head")
13300       {
13301         aCustomCam = aView->View()->PosedXRCamera();
13302       }
13303       else
13304       {
13305         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13306         return 1;
13307       }
13308       if (aCustomCam.IsNull())
13309       {
13310         Message::SendFail() << "Error: undefined XR pose";
13311         return 0;
13312       }
13313     }
13314     else if (aFile.IsEmpty())
13315     {
13316       aFile = theArgVec[anArgIter];
13317     }
13318     else
13319     {
13320       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13321       return 1;
13322     }
13323   }
13324   if (aFile.IsEmpty())
13325   {
13326     Message::SendFail ("Syntax error: image file name is missing");
13327     return 1;
13328   }
13329
13330   Standard_Integer aWidth = 0, aHeight = 0;
13331   aView->Window()->Size (aWidth, aHeight);
13332
13333   Image_AlienPixMap aPixMap;
13334   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13335   {
13336     Message::SendFail ("Error: can't allocate image");
13337     return 1;
13338   }
13339
13340   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13341   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13342   if (!aCustomCam.IsNull())
13343   {
13344     aView->SetCamera (aCustomCam);
13345   }
13346   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13347   {
13348     Message::SendFail ("Error: can't generate selection image");
13349     return 1;
13350   }
13351   if (!aCustomCam.IsNull())
13352   {
13353     aView->SetCamera (aCamBack);
13354   }
13355   aView->SetImmediateUpdate (wasImmUpdate);
13356
13357   if (!aPixMap.Save (aFile))
13358   {
13359     Message::SendFail ("Error: can't save selection image");
13360     return 0;
13361   }
13362   return 0;
13363 }
13364
13365 //===============================================================================================
13366 //function : VViewCube
13367 //purpose  :
13368 //===============================================================================================
13369 static int VViewCube (Draw_Interpretor& ,
13370                       Standard_Integer  theNbArgs,
13371                       const char**      theArgVec)
13372 {
13373   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13374   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13375   if (aContext.IsNull() || aView.IsNull())
13376   {
13377     Message::SendFail ("Error: no active viewer");
13378     return 1;
13379   }
13380   else if (theNbArgs < 2)
13381   {
13382     Message::SendFail ("Syntax error: wrong number arguments");
13383     return 1;
13384   }
13385
13386   Handle(AIS_ViewCube) aViewCube;
13387   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13388   Quantity_Color aColorRgb;
13389   TCollection_AsciiString aName;
13390   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13391   {
13392     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13393     anArg.LowerCase();
13394     if (anUpdateTool.parseRedrawMode (anArg))
13395     {
13396       //
13397     }
13398     else if (aViewCube.IsNull())
13399     {
13400       aName = theArgVec[anArgIter];
13401       if (aName.StartsWith ("-"))
13402       {
13403         Message::SendFail ("Syntax error: object name should be specified");
13404         return 1;
13405       }
13406       Handle(AIS_InteractiveObject) aPrs;
13407       GetMapOfAIS().Find2 (aName, aPrs);
13408       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13409       if (aViewCube.IsNull())
13410       {
13411         aViewCube = new AIS_ViewCube();
13412         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13413         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13414         aViewCube->SetFixedAnimationLoop (false);
13415       }
13416     }
13417     else if (anArg == "-reset")
13418     {
13419       aViewCube->ResetStyles();
13420     }
13421     else if (anArg == "-color"
13422           || anArg == "-boxcolor"
13423           || anArg == "-boxsidecolor"
13424           || anArg == "-sidecolor"
13425           || anArg == "-boxedgecolor"
13426           || anArg == "-edgecolor"
13427           || anArg == "-boxcornercolor"
13428           || anArg == "-cornercolor"
13429           || anArg == "-innercolor"
13430           || anArg == "-textcolor"
13431           || anArg == "-xaxistextcolor"
13432           || anArg == "-yaxistextcolor"
13433           || anArg == "-zaxistextcolor")
13434     {
13435       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
13436                                                      theArgVec + anArgIter + 1,
13437                                                      aColorRgb);
13438       if (aNbParsed == 0)
13439       {
13440         Message::SendFail() << "Syntax error at '" << anArg << "'";
13441         return 1;
13442       }
13443       anArgIter += aNbParsed;
13444       if (anArg == "-boxcolor")
13445       {
13446         aViewCube->SetBoxColor (aColorRgb);
13447       }
13448       else if (anArg == "-boxsidecolor"
13449             || anArg == "-sidecolor")
13450       {
13451         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13452         aViewCube->SynchronizeAspects();
13453       }
13454       else if (anArg == "-boxedgecolor"
13455             || anArg == "-edgecolor")
13456       {
13457         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13458         aViewCube->SynchronizeAspects();
13459       }
13460       else if (anArg == "-boxcornercolor"
13461             || anArg == "-cornercolor")
13462       {
13463         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13464         aViewCube->SynchronizeAspects();
13465       }
13466       else if (anArg == "-innercolor")
13467       {
13468         aViewCube->SetInnerColor (aColorRgb);
13469       }
13470       else if (anArg == "-textcolor")
13471       {
13472         aViewCube->SetTextColor (aColorRgb);
13473       }
13474       else if (anArg == "-xaxistextcolor"
13475             || anArg == "-yaxistextcolor"
13476             || anArg == "-zaxistextcolor")
13477       {
13478         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
13479                                 ? Prs3d_DatumParts_XAxis
13480                                 : (anArg.Value (2) == 'y'
13481                                  ? Prs3d_DatumParts_YAxis
13482                                  : Prs3d_DatumParts_ZAxis);
13483         aViewCube->Attributes()->SetOwnDatumAspects();
13484         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
13485       }
13486       else
13487       {
13488         aViewCube->SetColor (aColorRgb);
13489       }
13490     }
13491     else if (anArgIter + 1 < theNbArgs
13492           && (anArg == "-transparency"
13493            || anArg == "-boxtransparency"))
13494     {
13495       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13496       if (aValue < 0.0 || aValue > 1.0)
13497       {
13498         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13499         return 1;
13500       }
13501
13502       if (anArg == "-boxtransparency")
13503       {
13504         aViewCube->SetBoxTransparency (aValue);
13505       }
13506       else
13507       {
13508         aViewCube->SetTransparency (aValue);
13509       }
13510     }
13511     else if (anArg == "-axes"
13512           || anArg == "-edges"
13513           || anArg == "-vertices"
13514           || anArg == "-vertexes"
13515           || anArg == "-fixedanimation")
13516     {
13517       bool toShow = true;
13518       if (anArgIter + 1 < theNbArgs
13519        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
13520       {
13521         ++anArgIter;
13522       }
13523       if (anArg == "-fixedanimation")
13524       {
13525         aViewCube->SetFixedAnimationLoop (toShow);
13526       }
13527       else if (anArg == "-axes")
13528       {
13529         aViewCube->SetDrawAxes (toShow);
13530       }
13531       else if (anArg == "-edges")
13532       {
13533         aViewCube->SetDrawEdges (toShow);
13534       }
13535       else
13536       {
13537         aViewCube->SetDrawVertices (toShow);
13538       }
13539     }
13540     else if (anArg == "-yup"
13541           || anArg == "-zup")
13542     {
13543       bool isOn = true;
13544       if (anArgIter + 1 < theNbArgs
13545        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
13546       {
13547         ++anArgIter;
13548       }
13549       if (anArg == "-yup")
13550       {
13551         aViewCube->SetYup (isOn);
13552       }
13553       else
13554       {
13555         aViewCube->SetYup (!isOn);
13556       }
13557     }
13558     else if (anArgIter + 1 < theNbArgs
13559           && anArg == "-font")
13560     {
13561       aViewCube->SetFont (theArgVec[++anArgIter]);
13562     }
13563     else if (anArgIter + 1 < theNbArgs
13564           && anArg == "-fontheight")
13565     {
13566       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
13567     }
13568     else if (anArgIter + 1 < theNbArgs
13569           && (anArg == "-size"
13570            || anArg == "-boxsize"))
13571     {
13572       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
13573                           anArg != "-boxsize");
13574     }
13575     else if (anArgIter + 1 < theNbArgs
13576           && (anArg == "-boxfacet"
13577            || anArg == "-boxfacetextension"
13578            || anArg == "-facetextension"
13579            || anArg == "-extension"))
13580     {
13581       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
13582     }
13583     else if (anArgIter + 1 < theNbArgs
13584           && (anArg == "-boxedgegap"
13585            || anArg == "-edgegap"))
13586     {
13587       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
13588     }
13589     else if (anArgIter + 1 < theNbArgs
13590           && (anArg == "-boxedgeminsize"
13591            || anArg == "-edgeminsize"))
13592     {
13593       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
13594     }
13595     else if (anArgIter + 1 < theNbArgs
13596           && (anArg == "-boxcornerminsize"
13597            || anArg == "-cornerminsize"))
13598     {
13599       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
13600     }
13601     else if (anArgIter + 1 < theNbArgs
13602           && anArg == "-axespadding")
13603     {
13604       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
13605     }
13606     else if (anArgIter + 1 < theNbArgs
13607           && anArg == "-roundradius")
13608     {
13609       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
13610     }
13611     else if (anArgIter + 1 < theNbArgs
13612           && anArg == "-duration")
13613     {
13614       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
13615     }
13616     else if (anArgIter + 1 < theNbArgs
13617           && anArg == "-axesradius")
13618     {
13619       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
13620     }
13621     else if (anArgIter + 1 < theNbArgs
13622           && anArg == "-axesconeradius")
13623     {
13624       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
13625     }
13626     else if (anArgIter + 1 < theNbArgs
13627           && anArg == "-axessphereradius")
13628     {
13629       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
13630     }
13631     else
13632     {
13633       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13634       return 1;
13635     }
13636   }
13637   if (aViewCube.IsNull())
13638   {
13639     Message::SendFail ("Syntax error: wrong number of arguments");
13640     return 1;
13641   }
13642
13643   ViewerTest::Display (aName, aViewCube, false);
13644   return 0;
13645 }
13646
13647 //! Parse color type argument.
13648 static bool parseColorType (const char* theString,
13649                             Quantity_TypeOfColor& theType)
13650 {
13651   TCollection_AsciiString aType (theString);
13652   aType.LowerCase();
13653   if      (aType == "rgb")  { theType = Quantity_TOC_RGB; }
13654   else if (aType == "srgb") { theType = Quantity_TOC_sRGB; }
13655   else if (aType == "hex")  { theType = Quantity_TOC_sRGB; }
13656   else if (aType == "name") { theType = Quantity_TOC_sRGB; }
13657   else if (aType == "hls")  { theType = Quantity_TOC_HLS; }
13658   else if (aType == "lab")  { theType = Quantity_TOC_CIELab; }
13659   else if (aType == "lch")  { theType = Quantity_TOC_CIELch; }
13660   else { return false; }
13661   return true;
13662 }
13663
13664 //===============================================================================================
13665 //function : VColorConvert
13666 //purpose  :
13667 //===============================================================================================
13668 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
13669 {
13670   Quantity_TypeOfColor aTypeFrom = Quantity_TOC_RGB, aTypeTo = Quantity_TOC_RGB;
13671   double anInput[4] = {};
13672   Quantity_ColorRGBA aColor (0.0f, 0.0f, 0.0f, 1.0f);
13673   bool toPrintHex = false, toPrintName = false, hasAlpha = false;
13674   for (int anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13675   {
13676     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
13677     anArgCase.LowerCase();
13678     if ((anArgCase == "-from"
13679       || anArgCase == "from")
13680      && anArgIter + 1 < theNbArgs
13681      && parseColorType (theArgVec[anArgIter + 1], aTypeFrom))
13682     {
13683       ++anArgIter;
13684     }
13685     else if ((anArgCase == "-to"
13686            || anArgCase == "to")
13687           && anArgIter + 1 < theNbArgs
13688           && parseColorType (theArgVec[anArgIter + 1], aTypeTo))
13689     {
13690       TCollection_AsciiString aToStr (theArgVec[++anArgIter]);
13691       aToStr.LowerCase();
13692       toPrintHex  = (aToStr == "hex");
13693       toPrintName = (aToStr == "name");
13694     }
13695     else if (Quantity_ColorRGBA::ColorFromHex (theArgVec[anArgIter], aColor))
13696     {
13697       hasAlpha = anArgCase.Length() >= 8;
13698     }
13699     else if (Quantity_Color::ColorFromName (theArgVec[anArgIter], aColor.ChangeRGB()))
13700     {
13701       //
13702     }
13703     else if (anArgIter + 2 < theNbArgs
13704           && Draw::ParseReal (theArgVec[anArgIter + 0], anInput[0])
13705           && Draw::ParseReal (theArgVec[anArgIter + 1], anInput[1])
13706           && Draw::ParseReal (theArgVec[anArgIter + 2], anInput[2]))
13707     {
13708       if (anArgIter + 3 < theNbArgs
13709        && Draw::ParseReal (theArgVec[anArgIter + 3], anInput[3]))
13710       {
13711         anArgIter += 1;
13712         aColor.SetAlpha ((float )anInput[3]);
13713         hasAlpha = true;
13714       }
13715       anArgIter += 2;
13716       aColor.ChangeRGB().SetValues (anInput[0], anInput[1], anInput[2], aTypeFrom);
13717     }
13718     else
13719     {
13720       theDI << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13721       return 1;
13722     }
13723   }
13724
13725   if (toPrintHex)
13726   {
13727     if (hasAlpha || aColor.Alpha() < 1.0f)
13728     {
13729       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
13730     }
13731     else
13732     {
13733       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
13734     }
13735   }
13736   else if (toPrintName)
13737   {
13738     theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
13739   }
13740   else
13741   {
13742     double anOutput[3] = {};
13743     aColor.GetRGB().Values (anOutput[0], anOutput[1], anOutput[2], aTypeTo);
13744
13745     // print values with 6 decimal digits
13746     char aBuffer[1024];
13747     if (hasAlpha || aColor.Alpha() < 1.0f)
13748     {
13749       Sprintf (aBuffer, "%.6f %.6f %.6f %.6f", anOutput[0], anOutput[1], anOutput[2], aColor.Alpha());
13750     }
13751     else
13752     {
13753       Sprintf (aBuffer, "%.6f %.6f %.6f", anOutput[0], anOutput[1], anOutput[2]);
13754     }
13755     theDI << aBuffer;
13756   }
13757   return 0;
13758 }
13759  
13760 //===============================================================================================
13761 //function : VColorDiff
13762 //purpose  :
13763 //===============================================================================================
13764 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13765 {
13766   if (theNbArgs != 7)
13767   {
13768     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13769     return 1;
13770   }
13771
13772   double aR1 = Draw::Atof (theArgVec[1]);
13773   double aG1 = Draw::Atof (theArgVec[2]);
13774   double aB1 = Draw::Atof (theArgVec[3]);
13775   double aR2 = Draw::Atof (theArgVec[4]);
13776   double aG2 = Draw::Atof (theArgVec[5]);
13777   double aB2 = Draw::Atof (theArgVec[6]);
13778
13779   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
13780   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
13781
13782   theDI << aColor1.DeltaE2000 (aColor2);
13783
13784   return 0;
13785 }
13786  
13787 //===============================================================================================
13788 //function : VSelBvhBuild
13789 //purpose  :
13790 //===============================================================================================
13791 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
13792 {
13793   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
13794   if (aCtx.IsNull())
13795   {
13796     Message::SendFail ("Error: no active viewer");
13797     return 1;
13798   }
13799
13800   if (theNbArgs < 2)
13801   {
13802     Message::SendFail ("Error: command syntax is incorrect, see help");
13803     return 1;
13804   }
13805
13806   Standard_Integer toEnable = -1;
13807   Standard_Integer aThreadsNb = -1;
13808   Standard_Boolean toWait = Standard_False;
13809
13810   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13811   {
13812     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13813     anArg.LowerCase();
13814
13815     if (anArg == "-nbthreads"
13816         && anArgIter + 1 < theNbArgs)
13817     {
13818       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
13819       if (aThreadsNb < 1)
13820       {
13821         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
13822       }
13823     }
13824     else if (anArg == "-wait")
13825     {
13826       toWait = Standard_True;
13827     }
13828     else if (toEnable == -1)
13829     {
13830       Standard_Boolean toEnableValue = Standard_True;
13831       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
13832       {
13833         toEnable = toEnableValue ? 1 : 0;
13834       }
13835       else
13836       {
13837         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13838         return 1;
13839       }
13840     }
13841     else
13842     {
13843       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13844       return 1;
13845     }
13846   }
13847
13848   if (aThreadsNb == -1)
13849   {
13850     aThreadsNb = 1;
13851   }
13852   if (toEnable != -1)
13853   {
13854     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
13855   }
13856   if (toWait)
13857   {
13858     aCtx->MainSelector()->WaitForBVHBuild();
13859   }
13860
13861   return 0;
13862 }
13863
13864 //=======================================================================
13865 //function : ViewerTest_ExitProc
13866 //purpose  :
13867 //=======================================================================
13868 static void ViewerTest_ExitProc (ClientData )
13869 {
13870   NCollection_List<TCollection_AsciiString> aViewList;
13871   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
13872        anIter.More(); anIter.Next())
13873   {
13874     aViewList.Append (anIter.Key1());
13875   }
13876
13877   for (NCollection_List<TCollection_AsciiString>::Iterator anIter (aViewList);
13878        anIter.More(); anIter.Next())
13879   {
13880     ViewerTest::RemoveView (anIter.Value(), true);
13881   }
13882 }
13883
13884 //=======================================================================
13885 //function : ViewerCommands
13886 //purpose  :
13887 //=======================================================================
13888
13889 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
13890 {
13891   static bool TheIsInitialized = false;
13892   if (TheIsInitialized)
13893   {
13894     return;
13895   }
13896
13897   TheIsInitialized = true;
13898   // define destruction callback to destroy views in a well-defined order
13899   Tcl_CreateExitHandler (ViewerTest_ExitProc, 0);
13900
13901   const char* aGroup = "AIS Viewer";
13902   const char* aFileName = __FILE__;
13903   auto addCmd = [&](const char* theName, Draw_Interpretor::CommandFunction theFunc, const char* theHelp)
13904   {
13905     theCommands.Add (theName, theHelp, aFileName, theFunc, aGroup);
13906   };
13907
13908   addCmd ("vdriver", VDriver, /* [vdriver] */ R"(
13909 vdriver [-list] [-default DriverName] [-load DriverName]
13910 Manages active graphic driver factory.
13911 Prints current active driver when called without arguments.
13912 Makes specified driver active when ActiveName argument is specified.
13913  -list    print registered factories
13914  -default define which factory should be used by default (to be used by next vinit call)
13915  -load    try loading factory plugin and set it as default one
13916 )" /* [vdriver] */);
13917
13918   addCmd ("vinit", VInit, /* [vinit] */ R"(
13919 vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]
13920       [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {0|1}]=0 [-2d_mode {0|1}]=0
13921       [-display displayName] [-dpiAware {0|1}]=0
13922       [-subview] [-parent OtherView] [-composer {0|1}]=0 [-margins DX DY]=0
13923 Creates new View window with specified name viewName.
13924 By default the new view is created in the viewer and in graphic driver shared with active view.
13925  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}
13926        if driverName isn't specified the driver will be shared with active view;
13927        if viewerName isn't specified the viewer will be shared with active view.
13928  -display HostName.DisplayNumber[:ScreenNumber]
13929
13930 Display name will be used within creation of graphic driver, when specified.
13931  -left,  -top    pixel position of left top corner of the window.
13932  -width, -height width and height of window respectively.
13933  -cloneActive flag to copy camera and dimensions of active view.
13934  -exitOnClose when specified, closing the view will exit application.
13935  -closeOnEscape when specified, view will be closed on pressing Escape.
13936  -virtual create an offscreen window within interactive session
13937  -subview create a subview within another view
13938  -2d_mode when on, view will not react on rotate scene events
13939  -dpiAware override dpi aware hint (Windows platform)
13940 Additional commands for operations with views: vclose, vactivate, vviewlist.
13941 )" /* [vinit] */);
13942
13943   addCmd ("vclose", VClose, /* [vclose] */ R"(
13944 vclose [view_id [keep_context=0|1]]
13945 or vclose ALL - to remove all created views
13946  - removes view(viewer window) defined by its view_id.
13947  - keep_context: by default 0; if 1 and the last view is deleted the current context is not removed.
13948 )" /* [vclose] */);
13949
13950   addCmd ("vactivate", VActivate, /* [vactivate] */ R"(
13951 vactivate view_id [-noUpdate]
13952 Activates view(viewer window) defined by its view_id.
13953 )" /* [vactivate] */);
13954
13955   addCmd ("vviewlist", VViewList, /* [vviewlist] */ R"(
13956 vviewlist [format={tree, long}]=tree
13957 Prints current list of views per viewer and graphic_driver ID shared between viewers
13958  - format: format of result output, if tree the output is a tree view;
13959            otherwise it's a list of full view names.
13960 )" /* [vviewlist] */);
13961
13962   addCmd ("vhelp", VHelp, /* [vhelp] */ R"(
13963 vhelp : display help on the viewer commands and list of hotkeys.
13964 )" /* [vhelp] */);
13965
13966   addCmd ("vviewproj", VViewProj, /* [vviewproj] */ R"(
13967 vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]
13968           [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]
13969 Setup view direction
13970  -Yup      use Y-up convention instead of Zup (which is default).
13971  +-X+-Y+-Z define direction as combination of DX, DY and DZ;
13972            for example '+Z' will show front of the model,
13973            '-X-Y+Z' will define left axonometric view.
13974  -frame    define camera Up and Right directions (regardless Up convention);
13975            for example '+X+Z' will show front of the model with Z-up.
13976 )" /* [vviewproj] */);
13977
13978   addCmd ("vtop", VViewProj, /* [vtop] */ R"(
13979 vtop or <T> : Display top view (+X+Y) in the 3D viewer window.
13980 )" /* [vtop] */);
13981
13982   addCmd ("vbottom", VViewProj, /* [vbottom] */ R"(
13983 vbottom : Display bottom view (+X-Y) in the 3D viewer window.
13984 )" /* [vbottom] */);
13985
13986   addCmd ("vleft", VViewProj, /* [vleft] */ R"(
13987 vleft : Display left view (-Y+Z) in the 3D viewer window.
13988 )" /* [vleft] */);
13989
13990   addCmd ("vright", VViewProj, /* [vright] */ R"(
13991 vright : Display right view (+Y+Z) in the 3D viewer window.
13992 )" /* [vright] */);
13993
13994   addCmd ("vaxo", VViewProj, /* [vaxo] */ R"(
13995 vaxo or <A> : Display axonometric view (+X-Y+Z) in the 3D viewer window.
13996 )" /* [vaxo] */);
13997
13998   addCmd ("vfront", VViewProj, /* [vfront] */ R"(
13999 vfront : Display front view (+X+Z) in the 3D viewer window.
14000 )" /* [vfront] */);
14001
14002   addCmd ("vback", VViewProj, /* [vfront] */ R"(
14003 vback : Display back view (-X+Z) in the 3D viewer window.
14004 )" /* [vback] */);
14005
14006   addCmd ("vpick", VPick, /* [vpick] */ R"(
14007 vpick X Y Z [shape subshape]
14008 )" /* [vpick] */);
14009
14010   addCmd ("vfit", VFit, /* [vfit] */ R"(
14011 vfit or <F> [-selected] [-noupdate]
14012 Fit all / selected. Objects in the view are visualized to occupy the maximum surface.
14013 )" /* [vfit] */);
14014
14015   addCmd ("vfitarea", VFitArea, /* [vfitarea] */ R"(
14016 vfitarea [x1 y1 x2 y2] [x1 y1 z1 x2 y2 z2]
14017 Fit view to show area located between two points
14018 given in world 2D or 3D coordinates.
14019 )" /* [vfitarea] */);
14020
14021   addCmd ("vzfit", VZFit, /* [vzfit] */ R"(
14022 vzfit [scale]
14023 Automatic depth panning.
14024 Matches Z near, Z far view volume planes to the displayed objects.
14025  - "scale" specifies factor to scale computed z range.
14026 )" /* [vzfit] */);
14027
14028   addCmd ("vrepaint", VRepaint, /* [vrepaint] */ R"(
14029 vrepaint [-immediate] [-continuous FPS]
14030 Force redraw of active View.
14031  -immediate  flag performs redraw of immediate layers only;
14032  -continuous activates/deactivates continuous redraw of active View,
14033              0 means no continuous rendering,
14034             -1 means non-stop redraws,
14035             >0 specifies target framerate.
14036 )" /* [vrepaint] */);
14037
14038   addCmd ("vclear", VClear, /* [vclear] */ R"(
14039 vclear : Remove all the object from the viewer
14040 )" /* [vclear] */);
14041
14042   addCmd ("vbackground", VBackground, /* [vbackground] */ R"(
14043 vbackground [-color Color [-default]]
14044     [-gradient Color1 Color2 [-default]
14045     [-gradientMode {NONE|HORIZONTAL|VERTICAL|DIAG1|DIAG2|CORNER1|CORNER2|CORNER3|ELLIPTICAL}]=VERT]
14046     [-imageFile ImageFile [-imageMode {CENTERED|TILED|STRETCH|NONE}]=CENTERED [-srgb {0|1}]=1]
14047     [-cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]=0]
14048     [-skydome [-sunDir X Y Z=0 1 0] [-cloud Cloudy=0.2] [-time Time=0.0]
14049               [-fog Haze=0.0] [-size SizePx=512]]
14050     [-pbrEnv {ibl|noibl|keep}]
14051 Changes background or some background settings.
14052  -color        sets background color
14053  -gradient     sets background gradient starting and ending colors
14054  -gradientMode sets gradient fill method
14055  -default      sets background default gradient or color
14056  -imageFile    sets filename of image used as background
14057  -imageMode    sets image fill type
14058  -cubemap      sets environment cubemap as background
14059  -invertedz    sets inversion of Z axis for background cubemap rendering; FALSE when unspecified
14060  -pbrEnv       sets on/off Image Based Lighting (IBL) from background cubemap for PBR
14061  -srgb         prefer sRGB texture format when applicable; TRUE when unspecified"
14062  -order        defines order of tiles in one image cubemap
14063                TileIndexi defubes an index in range [0, 5] for i tile of one image packed cubemap
14064                (has no effect in case of multi-image cubemaps).
14065 Skydome background parameters (generated cubemap):
14066  -skydome      sets procedurally generated skydome as background
14067  -sunDir       sets direction to the sun, direction with negative y component represents moon direction (-x, -y, -z)
14068  -cloud        sets cloud intensity (0.0 - clear sky, 1.0 - very high cloudy)
14069  -time         might be tweaked to slightly change appearance of clouds
14070  -fog          sets mist intensity (0.0 - no mist at all, 1.0 - high mist)
14071  -size         sets size in pixels of cubemap side
14072 )" /* [vbackground] */);
14073
14074   addCmd ("vsetbg", VBackground, /* [vsetbg] */ R"(
14075 Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.
14076 )" /* [vsetbg] */);
14077
14078   addCmd ("vsetbgmode", VBackground, /* [vsetbgmode] */ R"(
14079 Alias for 'vbackground -imageMode FillType'.
14080 )" /* [vsetbgmode] */);
14081
14082   addCmd ("vsetgradientbg", VBackground, /* [vsetgradientbg] */ R"(
14083 Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.
14084 )" /* [vsetgradientbg] */);
14085
14086   addCmd ("vsetgrbgmode", VBackground, /* [vsetgrbgmode] */ R"(
14087 Alias for 'vbackground -gradientMode FillMethod'.
14088 )" /* [vsetgrbgmode] */);
14089
14090   addCmd ("vsetcolorbg", VBackground, /* [vsetcolorbg] */ R"(
14091 Alias for 'vbackground -color Color'.
14092 )" /* [vsetcolorbg] */);
14093
14094   addCmd ("vsetdefaultbg", VBackground, /* [vsetdefaultbg] */ R"(
14095 Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'
14096   and for 'vbackground -default -color Color'.
14097 )" /* [vsetdefaultbg] */);
14098
14099   addCmd ("vscale", VScale, /* [vscale] */ R"(
14100 vscale X Y Z
14101 )" /* [vscale] */);
14102
14103   addCmd ("vzbufftrihedron", VZBuffTrihedron, /* [vzbufftrihedron] */ R"(
14104 vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]
14105        [-position center|left_lower|left_upper|right_lower|right_upper]
14106        [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]
14107        [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]
14108        [-nbfacets value=12] [-colorLabels color=WHITE]
14109        [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]
14110 Displays a trihedron.
14111 )" /* [vzbufftrihedron] */);
14112
14113   addCmd ("vrotate", VRotate, /* [vrotate] */ R"(
14114 vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]
14115  -mouseStart start rotation according to the mouse position;
14116  -mouseMove  continue rotation with angle computed
14117              from last and new mouse position.
14118 )" /* [vrotate] */);
14119
14120   addCmd ("vzoom", VZoom, /* [vzoom] */ R"(
14121 vzoom coef
14122 )" /* [vzoom] */);
14123
14124   addCmd ("vpan", VPan, /* [vpan] */ R"(
14125 vpan dx dy
14126 )" /* [vpan] */);
14127
14128   addCmd ("vcolorscale", VColorScale, /* [vcolorscale] */ R"(
14129 vcolorscale name [-noupdate|-update] [-demo]
14130       [-range RangeMin=0 RangeMax=1 NbIntervals=10]
14131       [-font HeightFont=20]
14132       [-logarithmic {on|off}=off] [-reversed {on|off}=off]
14133       [-smoothTransition {on|off}=off]
14134       [-hueRange MinAngle=230 MaxAngle=0]
14135       [-colorRange MinColor=BLUE1 MaxColor=RED]
14136       [-textPos {left|right|center|none}=right]
14137       [-labelAtBorder {on|off}=on]
14138       [-colors Color1 Color2 ...] [-color Index Color]
14139       [-labels Label1 Label2 ...] [-label Index Label]
14140       [-freeLabels NbOfLabels Label1 Label2 ...]
14141       [-xy Left=0 Bottom=0]
14142       [-uniform lightness hue_from hue_to]
14143  -demo       display a color scale with demonstration values
14144  -colors     set colors for all intervals
14145  -color      set color for specific interval
14146  -uniform    generate colors with the same lightness
14147  -textpos    horizontal label position relative to color scale bar
14148  -labelAtBorder vertical label position relative to color interval;
14149              at border means the value inbetween neighbor intervals,
14150              at center means the center value within current interval
14151  -labels     set labels for all intervals
14152  -freeLabels same as -labels but does not require
14153              matching the number of intervals
14154  -label      set label for specific interval
14155  -title      set title
14156  -reversed   setup smooth color transition between intervals
14157  -smoothTransition swap colorscale direction
14158  -hueRange   set hue angles corresponding to minimum and maximum values
14159 )" /* [vcolorscale] */);
14160
14161   addCmd ("vgraduatedtrihedron", VGraduatedTrihedron, /* [vgraduatedtrihedron] */ R"(
14162 vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]
14163     [-namefont Name] [-valuesfont Name]
14164     [-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]
14165     [-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]
14166     [-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]
14167     [-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]
14168     [-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]
14169     [-xcolor Color] [-ycolor Color] [-zcolor Color]
14170     [-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]
14171     [-xticks Number] [-yticks Number] [-zticks Number]
14172     [-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]
14173     [-drawgrid on/off] [-drawaxes on/off]
14174 Display or erase graduated trihedron
14175  - xname, yname, zname - names of axes, default: X, Y, Z
14176  - namefont - font of axes names. Default: Arial
14177  - xnameoffset, ynameoffset, znameoffset - offset of name
14178    from values or tickmarks or axis. Default: 30
14179  - xnamecolor, ynamecolor, znamecolor - colors of axes names
14180  - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values
14181    from tickmarks or axis. Default: 10
14182  - valuesfont - font of axes values. Default: Arial
14183  - xcolor, ycolor, zcolor - color of axis and values
14184  - xticks, yticks, xzicks - number of tickmark on axes. Default: 5
14185  - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10
14186 )" /* [vgraduatedtrihedron] */);
14187
14188   addCmd ("vtile", VTile, /* [vtile] */ R"(
14189 vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]
14190 Setup view to draw a tile (a part of virtual bigger viewport).
14191  -totalSize the size of virtual bigger viewport
14192  -tileSize  tile size (the view size will be used if omitted)
14193  -lowerLeft tile offset as lower left corner
14194  -upperLeft tile offset as upper left corner
14195 )" /* [vtile] */);
14196
14197   addCmd ("vzlayer", VZLayer, /* [vzlayer] */ R"(
14198 vzlayer [layerId]
14199         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]
14200         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]
14201         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]
14202         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]
14203 ZLayer list management
14204  -add      add new z layer to viewer and print its id
14205  -insertBefore add new z layer and insert it before existing one
14206  -insertAfter  add new z layer and insert it after  existing one
14207  -delete   delete z layer
14208  -get      print sequence of z layers
14209  -settings print status of z layer settings
14210  -disable  disables given setting
14211  -enable   enables  given setting
14212 )" /* [vzlayer] */);
14213
14214   addCmd ("vlayerline", VLayerLine, /* [vlayerline] */ R"(
14215 vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]
14216 )" /* [vlayerline] */);
14217
14218   addCmd ("vgrid", VGrid, /* [vgrid] */ R"(
14219 vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]
14220       [-step X Y] [-size DX DY]
14221       [-step StepRadius NbDivisions] [-radius Radius]
14222 )" /* [vgrid] */);
14223
14224   addCmd ("vpriviledgedplane", VPriviledgedPlane, /* [vpriviledgedplane] */ R"(
14225 vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]
14226 Sets or prints viewer's priviledged plane geometry:
14227   Ox, Oy, Oz - plane origin;
14228   Nx, Ny, Nz - plane normal direction;
14229   Xx, Xy, Xz - plane x-reference axis direction.
14230 )" /* [vpriviledgedplane] */);
14231
14232   addCmd ("vconvert", VConvert, /* [vconvert] */ R"(
14233 vconvert v [Mode={window|view}]
14234 vconvert x y [Mode={window|view|grid|ray}]
14235 vconvert x y z [Mode={window|grid}]
14236 Convert the given coordinates to window/view/model space:
14237  - window - convert to window coordinates, pixels;
14238  - view   - convert to view projection plane;
14239  - grid   - convert to model coordinates, given on grid;
14240  - ray    - convert projection ray to model coordinates.
14241 )" /* [vconvert] */);
14242
14243   addCmd ("vfps", VFps, /* [vfps] */ R"(
14244 vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view.
14245 )" /* [vfps] */);
14246
14247   addCmd ("vstereo", VStereo, /* [vstereo] */ R"(
14248 vstereo [0|1] [-mode Mode] [-reverse {0|1}]
14249         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]
14250         [-anaglyph Filter] [-smoothInterlacing]
14251 Control stereo output mode. Available modes for -mode:
14252   quadBuffer       OpenGL QuadBuffer stereo;
14253     requires driver support;
14254     should be called BEFORE vinit!
14255   anaglyph         Anaglyph glasses, filters for -anaglyph:
14256     redCyan, redCyanSimple, yellowBlue, yellowBlueSimple, greenMagentaSimple.
14257   rowInterlaced    row-interlaced display
14258     smooth         smooth interlaced output for better text readability
14259   columnInterlaced column-interlaced display
14260   chessBoard       chess-board output
14261   sideBySide       horizontal pair
14262   overUnder        vertical   pair
14263   openVR           OpenVR (HMD), extra options:
14264     -mirrorComposer flag to mirror VR frame in the window (debug);
14265     -unitFactor     specifies meters scale factor for mapping VR input.
14266 )" /* [vstereo] */);
14267
14268   addCmd ("vmemgpu", VMemGpu, /* [vmemgpu] */ R"(
14269 vmemgpu [f]: print system-dependent GPU memory information if available;
14270 with f option returns free memory in bytes.
14271 )" /* [vmemgpu] */);
14272
14273   addCmd ("vreadpixel", VReadPixel, /* [vreadpixel] */ R"(
14274 vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]
14275 Read pixel value for active view.
14276 )" /* [vreadpixel] */);
14277
14278   addCmd ("diffimage", VDiffImage, /* [diffimage] */ R"(
14279 diffimage imageFile1 imageFile2 [diffImageFile]
14280           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]
14281           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]
14282 Compare two images by content and generate difference image.
14283 When -exitOnClose is specified, closing the view will exit application.
14284 When -closeOnEscape is specified, view will be closed on pressing Escape.
14285 )" /* [diffimage] */);
14286
14287   addCmd ("vselect", VSelect, /* [vselect] */ R"(
14288 vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1]
14289         [-replace|-replaceextra|-xor|-add|-remove]
14290 Emulate different types of selection:
14291  1) Single click selection.
14292  2) Selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2).
14293  3) Selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn).
14294  4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.
14295     If the flag is set to 1, both sensitives that were included completely
14296     and overlapped partially by defined rectangle or polygon will be detected,
14297     otherwise algorithm will chose only fully included sensitives.
14298     Default behavior is to detect only full inclusion
14299     (partial inclusion - overlap - is not allowed by default).
14300  5) Selection scheme replace, replaceextra, xor, add or remove (replace by default).
14301 )" /* [vselect] */);
14302
14303   addCmd ("vmoveto", VMoveTo, /* [vmoveto] */ R"(
14304 vmoveto [x y] [-reset]
14305 Emulate cursor movement to pixel position (x,y).
14306  -reset resets current highlighting.
14307 )" /* [vmoveto] */);
14308
14309   addCmd ("vselaxis", VSelectByAxis, /* [vselaxis] */ R"(
14310 vselaxis x y z dx dy dz [-onlyTop 0|1] [-display Name] [-showNormal 0|1]"
14311 Provides intersection by given axis and print result intersection points.
14312  -onlyTop       switches On/Off mode to find only top point or all;
14313  -display Name  displays intersecting axis and result intersection points for debug goals;
14314  -showNormal    adds displaying of normal in intersection point or not.
14315 )" /* [vselaxis] */);
14316
14317   addCmd ("vviewparams", VViewParams, /* [vviewparams] */ R"(
14318 vviewparams [-args] [-scale [s]]
14319             [-eye [x y z]] [-at [x y z]] [-up [x y z]]
14320             [-proj [x y z]] [-center x y] [-size sx]
14321 Manage current view parameters (camera orientation) or prints all
14322 current values when called without argument.
14323  -scale [s]    prints or sets viewport relative scale
14324  -eye  [x y z] prints or sets eye location
14325  -at   [x y z] prints or sets center of look
14326  -up   [x y z] prints or sets direction of up vector
14327  -proj [x y z] prints or sets direction of look
14328  -center x y   sets location of center of the screen in pixels
14329  -size [sx]    prints viewport projection width and height sizes
14330                or changes the size of its maximum dimension
14331  -args         prints vviewparams arguments for restoring current view
14332 )" /* [vviewparams] */);
14333
14334   addCmd ("v2dmode", V2DMode, /* [v2dmode] */ R"(
14335 v2dmode [-name viewName] [-mode {-on|-off}=-on]
14336   name - name of existing view, if not defined, the active view is changed;
14337   mode - switches On/Off rotation mode.
14338 Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:
14339  - rotation of the view by 3rd mouse button with Ctrl active
14340  - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right
14341 View camera position might be changed only by commands.
14342 )" /* [v2dmode] */);
14343
14344   addCmd ("vanimation", VAnimation, /* [vanimation] */ R"(
14345 Alias for vanim
14346 )" /* [vanimation] */);
14347
14348   addCmd ("vanim", VAnimation, /* [vanim] */ R"(
14349 List existing animations:
14350   vanim
14351
14352 Animation playback:
14353   vanim name {-play|-resume|-pause|-stop} [playFrom [playDuration]]
14354              [-speed Coeff] [-freeLook] [-noPauseOnClick] [-lockLoop]
14355
14356   -speed    playback speed (1.0 is normal speed)
14357   -freeLook skip camera animations
14358   -noPauseOnClick do not pause animation on mouse click
14359   -lockLoop disable any interactions
14360
14361 Animation definition:
14362   vanim Name/sub/name [-clear] [-delete]
14363         [-start TimeSec] [-duration TimeSec] [-end TimeSec]
14364
14365 Animation name defined in path-style (anim/name or anim.name)
14366 specifies nested animations.
14367 There is no syntax to explicitly add new animation,
14368 and all non-existing animations within the name will be
14369 implicitly created on first use (including parents).
14370
14371 Each animation might define the SINGLE action (see below),
14372 like camera transition, object transformation or custom callback.
14373 Child animations can be used for defining concurrent actions.
14374
14375 Camera animation:
14376   vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]
14377                    [-at1  X Y Z] [-at2  X Y Z]
14378                    [-up1  X Y Z] [-up2  X Y Z]
14379                    [-scale1 Scale] [-scale2 Scale]
14380   -eyeX   camera Eye positions pair (start and end)
14381   -atX    camera Center positions pair
14382   -upX    camera Up directions pair
14383   -scaleX camera Scale factors pair
14384
14385 Object animation:
14386   vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]
14387                      [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]
14388                      [-scale1 Scale] [-scale2 Scale]
14389  -locX   object Location points pair (translation)
14390  -rotX   object Orientations pair (quaternions)
14391  -scaleX object Scale factors pair (quaternions)
14392
14393 Custom callback:
14394   vanim name -invoke "Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN"
14395
14396   %Pts        overall animation presentation timestamp
14397   %LocalPts   local animation timestamp
14398   %Normalized local animation normalized value in range 0..1
14399
14400 Video recording:
14401   vanim name -record FileName [Width Height] [-fps FrameRate=24]
14402         [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]
14403         [-crf Value] [-preset Preset]
14404   -fps     video framerate
14405   -format  file format, container (matroska, etc.)
14406   -vcodec  video codec identifier (ffv1, mjpeg, etc.)
14407   -pix_fmt image pixel format (yuv420p, rgb24, etc.)
14408   -crf     constant rate factor (specific to codec)
14409   -preset  codec parameters preset (specific to codec)
14410 )" /* [vanim] */);
14411
14412   addCmd ("vchangeselected", VChangeSelected, /* [vchangeselected] */ R"(
14413 vchangeselected shape : Add shape to selection or remove one from it.
14414 )" /* [vchangeselected] */);
14415
14416   addCmd ("vnbselected", VNbSelected, /* [vnbselected] */ R"(
14417 vnbselected : Returns number of selected objects in the interactive context.
14418 )" /* [vnbselected] */);
14419
14420   addCmd ("vcamera", VCamera, /* [vcamera] */ R"(
14421 vcamera [PrsName] [-ortho] [-projtype]
14422         [-persp]
14423         [-fovy   [Angle]] [-distance [Distance]]
14424         [-stereo] [-leftEye] [-rightEye]
14425         [-iod [Distance]] [-iodType    [absolute|relative]]
14426         [-zfocus [Value]] [-zfocusType [absolute|relative]]
14427         [-fov2d  [Angle]] [-lockZup {0|1}]
14428         [-rotationMode {active|pick|pickCenter|cameraAt|scene}]
14429         [-navigationMode {orbit|walk|flight}]
14430         [-xrPose base|head=base]
14431 Manages camera parameters.
14432 Displays frustum when presentation name PrsName is specified.
14433 Prints current value when option called without argument.
14434
14435 Orthographic camera:
14436  -ortho      activate orthographic projection.
14437
14438 Perspective camera:
14439  -persp      activate perspective  projection (mono);
14440  -fovy       field of view in y axis, in degrees;
14441  -fov2d      field of view limit for 2d on-screen elements;
14442  -distance   distance of eye from camera center;
14443  -lockZup    lock Z up (turntable mode);
14444  -rotationMode rotation mode (gravity point);
14445  -navigationMode navigation mode.
14446
14447 Stereoscopic camera:
14448  -stereo     perspective  projection (stereo);
14449  -leftEye    perspective  projection (left  eye);
14450  -rightEye   perspective  projection (right eye);
14451  -iod        intraocular distance value;
14452  -iodType    distance type, absolute or relative;
14453  -zfocus     stereographic focus value;
14454  -zfocusType focus type, absolute or relative.
14455 )" /* [vcamera] */);
14456
14457   addCmd ("vautozfit", VAutoZFit, /* [vautozfit] */ R"(
14458 vautozfit [on={1|0}] [scale]
14459 Prints or changes parameters of automatic z-fit mode:
14460  "on" - turns automatic z-fit on or off;
14461  "scale" - specifies factor to scale computed z range.
14462 )" /* [vautozfit] */);
14463
14464   addCmd ("vzrange", VZRange, /* [vzrange] */ R"(
14465 vzrange [znear] [zfar]
14466 Applies provided znear/zfar to view or prints current values.
14467 )" /* [vzrange] */);
14468
14469   addCmd ("vsetviewsize", VSetViewSize, /* [vsetviewsize] */ R"(
14470 vsetviewsize size
14471 )" /* [vsetviewsize] */);
14472
14473   addCmd ("vmoveview", VMoveView, /* [vmoveview] */ R"(
14474 vmoveview Dx Dy Dz [Start = 1|0]
14475 )" /* [vmoveview] */);
14476
14477   addCmd ("vtranslateview", VTranslateView, /* [vtranslateview] */ R"(
14478 vtranslateview Dx Dy Dz [Start = 1|0)]
14479 )" /* [vtranslateview] */);
14480
14481   addCmd ("vturnview", VTurnView, /* [vturnview] */ R"(
14482 vturnview Ax Ay Az [Start = 1|0]
14483 )" /* [vturnview] */);
14484
14485   addCmd ("vtextureenv", VTextureEnv, /* [vtextureenv] */ R"(
14486 vtextureenv {on|off} {image_file}
14487             [{clamp|repeat} {decal|modulate} {nearest|bilinear|trilinear} ss st ts tt rot]
14488 Enables or disables environment mapping in the 3D view, loading the texture from the given standard
14489 or user-defined file and optionally applying texture mapping parameters.
14490  ss, st - scale factors for s and t texture coordinates;
14491  ts, tt - translation for s and t texture coordinates;
14492  rot    - texture rotation angle in degrees.
14493 )" /* [vtextureenv] */);
14494
14495   addCmd ("vhlr", VHLR, /* [vhlr] */ R"(
14496 vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]
14497 Hidden Line Removal algorithm.
14498  -showHidden if set ON, hidden lines are drawn as dotted ones;
14499  -algoType   type of HLR algorithm:
14500             'algo' - exact HLR algorithm is applied;
14501             'polyAlgo' - polygonal HLR algorithm is applied.
14502 )" /* [vhlr] */);
14503
14504   addCmd ("vhlrtype", VHLRType, /* [vhlrtype] */ R"(
14505 vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]
14506 Changes the type of HLR algorithm using for shapes:
14507  'algo' - exact HLR algorithm is applied;
14508  'polyAlgo' - polygonal HLR algorithm is applied.
14509 If shapes are not given - option is applied to all shapes in the view.
14510 )" /* [vhlrtype] */);
14511
14512   addCmd ("vclipplane", VClipPlane, /* [vclipplane] */ R"(
14513 vclipplane planeName [{0|1}]
14514     [-equation1 A B C D]
14515     [-equation2 A B C D]
14516     [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]
14517     [-set|-unset|-setOverrideGlobal [objects|views]]
14518     [-maxPlanes]
14519     [-capping {0|1}]
14520       [-color R G B] [-transparency Value] [-hatch {on|off|ID}]
14521       [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]
14522         [-texRotate Angle]
14523       [-useObjMaterial {0|1}] [-useObjTexture {0|1}]
14524         [-useObjShader {0|1}]
14525
14526 Clipping planes management:
14527  -maxPlanes   print plane limit for view;
14528  -delete      delete plane with given name;
14529  {off|on|0|1} turn clipping on/off;
14530  -set|-unset  set/unset plane for Object or View list;
14531               applied to active View when list is omitted;
14532  -equation A B C D change plane equation;
14533  -clone SourcePlane NewPlane clone the plane definition.
14534
14535 Capping options:
14536  -capping {off|on|0|1} turn capping on/off;
14537  -color R G B          set capping color;
14538  -transparency Value   set capping transparency 0..1;
14539  -texName Texture      set capping texture;
14540  -texScale SX SY       set capping tex scale;
14541  -texOrigin TX TY      set capping tex origin;
14542  -texRotate Angle      set capping tex rotation;
14543  -hatch {on|off|ID}    set capping hatching mask;
14544  -useObjMaterial {off|on|0|1} use material of clipped object;
14545  -useObjTexture  {off|on|0|1} use texture of clipped object;
14546  -useObjShader   {off|on|0|1} use shader program of object.
14547 )" /* [vclipplane] */);
14548
14549   addCmd ("vdefaults", VDefaults, /* [vdefaults] */ R"(
14550 vdefaults [-absDefl value] [-devCoeff value] [-angDefl value]
14551           [-autoTriang {off/on | 0/1}]
14552 )" /* [vdefaults] */);
14553
14554   addCmd ("vlight", VLight, /* [vlight] */ R"(
14555 vlight [lightName] [-noupdate]
14556        [-clear|-defaults] [-layer Id] [-local|-global] [-disable|-enable]
14557        [-type {ambient|directional|spotlight|positional}] [-name value]
14558        [-position X Y Z] [-direction X Y Z] [-color colorName] [-intensity value]
14559        [-headlight 0|1] [-castShadows 0|1]
14560        [-range value] [-constAttenuation value] [-linearAttenuation value]
14561        [-spotExponent value] [-spotAngle angleDeg]
14562        [-smoothAngle value] [-smoothRadius value]
14563        [-display] [-showName 1|0] [-showRange 1|0] [-prsZoomable 1|0] [-prsSize Value]
14564        [-arcSize Value]
14565
14566 Command manages light sources. Without arguments shows list of lights.
14567 Arguments affecting the list of defined/active lights:
14568  -clear       remove all light sources;
14569  -defaults    defines two standard light sources;
14570  -reset       resets light source parameters to default values;
14571  -type        sets type of light source;
14572  -name        sets new name to light source;
14573  -global      assigns light source to all views (default state);
14574  -local       assigns light source to active view;
14575  -zlayer      assigns light source to specified Z-Layer.
14576
14577 Ambient light parameters:
14578  -color       sets (normalized) light color;
14579  -intensity   sets intensity of light source, 1.0 by default;
14580               affects also environment cubemap intensity.
14581
14582 Point light parameters:
14583  -color       sets (normalized) light color;
14584  -intensity   sets PBR intensity;
14585  -range       sets clamping distance;
14586  -constAtten  (obsolete) sets constant attenuation factor;
14587  -linearAtten (obsolete) sets linear   attenuation factor;
14588  -smoothRadius sets PBR smoothing radius.
14589
14590 Directional light parameters:
14591  -color       sets (normalized) light color;
14592  -intensity   sets PBR intensity;
14593  -direction   sets direction;
14594  -headlight   sets headlight flag;
14595  -castShadows enables/disables shadow casting;
14596  -smoothAngle sets PBR smoothing angle (in degrees) within 0..90 range.
14597
14598 Spot light parameters:
14599  -color       sets (normalized) light color;
14600  -intensity   sets PBR intensity;
14601  -range       sets clamping distance;
14602  -position    sets position;
14603  -direction   sets direction;
14604  -spotAngle   sets spotlight angle;
14605  -spotExp     sets spotlight exponenta;
14606  -headlight   sets headlight flag;
14607  -constAtten  (obsolete) sets constant attenuation factor;
14608  -linearAtten (obsolete) sets linear   attenuation factor.
14609
14610 Light presentation parameters:
14611  -display     adds light source presentation;
14612  -showName    shows/hides the name of light source; 1 by default;
14613  -showRange   shows/hides the range of spot/positional light source; 1 by default;
14614  -prsZoomable makes light presentation zoomable/non-zoomable;
14615  -prsDraggable makes light presentation draggable/non-draggable;
14616  -prsSize     sets light presentation size;
14617  -arcSize     sets arc presentation size(in pixels)
14618               for rotation directional light source; 25 by default.
14619
14620 Examples:
14621  vlight redlight -type POSITIONAL -headlight 1 -pos 0 1 1 -color RED
14622  vlight redlight -delete
14623 )" /* [vlight] */);
14624
14625   addCmd ("vpbrenv", VPBREnvironment, /* [vpbrenv] */ R"(
14626 vpbrenv -clear|-generate
14627 Clears or generates PBR environment map of active view.
14628  -clear clears PBR environment (fills by white color);
14629  -generate generates PBR environment from current background cubemap.
14630 )" /* [vpbrenv] */);
14631
14632   addCmd ("vraytrace", VRenderParams, /* [vraytrace] */ R"(
14633 vraytrace [0|1] : Turns on/off ray-tracing renderer.
14634  'vraytrace 0' alias for 'vrenderparams -raster'.
14635  'vraytrace 1' alias for 'vrenderparams -rayTrace'.
14636 )" /* [vraytrace] */);
14637
14638   addCmd ("vrenderparams", VRenderParams, /* [vrenderparams] */ R"(
14639 Manages rendering parameters, affecting visual appearance, quality and performance.
14640 Should be applied taking into account GPU hardware capabilities and performance.
14641
14642 Common parameters:
14643 vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]
14644               [-msaa 0..8=0] [-rendScale scale=1]
14645               [-resolution value=72] [-fontHinting {off|normal|light}=off]
14646               [-fontAutoHinting {auto|force|disallow}=auto]
14647               [-oit {off|weight|peel}] [-oit weighted [depthFactor=0.0]] [-oit peeling [nbLayers=4]]
14648               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]
14649               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]
14650               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]
14651               [-sync {default|views}] [-reset]
14652  -raster          Disables GPU ray-tracing.
14653  -shadingModel    Controls shading model.
14654  -msaa            Specifies number of samples for MSAA.
14655  -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA).
14656  -resolution      Sets new pixels density (PPI) used as text scaling factor.
14657  -fontHinting     Enables/disables font hinting for better readability on low-resolution screens.
14658  -fontAutoHinting Manages font autohinting.
14659  -lineFeather     Sets line feather factor while displaying mesh edges.
14660  -alphaToCoverage Enables/disables alpha to coverage (needs MSAA).
14661  -oit             Enables/disables order-independent transparency (OIT) rendering;
14662       off         unordered transparency (but opaque objects implicitly draw first);
14663       weighted    weight OIT is managed by depth weight factor 0.0..1.0;
14664       peeling     depth peeling OIT is managed by number of peeling layers.
14665   -shadows         Enables/disables shadows rendering.
14666   -shadowMapResolution Shadow texture map resolution.
14667   -shadowMapBias   Shadow map bias.
14668   -depthPrePass    Enables/disables depth pre-pass.
14669   -frustumCulling  Enables/disables objects frustum clipping or
14670                    sets state to check structures culled previously.
14671   -sync            Sets active View parameters as Viewer defaults / to other Views.
14672   -reset           Resets active View parameters to Viewer defaults.
14673
14674 Diagnostic output (on-screen overlay):
14675 vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points
14676                                  |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]
14677               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]
14678  -perfCounters       Show/hide performance counters (flags can be combined).
14679  -perfUpdateInterval Performance counters update interval.
14680  -perfChart          Show frame timers chart limited by specified number of frames.
14681  -perfChartMax       Maximum time in seconds with the chart.
14682
14683 Ray-Tracing options:
14684 vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]
14685               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]
14686               [-gi {on|off}=off] [-brng {on|off}=off]
14687               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]
14688               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]
14689               [-maxRad {value>0}=30.0]
14690               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]
14691               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]
14692  -rayTrace     Enables  GPU ray-tracing.
14693  -rayDepth     Defines maximum ray-tracing depth.
14694  -reflections  Enables/disables specular reflections.
14695  -fsaa         Enables/disables adaptive anti-aliasing.
14696  -gleam        Enables/disables transparency shadow effects.
14697  -gi           Enables/disables global illumination effects (Path-Tracing).
14698  -env          Enables/disables environment map background.
14699  -ignoreNormalMap Enables/disables normal map ignoring during path tracing.
14700  -twoSide      Enables/disables two-sided BSDF models (PT mode).
14701  -iss          Enables/disables adaptive screen sampling (PT mode).
14702  -maxRad       Value used for clamping radiance estimation (PT mode).
14703  -tileSize     Specifies   size of screen tiles in ISS mode (32 by default).
14704  -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default).
14705  -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF).
14706  -focal        Focal distance of perspective camera for depth-of-field effect.
14707  -exposure     Exposure value for tone mapping (0.0 value disables the effect).
14708  -whitePoint   White point value for filmic tone mapping.
14709  -toneMapping  Tone mapping mode (disabled, filmic).
14710
14711 PBR environment baking parameters (advanced/debug):
14712 vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]
14713               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]
14714  -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size).
14715  -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map.
14716  -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during
14717                  diffuse IBL map's sherical harmonics calculation.
14718  -pbrEnvBSSN     Controls maximum number of samples per mipmap level
14719                  in Monte-Carlo integration during specular IBL maps generation.
14720  -pbrEnvBP       Controls strength of samples number reducing
14721                  during specular IBL maps generation (1 disables reducing).
14722
14723 Debug options:
14724 vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]
14725  -issd         Shows screen sampling distribution in ISS mode.
14726  -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging).
14727  -brng         Enables/disables blocked RNG (fast coherent PT).
14728 )" /* [vrenderparams] */);
14729
14730   addCmd ("vstatprofiler", VStatProfiler, /* [vstatprofiler] */ R"(
14731 vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups
14732                 |allArrays|fillArrays|lineArrays|pointArrays|textArrays
14733                 |triangles|points|geomMem|textureMem|frameMem
14734                 |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage
14735                 |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]
14736               [-noredraw]
14737 Prints rendering statistics for specified counters or for all when unspecified.
14738 Set '-noredraw' flag to avoid additional redraw call and use already collected values.
14739 )" /* [vstatprofiler] */);
14740
14741   addCmd ("vplace", VPlace, /* [vplace] */ R"(
14742 vplace dx dy : Places the point (in pixels) at the center of the window
14743 )" /* [vplace] */);
14744
14745   addCmd ("vxrotate", VXRotate, /* [vxrotate] */ R"(
14746 vxrotate
14747 )" /* [vxrotate] */);
14748
14749   addCmd ("vmanipulator", VManipulator, /* [vmanipulator] */ R"(
14750 vmanipulator Name [-attach AISObject | -detach | ...]
14751 Tool to create and manage AIS manipulators.
14752 Options:
14753  '-attach AISObject'                 attach manipulator to AISObject
14754  '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching
14755  '-adjustSize     {0|1}'             adjust size when attaching
14756  '-enableModes    {0|1}'             enable modes when attaching
14757  '-view  {active | [name of view]}'  display manipulator only in defined view,
14758                                      by default it is displayed in all views of the current viewer
14759  '-detach'                           detach manipulator
14760  '-startTransform mouse_x mouse_y' - invoke start of transformation
14761  '-transform      mouse_x mouse_y' - invoke transformation
14762  '-stopTransform  [abort]'         - invoke stop of transformation
14763  '-move x y z'                     - move attached object
14764  '-rotate x y z dx dy dz angle'    - rotate attached object
14765  '-scale factor'                   - scale attached object
14766  '-autoActivate      {0|1}'        - set activation on detection
14767  '-followTranslation {0|1}'        - set following translation transform
14768  '-followRotation    {0|1}'        - set following rotation transform
14769  '-followDragging    {0|1}'        - set following dragging transform
14770  '-gap value'                      - set gap between sub-parts
14771  '-part axis mode    {0|1}'        - set visual part
14772  '-parts axis mode   {0|1}'        - set visual part
14773  '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator
14774  '-size value'                     - set size of manipulator
14775  '-zoomable {0|1}'                 - set zoom persistence
14776 )" /* [vmanipulator] */);
14777
14778   addCmd ("vselprops", VSelectionProperties, /* [vselprops] */ R"(
14779 vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]
14780 Customizes selection and dynamic highlight parameters for the whole interactive context:
14781  -autoActivate {0|1}     disables|enables default computation
14782                          and activation of global selection mode
14783  -autoHighlight {0|1}    disables|enables automatic highlighting in 3D Viewer
14784  -highlightSelected {0|1} disables|enables highlighting of detected object in selected state
14785  -pickStrategy {first|topmost} : defines picking strategy
14786                'first'   to pick first acceptable (default)
14787                'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)
14788  -pixTol    value        sets up pixel tolerance
14789  -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth
14790  -depthTol {sensfactor}  use sensitive factor for sorting results by depth
14791  -preferClosest {0|1}    sets if depth should take precedence over priority while sorting results
14792  -dispMode  dispMode     sets display mode for highlighting
14793  -layer     ZLayer       sets ZLayer for highlighting
14794  -color     {name|r g b} sets highlight color
14795  -transp    value        sets transparency coefficient for highlight
14796  -material  material     sets highlight material
14797  -print                  prints current state of all mentioned parameters
14798 )" /* [vselprops] */);
14799
14800   addCmd ("vhighlightselected", VSelectionProperties, /* [vhighlightselected] */ R"(
14801 vhighlightselected [0|1] : alias for vselprops -highlightSelected.
14802 )" /* [vhighlightselected] */);
14803
14804   addCmd ("vseldump", VDumpSelectionImage, /* [vseldump] */ R"(
14805 vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|entityType|surfNormal}=depth
14806          -pickedIndex Index=1
14807          [-xrPose base|head=base]
14808 Generate an image based on detection results:
14809   depth       normalized depth values
14810   unnormDepth unnormalized depth values
14811   object      color of detected object
14812   owner       color of detected owner
14813   selMode     color of selection mode
14814   entity      color of detected entity
14815   entityType  color of detected entity type
14816   surfNormal  normal direction values
14817 )" /* [vseldump] */);
14818
14819   addCmd ("vviewcube", VViewCube, /* [vviewcube] */ R"(
14820 vviewcube name
14821 Displays interactive view manipulation object. Options:
14822  -reset                   reset geometric and visual attributes
14823  -size Size               adapted size of View Cube
14824  -boxSize Size            box size
14825  -axes  {0|1}             show/hide axes (trihedron)
14826  -edges {0|1}             show/hide edges of View Cube
14827  -vertices {0|1}          show/hide vertices of View Cube
14828  -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation
14829  -color Color             color of View Cube
14830  -boxColor Color          box color
14831  -boxSideColor Color      box sides color
14832  -boxEdgeColor Color      box edges color
14833  -boxCornerColor Color    box corner color
14834  -textColor Color         color of side text of view cube
14835  -innerColor Color        inner box color
14836  -transparency Value      transparency of object within [0, 1] range
14837  -boxTransparency Value   transparency of box    within [0, 1] range
14838  -xAxisTextColor Color    color of X axis label
14839  -yAxisTextColor Color    color of Y axis label
14840  -zAxisTextColor Color    color of Z axis label
14841  -font Name               font name
14842  -fontHeight Value        font height
14843  -boxFacetExtension Value box facet extension
14844  -boxEdgeGap Value        gap between box edges and box sides
14845  -boxEdgeMinSize Value    minimal box edge size
14846  -boxCornerMinSize Value  minimal box corner size
14847  -axesPadding Value       padding between box and arrows
14848  -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range
14849  -axesRadius Value        radius of axes of the trihedron
14850  -axesConeRadius Value    radius of the cone (arrow) of the trihedron
14851  -axesSphereRadius Value  radius of the sphere (central point) of trihedron
14852  -fixedAnimation {0|1}    uninterruptible animation loop
14853  -duration Seconds        animation duration in seconds
14854 )" /* [vviewcube] */);
14855
14856   addCmd ("vcolorconvert", VColorConvert, /* [vcolorconvert] */ R"(
14857 vcolorconvert [-from {sRGB|HLS|Lab|Lch|RGB}]=RGB [-to {sRGB|HLS|Lab|Lch|RGB|hex|name}]=RGB C1 C2 C2
14858 To convert color from specified color space to linear RGB:
14859   vcolorconvert -from {sRGB|HLS|Lab|Lch|RGB} C1 C2 C2
14860 To convert linear RGB color to specified color space:
14861   vcolorconvert -to {sRGB|HLS|Lab|Lch|RGB|hex|name} R G B
14862 )" /* [vcolorconvert] */);
14863
14864   addCmd ("vcolordiff", VColorDiff, /* [vcolordiff] */ R"(
14865 vcolordiff R1 G1 B1 R2 G2 B2 : returns CIEDE2000 color difference between two RGB colors.
14866 )" /* [vcolordiff] */);
14867
14868   addCmd ("vselbvhbuild", VSelBvhBuild, /* [vselbvhbuild] */ R"(
14869 vselbvhbuild [{0|1}] [-nbThreads value] [-wait]
14870 Turns on/off prebuilding of BVH within background thread(s).
14871  -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1);
14872  -wait        waits for building all of BVH.
14873 )" /* [vselbvhbuild] */);
14874 }