0032780: Visualization, TKOpenGl - add smoothing to row interlaced stereoscopic output
[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_Texture2Dmanual.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 Standard_Integer thePxLeft,
481                                                 const Standard_Integer thePxTop,
482                                                 const Standard_Integer thePxWidth,
483                                                 const Standard_Integer thePxHeight,
484                                                 const TCollection_AsciiString& theViewName,
485                                                 const TCollection_AsciiString& theDisplayName,
486                                                 const Handle(V3d_View)& theViewToClone,
487                                                 const Standard_Boolean theIsVirtual)
488 {
489   // Default position and dimension of the viewer window.
490   // Note that left top corner is set to be sufficiently small to have
491   // window fit in the small screens (actual for remote desktops, see #23003).
492   // The position corresponds to the window's client area, thus some
493   // gap is added for window frame to be visible.
494   Standard_Integer aPxLeft  = 20,  aPxTop    = 40;
495   Standard_Integer aPxWidth = 409, aPxHeight = 409;
496   Standard_Boolean isDefViewSize = Standard_True;
497   Standard_Boolean toCreateViewer = Standard_False;
498   const Standard_Boolean isVirtual = Draw_VirtualWindows || theIsVirtual;
499   if (!theViewToClone.IsNull())
500   {
501     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
502     isDefViewSize = Standard_False;
503   #if !defined(__EMSCRIPTEN__)
504     (void )isDefViewSize;
505   #endif
506   }
507
508   Handle(Graphic3d_GraphicDriverFactory) aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
509   if (aFactory.IsNull())
510   {
511     Draw::GetInterpretor().Eval ("pload OPENGL");
512     aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
513     if (aFactory.IsNull())
514     {
515       Draw::GetInterpretor().Eval ("pload GLES");
516       aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
517       if (aFactory.IsNull())
518       {
519         throw Standard_ProgramError("Error: no graphic driver factory found");
520       }
521     }
522   }
523
524   Handle(Graphic3d_GraphicDriver) aGraphicDriver;
525   ViewerTest_Names aViewNames(theViewName);
526   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
527   {
528     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
529   }
530
531   if (thePxLeft != 0)
532   {
533     aPxLeft = thePxLeft;
534   }
535   if (thePxTop != 0)
536   {
537     aPxTop = thePxTop;
538   }
539   if (thePxWidth != 0)
540   {
541     isDefViewSize = Standard_False;
542     aPxWidth = thePxWidth;
543   }
544   if (thePxHeight != 0)
545   {
546     isDefViewSize = Standard_False;
547     aPxHeight = thePxHeight;
548   }
549
550   // Get graphic driver (create it or get from another view)
551   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
552   if (isNewDriver)
553   {
554     // Get connection string
555   #if defined(HAVE_XLIB)
556     if (!theDisplayName.IsEmpty())
557     {
558       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
559     }
560     else
561     {
562       Aspect_XDisplay* aDispX = NULL;
563       // create dedicated display connection instead of reusing Tk connection
564       // so that to proceed events independently through VProcessEvents()/ViewerMainLoop() callbacks
565       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
566       Tcl_Interp* aTclInterp = aCommands.Interp();
567       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
568       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
569       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
570     }
571   #else
572     (void)theDisplayName; // avoid warning on unused argument
573     SetDisplayConnection (new Aspect_DisplayConnection ());
574   #endif
575
576     aGraphicDriver = aFactory->CreateDriver (GetDisplayConnection());
577     if (isVirtual)
578     {
579       // don't waste the time waiting for VSync when window is not displayed on the screen
580       aGraphicDriver->SetVerticalSync (false);
581     }
582
583     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
584     toCreateViewer = Standard_True;
585   }
586   else
587   {
588     aGraphicDriver = ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName());
589   }
590
591   //Dispose the window if input parameters are default
592   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
593   {
594     Standard_Integer aTop = 0,
595                      aLeft = 0,
596                      aRight = 0,
597                      aBottom = 0,
598                      aScreenWidth = 0,
599                      aScreenHeight = 0;
600
601     // Get screen resolution
602 #if defined(_WIN32)
603     RECT aWindowSize;
604     GetClientRect(GetDesktopWindow(), &aWindowSize);
605     aScreenHeight = aWindowSize.bottom;
606     aScreenWidth = aWindowSize.right;
607 #elif defined(HAVE_XLIB)
608     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
609     Screen* aScreen = DefaultScreenOfDisplay(aDispX);
610     aScreenWidth  = WidthOfScreen(aScreen);
611     aScreenHeight = HeightOfScreen(aScreen);
612 #elif defined(__APPLE__)
613     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
614 #else
615     // not implemented
616 #endif
617
618     TCollection_AsciiString anOverlappedViewId("");
619
620     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
621     {
622       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
623
624       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
625         && aRight + 2*aPxWidth + 40 > aScreenWidth)
626       {
627         if (aBottom + aPxHeight + 40 > aScreenHeight)
628         {
629           aPxLeft = 20;
630           aPxTop = 40;
631           break;
632         }
633         aPxLeft = 20;
634         aPxTop = aBottom + 40;
635       }
636       else
637         aPxLeft = aRight + 20;
638     }
639   }
640
641   // Get viewer name
642   TCollection_AsciiString aTitle("3D View - ");
643   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
644
645   // Change name of current active window
646   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
647   {
648     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
649   }
650
651   // Create viewer
652   Handle(V3d_Viewer) a3DViewer;
653   // If it's the single view, we first look for empty context
654   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
655   {
656     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
657       anIter(ViewerTest_myContexts);
658     if (anIter.More())
659       ViewerTest::SetAISContext (anIter.Value());
660     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
661   }
662   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
663   {
664     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
665     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
666   }
667   else if (a3DViewer.IsNull())
668   {
669     toCreateViewer = Standard_True;
670     a3DViewer = new V3d_Viewer(aGraphicDriver);
671     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
672     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
673                                            ViewerTest_DefaultBackground.GradientColor2,
674                                            ViewerTest_DefaultBackground.FillMethod);
675   }
676
677   // AIS context setup
678   if (ViewerTest::GetAISContext().IsNull() ||
679       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
680   {
681     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
682     ViewerTest::SetAISContext (aContext);
683     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
684   }
685   else
686   {
687     ViewerTest::ResetEventManager();
688   }
689
690   // Create window
691 #if defined(_WIN32)
692   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
693                                    isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
694                                     aPxLeft, aPxTop,
695                                     aPxWidth, aPxHeight,
696                                     Quantity_NOC_BLACK);
697   VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
698 #elif defined(HAVE_XLIB)
699   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
700                                   aTitle.ToCString(),
701                                   aPxLeft, aPxTop,
702                                   aPxWidth, aPxHeight);
703 #elif defined(__APPLE__)
704   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
705                                      aPxLeft, aPxTop,
706                                      aPxWidth, aPxHeight);
707   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
708 #elif defined(__EMSCRIPTEN__)
709   // current EGL implementation in Emscripten supports only one global WebGL canvas returned by Module.canvas property;
710   // the code should be revised for handling multiple canvas elements (which is technically also possible)
711   TCollection_AsciiString aCanvasId = getModuleCanvasId();
712   if (!aCanvasId.IsEmpty())
713   {
714     aCanvasId = TCollection_AsciiString("#") + aCanvasId;
715   }
716
717   VT_GetWindow() = new Wasm_Window (aCanvasId);
718   Graphic3d_Vec2i aRealSize;
719   VT_GetWindow()->Size (aRealSize.x(), aRealSize.y());
720   if (!isDefViewSize || (aRealSize.x() <= 0 && aRealSize.y() <= 0))
721   {
722     // Wasm_Window wraps an existing HTML element without creating a new one.
723     // Keep size defined on a web page instead of defaulting to 409x409 (as in case of other platform),
724     // but resize canvas if vinit has been called with explicitly specified dimensions.
725     VT_GetWindow()->SetSizeLogical (Graphic3d_Vec2d (aPxWidth, aPxHeight));
726   }
727 #else
728   // not implemented
729   VT_GetWindow() = new Aspect_NeutralWindow();
730   VT_GetWindow()->SetSize (aPxWidth, aPxHeight);
731 #endif
732   VT_GetWindow()->SetVirtual (isVirtual);
733
734   // View setup
735   Handle(V3d_View) aView;
736   if (!theViewToClone.IsNull())
737   {
738     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
739   }
740   else
741   {
742     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
743   }
744
745   aView->SetWindow (VT_GetWindow());
746   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
747
748   ViewerTest::CurrentView(aView);
749   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
750
751   // Setup for X11 or NT
752   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
753   ViewerTest_EventManager::SetupWindowCallbacks (VT_GetWindow());
754
755   // Set parameters for V3d_View and V3d_Viewer
756   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
757   aV3dView->SetComputedMode(Standard_False);
758
759   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
760   if (toCreateViewer)
761   {
762     a3DViewer->SetDefaultLights();
763     a3DViewer->SetLightOn();
764   }
765
766 #if defined(HAVE_XLIB)
767   if (isNewDriver)
768   {
769     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
770     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
771   }
772 #endif
773
774   VT_GetWindow()->Map();
775
776   // Set the handle of created view in the event manager
777   ViewerTest::ResetEventManager();
778
779   ViewerTest::CurrentView()->Redraw();
780
781   aView.Nullify();
782   a3DViewer.Nullify();
783
784   return aViewNames.GetViewName();
785 }
786
787 //==============================================================================
788 //function : RedrawAllViews
789 //purpose  : Redraw all created views
790 //==============================================================================
791 void ViewerTest::RedrawAllViews()
792 {
793   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
794   for (; aViewIt.More(); aViewIt.Next())
795   {
796     const Handle(V3d_View)& aView = aViewIt.Key2();
797     aView->Redraw();
798   }
799 }
800
801 //==============================================================================
802 //function : VDriver
803 //purpose  :
804 //==============================================================================
805 static int VDriver (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
806 {
807   if (theArgsNb == 1)
808   {
809     theDi << "Registered: ";
810     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
811          aFactoryIter.More(); aFactoryIter.Next())
812     {
813       const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
814       theDi << aFactory->Name() << " ";
815     }
816
817     theDi << "\n";
818     theDi << "Default: ";
819     if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
820     {
821       theDi << aFactory->Name();
822     }
823     else
824     {
825       theDi << "NONE";
826     }
827     return 0;
828   }
829
830   TCollection_AsciiString aNewActive;
831   bool toLoad = false;
832   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
833   {
834     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
835     anArgCase.LowerCase();
836     if (anArgCase == "-list")
837     {
838       for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
839            aFactoryIter.More(); aFactoryIter.Next())
840       {
841         const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
842         theDi << aFactory->Name() << " ";
843       }
844     }
845     else if ((anArgCase == "-default"
846            || anArgCase == "-load")
847           && aNewActive.IsEmpty())
848     {
849       toLoad = (anArgCase == "-load");
850       if (anArgIter + 1 < theArgsNb)
851       {
852         aNewActive = theArgVec[++anArgIter];
853       }
854       else if (toLoad)
855       {
856         theDi << "Syntax error at '" << theArgVec[anArgIter] << "'";
857         return 1;
858       }
859       else
860       {
861         if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
862         {
863           theDi << aFactory->Name();
864         }
865         else
866         {
867           theDi << "NONE";
868         }
869       }
870     }
871     else if (aNewActive.IsEmpty())
872     {
873       aNewActive = theArgVec[anArgIter];
874     }
875     else
876     {
877       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
878       return 1;
879     }
880   }
881
882   if (!aNewActive.IsEmpty())
883   {
884     const TCollection_AsciiString aNameCopy = aNewActive;
885     if (TCollection_AsciiString::IsSameString (aNewActive, "gl", false)
886      || TCollection_AsciiString::IsSameString (aNewActive, "opengl", false)
887      || TCollection_AsciiString::IsSameString (aNewActive, "tkopengl", false))
888     {
889       aNewActive = "tkopengl";
890     }
891     else if (TCollection_AsciiString::IsSameString (aNewActive, "gles", false)
892           || TCollection_AsciiString::IsSameString (aNewActive, "opengles", false)
893           || TCollection_AsciiString::IsSameString (aNewActive, "tkopengles", false))
894     {
895       aNewActive = "tkopengles";
896     }
897     else if (TCollection_AsciiString::IsSameString (aNewActive, "d3d", false)
898           || TCollection_AsciiString::IsSameString (aNewActive, "d3dhost", false)
899           || TCollection_AsciiString::IsSameString (aNewActive, "tkd3dhost", false))
900     {
901       aNewActive = "tkd3dhost";
902     }
903
904     if (toLoad)
905     {
906       if (aNewActive == "tkopengl")
907       {
908         Draw::GetInterpretor().Eval ("pload OPENGL");
909       }
910       else if (aNewActive == "tkopengles")
911       {
912         Draw::GetInterpretor().Eval ("pload GLES");
913       }
914       else if (aNewActive == "tkd3dhost")
915       {
916         Draw::GetInterpretor().Eval ("pload D3DHOST");
917       }
918       else
919       {
920         theDi << "Syntax error: unable to load plugin for unknown driver factory '" << aNameCopy << "'";
921         return 1;
922       }
923     }
924
925     bool isFound = false;
926     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
927          aFactoryIter.More(); aFactoryIter.Next())
928     {
929       Handle(Graphic3d_GraphicDriverFactory) aFactory = aFactoryIter.Value();
930       if (TCollection_AsciiString::IsSameString (aFactory->Name(), aNewActive, false))
931       {
932         Graphic3d_GraphicDriverFactory::RegisterFactory (aFactory, true);
933         isFound = true;
934         break;
935       }
936     }
937
938     if (!isFound)
939     {
940       theDi << "Syntax error: driver factory '" << aNameCopy << "' not found";
941       return 1;
942     }
943   }
944
945   return 0;
946 }
947
948 //==============================================================================
949 //function : Vinit
950 //purpose  : Create the window viewer and initialize all the global variable
951 //    Use Tcl_CreateFileHandler on UNIX to catch the X11 Viewer event
952 //==============================================================================
953 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
954 {
955   TCollection_AsciiString aViewName, aDisplayName;
956   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
957   Standard_Boolean isVirtual = false;
958   Handle(V3d_View) aCopyFrom;
959   TCollection_AsciiString aName, aValue;
960   int is2dMode = -1, aDpiAware = -1;
961   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
962   {
963     const TCollection_AsciiString anArg = theArgVec[anArgIt];
964     TCollection_AsciiString anArgCase = anArg;
965     anArgCase.LowerCase();
966     if (anArgIt + 1 < theArgsNb
967      && anArgCase == "-name")
968     {
969       aViewName = theArgVec[++anArgIt];
970     }
971     else if (anArgIt + 1 < theArgsNb
972           && (anArgCase == "-left"
973            || anArgCase == "-l"))
974     {
975       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
976     }
977     else if (anArgIt + 1 < theArgsNb
978           && (anArgCase == "-top"
979            || anArgCase == "-t"))
980     {
981       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
982     }
983     else if (anArgIt + 1 < theArgsNb
984           && (anArgCase == "-width"
985            || anArgCase == "-w"))
986     {
987       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
988     }
989     else if (anArgIt + 1 < theArgsNb
990           && (anArgCase == "-height"
991            || anArgCase == "-h"))
992     {
993       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
994     }
995     else if (anArgCase == "-virtual"
996           || anArgCase == "-offscreen")
997     {
998       isVirtual = true;
999       if (anArgIt + 1 < theArgsNb
1000        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isVirtual))
1001       {
1002         ++anArgIt;
1003       }
1004     }
1005     else if (anArgCase == "-exitonclose")
1006     {
1007       ViewerTest_EventManager::ToExitOnCloseView() = true;
1008       if (anArgIt + 1 < theArgsNb
1009        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
1010       {
1011         ++anArgIt;
1012       }
1013     }
1014     else if (anArgCase == "-closeonescape"
1015           || anArgCase == "-closeonesc")
1016     {
1017       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
1018       if (anArgIt + 1 < theArgsNb
1019        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
1020       {
1021         ++anArgIt;
1022       }
1023     }
1024     else if (anArgCase == "-2d_mode"
1025           || anArgCase == "-2dmode"
1026           || anArgCase == "-2d")
1027     {
1028       bool toEnable = true;
1029       if (anArgIt + 1 < theArgsNb
1030        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
1031       {
1032         ++anArgIt;
1033       }
1034       is2dMode = toEnable ? 1 : 0;
1035     }
1036     else if (anArgIt + 1 < theArgsNb
1037           && (anArgCase == "-disp"
1038            || anArgCase == "-display"))
1039     {
1040       aDisplayName = theArgVec[++anArgIt];
1041     }
1042     else if (anArgCase == "-dpiaware")
1043     {
1044       aDpiAware = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt) ? 1 : 0;
1045     }
1046     else if (!ViewerTest::CurrentView().IsNull()
1047           &&  aCopyFrom.IsNull()
1048           && (anArgCase == "-copy"
1049            || anArgCase == "-clone"
1050            || anArgCase == "-cloneactive"
1051            || anArgCase == "-cloneactiveview"))
1052     {
1053       aCopyFrom = ViewerTest::CurrentView();
1054     }
1055     // old syntax
1056     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
1057     {
1058       aName.LowerCase();
1059       if (aName == "name")
1060       {
1061         aViewName = aValue;
1062       }
1063       else if (aName == "l"
1064             || aName == "left")
1065       {
1066         aPxLeft = aValue.IntegerValue();
1067       }
1068       else if (aName == "t"
1069             || aName == "top")
1070       {
1071         aPxTop = aValue.IntegerValue();
1072       }
1073       else if (aName == "disp"
1074             || aName == "display")
1075       {
1076         aDisplayName = aValue;
1077       }
1078       else if (aName == "w"
1079             || aName == "width")
1080       {
1081         aPxWidth = aValue.IntegerValue();
1082       }
1083       else if (aName == "h"
1084             || aName == "height")
1085       {
1086         aPxHeight = aValue.IntegerValue();
1087       }
1088       else
1089       {
1090         Message::SendFail() << "Syntax error: unknown argument " << anArg;
1091         return 1;
1092       }
1093     }
1094     else if (aViewName.IsEmpty())
1095     {
1096       aViewName = anArg;
1097     }
1098     else
1099     {
1100       Message::SendFail() << "Syntax error: unknown argument " << anArg;
1101       return 1;
1102     }
1103   }
1104
1105 #if defined(_WIN32)
1106   if (aDpiAware != -1)
1107   {
1108     typedef void* (WINAPI *SetThreadDpiAwarenessContext_t)(void*);
1109     if (HMODULE aUser32Module = GetModuleHandleW (L"User32"))
1110     {
1111       SetThreadDpiAwarenessContext_t aSetDpiAware = (SetThreadDpiAwarenessContext_t )GetProcAddress (aUser32Module, "SetThreadDpiAwarenessContext");
1112       if (aDpiAware == 1)
1113       {
1114         // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
1115         if (aSetDpiAware ((void* )-4) == NULL)
1116         {
1117           // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE for older systems
1118           if (aSetDpiAware ((void* )-3) == NULL)
1119           {
1120             Message::SendFail() << "Error: unable to enable DPI awareness";
1121           }
1122         }
1123       }
1124       else
1125       {
1126         // DPI_AWARENESS_CONTEXT_UNAWARE
1127         if (aSetDpiAware ((void* )-1) == NULL)
1128         {
1129           Message::SendFail() << "Error: unable to disable DPI awareness";
1130         }
1131       }
1132     }
1133   }
1134 #else
1135   (void )aDpiAware;
1136 #if !defined(HAVE_XLIB)
1137   if (!aDisplayName.IsEmpty())
1138   {
1139     aDisplayName.Clear();
1140     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
1141   }
1142 #endif
1143 #endif
1144
1145   ViewerTest_Names aViewNames (aViewName);
1146   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1147   {
1148     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
1149     theDi.Eval (aCommand.ToCString());
1150     if (is2dMode != -1)
1151     {
1152       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1153     }
1154     return 0;
1155   }
1156
1157   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
1158                                                             aViewName, aDisplayName, aCopyFrom, isVirtual);
1159   if (is2dMode != -1)
1160   {
1161     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1162   }
1163   theDi << aViewId;
1164   return 0;
1165 }
1166
1167 //! Parse HLR algo type.
1168 static Standard_Boolean parseHlrAlgoType (const char* theName,
1169                                           Prs3d_TypeOfHLR& theType)
1170 {
1171   TCollection_AsciiString aName (theName);
1172   aName.LowerCase();
1173   if (aName == "polyalgo")
1174   {
1175     theType = Prs3d_TOH_PolyAlgo;
1176   }
1177   else if (aName == "algo")
1178   {
1179     theType = Prs3d_TOH_Algo;
1180   }
1181   else
1182   {
1183     return Standard_False;
1184   }
1185   return Standard_True;
1186 }
1187
1188 //==============================================================================
1189 //function : VHLR
1190 //purpose  : hidden lines removal algorithm
1191 //==============================================================================
1192
1193 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
1194 {
1195   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1196   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1197   if (aView.IsNull())
1198   {
1199     Message::SendFail ("Error: no active viewer");
1200     return 1;
1201   }
1202
1203   Standard_Boolean hasHlrOnArg = Standard_False;
1204   Standard_Boolean hasShowHiddenArg = Standard_False;
1205   Standard_Boolean isHLROn = Standard_False;
1206   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
1207   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
1208   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1209   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1210   {
1211     TCollection_AsciiString anArg (argv[anArgIter]);
1212     anArg.LowerCase();
1213     if (anUpdateTool.parseRedrawMode (anArg))
1214     {
1215       continue;
1216     }
1217     else if (anArg == "-showhidden"
1218           && anArgIter + 1 < argc
1219           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
1220     {
1221       ++anArgIter;
1222       hasShowHiddenArg = Standard_True;
1223       continue;
1224     }
1225     else if ((anArg == "-type"
1226            || anArg == "-algo"
1227            || anArg == "-algotype")
1228           && anArgIter + 1 < argc
1229           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1230     {
1231       ++anArgIter;
1232       continue;
1233     }
1234     else if (!hasHlrOnArg
1235           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
1236     {
1237       hasHlrOnArg = Standard_True;
1238       continue;
1239     }
1240     // old syntax
1241     else if (!hasShowHiddenArg
1242           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
1243     {
1244       hasShowHiddenArg = Standard_True;
1245       continue;
1246     }
1247     else
1248     {
1249       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
1250       return 1;
1251     }
1252   }
1253   if (!hasHlrOnArg)
1254   {
1255     di << "HLR:        " << aView->ComputedMode() << "\n";
1256     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
1257     di << "HlrAlgo:    ";
1258     switch (aCtx->DefaultDrawer()->TypeOfHLR())
1259     {
1260       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
1261       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
1262       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
1263     }
1264     anUpdateTool.Invalidate();
1265     return 0;
1266   }
1267
1268   Standard_Boolean toRecompute = Standard_False;
1269   if (aTypeOfHLR != Prs3d_TOH_NotSet
1270    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
1271   {
1272     toRecompute = Standard_True;
1273     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1274   }
1275   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
1276   {
1277     toRecompute = Standard_True;
1278     if (toShowHidden)
1279     {
1280       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
1281     }
1282     else
1283     {
1284       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
1285     }
1286   }
1287
1288   // redisplay shapes
1289   if (aView->ComputedMode() && isHLROn && toRecompute)
1290   {
1291     AIS_ListOfInteractive aListOfShapes;
1292     aCtx->DisplayedObjects (aListOfShapes);
1293     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
1294     {
1295       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
1296       {
1297         aCtx->Redisplay (aShape, Standard_False);
1298       }
1299     }
1300   }
1301
1302   aView->SetComputedMode (isHLROn);
1303   return 0;
1304 }
1305
1306 //==============================================================================
1307 //function : VHLRType
1308 //purpose  : change type of using HLR algorithm
1309 //==============================================================================
1310
1311 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
1312 {
1313   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1314   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1315   if (aView.IsNull())
1316   {
1317     Message::SendFail ("Error: no active viewer");
1318     return 1;
1319   }
1320
1321   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
1322   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1323   AIS_ListOfInteractive aListOfShapes;
1324   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1325   {
1326     TCollection_AsciiString anArg (argv[anArgIter]);
1327     anArg.LowerCase();
1328     if (anUpdateTool.parseRedrawMode (anArg))
1329     {
1330       continue;
1331     }
1332     else if ((anArg == "-type"
1333            || anArg == "-algo"
1334            || anArg == "-algotype")
1335           && anArgIter + 1 < argc
1336           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1337     {
1338       ++anArgIter;
1339       continue;
1340     }
1341     // old syntax
1342     else if (aTypeOfHLR == Prs3d_TOH_NotSet
1343           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
1344     {
1345       continue;
1346     }
1347     else
1348     {
1349       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
1350       TCollection_AsciiString aName (argv[anArgIter]);
1351       if (!aMap.IsBound2 (aName))
1352       {
1353         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
1354         return 1;
1355       }
1356
1357       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
1358       if (aShape.IsNull())
1359       {
1360         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
1361         return 1;
1362       }
1363       aListOfShapes.Append (aShape);
1364       continue;
1365     }
1366   }
1367   if (aTypeOfHLR == Prs3d_TOH_NotSet)
1368   {
1369     Message::SendFail ("Syntax error: wrong number of arguments");
1370     return 1;
1371   }
1372
1373   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
1374   if (isGlobal)
1375   {
1376     aCtx->DisplayedObjects (aListOfShapes);
1377     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1378   }
1379
1380   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
1381   {
1382     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
1383     if (aShape.IsNull())
1384     {
1385       continue;
1386     }
1387
1388     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
1389                             && aView->ComputedMode();
1390     if (!isGlobal
1391      || aShape->TypeOfHLR() != aTypeOfHLR)
1392     {
1393       aShape->SetTypeOfHLR (aTypeOfHLR);
1394     }
1395     if (toUpdateShape)
1396     {
1397       aCtx->Redisplay (aShape, Standard_False);
1398     }
1399   }
1400   return 0;
1401 }
1402
1403 //==============================================================================
1404 //function : FindViewIdByWindowHandle
1405 //purpose  : Find theView Id in the map of views by window handle
1406 //==============================================================================
1407 #if defined(_WIN32) || defined(HAVE_XLIB)
1408 static TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
1409 {
1410   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
1411        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1412   {
1413     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
1414     if (aWindowHandle == theWindowHandle)
1415       return anIter.Key1();
1416   }
1417   return TCollection_AsciiString("");
1418 }
1419 #endif
1420
1421 //! Make the view active
1422 void ActivateView (const TCollection_AsciiString& theViewName,
1423                    Standard_Boolean theToUpdate = Standard_True)
1424 {
1425   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1426   if (aView.IsNull())
1427   {
1428     return;
1429   }
1430
1431   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
1432   if (!anAISContext.IsNull())
1433   {
1434     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1435     {
1436       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1437     }
1438
1439     ViewerTest::CurrentView (aView);
1440     ViewerTest::SetAISContext (anAISContext);
1441     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
1442     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(ViewerTest::CurrentView()->Window());
1443     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
1444     if (theToUpdate)
1445     {
1446       ViewerTest::CurrentView()->Redraw();
1447     }
1448   }
1449 }
1450
1451 //==============================================================================
1452 //function : RemoveView
1453 //purpose  :
1454 //==============================================================================
1455 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
1456                              const Standard_Boolean  theToRemoveContext)
1457 {
1458   if (!ViewerTest_myViews.IsBound2 (theView))
1459   {
1460     return;
1461   }
1462
1463   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
1464   RemoveView (aViewName, theToRemoveContext);
1465 }
1466
1467 //==============================================================================
1468 //function : RemoveView
1469 //purpose  : Close and remove view from display, clear maps if necessary
1470 //==============================================================================
1471 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
1472 {
1473   if (!ViewerTest_myViews.IsBound1(theViewName))
1474   {
1475     Message::SendFail() << "Wrong view name";
1476     return;
1477   }
1478
1479   // Activate another view if it's active now
1480   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
1481   {
1482     if (ViewerTest_myViews.Extent() > 1)
1483     {
1484       TCollection_AsciiString aNewViewName;
1485       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1486            anIter.More(); anIter.Next())
1487       {
1488         if (anIter.Key1() != theViewName)
1489         {
1490           aNewViewName = anIter.Key1();
1491           break;
1492         }
1493       }
1494       ActivateView (aNewViewName);
1495     }
1496     else
1497     {
1498       VT_GetWindow().Nullify();
1499       ViewerTest::CurrentView (Handle(V3d_View)());
1500       if (isContextRemoved)
1501       {
1502         Handle(AIS_InteractiveContext) anEmptyContext;
1503         ViewerTest::SetAISContext(anEmptyContext);
1504       }
1505     }
1506   }
1507
1508   // Delete view
1509   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1510   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
1511   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
1512   aRedrawer.Stop (aView);
1513
1514   // Remove view resources
1515   ViewerTest_myViews.UnBind1(theViewName);
1516   aView->Window()->Unmap();
1517   aView->Remove();
1518
1519 #if defined(HAVE_XLIB)
1520   XFlush ((::Display* )GetDisplayConnection()->GetDisplayAspect());
1521 #endif
1522
1523   // Keep context opened only if the closed view is last to avoid
1524   // unused empty contexts
1525   if (!aCurrentContext.IsNull())
1526   {
1527     // Check if there are more defined views in the viewer
1528     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
1529      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
1530     {
1531       // Remove driver if there is no viewers that use it
1532       Standard_Boolean isRemoveDriver = Standard_True;
1533       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1534           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
1535       {
1536         if (aCurrentContext != anIter.Key2() &&
1537           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
1538         {
1539           isRemoveDriver = Standard_False;
1540           break;
1541         }
1542       }
1543
1544       aCurrentContext->RemoveAll (Standard_False);
1545       if(isRemoveDriver)
1546       {
1547         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
1548       #if defined(HAVE_XLIB)
1549         Tcl_DeleteFileHandler (XConnectionNumber ((::Display* )aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplayAspect()));
1550       #endif
1551       }
1552
1553       ViewerTest_myContexts.UnBind2(aCurrentContext);
1554     }
1555   }
1556   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
1557   if (ViewerTest_EventManager::ToExitOnCloseView())
1558   {
1559     Draw_Interprete ("exit");
1560   }
1561 }
1562
1563 //==============================================================================
1564 //function : VClose
1565 //purpose  : Remove the view defined by its name
1566 //==============================================================================
1567
1568 static int VClose (Draw_Interpretor& /*theDi*/,
1569                    Standard_Integer  theArgsNb,
1570                    const char**      theArgVec)
1571 {
1572   NCollection_List<TCollection_AsciiString> aViewList;
1573   if (theArgsNb > 1)
1574   {
1575     TCollection_AsciiString anArg (theArgVec[1]);
1576     anArg.UpperCase();
1577     if (anArg.IsEqual ("ALL")
1578      || anArg.IsEqual ("*"))
1579     {
1580       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1581            anIter.More(); anIter.Next())
1582       {
1583         aViewList.Append (anIter.Key1());
1584       }
1585       if (aViewList.IsEmpty())
1586       {
1587         std::cout << "No view to close\n";
1588         return 0;
1589       }
1590     }
1591     else
1592     {
1593       ViewerTest_Names aViewName (theArgVec[1]);
1594       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
1595       {
1596         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
1597         return 1;
1598       }
1599       aViewList.Append (aViewName.GetViewName());
1600     }
1601   }
1602   else
1603   {
1604     // close active view
1605     if (ViewerTest::CurrentView().IsNull())
1606     {
1607       Message::SendFail ("Error: no active view");
1608       return 1;
1609     }
1610     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1611   }
1612
1613   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
1614   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
1615        anIter.More(); anIter.Next())
1616   {
1617     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
1618   }
1619
1620   return 0;
1621 }
1622
1623 //==============================================================================
1624 //function : VActivate
1625 //purpose  : Activate the view defined by its ID
1626 //==============================================================================
1627
1628 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1629 {
1630   if (theArgsNb == 1)
1631   {
1632     theDi.Eval("vviewlist");
1633     return 0;
1634   }
1635
1636   TCollection_AsciiString aNameString;
1637   Standard_Boolean toUpdate = Standard_True;
1638   Standard_Boolean toActivate = Standard_True;
1639   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
1640   {
1641     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1642     anArg.LowerCase();
1643     if (toUpdate
1644      && anArg == "-noupdate")
1645     {
1646       toUpdate = Standard_False;
1647     }
1648     else if (toActivate
1649           && aNameString.IsEmpty()
1650           && anArg == "none")
1651     {
1652       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1653       VT_GetWindow().Nullify();
1654       ViewerTest::CurrentView (Handle(V3d_View)());
1655       ViewerTest::ResetEventManager();
1656       theDi << theArgVec[0] << ": all views are inactive\n";
1657       toActivate = Standard_False;
1658     }
1659     else if (toActivate
1660           && aNameString.IsEmpty())
1661     {
1662       aNameString = theArgVec[anArgIter];
1663     }
1664     else
1665     {
1666       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
1667       return 1;
1668     }
1669   }
1670
1671   if (!toActivate)
1672   {
1673     return 0;
1674   }
1675   else if (aNameString.IsEmpty())
1676   {
1677     Message::SendFail ("Syntax error: wrong number of arguments");
1678     return 1;
1679   }
1680
1681   // Check if this view exists in the viewer with the driver
1682   ViewerTest_Names aViewNames (aNameString);
1683   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
1684   {
1685     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
1686     return 1;
1687   }
1688
1689   // Check if it is active already
1690   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
1691   {
1692     theDi << theArgVec[0] << ": the view is active already\n";
1693     return 0;
1694   }
1695
1696   ActivateView (aViewNames.GetViewName(), toUpdate);
1697   return 0;
1698 }
1699
1700 //==============================================================================
1701 //function : VViewList
1702 //purpose  : Print current list of views per viewer and graphic driver ID
1703 //           shared between viewers
1704 //==============================================================================
1705
1706 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1707 {
1708   if (theArgsNb > 2)
1709   {
1710     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
1711           << "Usage: " << theArgVec[0] << " name";
1712     return 1;
1713   }
1714   if (ViewerTest_myContexts.Size() < 1)
1715     return 0;
1716
1717   Standard_Boolean isTreeView =
1718     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
1719
1720   if (isTreeView)
1721   {
1722     theDi << theArgVec[0] <<":\n";
1723   }
1724
1725   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
1726        aDriverIter.More(); aDriverIter.Next())
1727   {
1728     if (isTreeView)
1729       theDi << aDriverIter.Key1() << ":\n";
1730
1731     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1732       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
1733     {
1734       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
1735       {
1736         if (isTreeView)
1737         {
1738           TCollection_AsciiString aContextName(aContextIter.Key1());
1739           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
1740         }
1741
1742         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
1743              aViewIter.More(); aViewIter.Next())
1744         {
1745           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
1746           {
1747             TCollection_AsciiString aViewName(aViewIter.Key1());
1748             if (isTreeView)
1749             {
1750               if (aViewIter.Value() == ViewerTest::CurrentView())
1751                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
1752               else
1753                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
1754             }
1755             else
1756             {
1757               theDi << aViewName << " ";
1758             }
1759           }
1760         }
1761       }
1762     }
1763   }
1764   return 0;
1765 }
1766
1767 //==============================================================================
1768 //function : GetMousePosition
1769 //purpose  :
1770 //==============================================================================
1771 void ViewerTest::GetMousePosition (Standard_Integer& theX,
1772                                    Standard_Integer& theY)
1773 {
1774   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
1775   {
1776     theX = aViewCtrl->LastMousePosition().x();
1777     theY = aViewCtrl->LastMousePosition().y();
1778   }
1779 }
1780
1781 //==============================================================================
1782 //function : VViewProj
1783 //purpose  : Switch view projection
1784 //==============================================================================
1785 static int VViewProj (Draw_Interpretor& ,
1786                       Standard_Integer theNbArgs,
1787                       const char** theArgVec)
1788 {
1789   static Standard_Boolean isYup = Standard_False;
1790   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
1791   if (aView.IsNull())
1792   {
1793     Message::SendFail ("Error: no active viewer");
1794     return 1;
1795   }
1796
1797   TCollection_AsciiString aCmdName (theArgVec[0]);
1798   Standard_Boolean isGeneralCmd = Standard_False;
1799   if (aCmdName == "vfront")
1800   {
1801     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1802   }
1803   else if (aCmdName == "vback")
1804   {
1805     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1806   }
1807   else if (aCmdName == "vtop")
1808   {
1809     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1810   }
1811   else if (aCmdName == "vbottom")
1812   {
1813     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1814   }
1815   else if (aCmdName == "vleft")
1816   {
1817     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1818   }
1819   else if (aCmdName == "vright")
1820   {
1821     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1822   }
1823   else if (aCmdName == "vaxo")
1824   {
1825     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1826   }
1827   else
1828   {
1829     isGeneralCmd = Standard_True;
1830     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
1831     {
1832       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
1833       anArgCase.LowerCase();
1834       if (anArgCase == "-zup")
1835       {
1836         isYup = Standard_False;
1837       }
1838       else if (anArgCase == "-yup")
1839       {
1840         isYup = Standard_True;
1841       }
1842       else if (anArgCase == "-front"
1843             || anArgCase == "front"
1844             || anArgCase == "-f"
1845             || anArgCase == "f")
1846       {
1847         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1848       }
1849       else if (anArgCase == "-back"
1850             || anArgCase == "back"
1851             || anArgCase == "-b"
1852             || anArgCase == "b")
1853       {
1854         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1855       }
1856       else if (anArgCase == "-top"
1857             || anArgCase == "top"
1858             || anArgCase == "-t"
1859             || anArgCase == "t")
1860       {
1861         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1862       }
1863       else if (anArgCase == "-bottom"
1864             || anArgCase == "bottom"
1865             || anArgCase == "-bot"
1866             || anArgCase == "bot"
1867             || anArgCase == "-b"
1868             || anArgCase == "b")
1869       {
1870         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1871       }
1872       else if (anArgCase == "-left"
1873             || anArgCase == "left"
1874             || anArgCase == "-l"
1875             || anArgCase == "l")
1876       {
1877         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1878       }
1879       else if (anArgCase == "-right"
1880             || anArgCase == "right"
1881             || anArgCase == "-r"
1882             || anArgCase == "r")
1883       {
1884         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1885       }
1886       else if (anArgCase == "-axoleft"
1887             || anArgCase == "-leftaxo"
1888             || anArgCase == "axoleft"
1889             || anArgCase == "leftaxo")
1890       {
1891         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
1892       }
1893       else if (anArgCase == "-axo"
1894             || anArgCase == "axo"
1895             || anArgCase == "-a"
1896             || anArgCase == "a"
1897             || anArgCase == "-axoright"
1898             || anArgCase == "-rightaxo"
1899             || anArgCase == "axoright"
1900             || anArgCase == "rightaxo")
1901       {
1902         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1903       }
1904       else if (anArgCase == "+x")
1905       {
1906         aView->SetProj (V3d_Xpos, isYup);
1907       }
1908       else if (anArgCase == "-x")
1909       {
1910         aView->SetProj (V3d_Xneg, isYup);
1911       }
1912       else if (anArgCase == "+y")
1913       {
1914         aView->SetProj (V3d_Ypos, isYup);
1915       }
1916       else if (anArgCase == "-y")
1917       {
1918         aView->SetProj (V3d_Yneg, isYup);
1919       }
1920       else if (anArgCase == "+z")
1921       {
1922         aView->SetProj (V3d_Zpos, isYup);
1923       }
1924       else if (anArgCase == "-z")
1925       {
1926         aView->SetProj (V3d_Zneg, isYup);
1927       }
1928       else if (anArgCase == "+x+y+z")
1929       {
1930         aView->SetProj (V3d_XposYposZpos, isYup);
1931       }
1932       else if (anArgCase == "+x+y-z")
1933       {
1934         aView->SetProj (V3d_XposYposZneg, isYup);
1935       }
1936       else if (anArgCase == "+x-y+z")
1937       {
1938         aView->SetProj (V3d_XposYnegZpos, isYup);
1939       }
1940       else if (anArgCase == "+x-y-z")
1941       {
1942         aView->SetProj (V3d_XposYnegZneg, isYup);
1943       }
1944       else if (anArgCase == "-x+y+z")
1945       {
1946         aView->SetProj (V3d_XnegYposZpos, isYup);
1947       }
1948       else if (anArgCase == "-x+y-z")
1949       {
1950         aView->SetProj (V3d_XnegYposZneg, isYup);
1951       }
1952       else if (anArgCase == "-x-y+z")
1953       {
1954         aView->SetProj (V3d_XnegYnegZpos, isYup);
1955       }
1956       else if (anArgCase == "-x-y-z")
1957       {
1958         aView->SetProj (V3d_XnegYnegZneg, isYup);
1959       }
1960       else if (anArgCase == "+x+y")
1961       {
1962         aView->SetProj (V3d_XposYpos, isYup);
1963       }
1964       else if (anArgCase == "+x-y")
1965       {
1966         aView->SetProj (V3d_XposYneg, isYup);
1967       }
1968       else if (anArgCase == "-x+y")
1969       {
1970         aView->SetProj (V3d_XnegYpos, isYup);
1971       }
1972       else if (anArgCase == "-x-y")
1973       {
1974         aView->SetProj (V3d_XnegYneg, isYup);
1975       }
1976       else if (anArgCase == "+x+z")
1977       {
1978         aView->SetProj (V3d_XposZpos, isYup);
1979       }
1980       else if (anArgCase == "+x-z")
1981       {
1982         aView->SetProj (V3d_XposZneg, isYup);
1983       }
1984       else if (anArgCase == "-x+z")
1985       {
1986         aView->SetProj (V3d_XnegZpos, isYup);
1987       }
1988       else if (anArgCase == "-x-z")
1989       {
1990         aView->SetProj (V3d_XnegZneg, isYup);
1991       }
1992       else if (anArgCase == "+y+z")
1993       {
1994         aView->SetProj (V3d_YposZpos, isYup);
1995       }
1996       else if (anArgCase == "+y-z")
1997       {
1998         aView->SetProj (V3d_YposZneg, isYup);
1999       }
2000       else if (anArgCase == "-y+z")
2001       {
2002         aView->SetProj (V3d_YnegZpos, isYup);
2003       }
2004       else if (anArgCase == "-y-z")
2005       {
2006         aView->SetProj (V3d_YnegZneg, isYup);
2007       }
2008       else if (anArgIter + 1 < theNbArgs
2009             && anArgCase == "-frame"
2010             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2011       {
2012         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2013         aFrameDef.LowerCase();
2014         gp_Dir aRight, anUp;
2015         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2016         {
2017           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2018           return 1;
2019         }
2020
2021         if (aFrameDef.Value (2) == 'x')
2022         {
2023           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2024         }
2025         else if (aFrameDef.Value (2) == 'y')
2026         {
2027           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2028         }
2029         else if (aFrameDef.Value (2) == 'z')
2030         {
2031           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2032         }
2033         else
2034         {
2035           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2036           return 1;
2037         }
2038
2039         if (aFrameDef.Value (4) == 'x')
2040         {
2041           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2042         }
2043         else if (aFrameDef.Value (4) == 'y')
2044         {
2045           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2046         }
2047         else if (aFrameDef.Value (4) == 'z')
2048         {
2049           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2050         }
2051         else
2052         {
2053           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2054           return 1;
2055         }
2056
2057         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2058         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2059         const gp_Dir aDir = anUp.Crossed (aRight);
2060         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2061         aCamera->SetDirection (aDir);
2062         aCamera->SetUp (anUp);
2063         aCamera->OrthogonalizeUp();
2064
2065         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2066         aView->Update();
2067       }
2068       else
2069       {
2070         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2071         return 1;
2072       }
2073     }
2074   }
2075
2076   if (!isGeneralCmd
2077     && theNbArgs != 1)
2078   {
2079     Message::SendFail ("Syntax error: wrong number of arguments");
2080     return 1;
2081   }
2082   return 0;
2083 }
2084
2085 //==============================================================================
2086 //function : VHelp
2087 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
2088 //Draw arg : No args
2089 //==============================================================================
2090
2091 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
2092 {
2093   di << "=========================\n";
2094   di << "F : FitAll\n";
2095   di << "T : TopView\n";
2096   di << "B : BottomView\n";
2097   di << "R : RightView\n";
2098   di << "L : LeftView\n";
2099   di << "Backspace : AxonometricView\n";
2100
2101   di << "=========================\n";
2102   di << "W, S : Fly   forward/backward\n";
2103   di << "A, D : Slide left/right\n";
2104   di << "Q, E : Bank  left/right\n";
2105   di << "-, + : Change flying speed\n";
2106   di << "Arrows : look left/right/up/down\n";
2107   di << "Arrows+Shift : slide left/right/up/down\n";
2108
2109   di << "=========================\n";
2110   di << "S + Ctrl : Shading\n";
2111   di << "W + Ctrl : Wireframe\n";
2112   di << "H : HiddenLineRemoval\n";
2113   di << "U : Unset display mode\n";
2114   di << "Delete : Remove selection from viewer\n";
2115
2116   di << "=========================\n";
2117   di << "Selection mode \n";
2118   di << "0 : Shape\n";
2119   di << "1 : Vertex\n";
2120   di << "2 : Edge\n";
2121   di << "3 : Wire\n";
2122   di << "4 : Face\n";
2123   di << "5 : Shell\n";
2124   di << "6 : Solid\n";
2125   di << "7 : Compound\n";
2126
2127   di << "=========================\n";
2128   di << "< : Hilight next detected\n";
2129   di << "> : Hilight previous detected\n";
2130
2131   return 0;
2132 }
2133
2134 #ifdef _WIN32
2135
2136 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
2137                                            UINT theMsg,
2138                                            WPARAM wParam,
2139                                            LPARAM lParam )
2140 {
2141   if (ViewerTest_myViews.IsEmpty())
2142   {
2143     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2144   }
2145
2146   switch (theMsg)
2147   {
2148     case WM_CLOSE:
2149     {
2150       // Delete view from map of views
2151       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
2152       return 0;
2153     }
2154     case WM_ACTIVATE:
2155     {
2156       if (LOWORD(wParam) == WA_CLICKACTIVE
2157        || LOWORD(wParam) == WA_ACTIVE
2158        || ViewerTest::CurrentView().IsNull())
2159       {
2160         // Activate inactive window
2161         if (VT_GetWindow().IsNull()
2162          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
2163         {
2164           ActivateView (FindViewIdByWindowHandle (theWinHandle));
2165         }
2166       }
2167       return 0;
2168     }
2169     default:
2170     {
2171       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2172       if (!aView.IsNull()
2173        && !VT_GetWindow().IsNull())
2174       {
2175         MSG aMsg = {};
2176         aMsg.hwnd = theWinHandle;
2177         aMsg.message = theMsg;
2178         aMsg.wParam = wParam;
2179         aMsg.lParam = lParam;
2180         if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg))
2181         {
2182           return 0;
2183         }
2184       }
2185     }
2186   }
2187   return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2188 }
2189
2190 //==============================================================================
2191 //function : ViewerMainLoop
2192 //purpose  : Get a Event on the view and dispatch it
2193 //==============================================================================
2194
2195 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2196 {
2197   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
2198   if (aViewCtrl.IsNull()
2199    || theNbArgs < 4)
2200   {
2201     return 0;
2202   }
2203
2204   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2205
2206   std::cout << "Start picking\n";
2207
2208   MSG aMsg;
2209   aMsg.wParam = 1;
2210   while (aViewCtrl->ToPickPoint())
2211   {
2212     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
2213     if (GetMessageW (&aMsg, NULL, 0, 0))
2214     {
2215       TranslateMessage (&aMsg);
2216       DispatchMessageW (&aMsg);
2217     }
2218   }
2219
2220   std::cout << "Picking done\n";
2221   return 0;
2222 }
2223
2224 #elif defined(HAVE_XLIB)
2225
2226 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2227 {
2228   static XEvent aReport;
2229   const Standard_Boolean toPick = theNbArgs > 0;
2230   if (theNbArgs > 0)
2231   {
2232     if (ViewerTest::CurrentEventManager().IsNull())
2233     {
2234       return 0;
2235     }
2236     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2237   }
2238
2239   Display* aDisplay = (Display* )GetDisplayConnection()->GetDisplayAspect();
2240   XNextEvent (aDisplay, &aReport);
2241
2242   // Handle event for the chosen display connection
2243   switch (aReport.type)
2244   {
2245     case ClientMessage:
2246     {
2247       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
2248       {
2249         // Close the window
2250         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
2251         return toPick ? 0 : 1;
2252       }
2253       break;
2254     }
2255     case FocusIn:
2256     {
2257       // Activate inactive view
2258       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
2259       if (aWindow != aReport.xfocus.window)
2260       {
2261         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
2262       }
2263       break;
2264     }
2265     default:
2266     {
2267       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2268       if (!aView.IsNull()
2269        && !VT_GetWindow().IsNull())
2270       {
2271         VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aReport);
2272       }
2273       break;
2274     }
2275   }
2276   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
2277 }
2278
2279 //==============================================================================
2280 //function : VProcessEvents
2281 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
2282 //==============================================================================
2283 static void VProcessEvents (ClientData theDispX, int)
2284 {
2285   Display* aDispX = (Display* )theDispX;
2286   Handle(Aspect_DisplayConnection) aDispConn;
2287   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
2288        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
2289   {
2290     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
2291     if ((Display* )aDispConnTmp->GetDisplayAspect() == aDispX)
2292     {
2293       aDispConn = aDispConnTmp;
2294       break;
2295     }
2296   }
2297   if (aDispConn.IsNull())
2298   {
2299     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
2300     return;
2301   }
2302
2303   // process new events in queue
2304   SetDisplayConnection (aDispConn);
2305   int aNbRemain = 0;
2306   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
2307   {
2308     const int anEventResult = ViewerMainLoop (0, NULL);
2309     if (anEventResult == 0)
2310     {
2311       return;
2312     }
2313
2314     aNbRemain = XPending (aDispX);
2315     if (++anEventIter >= aNbEventsMax
2316      || aNbRemain <= 0)
2317     {
2318       break;
2319     }
2320   }
2321
2322   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
2323   // it is possible that new events will arrive to queue before the end of this callback
2324   // so that either this callback should go into an infinite loop (blocking processing of other events)
2325   // or to keep unprocessed events till the next queue update (which can arrive not soon).
2326   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
2327   if (aNbRemain != 0)
2328   {
2329     XEvent aDummyEvent;
2330     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
2331     aDummyEvent.type = ClientMessage;
2332     aDummyEvent.xclient.format = 32;
2333     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
2334     XFlush (aDispX);
2335   }
2336
2337   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
2338   {
2339     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
2340   }
2341 }
2342 #elif !defined(__APPLE__)
2343 // =======================================================================
2344 // function : ViewerMainLoop
2345 // purpose  :
2346 // =======================================================================
2347 int ViewerMainLoop (Standard_Integer , const char** )
2348 {
2349   // unused
2350   return 0;
2351 }
2352 #endif
2353
2354 //==============================================================================
2355 //function : VFit
2356 //purpose  :
2357 //==============================================================================
2358
2359 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
2360 {
2361   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2362   if (aView.IsNull())
2363   {
2364     Message::SendFail ("Error: no active viewer");
2365     return 1;
2366   }
2367
2368   Standard_Boolean toFit = Standard_True;
2369   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2370   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2371   {
2372     TCollection_AsciiString anArg (theArgv[anArgIter]);
2373     anArg.LowerCase();
2374     if (anUpdateTool.parseRedrawMode (anArg))
2375     {
2376       continue;
2377     }
2378     else if (anArg == "-selected")
2379     {
2380       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
2381       toFit = Standard_False;
2382     }
2383     else
2384     {
2385       Message::SendFail() << "Syntax error at '" << anArg << "'";
2386     }
2387   }
2388
2389   if (toFit)
2390   {
2391     aView->FitAll (0.01, Standard_False);
2392   }
2393   return 0;
2394 }
2395
2396 //=======================================================================
2397 //function : VFitArea
2398 //purpose  : Fit view to show area located between two points
2399 //         : given in world 2D or 3D coordinates.
2400 //=======================================================================
2401 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
2402 {
2403   Handle(V3d_View) aView = ViewerTest::CurrentView();
2404   if (aView.IsNull())
2405   {
2406     Message::SendFail ("Error: No active viewer");
2407     return 1;
2408   }
2409
2410   // Parse arguments.
2411   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
2412   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
2413
2414   if (theArgNb == 5)
2415   {
2416     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2417     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2418     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
2419     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
2420   }
2421   else if (theArgNb == 7)
2422   {
2423     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2424     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2425     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
2426     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
2427     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
2428     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
2429   }
2430   else
2431   {
2432     Message::SendFail ("Syntax error: Invalid number of arguments");
2433     theDI.PrintHelp(theArgVec[0]);
2434     return 1;
2435   }
2436
2437   // Convert model coordinates to view space
2438   Handle(Graphic3d_Camera) aCamera = aView->Camera();
2439   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
2440   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
2441
2442   // Determine fit area
2443   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
2444   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
2445
2446   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
2447
2448   if (aDiagonal < Precision::Confusion())
2449   {
2450     Message::SendFail ("Error: view area is too small");
2451     return 1;
2452   }
2453
2454   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
2455   return 0;
2456 }
2457
2458 //==============================================================================
2459 //function : VZFit
2460 //purpose  : ZFitall, no DRAW arguments
2461 //Draw arg : No args
2462 //==============================================================================
2463 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
2464 {
2465   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
2466
2467   if (aCurrentView.IsNull())
2468   {
2469     Message::SendFail ("Error: no active viewer");
2470     return 1;
2471   }
2472
2473   if (theArgsNb == 1)
2474   {
2475     aCurrentView->ZFitAll();
2476     aCurrentView->Redraw();
2477     return 0;
2478   }
2479
2480   Standard_Real aScale = 1.0;
2481
2482   if (theArgsNb >= 2)
2483   {
2484     aScale = Draw::Atoi (theArgVec[1]);
2485   }
2486
2487   aCurrentView->ZFitAll (aScale);
2488   aCurrentView->Redraw();
2489
2490   return 0;
2491 }
2492
2493 //==============================================================================
2494 //function : VRepaint
2495 //purpose  :
2496 //==============================================================================
2497 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
2498 {
2499   Handle(V3d_View) aView = ViewerTest::CurrentView();
2500   if (aView.IsNull())
2501   {
2502     Message::SendFail ("Error: no active viewer");
2503     return 1;
2504   }
2505
2506   Standard_Boolean isImmediateUpdate = Standard_False;
2507   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2508   {
2509     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2510     anArg.LowerCase();
2511     if (anArg == "-immediate"
2512      || anArg == "-imm")
2513     {
2514       isImmediateUpdate = Standard_True;
2515       if (anArgIter + 1 < theArgNb
2516        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
2517       {
2518         ++anArgIter;
2519       }
2520     }
2521     else if (anArg == "-continuous"
2522           || anArg == "-cont"
2523           || anArg == "-fps"
2524           || anArg == "-framerate")
2525     {
2526       Standard_Real aFps = -1.0;
2527       if (anArgIter + 1 < theArgNb
2528        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
2529       {
2530         aFps = Draw::Atof (theArgVec[++anArgIter]);
2531       }
2532
2533       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2534       ViewerTest::CurrentEventManager()->SetContinuousRedraw (false);
2535       if (aFps >= 1.0)
2536       {
2537         aRedrawer.Start (aView, aFps);
2538       }
2539       else if (aFps < 0.0)
2540       {
2541         if (ViewerTest::GetViewerFromContext()->ActiveViews().Extent() == 1)
2542         {
2543           aRedrawer.Stop();
2544           ViewerTest::CurrentEventManager()->SetContinuousRedraw (true);
2545           ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
2546           continue;
2547         }
2548         aRedrawer.Start (aView, aFps);
2549       }
2550       else
2551       {
2552         aRedrawer.Stop();
2553       }
2554     }
2555     else
2556     {
2557       Message::SendFail() << "Syntax error at '" << anArg << "'";
2558       return 1;
2559     }
2560   }
2561
2562   if (isImmediateUpdate)
2563   {
2564     aView->RedrawImmediate();
2565   }
2566   else
2567   {
2568     aView->Redraw();
2569   }
2570   return 0;
2571 }
2572
2573 //==============================================================================
2574 //function : VClear
2575 //purpose  : Remove all the object from the viewer
2576 //Draw arg : No args
2577 //==============================================================================
2578
2579 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
2580 {
2581   Handle(V3d_View) V = ViewerTest::CurrentView();
2582   if(!V.IsNull())
2583     ViewerTest::Clear();
2584   return 0;
2585 }
2586
2587 //==============================================================================
2588 //function : VPick
2589 //purpose  :
2590 //==============================================================================
2591
2592 static int VPick (Draw_Interpretor& ,
2593                   Standard_Integer theNbArgs,
2594                   const char** theArgVec)
2595 {
2596   if (ViewerTest::CurrentView().IsNull())
2597   {
2598     return 1;
2599   }
2600
2601   if (theNbArgs < 4)
2602   {
2603     Message::SendFail ("Syntax error: wrong number of arguments");
2604     return 1;
2605   }
2606
2607   while (ViewerMainLoop (theNbArgs, theArgVec))
2608   {
2609     //
2610   }
2611
2612   return 0;
2613 }
2614
2615 //! Parse image fill method.
2616 static bool parseImageMode (const TCollection_AsciiString& theName,
2617                             Aspect_FillMethod& theMode)
2618 {
2619   TCollection_AsciiString aName = theName;
2620   aName.LowerCase();
2621   if (aName == "none")
2622   {
2623     theMode = Aspect_FM_NONE;
2624   }
2625   else if (aName == "centered")
2626   {
2627     theMode = Aspect_FM_CENTERED;
2628   }
2629   else if (aName == "tiled")
2630   {
2631     theMode = Aspect_FM_TILED;
2632   }
2633   else if (aName == "stretch")
2634   {
2635     theMode = Aspect_FM_STRETCH;
2636   }
2637   else
2638   {
2639     return false;
2640   }
2641   return true;
2642 }
2643
2644 //! Parse gradient fill method.
2645 static bool parseGradientMode (const TCollection_AsciiString& theName,
2646                                Aspect_GradientFillMethod& theMode)
2647 {
2648   TCollection_AsciiString aName = theName;
2649   aName.LowerCase();
2650   if (aName == "none")
2651   {
2652     theMode = Aspect_GradientFillMethod_None;
2653   }
2654   else if (aName == "hor"
2655         || aName == "horizontal")
2656   {
2657     theMode = Aspect_GradientFillMethod_Horizontal;
2658   }
2659   else if (aName == "ver"
2660         || aName == "vert"
2661         || aName == "vertical")
2662   {
2663     theMode = Aspect_GradientFillMethod_Vertical;
2664   }
2665   else if (aName == "diag"
2666         || aName == "diagonal"
2667         || aName == "diag1"
2668         || aName == "diagonal1")
2669   {
2670     theMode = Aspect_GradientFillMethod_Diagonal1;
2671   }
2672   else if (aName == "diag2"
2673         || aName == "diagonal2")
2674   {
2675     theMode = Aspect_GradientFillMethod_Diagonal2;
2676   }
2677   else if (aName == "corner1")
2678   {
2679     theMode = Aspect_GradientFillMethod_Corner1;
2680   }
2681   else if (aName == "corner2")
2682   {
2683     theMode = Aspect_GradientFillMethod_Corner2;
2684   }
2685   else if (aName == "corner3")
2686   {
2687     theMode = Aspect_GradientFillMethod_Corner3;
2688   }
2689   else if (aName == "corner4")
2690   {
2691     theMode = Aspect_GradientFillMethod_Corner4;
2692   }
2693   else if (aName == "ellip"
2694         || aName == "elliptical")
2695   {
2696     theMode = Aspect_GradientFillMethod_Elliptical;
2697   }
2698   else
2699   {
2700     return false;
2701   }
2702   return true;
2703 }
2704
2705 //==============================================================================
2706 //function : VBackground
2707 //purpose  :
2708 //==============================================================================
2709 static int VBackground (Draw_Interpretor& theDI,
2710                         Standard_Integer  theNbArgs,
2711                         const char**      theArgVec)
2712 {
2713   if (theNbArgs < 2)
2714   {
2715     theDI << "Syntax error: wrong number of arguments";
2716     return 1;
2717   }
2718
2719   const TCollection_AsciiString aCmdName (theArgVec[0]);
2720   bool isDefault = aCmdName == "vsetdefaultbg";
2721   Standard_Integer aNbColors = 0;
2722   Quantity_ColorRGBA aColors[2];
2723
2724   Aspect_GradientFillMethod aGradientMode = Aspect_GradientFillMethod_None;
2725   bool hasGradientMode = false;
2726
2727   TCollection_AsciiString anImagePath;
2728   Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
2729   bool hasImageMode = false;
2730
2731   bool isSkydomeBg = false;
2732   Aspect_SkydomeBackground aSkydomeAspect;
2733
2734   NCollection_Sequence<TCollection_AsciiString> aCubeMapSeq;
2735   Graphic3d_CubeMapOrder aCubeOrder = Graphic3d_CubeMapOrder::Default();
2736   bool isCubeZInverted = false;
2737   bool isSRgb = true;
2738
2739   int toUseIBL = 1;
2740
2741   Handle(V3d_View) aView = ViewerTest::CurrentView();
2742   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
2743   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2744   {
2745     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2746     anArg.LowerCase();
2747     if (anUpdateTool.parseRedrawMode (anArg))
2748     {
2749       continue;
2750     }
2751     else if (anArg == "-default"
2752           || anArg == "-def")
2753     {
2754       isDefault = true;
2755     }
2756     else if (anArgIter + 1 < theNbArgs
2757           && (anArg == "-imagefile"
2758            || anArg == "-imgfile"
2759            || anArg == "-image"
2760            || anArg == "-img"))
2761     {
2762       anImagePath = theArgVec[++anArgIter];
2763     }
2764     else if (anArg == "-skydome"
2765           || anArg == "-sky")
2766     {
2767       isSkydomeBg = true;
2768     }
2769     else if (anArgIter + 3 < theNbArgs
2770           && isSkydomeBg
2771           && anArg == "-sundir")
2772     {
2773       float aX = (float) Draw::Atof (theArgVec[++anArgIter]);
2774       float aY = (float) Draw::Atof (theArgVec[++anArgIter]);
2775       float aZ = (float) Draw::Atof (theArgVec[++anArgIter]);
2776       aSkydomeAspect.SetSunDirection (gp_Dir(aX, aY, aZ));
2777     }
2778     else if (anArgIter + 1 < theNbArgs
2779           && isSkydomeBg
2780           && anArg == "-cloud")
2781     {
2782       float aCloudy = (float) Draw::Atof (theArgVec[++anArgIter]);
2783       aSkydomeAspect.SetCloudiness (aCloudy);
2784     }
2785     else if (anArgIter + 1 < theNbArgs
2786           && isSkydomeBg
2787           && anArg == "-time")
2788     {
2789       float aTime = (float) Draw::Atof (theArgVec[++anArgIter]);
2790       aSkydomeAspect.SetTimeParameter (aTime);
2791     }
2792     else if (anArgIter + 1 < theNbArgs
2793           && isSkydomeBg
2794           && anArg == "-fog")
2795     {
2796       float aFoggy = (float) Draw::Atof (theArgVec[++anArgIter]);
2797       aSkydomeAspect.SetFogginess (aFoggy);
2798     }
2799     else if (anArgIter + 1 < theNbArgs
2800           && isSkydomeBg
2801           && anArg == "-size")
2802     {
2803       Standard_Integer aSize = Draw::Atoi (theArgVec[++anArgIter]);
2804       aSkydomeAspect.SetSize (aSize);
2805     }
2806     else if (anArgIter + 1 < theNbArgs
2807           && aCubeMapSeq.IsEmpty()
2808           && (anArg == "-cubemap"
2809            || anArg == "-cmap"
2810            || anArg == "-cm"))
2811     {
2812       aCubeMapSeq.Append (theArgVec[++anArgIter]);
2813       for (Standard_Integer aCubeSideIter = 1; anArgIter + aCubeSideIter < theNbArgs; ++aCubeSideIter)
2814       {
2815         TCollection_AsciiString aSideArg (theArgVec[anArgIter + aCubeSideIter]);
2816         if (!aSideArg.IsEmpty()
2817           && aSideArg.Value (1) == '-')
2818         {
2819           break;
2820         }
2821
2822         aCubeMapSeq.Append (aSideArg);
2823         if (aCubeMapSeq.Size() == 6)
2824         {
2825           anArgIter += 5;
2826           break;
2827         }
2828       }
2829
2830       if (aCubeMapSeq.Size() > 1
2831        && aCubeMapSeq.Size() < 6)
2832       {
2833         aCubeMapSeq.Remove (2, aCubeMapSeq.Size());
2834       }
2835     }
2836     else if (anArgIter + 6 < theNbArgs
2837           && anArg == "-order")
2838     {
2839       for (Standard_Integer aCubeSideIter = 0; aCubeSideIter < 6; ++aCubeSideIter)
2840       {
2841         Standard_Integer aSideArg = 0;
2842         if (!Draw::ParseInteger (theArgVec[anArgIter + aCubeSideIter + 1], aSideArg)
2843          || aSideArg < 0
2844          || aSideArg > 5)
2845         {
2846           theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2847           return 1;
2848         }
2849         aCubeOrder.Set ((Graphic3d_CubeMapSide )aCubeSideIter, (unsigned char )aSideArg);
2850       }
2851       if (!aCubeOrder.IsValid())
2852       {
2853         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2854         return 1;
2855       }
2856       anArgIter += 6;
2857     }
2858     else if (anArg == "-invertedz"
2859           || anArg == "-noinvertedz"
2860           || anArg == "-invz"
2861           || anArg == "-noinvz")
2862     {
2863       isCubeZInverted = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2864     }
2865     else if (anArg == "-pbrenv"
2866           || anArg == "-nopbrenv"
2867           || anArg == "-ibl"
2868           || anArg == "-noibl")
2869     {
2870       toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2871       if (anArgIter + 1 < theNbArgs)
2872       {
2873         TCollection_AsciiString anIblArg (theArgVec[anArgIter + 1]);
2874         anIblArg.LowerCase();
2875         if (anIblArg == "keep"
2876          || anIblArg == "-1")
2877         {
2878           toUseIBL = -1;
2879           ++anArgIter;
2880         }
2881         else if (anIblArg == "ibl"
2882               || anIblArg == "1"
2883               || anIblArg == "on")
2884         {
2885           toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2886           ++anArgIter;
2887         }
2888         else if (anIblArg == "noibl"
2889               || anIblArg == "0"
2890               || anIblArg == "off")
2891         {
2892           toUseIBL = !anArg.StartsWith ("-no") ? 0 : 1;
2893           ++anArgIter;
2894         }
2895       }
2896     }
2897     else if (anArg == "-srgb"
2898           || anArg == "-nosrgb")
2899     {
2900       isSRgb = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2901     }
2902     else if (aNbColors < 2
2903           && (anArg == "-color"
2904            || anArg == "-col"))
2905     {
2906       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - (anArgIter + 1),
2907                                                      theArgVec + (anArgIter + 1),
2908                                                      aColors[aNbColors].ChangeRGB());
2909       if (aNbParsed == 0)
2910       {
2911         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2912         return 1;
2913       }
2914       anArgIter += aNbParsed;
2915       ++aNbColors;
2916     }
2917     else if (anArgIter + 1 < theNbArgs
2918           && (anArg == "-gradientmode"
2919            || anArg == "-gradmode"
2920            || anArg == "-gradmd"
2921            || anArg == "-grmode"
2922            || anArg == "-grmd")
2923           && parseGradientMode (theArgVec[anArgIter + 1], aGradientMode))
2924     {
2925       ++anArgIter;
2926       hasGradientMode = true;
2927     }
2928     else if (anArgIter + 1 < theNbArgs
2929           && (anArg == "-imagemode"
2930            || anArg == "-imgmode"
2931            || anArg == "-imagemd"
2932            || anArg == "-imgmd")
2933           && parseImageMode (theArgVec[anArgIter + 1], anImageMode))
2934     {
2935       ++anArgIter;
2936       hasImageMode = true;
2937     }
2938     else if (aNbColors == 0
2939           && anArgIter + 2 < theNbArgs
2940           && (anArg == "-gradient"
2941            || anArg == "-grad"
2942            || anArg == "-gr"))
2943     {
2944       Standard_Integer aNbParsed1 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
2945                                                       theArgVec + (anArgIter + 1),
2946                                                       aColors[aNbColors].ChangeRGB());
2947       anArgIter += aNbParsed1;
2948       ++aNbColors;
2949       if (aNbParsed1 == 0)
2950       {
2951         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2952         return 1;
2953       }
2954       Standard_Integer aNbParsed2 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
2955                                                       theArgVec + (anArgIter + 1),
2956                                                       aColors[aNbColors].ChangeRGB());
2957       anArgIter += aNbParsed2;
2958       ++aNbColors;
2959       if (aNbParsed2 == 0)
2960       {
2961         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2962         return 1;
2963       }
2964     }
2965     else if (parseGradientMode (theArgVec[anArgIter], aGradientMode))
2966     {
2967       hasGradientMode = true;
2968     }
2969     else if (aNbColors < 2
2970           && (Quantity_ColorRGBA::ColorFromName(theArgVec[anArgIter], aColors[aNbColors])
2971            || Quantity_ColorRGBA::ColorFromHex (theArgVec[anArgIter], aColors[aNbColors])))
2972     {
2973       ++aNbColors;
2974     }
2975     else if (anImagePath.IsEmpty()
2976          &&  aNbColors == 0
2977          && !hasGradientMode
2978          &&  aCubeMapSeq.IsEmpty())
2979     {
2980       anImagePath = theArgVec[anArgIter];
2981     }
2982     else
2983     {
2984       theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2985       return 1;
2986     }
2987   }
2988
2989   if (!isDefault
2990    && aView.IsNull())
2991   {
2992     theDI << "Error: no active viewer";
2993     return 1;
2994   }
2995   else if (isDefault
2996        &&  aNbColors == 0
2997        && !hasGradientMode)
2998   {
2999     theDI << "Syntax error at '-default'";
3000     return 1;
3001   }
3002
3003   if (aNbColors == 1)
3004   {
3005     if (isDefault)
3006     {
3007       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
3008       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
3009       ViewerTest_DefaultBackground.FillMethod     = Aspect_GradientFillMethod_None;
3010       ViewerTest_DefaultBackground.FlatColor      = aColors[0].GetRGB();
3011       ViewerTest_DefaultBackground.SetDefaultGradient();
3012       ViewerTest_DefaultBackground.SetDefaultColor();
3013     }
3014     else
3015     {
3016       aView->SetBgGradientStyle (hasGradientMode ? aGradientMode : Aspect_GradientFillMethod_None);
3017       aView->SetBackgroundColor (aColors[0].GetRGB());
3018       if (toUseIBL != -1)
3019       {
3020         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
3021       }
3022     }
3023   }
3024   else if (aNbColors == 2)
3025   {
3026     if (isDefault)
3027     {
3028       ViewerTest_DefaultBackground.GradientColor1 = aColors[0].GetRGB();
3029       ViewerTest_DefaultBackground.GradientColor2 = aColors[1].GetRGB();
3030       if (hasGradientMode)
3031       {
3032         ViewerTest_DefaultBackground.FillMethod = aGradientMode;
3033       }
3034       else if (ViewerTest_DefaultBackground.FillMethod == Aspect_GradientFillMethod_None)
3035       {
3036         ViewerTest_DefaultBackground.FillMethod = Aspect_GradientFillMethod_Vertical;
3037       }
3038       ViewerTest_DefaultBackground.SetDefaultGradient();
3039     }
3040     else
3041     {
3042       if (!hasGradientMode)
3043       {
3044         aGradientMode = aView->GradientBackground().BgGradientFillMethod();
3045         if (aGradientMode == Aspect_GradientFillMethod_None)
3046         {
3047           aGradientMode = Aspect_GradientFillMethod_Vertical;
3048         }
3049       }
3050       aView->SetBgGradientColors (aColors[0].GetRGB(), aColors[1].GetRGB(), aGradientMode);
3051       if (toUseIBL != -1)
3052       {
3053         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
3054       }
3055     }
3056   }
3057   else if (hasGradientMode)
3058   {
3059     if (isDefault)
3060     {
3061       ViewerTest_DefaultBackground.FillMethod = aGradientMode;
3062       ViewerTest_DefaultBackground.SetDefaultGradient();
3063     }
3064     else
3065     {
3066       aView->SetBgGradientStyle (aGradientMode);
3067     }
3068   }
3069
3070   if (!anImagePath.IsEmpty())
3071   {
3072     Handle(Graphic3d_Texture2D) aTextureMap = new Graphic3d_Texture2Dmanual (anImagePath);
3073     aTextureMap->DisableModulate();
3074     aTextureMap->SetColorMap (isSRgb);
3075     if (!aTextureMap->IsDone())
3076     {
3077       theDI << "Syntax error at '" << anImagePath << "'";
3078       return 1;
3079     }
3080     aView->SetBackgroundImage (aTextureMap, anImageMode);
3081   }
3082   else if (hasImageMode)
3083   {
3084     aView->SetBgImageStyle (anImageMode);
3085   }
3086
3087   if (isSkydomeBg)
3088   {
3089     aView->SetBackgroundSkydome (aSkydomeAspect, toUseIBL != -1);
3090   }
3091
3092   if (!aCubeMapSeq.IsEmpty())
3093   {
3094     Handle(Graphic3d_CubeMap) aCubeMap;
3095     if (aCubeMapSeq.Size() == 1)
3096     {
3097       aCubeMap = new Graphic3d_CubeMapPacked (aCubeMapSeq.First(), aCubeOrder.Validated());
3098     }
3099     else
3100     {
3101       NCollection_Array1<TCollection_AsciiString> aCubeMapArr (0, 5);
3102       Standard_Integer aCubeSide = 0;
3103       for (NCollection_Sequence<TCollection_AsciiString>::Iterator aFileIter (aCubeMapSeq); aFileIter.More(); aFileIter.Next(), ++aCubeSide)
3104       {
3105         aCubeMapArr[aCubeSide] = aFileIter.Value();
3106       }
3107       aCubeMap = new Graphic3d_CubeMapSeparate (aCubeMapArr);
3108     }
3109
3110     aCubeMap->SetZInversion (isCubeZInverted);
3111     aCubeMap->SetColorMap (isSRgb);
3112
3113     aCubeMap->GetParams()->SetFilter (Graphic3d_TOTF_BILINEAR);
3114     aCubeMap->GetParams()->SetRepeat (false);
3115     aCubeMap->GetParams()->SetTextureUnit (Graphic3d_TextureUnit_EnvMap);
3116
3117     aView->SetBackgroundCubeMap (aCubeMap, toUseIBL != -1);
3118   }
3119   if (toUseIBL != -1
3120   && !aView.IsNull())
3121   {
3122     aView->SetImageBasedLighting (toUseIBL == 1);
3123   }
3124
3125   return 0;
3126 }
3127
3128 //==============================================================================
3129 //function : VScale
3130 //purpose  : View Scaling
3131 //==============================================================================
3132
3133 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3134 {
3135   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3136   if ( V3dView.IsNull() ) return 1;
3137
3138   if ( argc != 4 ) {
3139     di << argv[0] << "Invalid number of arguments\n";
3140     return 1;
3141   }
3142   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3143   return 0;
3144 }
3145 //==============================================================================
3146 //function : VZBuffTrihedron
3147 //purpose  :
3148 //==============================================================================
3149
3150 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3151                             Standard_Integer  theArgNb,
3152                             const char**      theArgVec)
3153 {
3154   Handle(V3d_View) aView = ViewerTest::CurrentView();
3155   if (aView.IsNull())
3156   {
3157     Message::SendFail ("Error: no active viewer");
3158     return 1;
3159   }
3160
3161   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3162
3163   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3164   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3165   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
3166   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
3167   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
3168   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3169   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3170   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3171   Standard_Real                 aScale        = 0.1;
3172   Standard_Real                 aSizeRatio    = 0.8;
3173   Standard_Real                 anArrowDiam   = 0.05;
3174   Standard_Integer              aNbFacets     = 12;
3175   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3176   {
3177     Standard_CString        anArg = theArgVec[anArgIter];
3178     TCollection_AsciiString aFlag (anArg);
3179     aFlag.LowerCase();
3180     if (anUpdateTool.parseRedrawMode (aFlag))
3181     {
3182       continue;
3183     }
3184     else if (aFlag == "-on")
3185     {
3186       continue;
3187     }
3188     else if (aFlag == "-off")
3189     {
3190       aView->TriedronErase();
3191       return 0;
3192     }
3193     else if (aFlag == "-pos"
3194           || aFlag == "-position"
3195           || aFlag == "-corner")
3196     {
3197       if (++anArgIter >= theArgNb)
3198       {
3199         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3200         return 1;
3201       }
3202
3203       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
3204       aPosName.LowerCase();
3205       if (aPosName == "center")
3206       {
3207         aPosition = Aspect_TOTP_CENTER;
3208       }
3209       else if (aPosName == "left_lower"
3210             || aPosName == "lower_left"
3211             || aPosName == "leftlower"
3212             || aPosName == "lowerleft")
3213       {
3214         aPosition = Aspect_TOTP_LEFT_LOWER;
3215       }
3216       else if (aPosName == "left_upper"
3217             || aPosName == "upper_left"
3218             || aPosName == "leftupper"
3219             || aPosName == "upperleft")
3220       {
3221         aPosition = Aspect_TOTP_LEFT_UPPER;
3222       }
3223       else if (aPosName == "right_lower"
3224             || aPosName == "lower_right"
3225             || aPosName == "rightlower"
3226             || aPosName == "lowerright")
3227       {
3228         aPosition = Aspect_TOTP_RIGHT_LOWER;
3229       }
3230       else if (aPosName == "right_upper"
3231             || aPosName == "upper_right"
3232             || aPosName == "rightupper"
3233             || aPosName == "upperright")
3234       {
3235         aPosition = Aspect_TOTP_RIGHT_UPPER;
3236       }
3237       else
3238       {
3239         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
3240         return 1;
3241       }
3242     }
3243     else if (aFlag == "-type")
3244     {
3245       if (++anArgIter >= theArgNb)
3246       {
3247         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3248         return 1;
3249       }
3250
3251       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
3252       aTypeName.LowerCase();
3253       if (aTypeName == "wireframe"
3254        || aTypeName == "wire")
3255       {
3256         aVisType = V3d_WIREFRAME;
3257       }
3258       else if (aTypeName == "zbuffer"
3259             || aTypeName == "shaded")
3260       {
3261         aVisType = V3d_ZBUFFER;
3262       }
3263       else
3264       {
3265         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
3266       }
3267     }
3268     else if (aFlag == "-scale")
3269     {
3270       if (++anArgIter >= theArgNb)
3271       {
3272         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3273         return 1;
3274       }
3275
3276       aScale = Draw::Atof (theArgVec[anArgIter]);
3277     }
3278     else if (aFlag == "-size"
3279           || aFlag == "-sizeratio")
3280     {
3281       if (++anArgIter >= theArgNb)
3282       {
3283         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3284         return 1;
3285       }
3286
3287       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
3288     }
3289     else if (aFlag == "-arrowdiam"
3290           || aFlag == "-arrowdiameter")
3291     {
3292       if (++anArgIter >= theArgNb)
3293       {
3294         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3295         return 1;
3296       }
3297
3298       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
3299     }
3300     else if (aFlag == "-nbfacets")
3301     {
3302       if (++anArgIter >= theArgNb)
3303       {
3304         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3305         return 1;
3306       }
3307
3308       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
3309     }
3310     else if (aFlag == "-colorlabel"
3311           || aFlag == "-colorlabels"
3312           || aFlag == "-colorlabelx"
3313           || aFlag == "-colorlabely"
3314           || aFlag == "-colorlabelz"
3315           || aFlag == "-colorarrowx"
3316           || aFlag == "-colorarrowy"
3317           || aFlag == "-colorarrowz")
3318     {
3319       Quantity_Color aColor;
3320       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
3321                                                      theArgVec + anArgIter + 1,
3322                                                      aColor);
3323       if (aNbParsed == 0)
3324       {
3325         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3326         return 1;
3327       }
3328
3329       if (aFlag == "-colorarrowx")
3330       {
3331         anArrowColorX = aColor;
3332       }
3333       else if (aFlag == "-colorarrowy")
3334       {
3335         anArrowColorY = aColor;
3336       }
3337       else if (aFlag == "-colorarrowz")
3338       {
3339         anArrowColorZ = aColor;
3340       }
3341       else if (aFlag == "-colorlabelx")
3342       {
3343         aLabelsColorX = aColor;
3344       }
3345       else if (aFlag == "-colorlabely")
3346       {
3347         aLabelsColorY = aColor;
3348       }
3349       else if (aFlag == "-colorlabelz")
3350       {
3351         aLabelsColorZ = aColor;
3352       }
3353       else
3354       {
3355         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
3356       }
3357       anArgIter += aNbParsed;
3358     }
3359     else
3360     {
3361       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3362       return 1;
3363     }
3364   }
3365
3366   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
3367   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
3368   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
3369   aTrihedron->SetSizeRatio    (aSizeRatio);
3370   aTrihedron->SetNbFacets     (aNbFacets);
3371   aTrihedron->SetArrowDiameter(anArrowDiam);
3372   aTrihedron->SetScale        (aScale);
3373   aTrihedron->SetPosition     (aPosition);
3374   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
3375   aTrihedron->Display (aView);
3376
3377   aView->ZFitAll();
3378   return 0;
3379 }
3380
3381 //==============================================================================
3382 //function : VRotate
3383 //purpose  : Camera Rotating
3384 //==============================================================================
3385
3386 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
3387 {
3388   Handle(V3d_View) aView = ViewerTest::CurrentView();
3389   if (aView.IsNull())
3390   {
3391     Message::SendFail ("Error: no active viewer");
3392     return 1;
3393   }
3394
3395   Standard_Boolean hasFlags = Standard_False;
3396   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3397   {
3398     Standard_CString        anArg (theArgVec[anArgIter]);
3399     TCollection_AsciiString aFlag (anArg);
3400     aFlag.LowerCase();
3401     if (aFlag == "-mousestart"
3402      || aFlag == "-mousefrom")
3403     {
3404       hasFlags = Standard_True;
3405       if (anArgIter + 2 >= theArgNb)
3406       {
3407         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3408         return 1;
3409       }
3410
3411       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3412       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3413       aView->StartRotation (anX, anY);
3414     }
3415     else if (aFlag == "-mousemove")
3416     {
3417       hasFlags = Standard_True;
3418       if (anArgIter + 2 >= theArgNb)
3419       {
3420         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3421         return 1;
3422       }
3423
3424       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3425       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3426       aView->Rotation (anX, anY);
3427     }
3428     else if (theArgNb != 4
3429           && theArgNb != 7)
3430     {
3431       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3432       return 1;
3433     }
3434   }
3435
3436   if (hasFlags)
3437   {
3438     return 0;
3439   }
3440   else if (theArgNb == 4)
3441   {
3442     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3443     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3444     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3445     aView->Rotate (anAX, anAY, anAZ);
3446     return 0;
3447   }
3448   else if (theArgNb == 7)
3449   {
3450     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3451     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3452     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3453
3454     Standard_Real anX = Draw::Atof (theArgVec[4]);
3455     Standard_Real anY = Draw::Atof (theArgVec[5]);
3456     Standard_Real anZ = Draw::Atof (theArgVec[6]);
3457
3458     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
3459     return 0;
3460   }
3461
3462   Message::SendFail ("Error: Invalid number of arguments");
3463   return 1;
3464 }
3465
3466 //==============================================================================
3467 //function : VZoom
3468 //purpose  : View zoom in / out (relative to current zoom)
3469 //==============================================================================
3470
3471 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3472   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3473   if ( V3dView.IsNull() ) {
3474     return 1;
3475   }
3476
3477   if ( argc == 2 ) {
3478     Standard_Real coef = Draw::Atof(argv[1]);
3479     if ( coef <= 0.0 ) {
3480       di << argv[1] << "Invalid value\n";
3481       return 1;
3482     }
3483     V3dView->SetZoom( Draw::Atof(argv[1]) );
3484     return 0;
3485   } else {
3486     di << argv[0] << " Invalid number of arguments\n";
3487     return 1;
3488   }
3489 }
3490
3491 //==============================================================================
3492 //function : VPan
3493 //purpose  : View panning (in pixels)
3494 //==============================================================================
3495
3496 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3497   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3498   if ( V3dView.IsNull() ) return 1;
3499
3500   if ( argc == 3 ) {
3501     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
3502     return 0;
3503   } else {
3504     di << argv[0] << " Invalid number of arguments\n";
3505     return 1;
3506   }
3507 }
3508
3509 //==============================================================================
3510 //function : VPlace
3511 //purpose  : Place the point (in pixels) at the center of the window
3512 //==============================================================================
3513 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
3514 {
3515   Handle(V3d_View) aView = ViewerTest::CurrentView();
3516   if (aView.IsNull())
3517   {
3518     Message::SendFail ("Error: no active viewer");
3519     return 1;
3520   }
3521
3522   if (theArgNb != 3)
3523   {
3524     Message::SendFail ("Syntax error: wrong number of arguments");
3525     return 1;
3526   }
3527
3528   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
3529
3530   return 0;
3531 }
3532
3533 static int VColorScale (Draw_Interpretor& theDI,
3534                         Standard_Integer  theArgNb,
3535                         const char**      theArgVec)
3536 {
3537   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
3538   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
3539   if (aContext.IsNull())
3540   {
3541     Message::SendFail ("Error: no active viewer");
3542     return 1;
3543   }
3544   if (theArgNb <= 1)
3545   {
3546     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
3547     return 1;
3548   }
3549
3550   Handle(AIS_ColorScale) aColorScale;
3551   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
3552   {
3553     // find existing object
3554     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
3555     if (aColorScale.IsNull())
3556     {
3557       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
3558       return 1;
3559     }
3560   }
3561
3562   if (theArgNb <= 2)
3563   {
3564     if (aColorScale.IsNull())
3565     {
3566       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
3567       return 1;
3568     }
3569
3570     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
3571           << "Min range: "            << aColorScale->GetMin() << "\n"
3572           << "Max range: "            << aColorScale->GetMax() << "\n"
3573           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
3574           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
3575           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
3576           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
3577           << "Label position: ";
3578     switch (aColorScale->GetLabelPosition())
3579     {
3580       case Aspect_TOCSP_NONE:
3581         theDI << "None\n";
3582         break;
3583       case Aspect_TOCSP_LEFT:
3584         theDI << "Left\n";
3585         break;
3586       case Aspect_TOCSP_RIGHT:
3587         theDI << "Right\n";
3588         break;
3589       case Aspect_TOCSP_CENTER:
3590         theDI << "Center\n";
3591         break;
3592     }
3593     return 0;
3594   }
3595
3596   if (aColorScale.IsNull())
3597   {
3598     aColorScale = new AIS_ColorScale();
3599     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
3600     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
3601   }
3602
3603   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
3604   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
3605   {
3606     Standard_CString        anArg = theArgVec[anArgIter];
3607     TCollection_AsciiString aFlag (anArg);
3608     aFlag.LowerCase();
3609     if (anUpdateTool.parseRedrawMode (aFlag))
3610     {
3611       continue;
3612     }
3613     else if (aFlag == "-range")
3614     {
3615       if (anArgIter + 3 >= theArgNb)
3616       {
3617         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
3618         return 1;
3619       }
3620
3621       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
3622       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
3623       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
3624       if (!aRangeMin.IsRealValue (Standard_True)
3625        || !aRangeMax.IsRealValue (Standard_True))
3626       {
3627         Message::SendFail ("Syntax error: the range values should be real");
3628         return 1;
3629       }
3630       else if (!aNbIntervals.IsIntegerValue())
3631       {
3632         Message::SendFail ("Syntax error: the number of intervals should be integer");
3633         return 1;
3634       }
3635
3636       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
3637       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
3638     }
3639     else if (aFlag == "-font")
3640     {
3641       if (anArgIter + 1 >= theArgNb)
3642       {
3643         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3644         return 1;
3645       }
3646       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
3647       if (!aFontArg.IsIntegerValue())
3648       {
3649         Message::SendFail ("Syntax error: HeightFont value should be integer");
3650         return 1;
3651       }
3652
3653       aColorScale->SetTextHeight (aFontArg.IntegerValue());
3654       anArgIter += 1;
3655     }
3656     else if (aFlag == "-textpos")
3657     {
3658       if (anArgIter + 1 >= theArgNb)
3659       {
3660         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3661         return 1;
3662       }
3663
3664       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
3665       aTextPosArg.LowerCase();
3666       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
3667       if (aTextPosArg == "none")
3668       {
3669         aLabPosition = Aspect_TOCSP_NONE;
3670       }
3671       else if (aTextPosArg == "left")
3672       {
3673         aLabPosition = Aspect_TOCSP_LEFT;
3674       }
3675       else if (aTextPosArg == "right")
3676       {
3677         aLabPosition = Aspect_TOCSP_RIGHT;
3678       }
3679       else if (aTextPosArg == "center")
3680       {
3681         aLabPosition = Aspect_TOCSP_CENTER;
3682       }
3683       else
3684       {
3685         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
3686         return 1;
3687       }
3688       aColorScale->SetLabelPosition (aLabPosition);
3689     }
3690     else if (aFlag == "-logarithmic"
3691           || aFlag == "-log")
3692     {
3693       if (anArgIter + 1 >= theArgNb)
3694       {
3695         Message::SendFail() << "Synta error at argument '" << anArg << "'";
3696         return 1;
3697       }
3698
3699       Standard_Boolean IsLog;
3700       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
3701       {
3702         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3703         return 1;
3704       }
3705       aColorScale->SetLogarithmic (IsLog);
3706     }
3707     else if (aFlag == "-huerange"
3708           || aFlag == "-hue")
3709     {
3710       if (anArgIter + 2 >= theArgNb)
3711       {
3712         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3713         return 1;
3714       }
3715
3716       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
3717       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
3718       aColorScale->SetHueRange (aHueMin, aHueMax);
3719     }
3720     else if (aFlag == "-colorrange")
3721     {
3722       Quantity_Color aColorMin, aColorMax;
3723       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3724                                                       theArgVec + (anArgIter + 1),
3725                                                       aColorMin);
3726       anArgIter += aNbParsed1;
3727       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3728                                                       theArgVec + (anArgIter + 1),
3729                                                       aColorMax);
3730       anArgIter += aNbParsed2;
3731       if (aNbParsed1 == 0
3732        || aNbParsed2 == 0)
3733       {
3734         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3735         return 1;
3736       }
3737
3738       aColorScale->SetColorRange (aColorMin, aColorMax);
3739     }
3740     else if (aFlag == "-reversed"
3741           || aFlag == "-inverted"
3742           || aFlag == "-topdown"
3743           || aFlag == "-bottomup")
3744     {
3745       Standard_Boolean toEnable = Standard_True;
3746       if (anArgIter + 1 < theArgNb
3747        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
3748       {
3749         ++anArgIter;
3750       }
3751       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
3752     }
3753     else if (aFlag == "-smooth"
3754           || aFlag == "-smoothtransition")
3755     {
3756       Standard_Boolean toEnable = Standard_True;
3757       if (anArgIter + 1 < theArgNb
3758        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3759       {
3760         ++anArgIter;
3761       }
3762       aColorScale->SetSmoothTransition (toEnable);
3763     }
3764     else if (aFlag == "-xy")
3765     {
3766       if (anArgIter + 2 >= theArgNb)
3767       {
3768         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3769         return 1;
3770       }
3771
3772       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
3773       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
3774       if (!anX.IsIntegerValue()
3775        || !anY.IsIntegerValue())
3776       {
3777         Message::SendFail ("Syntax error: coordinates should be integer values");
3778         return 1;
3779       }
3780
3781       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
3782     }
3783     else if (aFlag == "-width"
3784           || aFlag == "-w"
3785           || aFlag == "-breadth")
3786     {
3787       if (anArgIter + 1 >= theArgNb)
3788       {
3789         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3790         return 1;
3791       }
3792
3793       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
3794       if (!aBreadth.IsIntegerValue())
3795       {
3796         Message::SendFail ("Syntax error: a width should be an integer value");
3797         return 1;
3798       }
3799       aColorScale->SetBreadth (aBreadth.IntegerValue());
3800     }
3801     else if (aFlag == "-height"
3802           || aFlag == "-h")
3803     {
3804       if (anArgIter + 1 >= theArgNb)
3805       {
3806         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3807         return 1;
3808       }
3809
3810       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
3811       if (!aHeight.IsIntegerValue())
3812       {
3813         Message::SendFail ("Syntax error: a width should be an integer value");
3814         return 1;
3815       }
3816       aColorScale->SetHeight (aHeight.IntegerValue());
3817     }
3818     else if (aFlag == "-color")
3819     {
3820       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3821       {
3822         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
3823         return 1;
3824       }
3825       else if (anArgIter + 2 >= theArgNb)
3826       {
3827         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3828         return 1;
3829       }
3830
3831       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
3832       if (!anInd.IsIntegerValue())
3833       {
3834         Message::SendFail ("Syntax error: Index value should be integer");
3835         return 1;
3836       }
3837       const Standard_Integer anIndex = anInd.IntegerValue();
3838       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
3839       {
3840         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
3841         return 1;
3842       }
3843
3844       Quantity_Color aColor;
3845       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3846                                                      theArgVec + (anArgIter + 1),
3847                                                      aColor);
3848       if (aNbParsed == 0)
3849       {
3850         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3851         return 1;
3852       }
3853       aColorScale->SetIntervalColor (aColor, anIndex);
3854       aColorScale->SetColorType (Aspect_TOCSD_USER);
3855       anArgIter += aNbParsed;
3856     }
3857     else if (aFlag == "-label")
3858     {
3859       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3860       {
3861         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
3862         return 1;
3863       }
3864       else if (anArgIter + 2 >= theArgNb)
3865       {
3866         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3867         return 1;
3868       }
3869
3870       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
3871       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
3872       {
3873         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
3874         return 1;
3875       }
3876
3877       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
3878       aColorScale->SetLabel     (aText, anIndex);
3879       aColorScale->SetLabelType (Aspect_TOCSD_USER);
3880       anArgIter += 2;
3881     }
3882     else if (aFlag == "-labelat"
3883           || aFlag == "-labat"
3884           || aFlag == "-labelatborder"
3885           || aFlag == "-labatborder"
3886           || aFlag == "-labelatcenter"
3887           || aFlag == "-labatcenter")
3888     {
3889       Standard_Boolean toEnable = Standard_True;
3890       if (aFlag == "-labelat"
3891        || aFlag == "-labat")
3892       {
3893         Standard_Integer aLabAtBorder = -1;
3894         if (++anArgIter >= theArgNb)
3895         {
3896           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
3897           anAtBorder.LowerCase();
3898           if (anAtBorder == "border")
3899           {
3900             aLabAtBorder = 1;
3901           }
3902           else if (anAtBorder == "center")
3903           {
3904             aLabAtBorder = 0;
3905           }
3906         }
3907         if (aLabAtBorder == -1)
3908         {
3909           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3910           return 1;
3911         }
3912         toEnable = (aLabAtBorder == 1);
3913       }
3914       else if (anArgIter + 1 < theArgNb
3915             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3916       {
3917         ++anArgIter;
3918       }
3919       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
3920                                   || aFlag == "-labatcenter"
3921                                    ? !toEnable
3922                                    :  toEnable);
3923     }
3924     else if (aFlag == "-colors")
3925     {
3926       Aspect_SequenceOfColor aSeq;
3927       for (;;)
3928       {
3929         Quantity_Color aColor;
3930         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3931                                                        theArgVec + (anArgIter + 1),
3932                                                        aColor);
3933         if (aNbParsed == 0)
3934         {
3935           break;
3936         }
3937         anArgIter += aNbParsed;
3938         aSeq.Append (aColor);
3939       }
3940       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
3941       {
3942         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
3943                             << aColorScale->GetNumberOfIntervals() << " intervals";
3944         return 1;
3945       }
3946
3947       aColorScale->SetColors    (aSeq);
3948       aColorScale->SetColorType (Aspect_TOCSD_USER);
3949     }
3950     else if (aFlag == "-uniform")
3951     {
3952       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
3953       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
3954       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
3955       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
3956       aColorScale->SetColorType (Aspect_TOCSD_USER);
3957     }
3958     else if (aFlag == "-labels"
3959           || aFlag == "-freelabels")
3960     {
3961       if (anArgIter + 1 >= theArgNb)
3962       {
3963         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3964         return 1;
3965       }
3966
3967       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
3968                                  ? aColorScale->GetNumberOfIntervals() + 1
3969                                  : aColorScale->GetNumberOfIntervals();
3970       if (aFlag == "-freelabels")
3971       {
3972         ++anArgIter;
3973         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
3974       }
3975       if (anArgIter + aNbLabels >= theArgNb)
3976       {
3977         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
3978         return 1;
3979       }
3980
3981       TColStd_SequenceOfExtendedString aSeq;
3982       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
3983       {
3984         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
3985       }
3986       aColorScale->SetLabels (aSeq);
3987       aColorScale->SetLabelType (Aspect_TOCSD_USER);
3988     }
3989     else if (aFlag == "-title")
3990     {
3991       if (anArgIter + 1 >= theArgNb)
3992       {
3993         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3994         return 1;
3995       }
3996
3997       Standard_Boolean isTwoArgs = Standard_False;
3998       if (anArgIter + 2 < theArgNb)
3999       {
4000         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4001         aSecondArg.LowerCase();
4002       Standard_DISABLE_DEPRECATION_WARNINGS
4003         if (aSecondArg == "none")
4004         {
4005           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4006           isTwoArgs = Standard_True;
4007         }
4008         else if (aSecondArg == "left")
4009         {
4010           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4011           isTwoArgs = Standard_True;
4012         }
4013         else if (aSecondArg == "right")
4014         {
4015           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4016           isTwoArgs = Standard_True;
4017         }
4018         else if (aSecondArg == "center")
4019         {
4020           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4021           isTwoArgs = Standard_True;
4022         }
4023       Standard_ENABLE_DEPRECATION_WARNINGS
4024       }
4025
4026       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
4027       aColorScale->SetTitle (aTitle);
4028       if (isTwoArgs)
4029       {
4030         anArgIter += 1;
4031       }
4032       anArgIter += 1;
4033     }
4034     else if (aFlag == "-demoversion"
4035           || aFlag == "-demo")
4036     {
4037       aColorScale->SetPosition (0, 0);
4038       aColorScale->SetTextHeight (16);
4039       aColorScale->SetRange (0.0, 100.0);
4040       aColorScale->SetNumberOfIntervals (10);
4041       aColorScale->SetBreadth (0);
4042       aColorScale->SetHeight  (0);
4043       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4044       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4045       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4046     }
4047     else if (aFlag == "-findcolor")
4048     {
4049       if (anArgIter + 1 >= theArgNb)
4050       {
4051         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4052         return 1;
4053       }
4054
4055       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4056
4057       if (!anArg1.IsRealValue (Standard_True))
4058       {
4059         Message::SendFail ("Syntax error: the value should be real");
4060         return 1;
4061       }
4062
4063       Quantity_Color aColor;
4064       aColorScale->FindColor (anArg1.RealValue(), aColor);
4065       theDI << Quantity_Color::StringName (aColor.Name());
4066       return 0;
4067     }
4068     else
4069     {
4070       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4071       return 1;
4072     }
4073   }
4074
4075   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4076   aView->Window()->Size (aWinWidth, aWinHeight);
4077   if (aColorScale->GetBreadth() == 0)
4078   {
4079     aColorScale->SetBreadth (aWinWidth);
4080   }
4081   if (aColorScale->GetHeight() == 0)
4082   {
4083     aColorScale->SetHeight (aWinHeight);
4084   }
4085   aColorScale->SetToUpdate();
4086   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4087   return 0;
4088 }
4089
4090 //==============================================================================
4091 //function : VGraduatedTrihedron
4092 //purpose  : Displays or hides a graduated trihedron
4093 //==============================================================================
4094 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4095                                   Quantity_Color& theColor)
4096 {
4097   Quantity_NameOfColor aColorName;
4098   TCollection_AsciiString aVal = theValue;
4099   aVal.UpperCase();
4100   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4101   {
4102     return Standard_False;
4103   }
4104   theColor = Quantity_Color (aColorName);
4105   return Standard_True;
4106 }
4107
4108 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4109 {
4110   if (theArgNum < 2)
4111   {
4112     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4113                         << theArgs[0] <<"' for more information";
4114     return 1;
4115   }
4116
4117   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4118   TCollection_AsciiString aParseKey;
4119   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4120   {
4121     TCollection_AsciiString anArg (theArgs [anArgIt]);
4122
4123     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4124     {
4125       aParseKey = anArg;
4126       aParseKey.Remove (1);
4127       aParseKey.LowerCase();
4128       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4129       continue;
4130     }
4131
4132     if (aParseKey.IsEmpty())
4133     {
4134       continue;
4135     }
4136
4137     aMapOfArgs(aParseKey)->Append (anArg);
4138   }
4139
4140   // Check parameters
4141   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4142        aMapIt.More(); aMapIt.Next())
4143   {
4144     const TCollection_AsciiString& aKey = aMapIt.Key();
4145     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4146
4147     // Bool key, without arguments
4148     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4149         && anArgs->IsEmpty())
4150     {
4151       continue;
4152     }
4153
4154     // One argument
4155     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4156           && anArgs->Length() == 1)
4157     {
4158       continue;
4159     }
4160
4161     // On/off arguments
4162     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4163         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4164         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4165         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4166         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4167     {
4168       continue;
4169     }
4170
4171     // One string argument
4172     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4173           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4174           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4175     {
4176       continue;
4177     }
4178
4179     // One integer argument
4180     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4181           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4182           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4183           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4184          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4185     {
4186       continue;
4187     }
4188
4189     // One real argument
4190     if ( aKey.IsEqual ("arrowlength")
4191          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
4192     {
4193       continue;
4194     }
4195
4196     // Two string arguments
4197     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
4198          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4199     {
4200       continue;
4201     }
4202
4203     TCollection_AsciiString aLowerKey;
4204     aLowerKey  = "-";
4205     aLowerKey += aKey;
4206     aLowerKey.LowerCase();
4207     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
4208                         << "Type help for more information";
4209     return 1;
4210   }
4211
4212   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
4213   if (anAISContext.IsNull())
4214   {
4215     Message::SendFail ("Error: no active viewer");
4216     return 1;
4217   }
4218
4219   Standard_Boolean toDisplay = Standard_True;
4220   Quantity_Color aColor;
4221   Graphic3d_GraduatedTrihedron aTrihedronData;
4222   // Process parameters
4223   Handle(TColStd_HSequenceOfAsciiString) aValues;
4224   if (aMapOfArgs.Find ("off", aValues))
4225   {
4226     toDisplay = Standard_False;
4227   }
4228
4229   // AXES NAMES
4230   if (aMapOfArgs.Find ("xname", aValues))
4231   {
4232     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
4233   }
4234   if (aMapOfArgs.Find ("yname", aValues))
4235   {
4236     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
4237   }
4238   if (aMapOfArgs.Find ("zname", aValues))
4239   {
4240     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
4241   }
4242   if (aMapOfArgs.Find ("xdrawname", aValues))
4243   {
4244     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4245   }
4246   if (aMapOfArgs.Find ("ydrawname", aValues))
4247   {
4248     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4249   }
4250   if (aMapOfArgs.Find ("zdrawname", aValues))
4251   {
4252     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4253   }
4254   if (aMapOfArgs.Find ("xnameoffset", aValues))
4255   {
4256     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4257   }
4258   if (aMapOfArgs.Find ("ynameoffset", aValues))
4259   {
4260     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4261   }
4262   if (aMapOfArgs.Find ("znameoffset", aValues))
4263   {
4264     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4265   }
4266
4267   // COLORS
4268   if (aMapOfArgs.Find ("xnamecolor", aValues))
4269   {
4270     if (!GetColor (aValues->Value(1), aColor))
4271     {
4272       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
4273       return 1;
4274     }
4275     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
4276   }
4277   if (aMapOfArgs.Find ("ynamecolor", aValues))
4278   {
4279     if (!GetColor (aValues->Value(1), aColor))
4280     {
4281       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
4282       return 1;
4283     }
4284     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
4285   }
4286   if (aMapOfArgs.Find ("znamecolor", aValues))
4287   {
4288     if (!GetColor (aValues->Value(1), aColor))
4289     {
4290       Message::SendFail ("Syntax error: -znamecolor wrong color name");
4291       return 1;
4292     }
4293     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
4294   }
4295   if (aMapOfArgs.Find ("xcolor", aValues))
4296   {
4297     if (!GetColor (aValues->Value(1), aColor))
4298     {
4299       Message::SendFail ("Syntax error: -xcolor wrong color name");
4300       return 1;
4301     }
4302     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
4303   }
4304   if (aMapOfArgs.Find ("ycolor", aValues))
4305   {
4306     if (!GetColor (aValues->Value(1), aColor))
4307     {
4308       Message::SendFail ("Syntax error: -ycolor wrong color name");
4309       return 1;
4310     }
4311     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
4312   }
4313   if (aMapOfArgs.Find ("zcolor", aValues))
4314   {
4315     if (!GetColor (aValues->Value(1), aColor))
4316     {
4317       Message::SendFail ("Syntax error: -zcolor wrong color name");
4318       return 1;
4319     }
4320     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
4321   }
4322
4323   // TICKMARKS
4324   if (aMapOfArgs.Find ("xticks", aValues))
4325   {
4326     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4327   }
4328   if (aMapOfArgs.Find ("yticks", aValues))
4329   {
4330     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4331   }
4332   if (aMapOfArgs.Find ("zticks", aValues))
4333   {
4334     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4335   }
4336   if (aMapOfArgs.Find ("xticklength", aValues))
4337   {
4338     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4339   }
4340   if (aMapOfArgs.Find ("yticklength", aValues))
4341   {
4342     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4343   }
4344   if (aMapOfArgs.Find ("zticklength", aValues))
4345   {
4346     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4347   }
4348   if (aMapOfArgs.Find ("xdrawticks", aValues))
4349   {
4350     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4351   }
4352   if (aMapOfArgs.Find ("ydrawticks", aValues))
4353   {
4354     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4355   }
4356   if (aMapOfArgs.Find ("zdrawticks", aValues))
4357   {
4358     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4359   }
4360
4361   // VALUES
4362   if (aMapOfArgs.Find ("xdrawvalues", aValues))
4363   {
4364     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4365   }
4366   if (aMapOfArgs.Find ("ydrawvalues", aValues))
4367   {
4368     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4369   }
4370   if (aMapOfArgs.Find ("zdrawvalues", aValues))
4371   {
4372     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4373   }
4374   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
4375   {
4376     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4377   }
4378   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
4379   {
4380     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4381   }
4382   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
4383   {
4384     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4385   }
4386
4387   // ARROWS
4388   if (aMapOfArgs.Find ("arrowlength", aValues))
4389   {
4390     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
4391   }
4392
4393   // FONTS
4394   if (aMapOfArgs.Find ("namefont", aValues))
4395   {
4396     aTrihedronData.SetNamesFont (aValues->Value(1));
4397   }
4398   if (aMapOfArgs.Find ("valuesfont", aValues))
4399   {
4400     aTrihedronData.SetValuesFont (aValues->Value(1));
4401   }
4402
4403   if (aMapOfArgs.Find ("drawgrid", aValues))
4404   {
4405     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
4406   }
4407   if (aMapOfArgs.Find ("drawaxes", aValues))
4408   {
4409     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
4410   }
4411
4412   // The final step: display of erase trihedron
4413   if (toDisplay)
4414   {
4415     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
4416   }
4417   else
4418   {
4419     ViewerTest::CurrentView()->GraduatedTrihedronErase();
4420   }
4421
4422   ViewerTest::GetAISContext()->UpdateCurrentViewer();
4423   ViewerTest::CurrentView()->Redraw();
4424
4425   return 0;
4426 }
4427
4428 //==============================================================================
4429 //function : VTile
4430 //purpose  :
4431 //==============================================================================
4432 static int VTile (Draw_Interpretor& theDI,
4433                   Standard_Integer  theArgNb,
4434                   const char**      theArgVec)
4435 {
4436   Handle(V3d_View) aView = ViewerTest::CurrentView();
4437   if (aView.IsNull())
4438   {
4439     Message::SendFail ("Error: no active viewer");
4440     return 1;
4441   }
4442
4443   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
4444   if (theArgNb < 2)
4445   {
4446     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
4447           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
4448           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
4449     return 0;
4450   }
4451
4452   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
4453   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4454   {
4455     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4456     anArg.LowerCase();
4457     if (anArg == "-lowerleft"
4458      || anArg == "-upperleft")
4459     {
4460       if (anArgIter + 3 < theArgNb)
4461       {
4462         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4463         return 1;
4464       }
4465       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
4466       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4467       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4468     }
4469     else if (anArg == "-total"
4470           || anArg == "-totalsize"
4471           || anArg == "-viewsize")
4472     {
4473       if (anArgIter + 3 < theArgNb)
4474       {
4475         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4476         return 1;
4477       }
4478       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4479       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4480       if (aTile.TotalSize.x() < 1
4481        || aTile.TotalSize.y() < 1)
4482       {
4483         Message::SendFail ("Error: total size is incorrect");
4484         return 1;
4485       }
4486     }
4487     else if (anArg == "-tilesize")
4488     {
4489       if (anArgIter + 3 < theArgNb)
4490       {
4491         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4492         return 1;
4493       }
4494
4495       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4496       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4497       if (aTile.TileSize.x() < 1
4498        || aTile.TileSize.y() < 1)
4499       {
4500         Message::SendFail ("Error: tile size is incorrect");
4501         return 1;
4502       }
4503     }
4504     else if (anArg == "-unset")
4505     {
4506       aView->Camera()->SetTile (Graphic3d_CameraTile());
4507       aView->Redraw();
4508       return 0;
4509     }
4510   }
4511
4512   if (aTile.TileSize.x() < 1
4513    || aTile.TileSize.y() < 1)
4514   {
4515     Message::SendFail ("Error: tile size is undefined");
4516     return 1;
4517   }
4518   else if (aTile.TotalSize.x() < 1
4519         || aTile.TotalSize.y() < 1)
4520   {
4521     Message::SendFail ("Error: total size is undefined");
4522     return 1;
4523   }
4524
4525   aView->Camera()->SetTile (aTile);
4526   aView->Redraw();
4527   return 0;
4528 }
4529
4530 //! Format ZLayer ID.
4531 inline const char* formZLayerId (const Standard_Integer theLayerId)
4532 {
4533   switch (theLayerId)
4534   {
4535     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
4536     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
4537     case Graphic3d_ZLayerId_Top:     return "[TOP]";
4538     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
4539     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
4540     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
4541   }
4542   return "";
4543 }
4544
4545 //! Print the ZLayer information.
4546 inline void printZLayerInfo (Draw_Interpretor& theDI,
4547                              const Graphic3d_ZLayerSettings& theLayer)
4548 {
4549   if (!theLayer.Name().IsEmpty())
4550   {
4551     theDI << "  Name: " << theLayer.Name() << "\n";
4552   }
4553   if (theLayer.IsImmediate())
4554   {
4555     theDI << "  Immediate: TRUE\n";
4556   }
4557   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
4558   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
4559   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
4560   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
4561   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
4562   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
4563   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
4564   {
4565     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
4566   }
4567 }
4568
4569 //==============================================================================
4570 //function : VZLayer
4571 //purpose  : Test z layer operations for v3d viewer
4572 //==============================================================================
4573 static int VZLayer (Draw_Interpretor& theDI,
4574                     Standard_Integer  theArgNb,
4575                     const char**      theArgVec)
4576 {
4577   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
4578   if (aContextAIS.IsNull())
4579   {
4580     Message::SendFail ("Error: no active viewer");
4581     return 1;
4582   }
4583
4584   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
4585   if (theArgNb < 2)
4586   {
4587     TColStd_SequenceOfInteger aLayers;
4588     aViewer->GetAllZLayers (aLayers);
4589     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4590     {
4591       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
4592       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
4593       printZLayerInfo (theDI, aSettings);
4594     }
4595     return 0;
4596   }
4597
4598   Standard_Integer anArgIter = 1;
4599   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4600   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
4601   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
4602   {
4603     ++anArgIter;
4604   }
4605
4606   {
4607     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
4608     if (aFirstArg.IsIntegerValue())
4609     {
4610       ++anArgIter;
4611       aLayerId = aFirstArg.IntegerValue();
4612     }
4613     else
4614     {
4615       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
4616       {
4617         ++anArgIter;
4618       }
4619     }
4620   }
4621
4622   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
4623   for (; anArgIter < theArgNb; ++anArgIter)
4624   {
4625     // perform operation
4626     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4627     anArg.LowerCase();
4628     if (anUpdateTool.parseRedrawMode (anArg))
4629     {
4630       //
4631     }
4632     else if (anArg == "-add"
4633           || anArg == "add")
4634     {
4635       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4636       if (!aViewer->AddZLayer (aLayerId))
4637       {
4638         Message::SendFail ("Error: can not add a new z layer");
4639         return 0;
4640       }
4641
4642       theDI << aLayerId;
4643     }
4644     else if (anArg == "-insertbefore"
4645           && anArgIter + 1 < theArgNb
4646           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4647     {
4648       ++anArgIter;
4649       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4650       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4651       {
4652         Message::SendFail ("Error: can not add a new z layer");
4653         return 0;
4654       }
4655
4656       theDI << aLayerId;
4657     }
4658     else if (anArg == "-insertafter"
4659           && anArgIter + 1 < theArgNb
4660           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4661     {
4662       ++anArgIter;
4663       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4664       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4665       {
4666         Message::SendFail ("Error: can not add a new z layer");
4667         return 0;
4668       }
4669
4670       theDI << aLayerId;
4671     }
4672     else if (anArg == "-del"
4673           || anArg == "-delete"
4674           || anArg == "del")
4675     {
4676       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4677       {
4678         if (++anArgIter >= theArgNb)
4679         {
4680           Message::SendFail ("Syntax error: id of z layer to remove is missing");
4681           return 1;
4682         }
4683
4684         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4685       }
4686
4687       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
4688        || aLayerId == Graphic3d_ZLayerId_Default
4689        || aLayerId == Graphic3d_ZLayerId_Top
4690        || aLayerId == Graphic3d_ZLayerId_Topmost
4691        || aLayerId == Graphic3d_ZLayerId_TopOSD
4692        || aLayerId == Graphic3d_ZLayerId_BotOSD)
4693       {
4694         Message::SendFail ("Syntax error: standard Z layer can not be removed");
4695         return 1;
4696       }
4697
4698       // move all object displayed in removing layer to default layer
4699       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
4700            anObjIter.More(); anObjIter.Next())
4701       {
4702         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
4703         if (aPrs.IsNull()
4704          || aPrs->ZLayer() != aLayerId)
4705         {
4706           continue;
4707         }
4708         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
4709       }
4710
4711       if (!aViewer->RemoveZLayer (aLayerId))
4712       {
4713         Message::SendFail ("Z layer can not be removed");
4714       }
4715       else
4716       {
4717         theDI << aLayerId << " ";
4718       }
4719     }
4720     else if (anArg == "-get"
4721           || anArg == "get")
4722     {
4723       TColStd_SequenceOfInteger aLayers;
4724       aViewer->GetAllZLayers (aLayers);
4725       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4726       {
4727         theDI << aLayeriter.Value() << " ";
4728       }
4729
4730       theDI << "\n";
4731     }
4732     else if (anArg == "-name")
4733     {
4734       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4735       {
4736         Message::SendFail ("Syntax error: id of Z layer is missing");
4737         return 1;
4738       }
4739
4740       if (++anArgIter >= theArgNb)
4741       {
4742         Message::SendFail ("Syntax error: name is missing");
4743         return 1;
4744       }
4745
4746       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4747       aSettings.SetName (theArgVec[anArgIter]);
4748       aViewer->SetZLayerSettings (aLayerId, aSettings);
4749     }
4750     else if (anArg == "-origin")
4751     {
4752       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4753       {
4754         Message::SendFail ("Syntax error: id of Z layer is missing");
4755         return 1;
4756       }
4757
4758       if (anArgIter + 2 >= theArgNb)
4759       {
4760         Message::SendFail ("Syntax error: origin coordinates are missing");
4761         return 1;
4762       }
4763
4764       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4765       gp_XYZ anOrigin;
4766       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
4767       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
4768       anOrigin.SetZ (0.0);
4769       if (anArgIter + 3 < theArgNb)
4770       {
4771         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
4772         anArgIter += 3;
4773       }
4774       else
4775       {
4776         anArgIter += 2;
4777       }
4778       aSettings.SetOrigin (anOrigin);
4779       aViewer->SetZLayerSettings (aLayerId, aSettings);
4780     }
4781     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4782           && anArgIter + 1 < theArgNb
4783           && (anArg == "-cullingdistance"
4784            || anArg == "-cullingdist"
4785            || anArg == "-culldistance"
4786            || anArg == "-culldist"
4787            || anArg == "-distcull"
4788            || anArg == "-distculling"
4789            || anArg == "-distanceculling"))
4790     {
4791       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4792       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
4793       aSettings.SetCullingDistance (aDist);
4794       aViewer->SetZLayerSettings (aLayerId, aSettings);
4795     }
4796     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4797           && anArgIter + 1 < theArgNb
4798           && (anArg == "-cullingsize"
4799            || anArg == "-cullsize"
4800            || anArg == "-sizecull"
4801            || anArg == "-sizeculling"))
4802     {
4803       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4804       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
4805       aSettings.SetCullingSize (aSize);
4806       aViewer->SetZLayerSettings (aLayerId, aSettings);
4807     }
4808     else if (anArg == "-settings"
4809           || anArg == "settings")
4810     {
4811       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4812       {
4813         if (++anArgIter >= theArgNb)
4814         {
4815           Message::SendFail ("Syntax error: id of Z layer is missing");
4816           return 1;
4817         }
4818
4819         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4820       }
4821
4822       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4823       printZLayerInfo (theDI, aSettings);
4824     }
4825     else if (anArg == "-enable"
4826           || anArg == "enable"
4827           || anArg == "-disable"
4828           || anArg == "disable")
4829     {
4830       const Standard_Boolean toEnable = anArg == "-enable"
4831                                      || anArg == "enable";
4832       if (++anArgIter >= theArgNb)
4833       {
4834         Message::SendFail ("Syntax error: option name is missing");
4835         return 1;
4836       }
4837
4838       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
4839       aSubOp.LowerCase();
4840       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4841       {
4842         if (++anArgIter >= theArgNb)
4843         {
4844           Message::SendFail ("Syntax error: id of Z layer is missing");
4845           return 1;
4846         }
4847
4848         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4849       }
4850
4851       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4852       if (aSubOp == "depthtest"
4853        || aSubOp == "test")
4854       {
4855         aSettings.SetEnableDepthTest (toEnable);
4856       }
4857       else if (aSubOp == "depthwrite"
4858             || aSubOp == "write")
4859       {
4860         aSettings.SetEnableDepthWrite (toEnable);
4861       }
4862       else if (aSubOp == "depthclear"
4863             || aSubOp == "clear")
4864       {
4865         aSettings.SetClearDepth (toEnable);
4866       }
4867       else if (aSubOp == "depthoffset"
4868             || aSubOp == "offset")
4869       {
4870         Graphic3d_PolygonOffset aParams;
4871         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
4872         if (toEnable)
4873         {
4874           if (anArgIter + 2 >= theArgNb)
4875           {
4876             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
4877             return 1;
4878           }
4879
4880           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4881           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4882         }
4883         aSettings.SetPolygonOffset (aParams);
4884       }
4885       else if (aSubOp == "positiveoffset"
4886             || aSubOp == "poffset")
4887       {
4888         if (toEnable)
4889         {
4890           aSettings.SetDepthOffsetPositive();
4891         }
4892         else
4893         {
4894           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
4895         }
4896       }
4897       else if (aSubOp == "negativeoffset"
4898             || aSubOp == "noffset")
4899       {
4900         if (toEnable)
4901         {
4902           aSettings.SetDepthOffsetNegative();
4903         }
4904         else
4905         {
4906           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
4907         }
4908       }
4909       else if (aSubOp == "textureenv")
4910       {
4911         aSettings.SetEnvironmentTexture (toEnable);
4912       }
4913       else if (aSubOp == "raytracing")
4914       {
4915         aSettings.SetRaytracable (toEnable);
4916       }
4917
4918       aViewer->SetZLayerSettings (aLayerId, aSettings);
4919     }
4920     else
4921     {
4922       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
4923       return 1;
4924     }
4925   }
4926
4927   return 0;
4928 }
4929
4930 // The interactive presentation of 2d layer item
4931 // for "vlayerline" command it provides a presentation of
4932 // line with user-defined linewidth, linetype and transparency.
4933 class V3d_LineItem : public AIS_InteractiveObject
4934 {
4935 public:
4936   // CASCADE RTTI
4937   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
4938
4939   // constructor
4940   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
4941                                Standard_Real X2, Standard_Real Y2,
4942                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
4943                                Standard_Real theWidth    = 0.5,
4944                                Standard_Real theTransp   = 1.0);
4945
4946 private:
4947
4948   virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
4949                         const Handle(Prs3d_Presentation)& thePrs,
4950                         const Standard_Integer theMode) Standard_OVERRIDE;
4951
4952   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& ,
4953                                  const Standard_Integer ) Standard_OVERRIDE
4954   {}
4955
4956 private:
4957
4958   Standard_Real       myX1, myY1, myX2, myY2;
4959   Aspect_TypeOfLine   myType;
4960   Standard_Real       myWidth;
4961 };
4962
4963 // default constructor for line item
4964 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
4965                            Standard_Real X2, Standard_Real Y2,
4966                            Aspect_TypeOfLine theType,
4967                            Standard_Real theWidth,
4968                            Standard_Real theTransp) :
4969   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
4970   myType(theType), myWidth(theWidth)
4971 {
4972   SetTransparency (1-theTransp);
4973 }
4974
4975 // render line
4976 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager)& ,
4977                             const Handle(Prs3d_Presentation)& thePresentation,
4978                             const Standard_Integer )
4979 {
4980   thePresentation->Clear();
4981   Quantity_Color aColor (Quantity_NOC_RED);
4982   Standard_Integer aWidth, aHeight;
4983   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
4984   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
4985   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
4986   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
4987   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
4988   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
4989   aGroup->SetPrimitivesAspect (anAspect->Aspect());
4990   aGroup->AddPrimitiveArray (aPrim);
4991 }
4992
4993 //=============================================================================
4994 //function : VLayerLine
4995 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
4996 //         : linewidth, transparency coefficient
4997 //============================================================================
4998 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
4999 {
5000   // get the active view
5001   Handle(V3d_View) aView = ViewerTest::CurrentView();
5002   if (aView.IsNull())
5003   {
5004     di << "Call vinit before!\n";
5005     return 1;
5006   }
5007   else if (argc < 5)
5008   {
5009     di << "Use: " << argv[0];
5010     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5011     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5012     di << "              0 - solid  \n";
5013     di << "              1 - dashed \n";
5014     di << "              2 - dot    \n";
5015     di << "              3 - dashdot\n";
5016     di << " transparency : { 0.0 - 1.0 } \n";
5017     di << "                  0.0 - transparent\n";
5018     di << "                  1.0 - visible    \n";
5019     return 1;
5020   }
5021
5022   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5023   // get the input params
5024   Standard_Real X1 = Draw::Atof(argv[1]);
5025   Standard_Real Y1 = Draw::Atof(argv[2]);
5026   Standard_Real X2 = Draw::Atof(argv[3]);
5027   Standard_Real Y2 = Draw::Atof(argv[4]);
5028
5029   Standard_Real aWidth = 0.5;
5030   Standard_Real aTransparency = 1.0;
5031
5032   // has width
5033   if (argc > 5)
5034     aWidth = Draw::Atof(argv[5]);
5035
5036   // select appropriate line type
5037   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5038   if (argc > 6
5039   && !ViewerTest::ParseLineType (argv[6], aLineType))
5040   {
5041     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5042     return 1;
5043   }
5044
5045   // has transparency
5046   if (argc > 7)
5047   {
5048     aTransparency = Draw::Atof(argv[7]);
5049     if (aTransparency < 0 || aTransparency > 1.0)
5050       aTransparency = 1.0;
5051   }
5052
5053   static Handle (V3d_LineItem) aLine;
5054   if (!aLine.IsNull())
5055   {
5056     aContext->Erase (aLine, Standard_False);
5057   }
5058   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5059                             aLineType, aWidth,
5060                             aTransparency);
5061
5062   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5063   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5064   aLine->SetToUpdate();
5065   aContext->Display (aLine, Standard_True);
5066
5067   return 0;
5068 }
5069
5070
5071 //==============================================================================
5072 //function : VGrid
5073 //purpose  :
5074 //==============================================================================
5075
5076 static int VGrid (Draw_Interpretor& /*theDI*/,
5077                   Standard_Integer  theArgNb,
5078                   const char**      theArgVec)
5079 {
5080   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5081   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5082   if (aView.IsNull() || aViewer.IsNull())
5083   {
5084     Message::SendFail ("Error: no active viewer");
5085     return 1;
5086   }
5087
5088   Aspect_GridType     aType = aViewer->GridType();
5089   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5090   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5091   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5092   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5093   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5094   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5095   {
5096     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5097     anArg.LowerCase();
5098     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5099     {
5100       continue;
5101     }
5102     else if (anArgIter + 1 < theArgNb
5103           && anArg == "-type")
5104     {
5105       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5106       anArgNext.LowerCase();
5107       if (anArgNext == "r"
5108        || anArgNext == "rect"
5109        || anArgNext == "rectangular")
5110       {
5111         aType = Aspect_GT_Rectangular;
5112       }
5113       else if (anArgNext == "c"
5114             || anArgNext == "circ"
5115             || anArgNext == "circular")
5116       {
5117         aType = Aspect_GT_Circular;
5118       }
5119       else
5120       {
5121         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5122         return 1;
5123       }
5124     }
5125     else if (anArgIter + 1 < theArgNb
5126           && anArg == "-mode")
5127     {
5128       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5129       anArgNext.LowerCase();
5130       if (anArgNext == "l"
5131        || anArgNext == "line"
5132        || anArgNext == "lines")
5133       {
5134         aMode = Aspect_GDM_Lines;
5135       }
5136       else if (anArgNext == "p"
5137             || anArgNext == "point"
5138             || anArgNext == "points")
5139       {
5140         aMode = Aspect_GDM_Points;
5141       }
5142       else
5143       {
5144         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5145         return 1;
5146       }
5147     }
5148     else if (anArgIter + 2 < theArgNb
5149           && (anArg == "-origin"
5150            || anArg == "-orig"))
5151     {
5152       hasOrigin = true;
5153       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5154                               Draw::Atof (theArgVec[anArgIter + 2]));
5155       anArgIter += 2;
5156     }
5157     else if (anArgIter + 2 < theArgNb
5158           && anArg == "-step")
5159     {
5160       hasStep = true;
5161       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5162                             Draw::Atof (theArgVec[anArgIter + 2]));
5163       if (aNewStepXY.x() <= 0.0
5164        || aNewStepXY.y() <= 0.0)
5165       {
5166         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5167         return 1;
5168       }
5169       anArgIter += 2;
5170     }
5171     else if (anArgIter + 1 < theArgNb
5172           && (anArg == "-angle"
5173            || anArg == "-rotangle"
5174            || anArg == "-rotationangle"))
5175     {
5176       hasRotAngle = true;
5177       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5178     }
5179     else if (anArgIter + 1 < theArgNb
5180           && (anArg == "-zoffset"
5181            || anArg == "-dz"))
5182     {
5183       hasZOffset = true;
5184       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5185     }
5186     else if (anArgIter + 1 < theArgNb
5187           && anArg == "-radius")
5188     {
5189       hasSize = true;
5190       ++anArgIter;
5191       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
5192       if (aNewStepXY.x() <= 0.0)
5193       {
5194         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
5195         return 1;
5196       }
5197     }
5198     else if (anArgIter + 2 < theArgNb
5199           && anArg == "-size")
5200     {
5201       hasSize = true;
5202       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5203                             Draw::Atof (theArgVec[anArgIter + 2]));
5204       if (aNewStepXY.x() <= 0.0
5205        || aNewStepXY.y() <= 0.0)
5206       {
5207         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5208         return 1;
5209       }
5210       anArgIter += 2;
5211     }
5212     else if (anArg == "r"
5213           || anArg == "rect"
5214           || anArg == "rectangular")
5215     {
5216       aType = Aspect_GT_Rectangular;
5217     }
5218     else if (anArg == "c"
5219           || anArg == "circ"
5220           || anArg == "circular")
5221     {
5222       aType = Aspect_GT_Circular;
5223     }
5224     else if (anArg == "l"
5225           || anArg == "line"
5226           || anArg == "lines")
5227     {
5228       aMode = Aspect_GDM_Lines;
5229     }
5230     else if (anArg == "p"
5231           || anArg == "point"
5232           || anArg == "points")
5233     {
5234       aMode = Aspect_GDM_Points;
5235     }
5236     else if (anArgIter + 1 >= theArgNb
5237           && anArg == "off")
5238     {
5239       aViewer->DeactivateGrid();
5240       return 0;
5241     }
5242     else
5243     {
5244       Message::SendFail() << "Syntax error at '" << anArg << "'";
5245       return 1;
5246     }
5247   }
5248
5249   if (aType == Aspect_GT_Rectangular)
5250   {
5251     Graphic3d_Vec2d anOrigXY, aStepXY;
5252     Standard_Real aRotAngle = 0.0;
5253     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5254     if (hasOrigin)
5255     {
5256       anOrigXY = aNewOriginXY;
5257     }
5258     if (hasStep)
5259     {
5260       aStepXY = aNewStepXY;
5261     }
5262     if (hasRotAngle)
5263     {
5264       aRotAngle = aNewRotAngle;
5265     }
5266     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5267     if (hasSize || hasZOffset)
5268     {
5269       Graphic3d_Vec3d aSize;
5270       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5271       if (hasSize)
5272       {
5273         aSize.x() = aNewSizeXY.x();
5274         aSize.y() = aNewSizeXY.y();
5275       }
5276       if (hasZOffset)
5277       {
5278         aSize.z() = aNewZOffset;
5279       }
5280       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5281     }
5282   }
5283   else if (aType == Aspect_GT_Circular)
5284   {
5285     Graphic3d_Vec2d anOrigXY;
5286     Standard_Real aRadiusStep;
5287     Standard_Integer aDivisionNumber;
5288     Standard_Real aRotAngle = 0.0;
5289     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5290     if (hasOrigin)
5291     {
5292       anOrigXY = aNewOriginXY;
5293     }
5294     if (hasStep)
5295     {
5296       aRadiusStep     = aNewStepXY[0];
5297       aDivisionNumber = (int )aNewStepXY[1];
5298       if (aDivisionNumber < 1)
5299       {
5300         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
5301         return 1;
5302       }
5303     }
5304     if (hasRotAngle)
5305     {
5306       aRotAngle = aNewRotAngle;
5307     }
5308
5309     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5310     if (hasSize || hasZOffset)
5311     {
5312       Standard_Real aRadius = 0.0, aZOffset = 0.0;
5313       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
5314       if (hasSize)
5315       {
5316         aRadius = aNewSizeXY.x();
5317         if (aNewSizeXY.y() != 0.0)
5318         {
5319           Message::SendFail ("Syntax error: circular size should be specified as radius");
5320           return 1;
5321         }
5322       }
5323       if (hasZOffset)
5324       {
5325         aZOffset = aNewZOffset;
5326       }
5327       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
5328     }
5329   }
5330   aViewer->ActivateGrid (aType, aMode);
5331   return 0;
5332 }
5333
5334 //==============================================================================
5335 //function : VPriviledgedPlane
5336 //purpose  :
5337 //==============================================================================
5338
5339 static int VPriviledgedPlane (Draw_Interpretor& theDI,
5340                               Standard_Integer  theArgNb,
5341                               const char**      theArgVec)
5342 {
5343   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
5344   {
5345     Message::SendFail ("Error: wrong number of arguments! See usage:");
5346     theDI.PrintHelp (theArgVec[0]);
5347     return 1;
5348   }
5349
5350   // get the active viewer
5351   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5352   if (aViewer.IsNull())
5353   {
5354     Message::SendFail ("Error: no active viewer");
5355     return 1;
5356   }
5357
5358   if (theArgNb == 1)
5359   {
5360     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
5361     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
5362     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
5363     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
5364     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
5365           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
5366           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
5367     return 0;
5368   }
5369
5370   Standard_Integer anArgIdx = 1;
5371   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
5372   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
5373   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
5374   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
5375   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
5376   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
5377
5378   gp_Ax3 aPriviledgedPlane;
5379   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
5380   gp_Dir aNorm (aNormX, aNormY, aNormZ);
5381   if (theArgNb > 7)
5382   {
5383     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
5384     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
5385     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
5386     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
5387     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
5388   }
5389   else
5390   {
5391     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
5392   }
5393
5394   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
5395
5396   return 0;
5397 }
5398
5399 //==============================================================================
5400 //function : VConvert
5401 //purpose  :
5402 //==============================================================================
5403
5404 static int VConvert (Draw_Interpretor& theDI,
5405                      Standard_Integer  theArgNb,
5406                      const char**      theArgVec)
5407 {
5408   // get the active view
5409   Handle(V3d_View) aView = ViewerTest::CurrentView();
5410   if (aView.IsNull())
5411   {
5412     Message::SendFail ("Error: no active viewer");
5413     return 1;
5414   }
5415
5416   enum { Model, Ray, View, Window, Grid } aMode = Model;
5417
5418   // access coordinate arguments
5419   TColStd_SequenceOfReal aCoord;
5420   Standard_Integer anArgIdx = 1;
5421   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
5422   {
5423     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5424     if (!anArg.IsRealValue (Standard_True))
5425     {
5426       break;
5427     }
5428     aCoord.Append (anArg.RealValue());
5429   }
5430
5431   // non-numeric argument too early
5432   if (aCoord.IsEmpty())
5433   {
5434     Message::SendFail ("Error: wrong number of arguments! See usage:");
5435     theDI.PrintHelp (theArgVec[0]);
5436     return 1;
5437   }
5438
5439   // collect all other arguments and options
5440   for (; anArgIdx < theArgNb; ++anArgIdx)
5441   {
5442     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5443     anArg.LowerCase();
5444     if      (anArg == "window") aMode = Window;
5445     else if (anArg == "view")   aMode = View;
5446     else if (anArg == "grid")   aMode = Grid;
5447     else if (anArg == "ray")    aMode = Ray;
5448     else
5449     {
5450       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
5451       theDI.PrintHelp (theArgVec[0]);
5452       return 1;
5453     }
5454   }
5455
5456   // complete input checks
5457   if ((aCoord.Length() == 1 && theArgNb > 3) ||
5458       (aCoord.Length() == 2 && theArgNb > 4) ||
5459       (aCoord.Length() == 3 && theArgNb > 5))
5460   {
5461     Message::SendFail ("Error: wrong number of arguments! See usage:");
5462     theDI.PrintHelp (theArgVec[0]);
5463     return 1;
5464   }
5465
5466   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
5467   Standard_Integer aXYp[2] = {0, 0};
5468
5469   // convert one-dimensional coordinate
5470   if (aCoord.Length() == 1)
5471   {
5472     switch (aMode)
5473     {
5474       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
5475       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
5476       default:
5477         Message::SendFail ("Error: wrong arguments! See usage:");
5478         theDI.PrintHelp (theArgVec[0]);
5479         return 1;
5480     }
5481   }
5482
5483   // convert 2D coordinates from projection or view reference space
5484   if (aCoord.Length() == 2)
5485   {
5486     switch (aMode)
5487     {
5488       case Model :
5489         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5490         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5491         return 0;
5492
5493       case View :
5494         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
5495         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
5496         return 0;
5497
5498       case Window :
5499         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
5500         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5501         return 0;
5502
5503       case Grid :
5504         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5505         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
5506         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5507         return 0;
5508
5509       case Ray :
5510         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
5511                                 (Standard_Integer) aCoord (2),
5512                                 aXYZ[0], aXYZ[1], aXYZ[2],
5513                                 aXYZ[3], aXYZ[4], aXYZ[5]);
5514         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5515         return 0;
5516
5517       default:
5518         Message::SendFail ("Error: wrong arguments! See usage:");
5519         theDI.PrintHelp (theArgVec[0]);
5520         return 1;
5521     }
5522   }
5523
5524   // convert 3D coordinates from view reference space
5525   else if (aCoord.Length() == 3)
5526   {
5527     switch (aMode)
5528     {
5529       case Window :
5530         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
5531         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5532         return 0;
5533
5534       case Grid :
5535         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
5536         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5537         return 0;
5538
5539       default:
5540         Message::SendFail ("Error: wrong arguments! See usage:");
5541         theDI.PrintHelp (theArgVec[0]);
5542         return 1;
5543     }
5544   }
5545
5546   return 0;
5547 }
5548
5549 //==============================================================================
5550 //function : VFps
5551 //purpose  :
5552 //==============================================================================
5553
5554 static int VFps (Draw_Interpretor& theDI,
5555                  Standard_Integer  theArgNb,
5556                  const char**      theArgVec)
5557 {
5558   // get the active view
5559   Handle(V3d_View) aView = ViewerTest::CurrentView();
5560   if (aView.IsNull())
5561   {
5562     Message::SendFail ("Error: no active viewer");
5563     return 1;
5564   }
5565
5566   Standard_Integer aFramesNb = -1;
5567   Standard_Real aDuration = -1.0;
5568   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5569   {
5570     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5571     anArg.LowerCase();
5572     if (aDuration < 0.0
5573      && anArgIter + 1 < theArgNb
5574      && (anArg == "-duration"
5575       || anArg == "-dur"
5576       || anArg == "-time"))
5577     {
5578       aDuration = Draw::Atof (theArgVec[++anArgIter]);
5579     }
5580     else if (aFramesNb < 0
5581           && anArg.IsIntegerValue())
5582     {
5583       aFramesNb = anArg.IntegerValue();
5584       if (aFramesNb <= 0)
5585       {
5586         Message::SendFail() << "Syntax error at '" << anArg << "'";
5587         return 1;
5588       }
5589     }
5590     else
5591     {
5592       Message::SendFail() << "Syntax error at '" << anArg << "'";
5593       return 1;
5594     }
5595   }
5596   if (aFramesNb < 0 && aDuration < 0.0)
5597   {
5598     aFramesNb = 100;
5599   }
5600
5601   // the time is meaningless for first call
5602   // due to async OpenGl rendering
5603   aView->Redraw();
5604
5605   // redraw view in loop to estimate average values
5606   OSD_Timer aTimer;
5607   aTimer.Start();
5608   Standard_Integer aFrameIter = 1;
5609   for (;; ++aFrameIter)
5610   {
5611     aView->Redraw();
5612     if ((aFramesNb > 0
5613       && aFrameIter >= aFramesNb)
5614      || (aDuration > 0.0
5615       && aTimer.ElapsedTime() >= aDuration))
5616     {
5617       break;
5618     }
5619   }
5620   aTimer.Stop();
5621   Standard_Real aCpu;
5622   const Standard_Real aTime = aTimer.ElapsedTime();
5623   aTimer.OSD_Chronometer::Show (aCpu);
5624
5625   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
5626   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
5627
5628   // return statistics
5629   theDI << "FPS: " << aFpsAver << "\n"
5630         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
5631
5632   // compute additional statistics in ray-tracing mode
5633   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
5634   if (aParams.Method == Graphic3d_RM_RAYTRACING)
5635   {
5636     Graphic3d_Vec2i aWinSize (0, 0);
5637     aView->Window()->Size (aWinSize.x(), aWinSize.y());
5638
5639     // 1 shadow ray and 1 secondary ray pew each bounce
5640     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
5641     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
5642   }
5643
5644   return 0;
5645 }
5646
5647
5648 //==============================================================================
5649 //function : VMemGpu
5650 //purpose  :
5651 //==============================================================================
5652
5653 static int VMemGpu (Draw_Interpretor& theDI,
5654                     Standard_Integer  theArgNb,
5655                     const char**      theArgVec)
5656 {
5657   // get the context
5658   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5659   if (aContextAIS.IsNull())
5660   {
5661     Message::SendFail ("Error: no active viewer");
5662     return 1;
5663   }
5664
5665   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
5666   if (aDriver.IsNull())
5667   {
5668     Message::SendFail ("Error: graphic driver not available");
5669     return 1;
5670   }
5671
5672   Standard_Size aFreeBytes = 0;
5673   TCollection_AsciiString anInfo;
5674   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
5675   {
5676     Message::SendFail ("Error: information not available");
5677     return 1;
5678   }
5679
5680   if (theArgNb > 1 && *theArgVec[1] == 'f')
5681   {
5682     theDI << Standard_Real (aFreeBytes);
5683   }
5684   else
5685   {
5686     theDI << anInfo;
5687   }
5688
5689   return 0;
5690 }
5691
5692 // ==============================================================================
5693 // function : VReadPixel
5694 // purpose  :
5695 // ==============================================================================
5696 static int VReadPixel (Draw_Interpretor& theDI,
5697                        Standard_Integer  theArgNb,
5698                        const char**      theArgVec)
5699 {
5700   // get the active view
5701   Handle(V3d_View) aView = ViewerTest::CurrentView();
5702   if (aView.IsNull())
5703   {
5704     Message::SendFail ("Error: no active viewer");
5705     return 1;
5706   }
5707   else if (theArgNb < 3)
5708   {
5709     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
5710                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
5711     return 1;
5712   }
5713
5714   Image_Format         aFormat     = Image_Format_RGBA;
5715   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
5716
5717   Standard_Integer aWidth, aHeight;
5718   aView->Window()->Size (aWidth, aHeight);
5719   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
5720   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
5721   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
5722   {
5723     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
5724     return 1;
5725   }
5726
5727   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
5728   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
5729   {
5730     TCollection_AsciiString aParam (theArgVec[anIter]);
5731     aParam.LowerCase();
5732     if (aParam == "-rgb"
5733      || aParam == "rgb"
5734      || aParam == "-srgb"
5735      || aParam == "srgb")
5736     {
5737       aFormat     = Image_Format_RGB;
5738       aBufferType = Graphic3d_BT_RGB;
5739       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
5740     }
5741     else if (aParam == "-hls"
5742           || aParam == "hls")
5743     {
5744       aFormat     = Image_Format_RGB;
5745       aBufferType = Graphic3d_BT_RGB;
5746       toShowHls   = Standard_True;
5747     }
5748     else if (aParam == "-rgbf"
5749           || aParam == "rgbf")
5750     {
5751       aFormat     = Image_Format_RGBF;
5752       aBufferType = Graphic3d_BT_RGB;
5753     }
5754     else if (aParam == "-rgba"
5755           || aParam == "rgba"
5756           || aParam == "-srgba"
5757           || aParam == "srgba")
5758     {
5759       aFormat     = Image_Format_RGBA;
5760       aBufferType = Graphic3d_BT_RGBA;
5761       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
5762     }
5763     else if (aParam == "-rgbaf"
5764           || aParam == "rgbaf")
5765     {
5766       aFormat     = Image_Format_RGBAF;
5767       aBufferType = Graphic3d_BT_RGBA;
5768     }
5769     else if (aParam == "-depth"
5770           || aParam == "depth")
5771     {
5772       aFormat     = Image_Format_GrayF;
5773       aBufferType = Graphic3d_BT_Depth;
5774     }
5775     else if (aParam == "-name"
5776           || aParam == "name")
5777     {
5778       toShowName = Standard_True;
5779     }
5780     else if (aParam == "-hex"
5781           || aParam == "hex")
5782     {
5783       toShowHex = Standard_True;
5784     }
5785     else
5786     {
5787       Message::SendFail() << "Syntax error at '" << aParam << "'";
5788       return 1;
5789     }
5790   }
5791
5792   Image_PixMap anImage;
5793   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
5794   {
5795     Message::SendFail ("Error: image allocation failed");
5796     return 1;
5797   }
5798   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
5799   {
5800     Message::SendFail ("Error: image dump failed");
5801     return 1;
5802   }
5803
5804   // redirect possible warning messages that could have been added by ToPixMap
5805   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
5806   // contaminate result of the command
5807   Standard_CString aWarnLog = theDI.Result();
5808   if (aWarnLog != NULL && aWarnLog[0] != '\0')
5809   {
5810     std::cout << aWarnLog << std::endl;
5811   }
5812   theDI.Reset();
5813
5814   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
5815   if (toShowName)
5816   {
5817     if (aBufferType == Graphic3d_BT_RGBA)
5818     {
5819       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
5820     }
5821     else
5822     {
5823       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
5824     }
5825   }
5826   else if (toShowHex)
5827   {
5828     if (aBufferType == Graphic3d_BT_RGBA)
5829     {
5830       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
5831     }
5832     else
5833     {
5834       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
5835     }
5836   }
5837   else
5838   {
5839     switch (aBufferType)
5840     {
5841       default:
5842       case Graphic3d_BT_RGB:
5843       {
5844         if (toShowHls)
5845         {
5846           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
5847         }
5848         else if (toShow_sRGB)
5849         {
5850           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
5851           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
5852         }
5853         else
5854         {
5855           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
5856         }
5857         break;
5858       }
5859       case Graphic3d_BT_RGBA:
5860       {
5861         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
5862         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
5863         break;
5864       }
5865       case Graphic3d_BT_Depth:
5866       {
5867         theDI << aColor.GetRGB().Red();
5868         break;
5869       }
5870     }
5871   }
5872
5873   return 0;
5874 }
5875
5876 //! Auxiliary presentation for an image plane.
5877 class ViewerTest_ImagePrs : public AIS_InteractiveObject
5878 {
5879 public:
5880   //! Main constructor.
5881   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
5882                        const Standard_Real theWidth,
5883                        const Standard_Real theHeight,
5884                        const TCollection_AsciiString& theLabel)
5885   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
5886   {
5887     SetDisplayMode (0);
5888     SetHilightMode (1);
5889     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
5890     {
5891       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
5892       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
5893       Graphic3d_MaterialAspect aMat;
5894       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
5895       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
5896       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
5897       aMat.SetSpecularColor (Quantity_NOC_BLACK);
5898       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
5899       aFillAspect->SetFrontMaterial (aMat);
5900       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
5901       aFillAspect->SetTextureMapOn();
5902     }
5903     {
5904       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
5905       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
5906       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
5907       myDrawer->SetTextAspect (aTextAspect);
5908     }
5909     {
5910       const gp_Dir aNorm (0.0, 0.0, 1.0);
5911       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
5912       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
5913       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
5914       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
5915       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
5916       myTris->AddEdge (1);
5917       myTris->AddEdge (2);
5918       myTris->AddEdge (3);
5919       myTris->AddEdge (3);
5920       myTris->AddEdge (2);
5921       myTris->AddEdge (4);
5922
5923       myRect = new Graphic3d_ArrayOfPolylines (4);
5924       myRect->AddVertex (myTris->Vertice (1));
5925       myRect->AddVertex (myTris->Vertice (3));
5926       myRect->AddVertex (myTris->Vertice (4));
5927       myRect->AddVertex (myTris->Vertice (2));
5928     }
5929   }
5930
5931   //! Returns TRUE for accepted display modes.
5932   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
5933
5934   //! Compute presentation.
5935   virtual void Compute (const Handle(PrsMgr_PresentationManager)& ,
5936                         const Handle(Prs3d_Presentation)& thePrs,
5937                         const Standard_Integer theMode) Standard_OVERRIDE
5938   {
5939     switch (theMode)
5940     {
5941       case 0:
5942       {
5943         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
5944         aGroup->AddPrimitiveArray (myTris);
5945         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
5946         aGroup->AddPrimitiveArray (myRect);
5947         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
5948         return;
5949       }
5950       case 1:
5951       {
5952         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
5953         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
5954         aGroup->AddPrimitiveArray (myRect);
5955         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
5956         return;
5957       }
5958     }
5959   }
5960
5961   //! Compute selection.
5962   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
5963   {
5964     if (theMode == 0)
5965     {
5966       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
5967       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
5968       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
5969       theSel->Add (aSensitive);
5970     }
5971   }
5972
5973 private:
5974   Handle(Graphic3d_ArrayOfTriangles) myTris;
5975   Handle(Graphic3d_ArrayOfPolylines) myRect;
5976   TCollection_AsciiString myLabel;
5977   Standard_Real myWidth;
5978   Standard_Real myHeight;
5979 };
5980
5981 //==============================================================================
5982 //function : VDiffImage
5983 //purpose  : The draw-command compares two images.
5984 //==============================================================================
5985
5986 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
5987 {
5988   if (theArgNb < 3)
5989   {
5990     Message::SendFail ("Syntax error: not enough arguments");
5991     return 1;
5992   }
5993
5994   Standard_Integer anArgIter = 1;
5995   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
5996   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
5997   TCollection_AsciiString aDiffImagePath;
5998   Standard_Real    aTolColor        = -1.0;
5999   Standard_Integer toBlackWhite     = -1;
6000   Standard_Integer isBorderFilterOn = -1;
6001   Standard_Boolean isOldSyntax = Standard_False;
6002   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
6003   for (; anArgIter < theArgNb; ++anArgIter)
6004   {
6005     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6006     anArg.LowerCase();
6007     if (anArgIter + 1 < theArgNb
6008      && (anArg == "-toleranceofcolor"
6009       || anArg == "-tolerancecolor"
6010       || anArg == "-tolerance"
6011       || anArg == "-toler"))
6012     {
6013       aTolColor = Atof (theArgVec[++anArgIter]);
6014       if (aTolColor < 0.0 || aTolColor > 1.0)
6015       {
6016         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6017         return 1;
6018       }
6019     }
6020     else if (anArg == "-blackwhite")
6021     {
6022       Standard_Boolean toEnable = Standard_True;
6023       if (anArgIter + 1 < theArgNb
6024        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6025       {
6026         ++anArgIter;
6027       }
6028       toBlackWhite = toEnable ? 1 : 0;
6029     }
6030     else if (anArg == "-borderfilter")
6031     {
6032       Standard_Boolean toEnable = Standard_True;
6033       if (anArgIter + 1 < theArgNb
6034        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6035       {
6036         ++anArgIter;
6037       }
6038       isBorderFilterOn = toEnable ? 1 : 0;
6039     }
6040     else if (anArg == "-exitonclose")
6041     {
6042       ViewerTest_EventManager::ToExitOnCloseView() = true;
6043       if (anArgIter + 1 < theArgNb
6044        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
6045       {
6046         ++anArgIter;
6047       }
6048     }
6049     else if (anArg == "-closeonescape"
6050           || anArg == "-closeonesc")
6051     {
6052       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
6053       if (anArgIter + 1 < theArgNb
6054        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
6055       {
6056         ++anArgIter;
6057       }
6058     }
6059     else if (anArgIter + 3 < theArgNb
6060           && anArg == "-display")
6061     {
6062       aViewName   = theArgVec[++anArgIter];
6063       aPrsNameRef = theArgVec[++anArgIter];
6064       aPrsNameNew = theArgVec[++anArgIter];
6065       if (anArgIter + 1 < theArgNb
6066       && *theArgVec[anArgIter + 1] != '-')
6067       {
6068         aPrsNameDiff = theArgVec[++anArgIter];
6069       }
6070     }
6071     else if (aTolColor < 0.0
6072           && anArg.IsRealValue (Standard_True))
6073     {
6074       isOldSyntax = Standard_True;
6075       aTolColor = anArg.RealValue();
6076       if (aTolColor < 0.0 || aTolColor > 1.0)
6077       {
6078         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6079         return 1;
6080       }
6081     }
6082     else if (isOldSyntax
6083           && toBlackWhite == -1
6084           && (anArg == "0" || anArg == "1"))
6085     {
6086       toBlackWhite = anArg == "1" ? 1 : 0;
6087     }
6088     else if (isOldSyntax
6089           && isBorderFilterOn == -1
6090           && (anArg == "0" || anArg == "1"))
6091     {
6092       isBorderFilterOn = anArg == "1" ? 1 : 0;
6093     }
6094     else if (aDiffImagePath.IsEmpty())
6095     {
6096       aDiffImagePath = theArgVec[anArgIter];
6097     }
6098     else
6099     {
6100       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6101       return 1;
6102     }
6103   }
6104
6105   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
6106   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
6107   if (!anImgRef->Load (anImgPathRef))
6108   {
6109     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
6110     return 1;
6111   }
6112   if (!anImgNew->Load (anImgPathNew))
6113   {
6114     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
6115     return 1;
6116   }
6117
6118   // compare the images
6119   Image_Diff aComparer;
6120   Standard_Integer aDiffColorsNb = -1;
6121   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
6122   {
6123     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
6124     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
6125     aDiffColorsNb = aComparer.Compare();
6126     theDI << aDiffColorsNb << "\n";
6127   }
6128
6129   // save image of difference
6130   Handle(Image_AlienPixMap) aDiff;
6131   if (aDiffColorsNb > 0
6132   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
6133   {
6134     aDiff = new Image_AlienPixMap();
6135     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
6136     {
6137       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
6138       return 1;
6139     }
6140     aComparer.SaveDiffImage (*aDiff);
6141     if (!aDiffImagePath.IsEmpty()
6142      && !aDiff->Save (aDiffImagePath))
6143     {
6144       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
6145       return 1;
6146     }
6147   }
6148
6149   if (aViewName.IsEmpty())
6150   {
6151     return 0;
6152   }
6153
6154   ViewerTest_Names aViewNames (aViewName);
6155   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
6156   {
6157     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
6158     theDI.Eval (aCommand.ToCString());
6159   }
6160
6161   Standard_Integer aPxLeft = 0;
6162   Standard_Integer aPxTop  = 0;
6163   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
6164   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
6165                               ? int(anImgRef->SizeY() * 2)
6166                               : int(anImgRef->SizeY());
6167   TCollection_AsciiString aDisplayName;
6168   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
6169                                                             aViewName, aDisplayName);
6170
6171   Standard_Real aRatio = anImgRef->Ratio();
6172   Standard_Real aSizeX = 1.0;
6173   Standard_Real aSizeY = aSizeX / aRatio;
6174   {
6175     OSD_Path aPath (anImgPathRef);
6176     TCollection_AsciiString aLabelRef;
6177     if (!aPath.Name().IsEmpty())
6178     {
6179       aLabelRef = aPath.Name() + aPath.Extension();
6180     }
6181     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
6182
6183     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
6184     gp_Trsf aTrsfRef;
6185     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
6186     anImgRefPrs->SetLocalTransformation (aTrsfRef);
6187     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
6188   }
6189   {
6190     OSD_Path aPath (anImgPathNew);
6191     TCollection_AsciiString aLabelNew;
6192     if (!aPath.Name().IsEmpty())
6193     {
6194       aLabelNew = aPath.Name() + aPath.Extension();
6195     }
6196     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
6197
6198     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
6199     gp_Trsf aTrsfRef;
6200     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
6201     anImgNewPrs->SetLocalTransformation (aTrsfRef);
6202     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
6203   }
6204   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
6205   if (!aDiff.IsNull())
6206   {
6207     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
6208     gp_Trsf aTrsfDiff;
6209     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
6210     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
6211   }
6212   if (!aPrsNameDiff.IsEmpty())
6213   {
6214     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
6215   }
6216   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
6217   ViewerTest::CurrentView()->FitAll();
6218   return 0;
6219 }
6220
6221 //=======================================================================
6222 //function : VSelect
6223 //purpose  : Emulates different types of selection by mouse:
6224 //           1) single click selection
6225 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
6226 //           3) selection with polygon having corners at
6227 //           pixel positions (x1,y1),...,(xn,yn)
6228 //           4) any of these selections with shift button pressed
6229 //=======================================================================
6230 static Standard_Integer VSelect (Draw_Interpretor& ,
6231                                  Standard_Integer theNbArgs,
6232                                  const char** theArgVec)
6233 {
6234   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
6235   if (aCtx.IsNull())
6236   {
6237     Message::SendFail ("Error: no active viewer");
6238     return 1;
6239   }
6240
6241   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
6242   bool toAllowOverlap = false;
6243   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
6244   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6245   {
6246     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6247     anArg.LowerCase();
6248     if (anArg == "-allowoverlap")
6249     {
6250       toAllowOverlap = true;
6251       if (anArgIter + 1 < theNbArgs
6252        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
6253       {
6254         ++anArgIter;
6255       }
6256     }
6257     else if (anArg == "-replace")
6258     {
6259       aSelScheme = AIS_SelectionScheme_Replace;
6260     }
6261     else if (anArg == "-replaceextra")
6262     {
6263       aSelScheme = AIS_SelectionScheme_ReplaceExtra;
6264     }
6265     else if (anArg == "-xor"
6266           || anArg == "-shift")
6267     {
6268       aSelScheme = AIS_SelectionScheme_XOR;
6269     }
6270     else if (anArg == "-add")
6271     {
6272       aSelScheme = AIS_SelectionScheme_Add;
6273     }
6274     else if (anArg == "-remove")
6275     {
6276       aSelScheme = AIS_SelectionScheme_Remove;
6277     }
6278     else if (anArgIter + 1 < theNbArgs
6279           && anArg.IsIntegerValue()
6280           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
6281     {
6282       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
6283       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
6284     }
6285     else if (anArgIter + 1 == theNbArgs
6286           && anArg.IsIntegerValue())
6287     {
6288       if (anArg.IntegerValue() == 1)
6289       {
6290         aSelScheme = AIS_SelectionScheme_XOR;
6291       }
6292     }
6293     else
6294     {
6295       Message::SendFail() << "Syntax error at '" << anArg << "'";
6296       return 1;
6297     }
6298   }
6299
6300   if (toAllowOverlap)
6301   {
6302     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
6303   }
6304
6305   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
6306   if (aPnts.IsEmpty())
6307   {
6308     aCtx->SelectDetected (aSelScheme);
6309     aCtx->CurrentViewer()->Invalidate();
6310   }
6311   else if (aPnts.Length() == 2)
6312   {
6313     if (toAllowOverlap
6314      && aPnts.First().y() < aPnts.Last().y())
6315     {
6316       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6317     }
6318     else if (!toAllowOverlap
6319            && aPnts.First().y() > aPnts.Last().y())
6320     {
6321       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6322     }
6323
6324     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6325   }
6326   else
6327   {
6328     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6329   }
6330   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
6331   return 0;
6332 }
6333
6334 //=======================================================================
6335 //function : VMoveTo
6336 //purpose  : Emulates cursor movement to defined pixel position
6337 //=======================================================================
6338 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
6339                                 Standard_Integer theNbArgs,
6340                                 const char**     theArgVec)
6341 {
6342   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6343   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6344   if (aContext.IsNull())
6345   {
6346     Message::SendFail ("Error: no active viewer");
6347     return 1;
6348   }
6349
6350   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
6351   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6352   {
6353     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6354     anArgStr.LowerCase();
6355     if (anArgStr == "-reset"
6356      || anArgStr == "-clear")
6357     {
6358       if (anArgIter + 1 < theNbArgs)
6359       {
6360         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
6361         return 1;
6362       }
6363
6364       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
6365                                        && aContext->CurrentViewer()->GridEcho();
6366       if (toEchoGrid)
6367       {
6368         aContext->CurrentViewer()->HideGridEcho (aView);
6369       }
6370       if (aContext->ClearDetected() || toEchoGrid)
6371       {
6372         aContext->CurrentViewer()->RedrawImmediate();
6373       }
6374       return 0;
6375     }
6376     else if (aMousePos.x() == IntegerLast()
6377           && anArgStr.IsIntegerValue())
6378     {
6379       aMousePos.x() = anArgStr.IntegerValue();
6380     }
6381     else if (aMousePos.y() == IntegerLast()
6382           && anArgStr.IsIntegerValue())
6383     {
6384       aMousePos.y() = anArgStr.IntegerValue();
6385     }
6386     else
6387     {
6388       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6389       return 1;
6390     }
6391   }
6392
6393   if (aMousePos.x() == IntegerLast()
6394    || aMousePos.y() == IntegerLast())
6395   {
6396     Message::SendFail ("Syntax error: wrong number of arguments");
6397     return 1;
6398   }
6399
6400   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
6401   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
6402   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
6403
6404   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
6405   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
6406   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
6407   {
6408     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
6409     {
6410       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
6411       break;
6412     }
6413   }
6414   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
6415   return 0;
6416 }
6417
6418 //=======================================================================
6419 //function : VSelectByAxis
6420 //purpose  :
6421 //=======================================================================
6422 static Standard_Integer VSelectByAxis (Draw_Interpretor& theDI,
6423                                        Standard_Integer theNbArgs,
6424                                        const char**     theArgVec)
6425 {
6426   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6427   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6428   if (aContext.IsNull())
6429   {
6430     Message::SendFail ("Error: no active viewer");
6431     return 1;
6432   }
6433
6434   TCollection_AsciiString aName;
6435   gp_XYZ anAxisLocation(RealLast(), RealLast(), RealLast());
6436   gp_XYZ anAxisDirection(RealLast(), RealLast(), RealLast());
6437   Standard_Boolean isOnlyTop = true;
6438   Standard_Boolean toShowNormal = false;
6439   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6440   {
6441     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6442     anArgStr.LowerCase();
6443     if (anArgStr == "-display")
6444     {
6445       if (anArgIter + 1 >= theNbArgs)
6446       {
6447         Message::SendFail() << "Syntax error at argument '" << anArgStr << "'";
6448         return 1;
6449       }
6450       aName = theArgVec[++anArgIter];
6451     }
6452     else if (anArgStr == "-onlytop")
6453     {
6454       isOnlyTop = true;
6455       if (anArgIter + 1 < theNbArgs
6456         && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOnlyTop))
6457       {
6458         ++anArgIter;
6459       }
6460     }
6461     else if (anArgStr == "-shownormal")
6462     {
6463       toShowNormal = true;
6464       if (anArgIter + 1 < theNbArgs
6465         && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShowNormal))
6466       {
6467         ++anArgIter;
6468       }
6469     }
6470     else if (Precision::IsInfinite(anAxisLocation.X())
6471           && anArgStr.IsRealValue())
6472     {
6473       anAxisLocation.SetX (anArgStr.RealValue());
6474     }
6475     else if (Precision::IsInfinite(anAxisLocation.Y())
6476           && anArgStr.IsRealValue())
6477     {
6478       anAxisLocation.SetY (anArgStr.RealValue());
6479     }
6480     else if (Precision::IsInfinite(anAxisLocation.Z())
6481           && anArgStr.IsRealValue())
6482     {
6483       anAxisLocation.SetZ (anArgStr.RealValue());
6484     }
6485     else if (Precision::IsInfinite(anAxisDirection.X())
6486           && anArgStr.IsRealValue())
6487     {
6488       anAxisDirection.SetX (anArgStr.RealValue());
6489     }
6490     else if (Precision::IsInfinite(anAxisDirection.Y())
6491           && anArgStr.IsRealValue())
6492     {
6493       anAxisDirection.SetY (anArgStr.RealValue());
6494     }
6495     else if (Precision::IsInfinite(anAxisDirection.Z())
6496           && anArgStr.IsRealValue())
6497     {
6498       anAxisDirection.SetZ (anArgStr.RealValue());
6499     }
6500     else
6501     {
6502       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6503       return 1;
6504     }
6505   }
6506
6507   if (Precision::IsInfinite (anAxisLocation.X()) ||
6508       Precision::IsInfinite (anAxisLocation.Y()) ||
6509       Precision::IsInfinite (anAxisLocation.Z()) ||
6510       Precision::IsInfinite (anAxisDirection.X()) ||
6511       Precision::IsInfinite (anAxisDirection.Y()) ||
6512       Precision::IsInfinite (anAxisDirection.Z()))
6513   {
6514     Message::SendFail() << "Invalid axis location and direction";
6515     return 1;
6516   }
6517
6518   gp_Ax1 anAxis(anAxisLocation, anAxisDirection);
6519   gp_Pnt aTopPnt;
6520   if (!ViewerTest::CurrentEventManager()->PickAxis (aTopPnt, aContext, aView, anAxis))
6521   {
6522     theDI << "There are no any intersections with this axis.";
6523     return 0;
6524   }
6525   NCollection_Sequence<gp_Pnt> aPoints;
6526   NCollection_Sequence<Graphic3d_Vec3> aNormals;
6527   NCollection_Sequence<Standard_Real> aNormalLengths;
6528   for (Standard_Integer aPickIter = 1; aPickIter <= aContext->MainSelector()->NbPicked(); ++aPickIter)
6529   {
6530     const SelectMgr_SortCriterion& aPickedData = aContext->MainSelector()->PickedData (aPickIter);
6531     aPoints.Append (aPickedData.Point);
6532     aNormals.Append (aPickedData.Normal);
6533     Standard_Real aNormalLength = 1.0;
6534     if (!aPickedData.Entity.IsNull())
6535     {
6536       aNormalLength = 0.2 * aPickedData.Entity->BoundingBox().Size().maxComp();
6537     }
6538     aNormalLengths.Append (aNormalLength);
6539   }
6540   if (!aName.IsEmpty())
6541   {
6542     Standard_Boolean wasAuto = aContext->GetAutoActivateSelection();
6543     aContext->SetAutoActivateSelection (false);
6544
6545     // Display axis
6546     Quantity_Color anAxisColor = Quantity_NOC_GREEN;
6547     Handle(Geom_Axis2Placement) anAx2Axis =
6548       new Geom_Axis2Placement (gp_Ax2(anAxisLocation, anAxisDirection));
6549     Handle(AIS_Axis) anAISAxis = new AIS_Axis (gp_Ax1 (anAxisLocation, anAxisDirection));
6550     anAISAxis->SetColor (anAxisColor);
6551     ViewerTest::Display (TCollection_AsciiString (aName) + "_axis", anAISAxis, false);
6552
6553     // Display axis start point
6554     Handle(AIS_Point) anAISStartPnt = new AIS_Point (new Geom_CartesianPoint (anAxisLocation));
6555     anAISStartPnt->SetMarker (Aspect_TOM_O);
6556     anAISStartPnt->SetColor (anAxisColor);
6557     ViewerTest::Display (TCollection_AsciiString(aName) + "_start", anAISStartPnt, false);
6558
6559     Standard_Integer anIndex = 0;
6560     for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter(aPoints); aPntIter.More(); aPntIter.Next(), anIndex++)
6561     {
6562       const gp_Pnt& aPoint = aPntIter.Value();
6563
6564       // Display normals in intersection points
6565       if (toShowNormal)
6566       {
6567         const Graphic3d_Vec3& aNormal = aNormals.Value (anIndex + 1);
6568         Standard_Real aNormalLength = aNormalLengths.Value (anIndex + 1);
6569         if (aNormal.SquareModulus() > ShortRealEpsilon())
6570         {
6571           gp_Dir aNormalDir ((Standard_Real)aNormal.x(), (Standard_Real)aNormal.y(), (Standard_Real)aNormal.z());
6572           Handle(AIS_Axis) anAISNormal = new AIS_Axis (gp_Ax1 (aPoint, aNormalDir), aNormalLength);
6573           anAISNormal->SetColor (Quantity_NOC_BLUE);
6574           anAISNormal->SetInfiniteState (false);
6575           ViewerTest::Display (TCollection_AsciiString(aName) + "_normal_" + anIndex, anAISNormal, false);
6576         }
6577       }
6578
6579       // Display intersection points
6580       Handle(Geom_CartesianPoint) anIntersectPnt = new Geom_CartesianPoint (aPoint);
6581       Handle(AIS_Point) anAISIntersectPoint = new AIS_Point (anIntersectPnt);
6582       anAISIntersectPoint->SetMarker (Aspect_TOM_PLUS);
6583       anAISIntersectPoint->SetColor (Quantity_NOC_RED);
6584       ViewerTest::Display (TCollection_AsciiString(aName) + "_intersect_" + anIndex, anAISIntersectPoint, true);
6585     }
6586
6587     aContext->SetAutoActivateSelection (wasAuto);
6588   }
6589
6590   Standard_Integer anIndex = 0;
6591   for (NCollection_Sequence<gp_Pnt>::Iterator anIter(aPoints); anIter.More(); anIter.Next(), anIndex++)
6592   {
6593     const gp_Pnt& aPnt = anIter.Value();
6594     theDI << aPnt.X() << " " << aPnt.Y() << " " << aPnt.Z() << "\n";
6595   }
6596   return 0;
6597 }
6598
6599 namespace
6600 {
6601   //! Global map storing all animations registered in ViewerTest.
6602   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
6603
6604   //! The animation calling the Draw Harness command.
6605   class ViewerTest_AnimationProc : public AIS_Animation
6606   {
6607     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationProc, AIS_Animation)
6608   public:
6609
6610     //! Main constructor.
6611     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
6612                               Draw_Interpretor* theDI,
6613                               const TCollection_AsciiString& theCommand)
6614     : AIS_Animation (theAnimationName),
6615       myDrawInter(theDI),
6616       myCommand  (theCommand)
6617     {
6618       //
6619     }
6620
6621   protected:
6622
6623     //! Evaluate the command.
6624     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
6625     {
6626       TCollection_AsciiString aCmd = myCommand;
6627       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
6628       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
6629       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
6630       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
6631       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
6632       myDrawInter->Eval (aCmd.ToCString());
6633     }
6634
6635     //! Find the keyword in the command and replace it with value.
6636     //! @return the position of the keyword to pass value
6637     void replace (TCollection_AsciiString&       theCmd,
6638                   const TCollection_AsciiString& theKey,
6639                   const TCollection_AsciiString& theVal)
6640     {
6641       TCollection_AsciiString aCmd (theCmd);
6642       aCmd.LowerCase();
6643       const Standard_Integer aPos = aCmd.Search (theKey);
6644       if (aPos == -1)
6645       {
6646         return;
6647       }
6648
6649       TCollection_AsciiString aPart1, aPart2;
6650       Standard_Integer aPart1To = aPos - 1;
6651       if (aPart1To >= 1
6652        && aPart1To <= theCmd.Length())
6653       {
6654         aPart1 = theCmd.SubString (1, aPart1To);
6655       }
6656
6657       Standard_Integer aPart2From = aPos + theKey.Length();
6658       if (aPart2From >= 1
6659        && aPart2From <= theCmd.Length())
6660       {
6661         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
6662       }
6663
6664       theCmd = aPart1 + theVal + aPart2;
6665     }
6666
6667   protected:
6668
6669     Draw_Interpretor*       myDrawInter;
6670     TCollection_AsciiString myCommand;
6671
6672   };
6673
6674   //! Auxiliary animation holder.
6675   class ViewerTest_AnimationHolder : public AIS_AnimationCamera
6676   {
6677     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationHolder, AIS_AnimationCamera)
6678   public:
6679     ViewerTest_AnimationHolder (const Handle(AIS_Animation)& theAnim,
6680                                 const Handle(V3d_View)& theView,
6681                                 const Standard_Boolean theIsFreeView)
6682     : AIS_AnimationCamera ("ViewerTest_AnimationHolder", Handle(V3d_View)())
6683     {
6684       if (theAnim->Timer().IsNull())
6685       {
6686         theAnim->SetTimer (new Media_Timer());
6687       }
6688       myTimer = theAnim->Timer();
6689       myView = theView;
6690       if (theIsFreeView)
6691       {
6692         myCamStart = new Graphic3d_Camera (theView->Camera());
6693       }
6694       Add (theAnim);
6695     }
6696
6697     //! Start playback.
6698     virtual void StartTimer (const Standard_Real    theStartPts,
6699                              const Standard_Real    thePlaySpeed,
6700                              const Standard_Boolean theToUpdate,
6701                              const Standard_Boolean theToStopTimer) Standard_OVERRIDE
6702     {
6703       base_type::StartTimer (theStartPts, thePlaySpeed, theToUpdate, theToStopTimer);
6704       if (theToStopTimer)
6705       {
6706         abortPlayback();
6707       }
6708     }
6709
6710     //! Pause animation.
6711     virtual void Pause() Standard_OVERRIDE
6712     {
6713       myState = AnimationState_Paused;
6714       // default implementation would stop all children,
6715       // but we want to keep wrapped animation paused
6716       myAnimations.First()->Pause();
6717       abortPlayback();
6718     }
6719
6720     //! Stop animation.
6721     virtual void Stop() Standard_OVERRIDE
6722     {
6723       base_type::Stop();
6724       abortPlayback();
6725     }
6726
6727     //! Process one step of the animation according to the input time progress, including all children.
6728     virtual void updateWithChildren (const AIS_AnimationProgress& thePosition) Standard_OVERRIDE
6729     {
6730       Handle(V3d_View) aView = myView;
6731       if (!aView.IsNull()
6732        && !myCamStart.IsNull())
6733       {
6734         myCamStart->Copy (aView->Camera());
6735       }
6736       base_type::updateWithChildren (thePosition);
6737       if (!aView.IsNull()
6738        && !myCamStart.IsNull())
6739       {
6740         aView->Camera()->Copy (myCamStart);
6741       }
6742     }
6743   private:
6744     void abortPlayback()
6745     {
6746       if (!myView.IsNull())
6747       {
6748         myView.Nullify();
6749       }
6750     }
6751   };
6752
6753   //! Replace the animation with the new one.
6754   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
6755                                 Handle(AIS_Animation)&       theAnimation,
6756                                 const Handle(AIS_Animation)& theAnimationNew)
6757   {
6758     theAnimationNew->CopyFrom (theAnimation);
6759     if (!theParentAnimation.IsNull())
6760     {
6761       theParentAnimation->Replace (theAnimation, theAnimationNew);
6762     }
6763     else
6764     {
6765       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
6766       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
6767     }
6768     theAnimation = theAnimationNew;
6769   }
6770
6771   //! Parse the point.
6772   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
6773   {
6774     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
6775     if (!anXYZ[0].IsRealValue (Standard_True)
6776      || !anXYZ[1].IsRealValue (Standard_True)
6777      || !anXYZ[2].IsRealValue (Standard_True))
6778     {
6779       return Standard_False;
6780     }
6781
6782     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
6783     return Standard_True;
6784   }
6785
6786   //! Parse the quaternion.
6787   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
6788   {
6789     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
6790     if (!anXYZW[0].IsRealValue (Standard_True)
6791      || !anXYZW[1].IsRealValue (Standard_True)
6792      || !anXYZW[2].IsRealValue (Standard_True)
6793      || !anXYZW[3].IsRealValue (Standard_True))
6794     {
6795       return Standard_False;
6796     }
6797
6798     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
6799     return Standard_True;
6800   }
6801
6802   //! Auxiliary class for flipping image upside-down.
6803   class ImageFlipper
6804   {
6805   public:
6806
6807     //! Empty constructor.
6808     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
6809
6810     //! Perform flipping.
6811     Standard_Boolean FlipY (Image_PixMap& theImage)
6812     {
6813       if (theImage.IsEmpty()
6814        || theImage.SizeX() == 0
6815        || theImage.SizeY() == 0)
6816       {
6817         return Standard_False;
6818       }
6819
6820       const Standard_Size aRowSize = theImage.SizeRowBytes();
6821       if (myTmp.Size() < aRowSize
6822       && !myTmp.Allocate (aRowSize))
6823       {
6824         return Standard_False;
6825       }
6826
6827       // for odd height middle row should be left as is
6828       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
6829       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
6830       {
6831         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
6832         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
6833         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
6834         memcpy (aTop,               aBot,         aRowSize);
6835         memcpy (aBot,               myTmp.Data(), aRowSize);
6836       }
6837       return Standard_True;
6838     }
6839
6840   private:
6841     NCollection_Buffer myTmp;
6842   };
6843
6844 }
6845
6846 //=================================================================================================
6847 //function : VViewParams
6848 //purpose  : Gets or sets AIS View characteristics
6849 //=================================================================================================
6850 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
6851 {
6852   Handle(V3d_View) aView = ViewerTest::CurrentView();
6853   if (aView.IsNull())
6854   {
6855     Message::SendFail ("Error: no active viewer");
6856     return 1;
6857   }
6858
6859   Standard_Boolean toSetProj     = Standard_False;
6860   Standard_Boolean toSetUp       = Standard_False;
6861   Standard_Boolean toSetAt       = Standard_False;
6862   Standard_Boolean toSetEye      = Standard_False;
6863   Standard_Boolean toSetScale    = Standard_False;
6864   Standard_Boolean toSetSize     = Standard_False;
6865   Standard_Boolean toSetCenter2d = Standard_False;
6866   Standard_Real    aViewScale = aView->Scale();
6867   Standard_Real    aViewAspect = aView->Camera()->Aspect();
6868   Standard_Real    aViewSize  = 1.0;
6869   Graphic3d_Vec2i  aCenter2d;
6870   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
6871   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
6872   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
6873   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
6874   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
6875   const Graphic3d_Mat4d& anOrientMat = aView->Camera()->OrientationMatrix();
6876   const Graphic3d_Mat4d& aProjMat = aView->Camera()->ProjectionMatrix();
6877   if (theArgsNb == 1)
6878   {
6879     // print all of the available view parameters
6880     char aText[4096];
6881     Sprintf (aText,
6882              "Scale:  %g\n"
6883              "Aspect: %g\n"
6884              "Proj:   %12g %12g %12g\n"
6885              "Up:     %12g %12g %12g\n"
6886              "At:     %12g %12g %12g\n"
6887              "Eye:    %12g %12g %12g\n"
6888              "OrientMat:    %12g %12g %12g %12g\n"
6889              "              %12g %12g %12g %12g\n"
6890              "              %12g %12g %12g %12g\n"
6891              "              %12g %12g %12g %12g\n"
6892              "ProjMat:      %12g %12g %12g %12g\n"
6893              "              %12g %12g %12g %12g\n"
6894              "              %12g %12g %12g %12g\n"
6895              "              %12g %12g %12g %12g\n",
6896               aViewScale, aViewAspect,
6897               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6898               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6899               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
6900               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z(),
6901               anOrientMat.GetValue (0, 0), anOrientMat.GetValue (0, 1), anOrientMat.GetValue (0, 2), anOrientMat.GetValue (0, 3),
6902               anOrientMat.GetValue (1, 0), anOrientMat.GetValue (1, 1), anOrientMat.GetValue (1, 2), anOrientMat.GetValue (1, 3),
6903               anOrientMat.GetValue (2, 0), anOrientMat.GetValue (2, 1), anOrientMat.GetValue (2, 2), anOrientMat.GetValue (2, 3),
6904               anOrientMat.GetValue (3, 0), anOrientMat.GetValue (3, 1), anOrientMat.GetValue (3, 2), anOrientMat.GetValue (3, 3),
6905               aProjMat.GetValue (0, 0), aProjMat.GetValue (0, 1), aProjMat.GetValue (0, 2), aProjMat.GetValue (0, 3),
6906               aProjMat.GetValue (1, 0), aProjMat.GetValue (1, 1), aProjMat.GetValue (1, 2), aProjMat.GetValue (1, 3),
6907               aProjMat.GetValue (2, 0), aProjMat.GetValue (2, 1), aProjMat.GetValue (2, 2), aProjMat.GetValue (2, 3),
6908               aProjMat.GetValue (3, 0), aProjMat.GetValue (3, 1), aProjMat.GetValue (3, 2), aProjMat.GetValue (3, 3));
6909     theDi << aText;
6910     return 0;
6911   }
6912
6913   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
6914   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
6915   {
6916     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6917     anArg.LowerCase();
6918     if (anUpdateTool.parseRedrawMode (anArg))
6919     {
6920       continue;
6921     }
6922     else if (anArg == "-cmd"
6923           || anArg == "-command"
6924           || anArg == "-args")
6925     {
6926       char aText[4096];
6927       Sprintf (aText,
6928                "-scale %g "
6929                "-proj %g %g %g "
6930                "-up %g %g %g "
6931                "-at %g %g %g\n",
6932                 aViewScale,
6933                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6934                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6935                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
6936       theDi << aText;
6937     }
6938     else if (anArg == "-scale"
6939           || anArg == "-size")
6940     {
6941       if (anArgIter + 1 < theArgsNb
6942        && *theArgVec[anArgIter + 1] != '-')
6943       {
6944         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
6945         if (aValueArg.IsRealValue (Standard_True))
6946         {
6947           ++anArgIter;
6948           if (anArg == "-scale")
6949           {
6950             toSetScale = Standard_True;
6951             aViewScale = aValueArg.RealValue();
6952           }
6953           else if (anArg == "-size")
6954           {
6955             toSetSize = Standard_True;
6956             aViewSize = aValueArg.RealValue();
6957           }
6958           continue;
6959         }
6960       }
6961       if (anArg == "-scale")
6962       {
6963         theDi << "Scale: " << aView->Scale() << "\n";
6964       }
6965       else if (anArg == "-size")
6966       {
6967         Graphic3d_Vec2d aSizeXY;
6968         aView->Size (aSizeXY.x(), aSizeXY.y());
6969         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
6970       }
6971     }
6972     else if (anArg == "-eye"
6973           || anArg == "-at"
6974           || anArg == "-up"
6975           || anArg == "-proj")
6976     {
6977       if (anArgIter + 3 < theArgsNb)
6978       {
6979         gp_XYZ anXYZ;
6980         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
6981         {
6982           anArgIter += 3;
6983           if (anArg == "-eye")
6984           {
6985             toSetEye = Standard_True;
6986             aViewEye = anXYZ;
6987           }
6988           else if (anArg == "-at")
6989           {
6990             toSetAt = Standard_True;
6991             aViewAt = anXYZ;
6992           }
6993           else if (anArg == "-up")
6994           {
6995             toSetUp = Standard_True;
6996             aViewUp = anXYZ;
6997           }
6998           else if (anArg == "-proj")
6999           {
7000             toSetProj = Standard_True;
7001             aViewProj = anXYZ;
7002           }
7003           continue;
7004         }
7005       }
7006
7007       if (anArg == "-eye")
7008       {
7009         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
7010       }
7011       else if (anArg == "-at")
7012       {
7013         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
7014       }
7015       else if (anArg == "-up")
7016       {
7017         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
7018       }
7019       else if (anArg == "-proj")
7020       {
7021         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
7022       }
7023     }
7024     else if (anArg == "-center")
7025     {
7026       if (anArgIter + 2 < theArgsNb)
7027       {
7028         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
7029         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
7030         if (anX.IsIntegerValue()
7031          && anY.IsIntegerValue())
7032         {
7033           toSetCenter2d = Standard_True;
7034           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
7035         }
7036       }
7037     }
7038     else
7039     {
7040       Message::SendFail() << "Syntax error at '" << anArg << "'";
7041       return 1;
7042     }
7043   }
7044
7045   // change view parameters in proper order
7046   if (toSetScale)
7047   {
7048     aView->SetScale (aViewScale);
7049   }
7050   if (toSetSize)
7051   {
7052     aView->SetSize (aViewSize);
7053   }
7054   if (toSetEye)
7055   {
7056     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
7057   }
7058   if (toSetAt)
7059   {
7060     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
7061   }
7062   if (toSetProj)
7063   {
7064     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
7065   }
7066   if (toSetUp)
7067   {
7068     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
7069   }
7070   if (toSetCenter2d)
7071   {
7072     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
7073   }
7074
7075   return 0;
7076 }
7077
7078 //==============================================================================
7079 //function : V2DMode
7080 //purpose  :
7081 //==============================================================================
7082 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
7083 {
7084   bool is2dMode = true;
7085   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
7086   if (aV3dView.IsNull())
7087   {
7088     Message::SendFail ("Error: no active viewer");
7089     return 1;
7090   }
7091   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
7092   {
7093     const TCollection_AsciiString anArg = theArgVec[anArgIt];
7094     TCollection_AsciiString anArgCase = anArg;
7095     anArgCase.LowerCase();
7096     if (anArgIt + 1 < theArgsNb
7097      && anArgCase == "-name")
7098     {
7099       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
7100       TCollection_AsciiString aViewName = aViewNames.GetViewName();
7101       if (!ViewerTest_myViews.IsBound1 (aViewName))
7102       {
7103         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
7104         return 1;
7105       }
7106       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
7107     }
7108     else if (anArgCase == "-mode")
7109     {
7110       if (anArgIt + 1 < theArgsNb
7111        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
7112       {
7113         ++anArgIt;
7114       }
7115     }
7116     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
7117     {
7118       //
7119     }
7120     else
7121     {
7122       Message::SendFail() << "Syntax error: unknown argument " << anArg;
7123       return 1;
7124     }
7125   }
7126
7127   aV3dView->SetView2DMode (is2dMode);
7128   return 0;
7129 }
7130
7131 //==============================================================================
7132 //function : VAnimation
7133 //purpose  :
7134 //==============================================================================
7135 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
7136                                     Standard_Integer  theArgNb,
7137                                     const char**      theArgVec)
7138 {
7139   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
7140   if (theArgNb < 2)
7141   {
7142     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
7143          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
7144     {
7145       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
7146     }
7147     return 0;
7148   }
7149   if (aCtx.IsNull())
7150   {
7151     Message::SendFail ("Error: no active viewer");
7152     return 1;
7153   }
7154
7155   Standard_Integer anArgIter = 1;
7156   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
7157   if (aNameArg.IsEmpty())
7158   {
7159     Message::SendFail ("Syntax error: animation name is not defined");
7160     return 1;
7161   }
7162
7163   TCollection_AsciiString aNameArgLower = aNameArg;
7164   aNameArgLower.LowerCase();
7165   if (aNameArgLower == "-reset"
7166    || aNameArgLower == "-clear")
7167   {
7168     ViewerTest_AnimationTimelineMap.Clear();
7169     return 0;
7170   }
7171   else if (aNameArg.Value (1) == '-')
7172   {
7173     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
7174     return 1;
7175   }
7176
7177   const char* aNameSplitter = "/";
7178   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
7179   if (aSplitPos == -1)
7180   {
7181     aNameSplitter = ".";
7182     aSplitPos = aNameArg.Search (aNameSplitter);
7183   }
7184
7185   // find existing or create a new animation by specified name within syntax "parent.child".
7186   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
7187   for (; !aNameArg.IsEmpty();)
7188   {
7189     TCollection_AsciiString aNameParent;
7190     if (aSplitPos != -1)
7191     {
7192       if (aSplitPos == aNameArg.Length())
7193       {
7194         Message::SendFail ("Syntax error: animation name is not defined");
7195         return 1;
7196       }
7197
7198       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
7199       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
7200
7201       aSplitPos = aNameArg.Search (aNameSplitter);
7202     }
7203     else
7204     {
7205       aNameParent = aNameArg;
7206       aNameArg.Clear();
7207     }
7208
7209     if (anAnimation.IsNull())
7210     {
7211       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
7212       {
7213         anAnimation = new AIS_Animation (aNameParent);
7214         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
7215       }
7216       aRootAnimation = anAnimation;
7217     }
7218     else
7219     {
7220       aParentAnimation = anAnimation;
7221       anAnimation = aParentAnimation->Find (aNameParent);
7222       if (anAnimation.IsNull())
7223       {
7224         anAnimation = new AIS_Animation (aNameParent);
7225         aParentAnimation->Add (anAnimation);
7226       }
7227     }
7228   }
7229   if (anAnimation.IsNull())
7230   {
7231     Message::SendFail() << "Syntax error: wrong number of arguments";
7232     return 1;
7233   }
7234
7235   if (anArgIter >= theArgNb)
7236   {
7237     // just print the list of children
7238     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
7239     {
7240       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
7241     }
7242     return 0;
7243   }
7244
7245   // animation parameters
7246   Standard_Boolean toPlay = Standard_False;
7247   Standard_Real aPlaySpeed     = 1.0;
7248   Standard_Real aPlayStartTime = anAnimation->StartPts();
7249   Standard_Real aPlayDuration  = anAnimation->Duration();
7250   Standard_Boolean isFreeCamera = Standard_False;
7251   Standard_Boolean toPauseOnClick = Standard_True;
7252   Standard_Boolean isLockLoop   = Standard_False;
7253
7254   // video recording parameters
7255   TCollection_AsciiString aRecFile;
7256   Image_VideoParams aRecParams;
7257
7258   Handle(V3d_View) aView = ViewerTest::CurrentView();
7259   for (; anArgIter < theArgNb; ++anArgIter)
7260   {
7261     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7262     anArg.LowerCase();
7263     // general options
7264     if (anArg == "-reset"
7265      || anArg == "-clear")
7266     {
7267       anAnimation->Clear();
7268     }
7269     else if (anArg == "-remove"
7270           || anArg == "-del"
7271           || anArg == "-delete")
7272     {
7273       if (aParentAnimation.IsNull())
7274       {
7275         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
7276       }
7277       else
7278       {
7279         aParentAnimation->Remove (anAnimation);
7280       }
7281     }
7282     // playback options
7283     else if (anArg == "-play")
7284     {
7285       toPlay = Standard_True;
7286       if (++anArgIter < theArgNb)
7287       {
7288         if (*theArgVec[anArgIter] == '-')
7289         {
7290           --anArgIter;
7291           continue;
7292         }
7293         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
7294
7295         if (++anArgIter < theArgNb)
7296         {
7297           if (*theArgVec[anArgIter] == '-')
7298           {
7299             --anArgIter;
7300             continue;
7301           }
7302           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7303         }
7304       }
7305     }
7306     else if (anArg == "-resume")
7307     {
7308       toPlay = Standard_True;
7309       aPlayStartTime = anAnimation->ElapsedTime();
7310       if (++anArgIter < theArgNb)
7311       {
7312         if (*theArgVec[anArgIter] == '-')
7313         {
7314           --anArgIter;
7315           continue;
7316         }
7317
7318         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7319       }
7320     }
7321     else if (anArg == "-pause")
7322     {
7323       anAnimation->Pause();
7324     }
7325     else if (anArg == "-stop")
7326     {
7327       anAnimation->Stop();
7328     }
7329     else if (anArg == "-playspeed"
7330           || anArg == "-speed")
7331     {
7332       if (++anArgIter >= theArgNb)
7333       {
7334         Message::SendFail() << "Syntax error at " << anArg << "";
7335         return 1;
7336       }
7337       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
7338     }
7339     else if (anArg == "-lock"
7340           || anArg == "-lockloop"
7341           || anArg == "-playlockloop")
7342     {
7343       isLockLoop = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
7344     }
7345     else if (anArg == "-freecamera"
7346           || anArg == "-nofreecamera"
7347           || anArg == "-playfreecamera"
7348           || anArg == "-noplayfreecamera"
7349           || anArg == "-freelook"
7350           || anArg == "-nofreelook")
7351     {
7352       isFreeCamera = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7353     }
7354     else if (anArg == "-pauseonclick"
7355           || anArg == "-nopauseonclick"
7356           || anArg == "-nopause")
7357     {
7358       toPauseOnClick = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7359     }
7360     // video recodring options
7361     else if (anArg == "-rec"
7362           || anArg == "-record")
7363     {
7364       if (++anArgIter >= theArgNb)
7365       {
7366         Message::SendFail() << "Syntax error at " << anArg;
7367         return 1;
7368       }
7369
7370       aRecFile = theArgVec[anArgIter];
7371       if (aRecParams.FpsNum <= 0)
7372       {
7373         aRecParams.FpsNum = 24;
7374       }
7375
7376       if (anArgIter + 2 < theArgNb
7377       && *theArgVec[anArgIter + 1] != '-'
7378       && *theArgVec[anArgIter + 2] != '-')
7379       {
7380         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
7381         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
7382         if (aWidthArg .IsIntegerValue()
7383          && aHeightArg.IsIntegerValue())
7384         {
7385           aRecParams.Width  = aWidthArg .IntegerValue();
7386           aRecParams.Height = aHeightArg.IntegerValue();
7387           anArgIter += 2;
7388         }
7389       }
7390     }
7391     else if (anArg == "-fps")
7392     {
7393       if (++anArgIter >= theArgNb)
7394       {
7395         Message::SendFail() << "Syntax error at " << anArg;
7396         return 1;
7397       }
7398
7399       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
7400       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
7401       if (aSplitIndex == 0)
7402       {
7403         aRecParams.FpsNum = aFpsArg.IntegerValue();
7404       }
7405       else
7406       {
7407         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
7408         aFpsArg.Split (aFpsArg.Length() - 1);
7409         const TCollection_AsciiString aNumStr = aFpsArg;
7410         aRecParams.FpsNum = aNumStr.IntegerValue();
7411         aRecParams.FpsDen = aDenStr.IntegerValue();
7412         if (aRecParams.FpsDen < 1)
7413         {
7414           Message::SendFail() << "Syntax error at " << anArg;
7415           return 1;
7416         }
7417       }
7418     }
7419     else if (anArg == "-format")
7420     {
7421       if (++anArgIter >= theArgNb)
7422       {
7423         Message::SendFail() << "Syntax error at " << anArg;
7424         return 1;
7425       }
7426       aRecParams.Format = theArgVec[anArgIter];
7427     }
7428     else if (anArg == "-pix_fmt"
7429           || anArg == "-pixfmt"
7430           || anArg == "-pixelformat")
7431     {
7432       if (++anArgIter >= theArgNb)
7433       {
7434         Message::SendFail() << "Syntax error at " << anArg;
7435         return 1;
7436       }
7437       aRecParams.PixelFormat = theArgVec[anArgIter];
7438     }
7439     else if (anArg == "-codec"
7440           || anArg == "-vcodec"
7441           || anArg == "-videocodec")
7442     {
7443       if (++anArgIter >= theArgNb)
7444       {
7445         Message::SendFail() << "Syntax error at " << anArg;
7446         return 1;
7447       }
7448       aRecParams.VideoCodec = theArgVec[anArgIter];
7449     }
7450     else if (anArg == "-crf"
7451           || anArg == "-preset"
7452           || anArg == "-qp")
7453     {
7454       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
7455       if (++anArgIter >= theArgNb)
7456       {
7457         Message::SendFail() << "Syntax error at " << anArg;
7458         return 1;
7459       }
7460
7461       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
7462     }
7463     // animation definition options
7464     else if (anArg == "-start"
7465           || anArg == "-starttime"
7466           || anArg == "-startpts")
7467     {
7468       if (++anArgIter >= theArgNb)
7469       {
7470         Message::SendFail() << "Syntax error at " << anArg;
7471         return 1;
7472       }
7473
7474       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
7475       aRootAnimation->UpdateTotalDuration();
7476     }
7477     else if (anArg == "-end"
7478           || anArg == "-endtime"
7479           || anArg == "-endpts")
7480     {
7481       if (++anArgIter >= theArgNb)
7482       {
7483         Message::SendFail() << "Syntax error at " << anArg;
7484         return 1;
7485       }
7486
7487       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
7488       aRootAnimation->UpdateTotalDuration();
7489     }
7490     else if (anArg == "-dur"
7491           || anArg == "-duration")
7492     {
7493       if (++anArgIter >= theArgNb)
7494       {
7495         Message::SendFail() << "Syntax error at " << anArg;
7496         return 1;
7497       }
7498
7499       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
7500       aRootAnimation->UpdateTotalDuration();
7501     }
7502     else if (anArg == "-command"
7503           || anArg == "-cmd"
7504           || anArg == "-invoke"
7505           || anArg == "-eval"
7506           || anArg == "-proc")
7507     {
7508       if (++anArgIter >= theArgNb)
7509       {
7510         Message::SendFail() << "Syntax error at " << anArg;
7511         return 1;
7512       }
7513
7514       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
7515       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
7516     }
7517     else if (anArg == "-objecttrsf"
7518           || anArg == "-objectransformation"
7519           || anArg == "-objtransformation"
7520           || anArg == "-objtrsf"
7521           || anArg == "-object"
7522           || anArg == "-obj")
7523     {
7524       if (++anArgIter >= theArgNb)
7525       {
7526         Message::SendFail() << "Syntax error at " << anArg;
7527         return 1;
7528       }
7529
7530       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
7531       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
7532       Handle(AIS_InteractiveObject) anObject;
7533       if (!aMapOfAIS.Find2 (anObjName, anObject))
7534       {
7535         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
7536         return 1;
7537       }
7538
7539       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
7540       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
7541       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
7542       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
7543       Standard_Boolean isTrsfSet = Standard_False;
7544       Standard_Integer aTrsfArgIter = anArgIter + 1;
7545       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
7546       {
7547         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
7548         aTrsfArg.LowerCase();
7549         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
7550         if (aTrsfArg.StartsWith ("-rotation")
7551          || aTrsfArg.StartsWith ("-rot"))
7552         {
7553           isTrsfSet = Standard_True;
7554           if (aTrsfArgIter + 4 >= theArgNb
7555           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
7556           {
7557             Message::SendFail() << "Syntax error at " << aTrsfArg;
7558             return 1;
7559           }
7560           aTrsfArgIter += 4;
7561         }
7562         else if (aTrsfArg.StartsWith ("-location")
7563               || aTrsfArg.StartsWith ("-loc"))
7564         {
7565           isTrsfSet = Standard_True;
7566           if (aTrsfArgIter + 3 >= theArgNb
7567           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
7568           {
7569             Message::SendFail() << "Syntax error at " << aTrsfArg;
7570             return 1;
7571           }
7572           aTrsfArgIter += 3;
7573         }
7574         else if (aTrsfArg.StartsWith ("-scale"))
7575         {
7576           isTrsfSet = Standard_True;
7577           if (++aTrsfArgIter >= theArgNb)
7578           {
7579             Message::SendFail() << "Syntax error at " << aTrsfArg;
7580             return 1;
7581           }
7582
7583           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
7584           if (!aScaleStr.IsRealValue (Standard_True))
7585           {
7586             Message::SendFail() << "Syntax error at " << aTrsfArg;
7587             return 1;
7588           }
7589           aScales[anIndex] = aScaleStr.RealValue();
7590         }
7591         else
7592         {
7593           anArgIter = aTrsfArgIter - 1;
7594           break;
7595         }
7596       }
7597       if (!isTrsfSet)
7598       {
7599         Message::SendFail() << "Syntax error at " << anArg;
7600         return 1;
7601       }
7602       else if (aTrsfArgIter >= theArgNb)
7603       {
7604         anArgIter = theArgNb;
7605       }
7606
7607       aTrsfs[0].SetRotation        (aRotQuats[0]);
7608       aTrsfs[1].SetRotation        (aRotQuats[1]);
7609       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
7610       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
7611       aTrsfs[0].SetScaleFactor     (aScales[0]);
7612       aTrsfs[1].SetScaleFactor     (aScales[1]);
7613
7614       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
7615       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
7616     }
7617     else if (anArg == "-viewtrsf"
7618           || anArg == "-view")
7619     {
7620       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
7621       if (aCamAnimation.IsNull())
7622       {
7623         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
7624         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
7625       }
7626
7627       Handle(Graphic3d_Camera) aCams[2] =
7628       {
7629         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
7630         new Graphic3d_Camera (aCamAnimation->View()->Camera())
7631       };
7632
7633       Standard_Boolean isTrsfSet = Standard_False;
7634       Standard_Integer aViewArgIter = anArgIter + 1;
7635       for (; aViewArgIter < theArgNb; ++aViewArgIter)
7636       {
7637         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
7638         aViewArg.LowerCase();
7639         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
7640         if (aViewArg.StartsWith ("-scale"))
7641         {
7642           isTrsfSet = Standard_True;
7643           if (++aViewArgIter >= theArgNb)
7644           {
7645             Message::SendFail() << "Syntax error at " << anArg;
7646             return 1;
7647           }
7648
7649           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
7650           if (!aScaleStr.IsRealValue (Standard_True))
7651           {
7652             Message::SendFail() << "Syntax error at " << aViewArg;
7653             return 1;
7654           }
7655           Standard_Real aScale = aScaleStr.RealValue();
7656           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
7657           aCams[anIndex]->SetScale (aScale);
7658         }
7659         else if (aViewArg.StartsWith ("-eye")
7660               || aViewArg.StartsWith ("-center")
7661               || aViewArg.StartsWith ("-at")
7662               || aViewArg.StartsWith ("-up"))
7663         {
7664           isTrsfSet = Standard_True;
7665           gp_XYZ anXYZ;
7666           if (aViewArgIter + 3 >= theArgNb
7667           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
7668           {
7669             Message::SendFail() << "Syntax error at " << aViewArg;
7670             return 1;
7671           }
7672           aViewArgIter += 3;
7673
7674           if (aViewArg.StartsWith ("-eye"))
7675           {
7676             aCams[anIndex]->SetEye (anXYZ);
7677           }
7678           else if (aViewArg.StartsWith ("-center")
7679                 || aViewArg.StartsWith ("-at"))
7680           {
7681             aCams[anIndex]->SetCenter (anXYZ);
7682           }
7683           else if (aViewArg.StartsWith ("-up"))
7684           {
7685             aCams[anIndex]->SetUp (anXYZ);
7686           }
7687         }
7688         else
7689         {
7690           anArgIter = aViewArgIter - 1;
7691           break;
7692         }
7693       }
7694       if (!isTrsfSet)
7695       {
7696         Message::SendFail() << "Syntax error at " << anArg;
7697         return 1;
7698       }
7699       else if (aViewArgIter >= theArgNb)
7700       {
7701         anArgIter = theArgNb;
7702       }
7703
7704       aCamAnimation->SetCameraStart(aCams[0]);
7705       aCamAnimation->SetCameraEnd  (aCams[1]);
7706     }
7707     else
7708     {
7709       Message::SendFail() << "Syntax error at " << anArg;
7710       return 1;
7711     }
7712   }
7713
7714   ViewerTest::CurrentEventManager()->AbortViewAnimation();
7715   ViewerTest::CurrentEventManager()->SetObjectsAnimation (Handle(AIS_Animation)());
7716   if (!toPlay && aRecFile.IsEmpty())
7717   {
7718     return 0;
7719   }
7720
7721   // Start animation timeline and process frame updating.
7722   if (aRecParams.FpsNum <= 0
7723   && !isLockLoop)
7724   {
7725     Handle(ViewerTest_AnimationHolder) aHolder = new ViewerTest_AnimationHolder (anAnimation, aView, isFreeCamera);
7726     aHolder->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7727     ViewerTest::CurrentEventManager()->SetPauseObjectsAnimation (toPauseOnClick);
7728     ViewerTest::CurrentEventManager()->SetObjectsAnimation (aHolder);
7729     ViewerTest::CurrentEventManager()->ProcessExpose();
7730     return 0;
7731   }
7732
7733   // Perform video recording
7734   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
7735   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
7736   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7737
7738   OSD_Timer aPerfTimer;
7739   aPerfTimer.Start();
7740
7741   Handle(Image_VideoRecorder) aRecorder;
7742   ImageFlipper aFlipper;
7743   Handle(Draw_ProgressIndicator) aProgress;
7744   if (!aRecFile.IsEmpty())
7745   {
7746     if (aRecParams.Width  <= 0
7747      || aRecParams.Height <= 0)
7748     {
7749       aView->Window()->Size (aRecParams.Width, aRecParams.Height);
7750     }
7751
7752     aRecorder = new Image_VideoRecorder();
7753     if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
7754     {
7755       Message::SendFail ("Error: failed to open video file for recording");
7756       return 0;
7757     }
7758
7759     aProgress = new Draw_ProgressIndicator (theDI, 1);
7760   }
7761
7762   // Manage frame-rated animation here
7763   Standard_Real aPts = aPlayStartTime;
7764   int64_t aNbFrames = 0;
7765   Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
7766                             "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
7767   Standard_Integer aSecondsProgress = 0;
7768   for (; aPts <= anUpperPts && aPS.More();)
7769   {
7770     Standard_Real aRecPts = 0.0;
7771     if (aRecParams.FpsNum > 0)
7772     {
7773       aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
7774     }
7775     else
7776     {
7777       aRecPts = aPlaySpeed * aPerfTimer.ElapsedTime();
7778     }
7779
7780     aPts = aPlayStartTime + aRecPts;
7781     ++aNbFrames;
7782     if (!anAnimation->Update (aPts))
7783     {
7784       break;
7785     }
7786
7787     if (!aRecorder.IsNull())
7788     {
7789       V3d_ImageDumpOptions aDumpParams;
7790       aDumpParams.Width          = aRecParams.Width;
7791       aDumpParams.Height         = aRecParams.Height;
7792       aDumpParams.BufferType     = Graphic3d_BT_RGBA;
7793       aDumpParams.StereoOptions  = V3d_SDO_MONO;
7794       aDumpParams.ToAdjustAspect = Standard_True;
7795       if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
7796       {
7797         Message::SendFail ("Error: view dump is failed");
7798         return 0;
7799       }
7800       aFlipper.FlipY (aRecorder->ChangeFrame());
7801       if (!aRecorder->PushFrame())
7802       {
7803         return 0;
7804       }
7805     }
7806     else
7807     {
7808       aView->Redraw();
7809     }
7810
7811     while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
7812     {
7813       aPS.Next();
7814       ++aSecondsProgress;
7815     }
7816   }
7817
7818   aPerfTimer.Stop();
7819   anAnimation->Stop();
7820   const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
7821   theDI << "Average FPS: " << aRecFps << "\n"
7822         << "Nb. Frames: "  << Standard_Real(aNbFrames);
7823
7824   aView->Redraw();
7825   aView->SetImmediateUpdate (wasImmediateUpdate);
7826   return 0;
7827 }
7828
7829
7830 //=======================================================================
7831 //function : VChangeSelected
7832 //purpose  : Adds the shape to selection or remove one from it
7833 //=======================================================================
7834 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
7835                                 Standard_Integer argc,
7836                                 const char ** argv)
7837 {
7838   if(argc != 2)
7839   {
7840     di<<"Usage : " << argv[0] << " shape \n";
7841     return 1;
7842   }
7843   //get AIS_Shape:
7844   TCollection_AsciiString aName(argv[1]);
7845   Handle(AIS_InteractiveObject) anAISObject;
7846   if (!GetMapOfAIS().Find2 (aName, anAISObject)
7847     || anAISObject.IsNull())
7848   {
7849     di<<"Use 'vdisplay' before";
7850     return 1;
7851   }
7852
7853   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
7854   return 0;
7855 }
7856
7857 //=======================================================================
7858 //function : VNbSelected
7859 //purpose  : Returns number of selected objects
7860 //=======================================================================
7861 static Standard_Integer VNbSelected (Draw_Interpretor& di,
7862                                 Standard_Integer argc,
7863                                 const char ** argv)
7864 {
7865   if(argc != 1)
7866   {
7867     di << "Usage : " << argv[0] << "\n";
7868     return 1;
7869   }
7870   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7871   if(aContext.IsNull())
7872   {
7873     di << "use 'vinit' command before " << argv[0] << "\n";
7874     return 1;
7875   }
7876   di << aContext->NbSelected() << "\n";
7877   return 0;
7878 }
7879
7880 //=======================================================================
7881 //function : VSetViewSize
7882 //purpose  :
7883 //=======================================================================
7884 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
7885                                 Standard_Integer argc,
7886                                 const char ** argv)
7887 {
7888   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7889   if(aContext.IsNull())
7890   {
7891     di << "use 'vinit' command before " << argv[0] << "\n";
7892     return 1;
7893   }
7894   if(argc != 2)
7895   {
7896     di<<"Usage : " << argv[0] << " Size\n";
7897     return 1;
7898   }
7899   Standard_Real aSize = Draw::Atof (argv[1]);
7900   if (aSize <= 0.)
7901   {
7902     di<<"Bad Size value  : " << aSize << "\n";
7903     return 1;
7904   }
7905
7906   Handle(V3d_View) aView = ViewerTest::CurrentView();
7907   aView->SetSize(aSize);
7908   return 0;
7909 }
7910
7911 //=======================================================================
7912 //function : VMoveView
7913 //purpose  :
7914 //=======================================================================
7915 static Standard_Integer VMoveView (Draw_Interpretor& di,
7916                                 Standard_Integer argc,
7917                                 const char ** argv)
7918 {
7919   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7920   if(aContext.IsNull())
7921   {
7922     di << "use 'vinit' command before " << argv[0] << "\n";
7923     return 1;
7924   }
7925   if(argc < 4 || argc > 5)
7926   {
7927     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
7928     return 1;
7929   }
7930   Standard_Real Dx = Draw::Atof (argv[1]);
7931   Standard_Real Dy = Draw::Atof (argv[2]);
7932   Standard_Real Dz = Draw::Atof (argv[3]);
7933   Standard_Boolean aStart = Standard_True;
7934   if (argc == 5)
7935   {
7936       aStart = (Draw::Atoi (argv[4]) > 0);
7937   }
7938
7939   Handle(V3d_View) aView = ViewerTest::CurrentView();
7940   aView->Move(Dx,Dy,Dz,aStart);
7941   return 0;
7942 }
7943
7944 //=======================================================================
7945 //function : VTranslateView
7946 //purpose  :
7947 //=======================================================================
7948 static Standard_Integer VTranslateView (Draw_Interpretor& di,
7949                                 Standard_Integer argc,
7950                                 const char ** argv)
7951 {
7952   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7953   if(aContext.IsNull())
7954   {
7955     di << "use 'vinit' command before " << argv[0] << "\n";
7956     return 1;
7957   }
7958   if(argc < 4 || argc > 5)
7959   {
7960     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
7961     return 1;
7962   }
7963   Standard_Real Dx = Draw::Atof (argv[1]);
7964   Standard_Real Dy = Draw::Atof (argv[2]);
7965   Standard_Real Dz = Draw::Atof (argv[3]);
7966   Standard_Boolean aStart = Standard_True;
7967   if (argc == 5)
7968   {
7969       aStart = (Draw::Atoi (argv[4]) > 0);
7970   }
7971
7972   Handle(V3d_View) aView = ViewerTest::CurrentView();
7973   aView->Translate(Dx,Dy,Dz,aStart);
7974   return 0;
7975 }
7976
7977 //=======================================================================
7978 //function : VTurnView
7979 //purpose  :
7980 //=======================================================================
7981 static Standard_Integer VTurnView (Draw_Interpretor& di,
7982                                 Standard_Integer argc,
7983                                 const char ** argv)
7984 {
7985   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7986   if(aContext.IsNull()) {
7987     di << "use 'vinit' command before " << argv[0] << "\n";
7988     return 1;
7989   }
7990   if(argc < 4 || argc > 5){
7991     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
7992     return 1;
7993   }
7994   Standard_Real Ax = Draw::Atof (argv[1]);
7995   Standard_Real Ay = Draw::Atof (argv[2]);
7996   Standard_Real Az = Draw::Atof (argv[3]);
7997   Standard_Boolean aStart = Standard_True;
7998   if (argc == 5)
7999   {
8000       aStart = (Draw::Atoi (argv[4]) > 0);
8001   }
8002
8003   Handle(V3d_View) aView = ViewerTest::CurrentView();
8004   aView->Turn(Ax,Ay,Az,aStart);
8005   return 0;
8006 }
8007
8008 //==============================================================================
8009 //function : VTextureEnv
8010 //purpose  : ENables or disables environment mapping
8011 //==============================================================================
8012 class OCC_TextureEnv : public Graphic3d_TextureEnv
8013 {
8014 public:
8015   OCC_TextureEnv(const Standard_CString FileName);
8016   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
8017   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
8018                             const Standard_Boolean theModulateFlag,
8019                             const Graphic3d_TypeOfTextureFilter theFilter,
8020                             const Standard_ShortReal theXScale,
8021                             const Standard_ShortReal theYScale,
8022                             const Standard_ShortReal theXShift,
8023                             const Standard_ShortReal theYShift,
8024                             const Standard_ShortReal theAngle);
8025   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
8026 };
8027 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
8028
8029 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
8030   : Graphic3d_TextureEnv(theFileName)
8031 {
8032 }
8033
8034 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
8035   : Graphic3d_TextureEnv(theTexId)
8036 {
8037 }
8038
8039 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
8040                                           const Standard_Boolean theModulateFlag,
8041                                           const Graphic3d_TypeOfTextureFilter theFilter,
8042                                           const Standard_ShortReal theXScale,
8043                                           const Standard_ShortReal theYScale,
8044                                           const Standard_ShortReal theXShift,
8045                                           const Standard_ShortReal theYShift,
8046                                           const Standard_ShortReal theAngle)
8047 {
8048   myParams->SetRepeat     (theRepeatFlag);
8049   myParams->SetModulate   (theModulateFlag);
8050   myParams->SetFilter     (theFilter);
8051   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
8052   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
8053   myParams->SetRotation   (theAngle);
8054 }
8055
8056 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
8057 {
8058   // get the active view
8059   Handle(V3d_View) aView = ViewerTest::CurrentView();
8060   if (aView.IsNull())
8061   {
8062     Message::SendFail ("Error: no active viewer");
8063     return 1;
8064   }
8065
8066   // Checking the input arguments
8067   Standard_Boolean anEnableFlag = Standard_False;
8068   Standard_Boolean isOk         = theArgNb >= 2;
8069   if (isOk)
8070   {
8071     TCollection_AsciiString anEnableOpt(theArgVec[1]);
8072     anEnableFlag = anEnableOpt.IsEqual("on");
8073     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
8074   }
8075   if (anEnableFlag)
8076   {
8077     isOk = (theArgNb == 3 || theArgNb == 11);
8078     if (isOk)
8079     {
8080       TCollection_AsciiString aTextureOpt(theArgVec[2]);
8081       isOk = (!aTextureOpt.IsIntegerValue() ||
8082              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
8083
8084       if (isOk && theArgNb == 11)
8085       {
8086         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
8087                                 aModulateOpt(theArgVec[4]),
8088                                 aFilterOpt  (theArgVec[5]),
8089                                 aSScaleOpt  (theArgVec[6]),
8090                                 aTScaleOpt  (theArgVec[7]),
8091                                 aSTransOpt  (theArgVec[8]),
8092                                 aTTransOpt  (theArgVec[9]),
8093                                 anAngleOpt  (theArgVec[10]);
8094         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
8095                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
8096                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
8097                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
8098                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
8099                 anAngleOpt.IsRealValue (Standard_True));
8100       }
8101     }
8102   }
8103
8104   if (!isOk)
8105   {
8106     Message::SendFail() << "Usage:\n"
8107                         << theArgVec[0] << " off\n"
8108                         << 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]";
8109     return 1;
8110   }
8111
8112   if (anEnableFlag)
8113   {
8114     TCollection_AsciiString aTextureOpt(theArgVec[2]);
8115     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
8116                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
8117                                      new OCC_TextureEnv(theArgVec[2]);
8118
8119     if (theArgNb == 11)
8120     {
8121       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
8122       aTexEnv->SetTextureParameters(
8123         aRepeatOpt.  IsEqual("repeat"),
8124         aModulateOpt.IsEqual("modulate"),
8125         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
8126                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
8127                                                                            Graphic3d_TOTF_TRILINEAR,
8128         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
8129         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
8130         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
8131         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
8132         (Standard_ShortReal)Draw::Atof(theArgVec[10])
8133         );
8134     }
8135     aView->SetTextureEnv(aTexEnv);
8136   }
8137   else // Disabling environment mapping
8138   {
8139     Handle(Graphic3d_TextureEnv) aTexture;
8140     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
8141   }
8142
8143   aView->Redraw();
8144   return 0;
8145 }
8146
8147 namespace
8148 {
8149   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
8150
8151   //! Remove registered clipping plane from all views and objects.
8152   static void removePlane (MapOfPlanes& theRegPlanes,
8153                            const TCollection_AsciiString& theName)
8154   {
8155     Handle(Graphic3d_ClipPlane) aClipPlane;
8156     if (!theRegPlanes.Find (theName, aClipPlane))
8157     {
8158       Message::SendWarning ("Warning: no such plane");
8159       return;
8160     }
8161
8162     theRegPlanes.UnBind (theName);
8163     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
8164          anIObjIt.More(); anIObjIt.Next())
8165     {
8166       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
8167       aPrs->RemoveClipPlane (aClipPlane);
8168     }
8169
8170     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
8171          aViewIt.More(); aViewIt.Next())
8172     {
8173       const Handle(V3d_View)& aView = aViewIt.Key2();
8174       aView->RemoveClipPlane(aClipPlane);
8175     }
8176
8177     ViewerTest::RedrawAllViews();
8178   }
8179 }
8180
8181 //===============================================================================================
8182 //function : VClipPlane
8183 //purpose  :
8184 //===============================================================================================
8185 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8186 {
8187   // use short-cut for created clip planes map of created (or "registered by name") clip planes
8188   static MapOfPlanes aRegPlanes;
8189
8190   if (theArgsNb < 2)
8191   {
8192     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
8193     {
8194       theDi << aPlaneIter.Key() << " ";
8195     }
8196     return 0;
8197   }
8198
8199   TCollection_AsciiString aCommand (theArgVec[1]);
8200   aCommand.LowerCase();
8201   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
8202   if (anActiveView.IsNull())
8203   {
8204     Message::SendFail ("Error: no active viewer");
8205     return 1;
8206   }
8207
8208   // print maximum number of planes for current viewer
8209   if (aCommand == "-maxplanes"
8210    || aCommand == "maxplanes")
8211   {
8212     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
8213           << " plane slots provided by driver.\n";
8214     return 0;
8215   }
8216
8217   // create / delete plane instance
8218   if (aCommand == "-create"
8219    || aCommand == "create"
8220    || aCommand == "-delete"
8221    || aCommand == "delete"
8222    || aCommand == "-clone"
8223    || aCommand == "clone")
8224   {
8225     if (theArgsNb < 3)
8226     {
8227       Message::SendFail ("Syntax error: plane name is required");
8228       return 1;
8229     }
8230
8231     Standard_Boolean toCreate = aCommand == "-create"
8232                              || aCommand == "create";
8233     Standard_Boolean toClone  = aCommand == "-clone"
8234                              || aCommand == "clone";
8235     Standard_Boolean toDelete = aCommand == "-delete"
8236                              || aCommand == "delete";
8237     TCollection_AsciiString aPlane (theArgVec[2]);
8238
8239     if (toCreate)
8240     {
8241       if (aRegPlanes.IsBound (aPlane))
8242       {
8243         std::cout << "Warning: existing plane has been overridden.\n";
8244         toDelete = true;
8245       }
8246       else
8247       {
8248         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8249         return 0;
8250       }
8251     }
8252     else if (toClone) // toClone
8253     {
8254       if (!aRegPlanes.IsBound (aPlane))
8255       {
8256         Message::SendFail ("Error: no such plane");
8257         return 1;
8258       }
8259       else if (theArgsNb < 4)
8260       {
8261         Message::SendFail ("Syntax error: enter name for new plane");
8262         return 1;
8263       }
8264
8265       TCollection_AsciiString aClone (theArgVec[3]);
8266       if (aRegPlanes.IsBound (aClone))
8267       {
8268         Message::SendFail ("Error: plane name is in use");
8269         return 1;
8270       }
8271
8272       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
8273
8274       aRegPlanes.Bind (aClone, aClipPlane->Clone());
8275       return 0;
8276     }
8277
8278     if (toDelete)
8279     {
8280       if (aPlane == "ALL"
8281        || aPlane == "all"
8282        || aPlane == "*")
8283       {
8284         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
8285         {
8286           aPlane = aPlaneIter.Key();
8287           removePlane (aRegPlanes, aPlane);
8288           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
8289         }
8290       }
8291       else
8292       {
8293         removePlane (aRegPlanes, aPlane);
8294       }
8295     }
8296
8297     if (toCreate)
8298     {
8299       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8300     }
8301     return 0;
8302   }
8303
8304   // set / unset plane command
8305   if (aCommand == "set"
8306    || aCommand == "unset")
8307   {
8308     if (theArgsNb < 5)
8309     {
8310       Message::SendFail ("Syntax error: need more arguments");
8311       return 1;
8312     }
8313
8314     // redirect to new syntax
8315     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
8316     anArgVec.SetValue (1, theArgVec[0]);
8317     anArgVec.SetValue (2, theArgVec[2]);
8318     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
8319     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
8320     {
8321       anArgVec.SetValue (anIt, theArgVec[anIt]);
8322     }
8323
8324     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
8325   }
8326
8327   // change plane command
8328   TCollection_AsciiString aPlaneName;
8329   Handle(Graphic3d_ClipPlane) aClipPlane;
8330   Standard_Integer anArgIter = 0;
8331   if (aCommand == "-change"
8332    || aCommand == "change")
8333   {
8334     // old syntax support
8335     if (theArgsNb < 3)
8336     {
8337       Message::SendFail ("Syntax error: need more arguments");
8338       return 1;
8339     }
8340
8341     anArgIter  = 3;
8342     aPlaneName = theArgVec[2];
8343     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
8344     {
8345       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
8346       return 1;
8347     }
8348   }
8349   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
8350   {
8351     anArgIter  = 2;
8352     aPlaneName = theArgVec[1];
8353   }
8354   else
8355   {
8356     anArgIter  = 2;
8357     aPlaneName = theArgVec[1];
8358     aClipPlane = new Graphic3d_ClipPlane();
8359     aRegPlanes.Bind (aPlaneName, aClipPlane);
8360     theDi << "Created new plane " << aPlaneName << ".\n";
8361   }
8362
8363   if (theArgsNb - anArgIter < 1)
8364   {
8365     Message::SendFail ("Syntax error: need more arguments");
8366     return 1;
8367   }
8368
8369   for (; anArgIter < theArgsNb; ++anArgIter)
8370   {
8371     const char**     aChangeArgs   = theArgVec + anArgIter;
8372     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
8373     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
8374     aChangeArg.LowerCase();
8375
8376     Standard_Boolean toEnable = Standard_True;
8377     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
8378     {
8379       aClipPlane->SetOn (toEnable);
8380     }
8381     else if (aChangeArg.StartsWith ("-equation")
8382           || aChangeArg.StartsWith ("equation"))
8383     {
8384       if (aNbChangeArgs < 5)
8385       {
8386         Message::SendFail ("Syntax error: need more arguments");
8387         return 1;
8388       }
8389
8390       Standard_Integer aSubIndex = 1;
8391       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
8392       if (aPrefixLen < aChangeArg.Length())
8393       {
8394         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
8395         if (!aSubStr.IsIntegerValue()
8396           || aSubStr.IntegerValue() <= 0)
8397         {
8398           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8399           return 1;
8400         }
8401         aSubIndex = aSubStr.IntegerValue();
8402       }
8403
8404       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
8405       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
8406       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
8407       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
8408       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8409       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
8410       {
8411         if (aSubPln->ChainNextPlane().IsNull())
8412         {
8413           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8414         }
8415         aSubPln = aSubPln->ChainNextPlane();
8416       }
8417       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8418       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
8419       anArgIter += 4;
8420     }
8421     else if ((aChangeArg == "-boxinterior"
8422            || aChangeArg == "-boxint"
8423            || aChangeArg == "-box")
8424             && aNbChangeArgs >= 7)
8425     {
8426       Graphic3d_BndBox3d aBndBox;
8427       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
8428       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
8429       anArgIter += 6;
8430
8431       Standard_Integer aNbSubPlanes = 6;
8432       const Graphic3d_Vec3d aDirArray[6] =
8433       {
8434         Graphic3d_Vec3d (-1, 0, 0),
8435         Graphic3d_Vec3d ( 1, 0, 0),
8436         Graphic3d_Vec3d ( 0,-1, 0),
8437         Graphic3d_Vec3d ( 0, 1, 0),
8438         Graphic3d_Vec3d ( 0, 0,-1),
8439         Graphic3d_Vec3d ( 0, 0, 1),
8440       };
8441       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8442       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
8443       {
8444         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
8445         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
8446         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
8447         if (aSubPlaneIter + 1 == aNbSubPlanes)
8448         {
8449           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8450         }
8451         else
8452         {
8453           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8454         }
8455         aSubPln = aSubPln->ChainNextPlane();
8456       }
8457     }
8458     else if (aChangeArg == "-capping"
8459           || aChangeArg == "capping")
8460     {
8461       if (aNbChangeArgs < 2)
8462       {
8463         Message::SendFail ("Syntax error: need more arguments");
8464         return 1;
8465       }
8466
8467       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8468       {
8469         aClipPlane->SetCapping (toEnable);
8470         anArgIter += 1;
8471       }
8472       else
8473       {
8474         // just skip otherwise (old syntax)
8475       }
8476     }
8477     else if (aChangeArg == "-useobjectmaterial"
8478           || aChangeArg == "-useobjectmat"
8479           || aChangeArg == "-useobjmat"
8480           || aChangeArg == "-useobjmaterial")
8481     {
8482       if (aNbChangeArgs < 2)
8483       {
8484         Message::SendFail ("Syntax error: need more arguments");
8485         return 1;
8486       }
8487
8488       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8489       {
8490         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
8491         anArgIter += 1;
8492       }
8493     }
8494     else if (aChangeArg == "-useobjecttexture"
8495           || aChangeArg == "-useobjecttex"
8496           || aChangeArg == "-useobjtexture"
8497           || aChangeArg == "-useobjtex")
8498     {
8499       if (aNbChangeArgs < 2)
8500       {
8501         Message::SendFail ("Syntax error: need more arguments");
8502         return 1;
8503       }
8504
8505       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8506       {
8507         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
8508         anArgIter += 1;
8509       }
8510     }
8511     else if (aChangeArg == "-useobjectshader"
8512           || aChangeArg == "-useobjshader")
8513     {
8514       if (aNbChangeArgs < 2)
8515       {
8516         Message::SendFail ("Syntax error: need more arguments");
8517         return 1;
8518       }
8519
8520       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8521       {
8522         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
8523         anArgIter += 1;
8524       }
8525     }
8526     else if (aChangeArg == "-color"
8527           || aChangeArg == "color")
8528     {
8529       Quantity_Color aColor;
8530       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
8531                                                      aChangeArgs + 1,
8532                                                      aColor);
8533       if (aNbParsed == 0)
8534       {
8535         Message::SendFail ("Syntax error: need more arguments");
8536         return 1;
8537       }
8538       aClipPlane->SetCappingColor (aColor);
8539       anArgIter += aNbParsed;
8540     }
8541     else if (aNbChangeArgs >= 1
8542           && (aChangeArg == "-material"
8543            || aChangeArg == "material"))
8544     {
8545       ++anArgIter;
8546       Graphic3d_NameOfMaterial aMatName;
8547       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
8548       {
8549         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
8550         return 1;
8551       }
8552       aClipPlane->SetCappingMaterial (aMatName);
8553     }
8554     else if ((aChangeArg == "-transparency"
8555            || aChangeArg == "-transp")
8556           && aNbChangeArgs >= 2)
8557     {
8558       TCollection_AsciiString aValStr (aChangeArgs[1]);
8559       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
8560       if (aValStr.IsRealValue (Standard_True))
8561       {
8562         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
8563         aMat.SetTransparency ((float )aValStr.RealValue());
8564         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
8565         aClipPlane->SetCappingMaterial (aMat);
8566       }
8567       else
8568       {
8569         aValStr.LowerCase();
8570         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
8571         if (aValStr == "opaque")
8572         {
8573           aMode = Graphic3d_AlphaMode_Opaque;
8574         }
8575         else if (aValStr == "mask")
8576         {
8577           aMode = Graphic3d_AlphaMode_Mask;
8578         }
8579         else if (aValStr == "blend")
8580         {
8581           aMode = Graphic3d_AlphaMode_Blend;
8582         }
8583         else if (aValStr == "maskblend"
8584               || aValStr == "blendmask")
8585         {
8586           aMode = Graphic3d_AlphaMode_MaskBlend;
8587         }
8588         else if (aValStr == "blendauto")
8589         {
8590           aMode = Graphic3d_AlphaMode_BlendAuto;
8591         }
8592         else
8593         {
8594           Message::SendFail() << "Syntax error at '" << aValStr << "'";
8595           return 1;
8596         }
8597         anAspect->SetAlphaMode (aMode);
8598         aClipPlane->SetCappingAspect (anAspect);
8599       }
8600       anArgIter += 1;
8601     }
8602     else if (aChangeArg == "-texname"
8603           || aChangeArg == "texname")
8604     {
8605       if (aNbChangeArgs < 2)
8606       {
8607         Message::SendFail ("Syntax error: need more arguments");
8608         return 1;
8609       }
8610
8611       TCollection_AsciiString aTextureName (aChangeArgs[1]);
8612       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
8613       if (!aTexture->IsDone())
8614       {
8615         aClipPlane->SetCappingTexture (NULL);
8616       }
8617       else
8618       {
8619         aTexture->EnableModulate();
8620         aTexture->EnableRepeat();
8621         aClipPlane->SetCappingTexture (aTexture);
8622       }
8623       anArgIter += 1;
8624     }
8625     else if (aChangeArg == "-texscale"
8626           || aChangeArg == "texscale")
8627     {
8628       if (aClipPlane->CappingTexture().IsNull())
8629       {
8630         Message::SendFail ("Error: no texture is set");
8631         return 1;
8632       }
8633
8634       if (aNbChangeArgs < 3)
8635       {
8636         Message::SendFail ("Syntax error: need more arguments");
8637         return 1;
8638       }
8639
8640       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8641       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8642       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
8643       anArgIter += 2;
8644     }
8645     else if (aChangeArg == "-texorigin"
8646           || aChangeArg == "texorigin") // texture origin
8647     {
8648       if (aClipPlane->CappingTexture().IsNull())
8649       {
8650         Message::SendFail ("Error: no texture is set");
8651         return 1;
8652       }
8653
8654       if (aNbChangeArgs < 3)
8655       {
8656         Message::SendFail ("Syntax error: need more arguments");
8657         return 1;
8658       }
8659
8660       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8661       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8662
8663       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
8664       anArgIter += 2;
8665     }
8666     else if (aChangeArg == "-texrotate"
8667           || aChangeArg == "texrotate") // texture rotation
8668     {
8669       if (aClipPlane->CappingTexture().IsNull())
8670       {
8671         Message::SendFail ("Error: no texture is set");
8672         return 1;
8673       }
8674
8675       if (aNbChangeArgs < 2)
8676       {
8677         Message::SendFail ("Syntax error: need more arguments");
8678         return 1;
8679       }
8680
8681       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8682       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
8683       anArgIter += 1;
8684     }
8685     else if (aChangeArg == "-hatch"
8686           || aChangeArg == "hatch")
8687     {
8688       if (aNbChangeArgs < 2)
8689       {
8690         Message::SendFail ("Syntax error: need more arguments");
8691         return 1;
8692       }
8693
8694       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
8695       aHatchStr.LowerCase();
8696       if (aHatchStr == "on")
8697       {
8698         aClipPlane->SetCappingHatchOn();
8699       }
8700       else if (aHatchStr == "off")
8701       {
8702         aClipPlane->SetCappingHatchOff();
8703       }
8704       else
8705       {
8706         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
8707       }
8708       anArgIter += 1;
8709     }
8710     else if (aChangeArg == "-delete"
8711           || aChangeArg == "delete")
8712     {
8713       removePlane (aRegPlanes, aPlaneName);
8714       return 0;
8715     }
8716     else if (aChangeArg == "-set"
8717           || aChangeArg == "-unset"
8718           || aChangeArg == "-setoverrideglobal")
8719     {
8720       // set / unset plane command
8721       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
8722       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
8723       Standard_Integer anIt = 1;
8724       for (; anIt < aNbChangeArgs; ++anIt)
8725       {
8726         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
8727         if (anEntityName.IsEmpty()
8728          || anEntityName.Value (1) == '-')
8729         {
8730           break;
8731         }
8732         else if (!toOverrideGlobal
8733                && ViewerTest_myViews.IsBound1 (anEntityName))
8734         {
8735           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
8736           if (toSet)
8737           {
8738             aView->AddClipPlane (aClipPlane);
8739           }
8740           else
8741           {
8742             aView->RemoveClipPlane (aClipPlane);
8743           }
8744           continue;
8745         }
8746         else if (GetMapOfAIS().IsBound2 (anEntityName))
8747         {
8748           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
8749           if (toSet)
8750           {
8751             aIObj->AddClipPlane (aClipPlane);
8752           }
8753           else
8754           {
8755             aIObj->RemoveClipPlane (aClipPlane);
8756           }
8757           if (!aIObj->ClipPlanes().IsNull())
8758           {
8759             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
8760           }
8761         }
8762         else
8763         {
8764           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
8765           return 1;
8766         }
8767       }
8768
8769       if (anIt == 1)
8770       {
8771         // apply to active view
8772         if (toSet)
8773         {
8774           anActiveView->AddClipPlane (aClipPlane);
8775         }
8776         else
8777         {
8778           anActiveView->RemoveClipPlane (aClipPlane);
8779         }
8780       }
8781       else
8782       {
8783         anArgIter = anArgIter + anIt - 1;
8784       }
8785     }
8786     else
8787     {
8788       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8789       return 1;
8790     }
8791   }
8792
8793   ViewerTest::RedrawAllViews();
8794   return 0;
8795 }
8796
8797 //===============================================================================================
8798 //function : VZRange
8799 //purpose  :
8800 //===============================================================================================
8801 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8802 {
8803   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8804
8805   if (aCurrentView.IsNull())
8806   {
8807     Message::SendFail ("Error: no active viewer");
8808     return 1;
8809   }
8810
8811   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
8812
8813   if (theArgsNb < 2)
8814   {
8815     theDi << "ZNear: " << aCamera->ZNear() << "\n";
8816     theDi << "ZFar: " << aCamera->ZFar() << "\n";
8817     return 0;
8818   }
8819
8820   if (theArgsNb == 3)
8821   {
8822     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
8823     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
8824
8825     if (aNewZNear >= aNewZFar)
8826     {
8827       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
8828       return 1;
8829     }
8830
8831     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
8832     {
8833       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
8834       return 1;
8835     }
8836
8837     aCamera->SetZRange (aNewZNear, aNewZFar);
8838   }
8839   else
8840   {
8841     Message::SendFail ("Syntax error: wrong command arguments");
8842     return 1;
8843   }
8844
8845   aCurrentView->Redraw();
8846
8847   return 0;
8848 }
8849
8850 //===============================================================================================
8851 //function : VAutoZFit
8852 //purpose  :
8853 //===============================================================================================
8854 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8855 {
8856   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8857
8858   if (aCurrentView.IsNull())
8859   {
8860     Message::SendFail ("Error: no active viewer");
8861     return 1;
8862   }
8863
8864   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
8865
8866   if (theArgsNb > 3)
8867   {
8868     Message::SendFail ("Syntax error: wrong command arguments");
8869     return 1;
8870   }
8871
8872   if (theArgsNb < 2)
8873   {
8874     theDi << "Auto z-fit mode: \n"
8875           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
8876           << "Scale: " << aScale << "\n";
8877     return 0;
8878   }
8879
8880   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
8881
8882   if (theArgsNb >= 3)
8883   {
8884     aScale = Draw::Atoi (theArgVec[2]);
8885   }
8886
8887   aCurrentView->SetAutoZFitMode (isOn, aScale);
8888   aCurrentView->Redraw();
8889   return 0;
8890 }
8891
8892 //! Auxiliary function to print projection type
8893 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
8894 {
8895   switch (theProjType)
8896   {
8897     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
8898     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
8899     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
8900     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
8901     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
8902   }
8903   return "UNKNOWN";
8904 }
8905
8906 //===============================================================================================
8907 //function : VCamera
8908 //purpose  :
8909 //===============================================================================================
8910 static int VCamera (Draw_Interpretor& theDI,
8911                     Standard_Integer  theArgsNb,
8912                     const char**      theArgVec)
8913 {
8914   Handle(V3d_View) aView = ViewerTest::CurrentView();
8915   if (aView.IsNull())
8916   {
8917     Message::SendFail ("Error: no active viewer");
8918     return 1;
8919   }
8920
8921   Handle(Graphic3d_Camera) aCamera = aView->Camera();
8922   if (theArgsNb < 2)
8923   {
8924     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
8925     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
8926     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
8927     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
8928     theDI << "Distance:   " << aCamera->Distance() << "\n";
8929     theDI << "IOD:        " << aCamera->IOD() << "\n";
8930     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
8931     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
8932     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
8933     theDI << "ZNear:      " << aCamera->ZNear() << "\n";
8934     theDI << "ZFar:       " << aCamera->ZFar() << "\n";
8935     return 0;
8936   }
8937
8938   TCollection_AsciiString aPrsName;
8939   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
8940   {
8941     Standard_CString        anArg = theArgVec[anArgIter];
8942     TCollection_AsciiString anArgCase (anArg);
8943     anArgCase.LowerCase();
8944     if (anArgCase == "-proj"
8945      || anArgCase == "-projection"
8946      || anArgCase == "-projtype"
8947      || anArgCase == "-projectiontype")
8948     {
8949       theDI << projTypeName (aCamera->ProjectionType()) << " ";
8950     }
8951     else if (anArgCase == "-ortho"
8952           || anArgCase == "-orthographic")
8953     {
8954       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
8955     }
8956     else if (anArgCase == "-persp"
8957           || anArgCase == "-perspective"
8958           || anArgCase == "-perspmono"
8959           || anArgCase == "-perspectivemono"
8960           || anArgCase == "-mono")
8961     {
8962       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
8963     }
8964     else if (anArgCase == "-stereo"
8965           || anArgCase == "-stereoscopic"
8966           || anArgCase == "-perspstereo"
8967           || anArgCase == "-perspectivestereo")
8968     {
8969       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
8970     }
8971     else if (anArgCase == "-left"
8972           || anArgCase == "-lefteye"
8973           || anArgCase == "-monoleft"
8974           || anArgCase == "-monolefteye"
8975           || anArgCase == "-perpsleft"
8976           || anArgCase == "-perpslefteye")
8977     {
8978       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
8979     }
8980     else if (anArgCase == "-right"
8981           || anArgCase == "-righteye"
8982           || anArgCase == "-monoright"
8983           || anArgCase == "-monorighteye"
8984           || anArgCase == "-perpsright")
8985     {
8986       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
8987     }
8988     else if (anArgCase == "-dist"
8989           || anArgCase == "-distance")
8990     {
8991       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
8992       if (anArgValue != NULL
8993       && *anArgValue != '-')
8994       {
8995         ++anArgIter;
8996         aCamera->SetDistance (Draw::Atof (anArgValue));
8997         continue;
8998       }
8999       theDI << aCamera->Distance() << " ";
9000     }
9001     else if (anArgCase == "-iod")
9002     {
9003       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9004       if (anArgValue != NULL
9005       && *anArgValue != '-')
9006       {
9007         ++anArgIter;
9008         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
9009         continue;
9010       }
9011       theDI << aCamera->IOD() << " ";
9012     }
9013     else if (anArgCase == "-iodtype")
9014     {
9015       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9016       TCollection_AsciiString anValueCase (anArgValue);
9017       anValueCase.LowerCase();
9018       if (anValueCase == "abs"
9019        || anValueCase == "absolute")
9020       {
9021         ++anArgIter;
9022         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
9023         continue;
9024       }
9025       else if (anValueCase == "rel"
9026             || anValueCase == "relative")
9027       {
9028         ++anArgIter;
9029         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
9030         continue;
9031       }
9032       else if (*anArgValue != '-')
9033       {
9034         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
9035         return 1;
9036       }
9037       switch (aCamera->GetIODType())
9038       {
9039         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
9040         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
9041       }
9042     }
9043     else if (anArgCase == "-zfocus")
9044     {
9045       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9046       if (anArgValue != NULL
9047       && *anArgValue != '-')
9048       {
9049         ++anArgIter;
9050         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
9051         continue;
9052       }
9053       theDI << aCamera->ZFocus() << " ";
9054     }
9055     else if (anArgCase == "-zfocustype")
9056     {
9057       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9058       TCollection_AsciiString anValueCase (anArgValue);
9059       anValueCase.LowerCase();
9060       if (anValueCase == "abs"
9061        || anValueCase == "absolute")
9062       {
9063         ++anArgIter;
9064         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
9065         continue;
9066       }
9067       else if (anValueCase == "rel"
9068             || anValueCase == "relative")
9069       {
9070         ++anArgIter;
9071         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
9072         continue;
9073       }
9074       else if (*anArgValue != '-')
9075       {
9076         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
9077         return 1;
9078       }
9079       switch (aCamera->ZFocusType())
9080       {
9081         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
9082         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
9083       }
9084     }
9085     else if (anArgCase == "-lockzup"
9086           || anArgCase == "-turntable")
9087     {
9088       bool toLockUp = true;
9089       if (++anArgIter < theArgsNb
9090       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
9091       {
9092         --anArgIter;
9093       }
9094       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
9095     }
9096     else if (anArgCase == "-rotationmode"
9097           || anArgCase == "-rotmode")
9098     {
9099       AIS_RotationMode aRotMode = AIS_RotationMode_BndBoxActive;
9100       TCollection_AsciiString aRotStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9101       aRotStr.LowerCase();
9102       if (aRotStr == "bndboxactive"
9103        || aRotStr == "active")
9104       {
9105         aRotMode = AIS_RotationMode_BndBoxActive;
9106       }
9107       else if (aRotStr == "picklast"
9108             || aRotStr == "pick")
9109       {
9110         aRotMode = AIS_RotationMode_PickLast;
9111       }
9112       else if (aRotStr == "pickcenter")
9113       {
9114         aRotMode = AIS_RotationMode_PickCenter;
9115       }
9116       else if (aRotStr == "cameraat"
9117             || aRotStr == "cameracenter")
9118       {
9119         aRotMode = AIS_RotationMode_CameraAt;
9120       }
9121       else if (aRotStr == "bndboxscene"
9122             || aRotStr == "boxscene")
9123       {
9124         aRotMode = AIS_RotationMode_BndBoxScene;
9125       }
9126       else
9127       {
9128         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9129         return 1;
9130       }
9131
9132       ViewerTest::CurrentEventManager()->SetRotationMode (aRotMode);
9133       ++anArgIter;
9134     }
9135     else if (anArgCase == "-navigationmode"
9136           || anArgCase == "-navmode")
9137     {
9138       AIS_NavigationMode aNavMode = AIS_NavigationMode_Orbit;
9139       TCollection_AsciiString aNavStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9140       aNavStr.LowerCase();
9141       if (aNavStr == "orbit")
9142       {
9143         aNavMode = AIS_NavigationMode_Orbit;
9144       }
9145       else if (aNavStr == "flight"
9146             || aNavStr == "fly"
9147             || aNavStr == "copter"
9148             || aNavStr == "helicopter")
9149       {
9150         aNavMode = AIS_NavigationMode_FirstPersonFlight;
9151       }
9152       else if (aNavStr == "walk"
9153             || aNavStr == "shooter")
9154       {
9155         aNavMode = AIS_NavigationMode_FirstPersonWalk;
9156       }
9157       else
9158       {
9159         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9160         return 1;
9161       }
9162
9163       Handle(ViewerTest_EventManager) aViewMgr = ViewerTest::CurrentEventManager();
9164       aViewMgr->SetNavigationMode (aNavMode);
9165       if (aNavMode == AIS_NavigationMode_Orbit)
9166       {
9167         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
9168       }
9169       else
9170       {
9171         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateView);
9172       }
9173       ++anArgIter;
9174     }
9175     else if (anArgCase == "-fov"
9176           || anArgCase == "-fovy"
9177           || anArgCase == "-fovx"
9178           || anArgCase == "-fov2d")
9179     {
9180       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9181       if (anArgValue != NULL
9182       && *anArgValue != '-')
9183       {
9184         ++anArgIter;
9185         if (anArgCase == "-fov2d")
9186         {
9187           aCamera->SetFOV2d (Draw::Atof (anArgValue));
9188         }
9189         else if (anArgCase == "-fovx")
9190         {
9191           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
9192         }
9193         else
9194         {
9195           aCamera->SetFOVy (Draw::Atof (anArgValue));
9196         }
9197         continue;
9198       }
9199       if (anArgCase == "-fov2d")
9200       {
9201         theDI << aCamera->FOV2d() << " ";
9202       }
9203       else if (anArgCase == "-fovx")
9204       {
9205         theDI << aCamera->FOVx() << " ";
9206       }
9207       else
9208       {
9209         theDI << aCamera->FOVy() << " ";
9210       }
9211     }
9212     else if (anArgIter + 1 < theArgsNb
9213           && anArgCase == "-xrpose")
9214     {
9215       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
9216       anXRArg.LowerCase();
9217       if (anXRArg == "base")
9218       {
9219         aCamera = aView->View()->BaseXRCamera();
9220       }
9221       else if (anXRArg == "head")
9222       {
9223         aCamera = aView->View()->PosedXRCamera();
9224       }
9225       else
9226       {
9227         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
9228         return 1;
9229       }
9230       if (aCamera.IsNull())
9231       {
9232         Message::SendFail() << "Error: undefined XR pose";
9233         return 0;
9234       }
9235       if (aView->AutoZFitMode())
9236       {
9237         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
9238         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
9239         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
9240       }
9241     }
9242     else if (aPrsName.IsEmpty()
9243          && !anArgCase.StartsWith ("-"))
9244     {
9245       aPrsName = anArg;
9246     }
9247     else
9248     {
9249       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
9250       return 1;
9251     }
9252   }
9253
9254   if (aPrsName.IsEmpty()
9255    || theArgsNb > 2)
9256   {
9257     aView->Redraw();
9258   }
9259
9260   if (!aPrsName.IsEmpty())
9261   {
9262     Handle(AIS_CameraFrustum) aCameraFrustum;
9263     if (GetMapOfAIS().IsBound2 (aPrsName))
9264     {
9265       // find existing object
9266       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
9267       if (aCameraFrustum.IsNull())
9268       {
9269         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
9270         return 1;
9271       }
9272     }
9273
9274     if (aCameraFrustum.IsNull())
9275     {
9276       aCameraFrustum = new AIS_CameraFrustum();
9277     }
9278     else
9279     {
9280       // not include displayed object of old camera frustum in the new one.
9281       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
9282       aView->ZFitAll();
9283     }
9284     aCameraFrustum->SetCameraFrustum (aCamera);
9285
9286     ViewerTest::Display (aPrsName, aCameraFrustum);
9287   }
9288
9289   return 0;
9290 }
9291
9292 //! Parse stereo output mode
9293 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
9294                                          Graphic3d_StereoMode& theMode)
9295 {
9296   TCollection_AsciiString aFlag (theArg);
9297   aFlag.LowerCase();
9298   if (aFlag == "quadbuffer")
9299   {
9300     theMode = Graphic3d_StereoMode_QuadBuffer;
9301   }
9302   else if (aFlag == "anaglyph")
9303   {
9304     theMode = Graphic3d_StereoMode_Anaglyph;
9305   }
9306   else if (aFlag == "row"
9307         || aFlag == "rowinterlaced")
9308   {
9309     theMode = Graphic3d_StereoMode_RowInterlaced;
9310   }
9311   else if (aFlag == "col"
9312         || aFlag == "colinterlaced"
9313         || aFlag == "columninterlaced")
9314   {
9315     theMode = Graphic3d_StereoMode_ColumnInterlaced;
9316   }
9317   else if (aFlag == "chess"
9318         || aFlag == "chessboard")
9319   {
9320     theMode = Graphic3d_StereoMode_ChessBoard;
9321   }
9322   else if (aFlag == "sbs"
9323         || aFlag == "sidebyside")
9324   {
9325     theMode = Graphic3d_StereoMode_SideBySide;
9326   }
9327   else if (aFlag == "ou"
9328         || aFlag == "overunder")
9329   {
9330     theMode = Graphic3d_StereoMode_OverUnder;
9331   }
9332   else if (aFlag == "pageflip"
9333         || aFlag == "softpageflip")
9334   {
9335     theMode = Graphic3d_StereoMode_SoftPageFlip;
9336   }
9337   else if (aFlag == "openvr"
9338         || aFlag == "vr")
9339   {
9340     theMode = Graphic3d_StereoMode_OpenVR;
9341   }
9342   else
9343   {
9344     return Standard_False;
9345   }
9346   return Standard_True;
9347 }
9348
9349 //! Parse anaglyph filter
9350 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
9351                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
9352 {
9353   TCollection_AsciiString aFlag (theArg);
9354   aFlag.LowerCase();
9355   if (aFlag == "redcyansimple")
9356   {
9357     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9358   }
9359   else if (aFlag == "redcyan"
9360         || aFlag == "redcyanoptimized")
9361   {
9362     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
9363   }
9364   else if (aFlag == "yellowbluesimple")
9365   {
9366     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
9367   }
9368   else if (aFlag == "yellowblue"
9369         || aFlag == "yellowblueoptimized")
9370   {
9371     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
9372   }
9373   else if (aFlag == "greenmagenta"
9374         || aFlag == "greenmagentasimple")
9375   {
9376     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
9377   }
9378   else
9379   {
9380     return Standard_False;
9381   }
9382   return Standard_True;
9383 }
9384
9385 //==============================================================================
9386 //function : VStereo
9387 //purpose  :
9388 //==============================================================================
9389
9390 static int VStereo (Draw_Interpretor& theDI,
9391                     Standard_Integer  theArgNb,
9392                     const char**      theArgVec)
9393 {
9394   Handle(V3d_View) aView = ViewerTest::CurrentView();
9395   if (aView.IsNull())
9396   {
9397     Message::SendFail ("Error: no active viewer");
9398     return 0;
9399   }
9400
9401   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9402   Graphic3d_RenderingParams* aParams = &aView->ChangeRenderingParams();
9403   if (theArgNb < 2)
9404   {
9405     Standard_Boolean isActive = aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo;
9406     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
9407     if (isActive)
9408     {
9409       TCollection_AsciiString aMode;
9410       switch (aView->RenderingParams().StereoMode)
9411       {
9412         case Graphic3d_StereoMode_QuadBuffer:
9413         {
9414           aMode = "quadBuffer";
9415           break;
9416         }
9417         case Graphic3d_StereoMode_RowInterlaced:
9418         {
9419           aMode = "rowInterlaced";
9420           if (aView->RenderingParams().ToSmoothInterlacing)
9421           {
9422             aMode.AssignCat (" (smoothed)");
9423           }
9424           break;
9425         }
9426         case Graphic3d_StereoMode_ColumnInterlaced:
9427         {
9428           aMode = "columnInterlaced";
9429           if (aView->RenderingParams().ToSmoothInterlacing)
9430           {
9431             aMode.AssignCat (" (smoothed)");
9432           }
9433           break;
9434         }
9435         case Graphic3d_StereoMode_ChessBoard:
9436         {
9437           aMode = "chessBoard";
9438           if (aView->RenderingParams().ToSmoothInterlacing)
9439           {
9440             aMode.AssignCat (" (smoothed)");
9441           }
9442           break;
9443         }
9444         case Graphic3d_StereoMode_SideBySide:
9445         {
9446           aMode = "sideBySide";
9447           break;
9448         }
9449         case Graphic3d_StereoMode_OverUnder:
9450         {
9451           aMode = "overUnder";
9452           break;
9453         }
9454         case Graphic3d_StereoMode_SoftPageFlip:
9455         {
9456           aMode = "softPageFlip";
9457           break;
9458         }
9459         case Graphic3d_StereoMode_OpenVR:
9460         {
9461           aMode = "openVR";
9462           break;
9463         }
9464         case Graphic3d_StereoMode_Anaglyph:
9465         {
9466           aMode = "anaglyph";
9467           switch (aView->RenderingParams().AnaglyphFilter)
9468           {
9469             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
9470             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
9471             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
9472             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
9473             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
9474             case Graphic3d_RenderingParams::Anaglyph_UserDefined         : aMode.AssignCat (" (userDefined)");        break;
9475           }
9476         }
9477       }
9478       theDI << "Mode " << aMode << "\n";
9479     }
9480     return 0;
9481   }
9482
9483   Graphic3d_StereoMode aMode = aParams->StereoMode;
9484   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
9485   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
9486   {
9487     Standard_CString        anArg = theArgVec[anArgIter];
9488     TCollection_AsciiString aFlag (anArg);
9489     aFlag.LowerCase();
9490     if (anUpdateTool.parseRedrawMode (aFlag))
9491     {
9492       continue;
9493     }
9494     else if (aFlag == "0"
9495           || aFlag == "off")
9496     {
9497       if (++anArgIter < theArgNb)
9498       {
9499         Message::SendFail ("Error: wrong number of arguments");
9500         return 1;
9501       }
9502
9503       if (aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
9504       {
9505         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9506       }
9507       return 0;
9508     }
9509     else if (aFlag == "1"
9510           || aFlag == "on")
9511     {
9512       if (++anArgIter < theArgNb)
9513       {
9514         Message::SendFail ("Error: wrong number of arguments");
9515         return 1;
9516       }
9517
9518       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9519       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
9520       {
9521         return 0;
9522       }
9523     }
9524     else if (aFlag == "-reverse"
9525           || aFlag == "-noreverse"
9526           || aFlag == "-reversed"
9527           || aFlag == "-swap"
9528           || aFlag == "-noswap")
9529     {
9530       aParams->ToReverseStereo = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
9531     }
9532     else if (aFlag == "-mode"
9533           || aFlag == "-stereomode")
9534     {
9535       if (++anArgIter >= theArgNb
9536       || !parseStereoMode (theArgVec[anArgIter], aMode))
9537       {
9538         Message::SendFail() << "Syntax error at '" << anArg << "'";
9539         return 1;
9540       }
9541
9542       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9543       {
9544         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9545       }
9546     }
9547     else if (aFlag == "-anaglyph"
9548           || aFlag == "-anaglyphfilter")
9549     {
9550       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9551       if (++anArgIter >= theArgNb
9552       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
9553       {
9554         Message::SendFail() << "Syntax error at '" << anArg << "'";
9555         return 1;
9556       }
9557
9558       aMode = Graphic3d_StereoMode_Anaglyph;
9559       aParams->AnaglyphFilter = aFilter;
9560     }
9561     else if (parseStereoMode (anArg, aMode)) // short syntax
9562     {
9563       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9564       {
9565         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9566       }
9567     }
9568     else if (anArgIter + 1 < theArgNb
9569           && aFlag == "-hmdfov2d")
9570     {
9571       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
9572       if (aParams->HmdFov2d < 10.0f
9573        || aParams->HmdFov2d > 180.0f)
9574       {
9575         Message::SendFail() << "Error: FOV is out of range";
9576         return 1;
9577       }
9578     }
9579     else if (aFlag == "-mirror"
9580           || aFlag == "-mirrorcomposer")
9581     {
9582       aParams->ToMirrorComposer = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);;
9583     }
9584     else if (aFlag == "-smooth"
9585           || aFlag == "-nosmooth"
9586           || aFlag == "-smoothinterlacing"
9587           || aFlag == "-nosmoothinterlacing")
9588     {
9589       aParams->ToSmoothInterlacing = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
9590     }
9591     else if (anArgIter + 1 < theArgNb
9592           && (aFlag == "-unitfactor"
9593            || aFlag == "-unitscale"))
9594     {
9595       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
9596     }
9597     else
9598     {
9599       Message::SendFail() << "Syntax error at '" << anArg << "'";
9600       return 1;
9601     }
9602   }
9603
9604   aParams->StereoMode = aMode;
9605   aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9606   if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
9607   {
9608     // initiate implicit continuous rendering
9609     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
9610   }
9611   return 0;
9612 }
9613
9614 //===============================================================================================
9615 //function : VDefaults
9616 //purpose  :
9617 //===============================================================================================
9618 static int VDefaults (Draw_Interpretor& theDi,
9619                       Standard_Integer  theArgsNb,
9620                       const char**      theArgVec)
9621 {
9622   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9623   if (aCtx.IsNull())
9624   {
9625     Message::SendFail ("Error: no active viewer");
9626     return 1;
9627   }
9628
9629   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
9630   if (theArgsNb < 2)
9631   {
9632     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
9633     {
9634       theDi << "DeflType:           relative\n"
9635             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
9636     }
9637     else
9638     {
9639       theDi << "DeflType:           absolute\n"
9640             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
9641     }
9642     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
9643     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
9644     return 0;
9645   }
9646
9647   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9648   {
9649     TCollection_AsciiString anArg (theArgVec[anArgIter]);
9650     anArg.UpperCase();
9651     if (anArg == "-ABSDEFL"
9652      || anArg == "-ABSOLUTEDEFLECTION"
9653      || anArg == "-DEFL"
9654      || anArg == "-DEFLECTION")
9655     {
9656       if (++anArgIter >= theArgsNb)
9657       {
9658         Message::SendFail() << "Syntax error at " << anArg;
9659         return 1;
9660       }
9661       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
9662       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
9663     }
9664     else if (anArg == "-RELDEFL"
9665           || anArg == "-RELATIVEDEFLECTION"
9666           || anArg == "-DEVCOEFF"
9667           || anArg == "-DEVIATIONCOEFF"
9668           || anArg == "-DEVIATIONCOEFFICIENT")
9669     {
9670       if (++anArgIter >= theArgsNb)
9671       {
9672         Message::SendFail() << "Syntax error at " << anArg;
9673         return 1;
9674       }
9675       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
9676       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
9677     }
9678     else if (anArg == "-ANGDEFL"
9679           || anArg == "-ANGULARDEFL"
9680           || anArg == "-ANGULARDEFLECTION")
9681     {
9682       if (++anArgIter >= theArgsNb)
9683       {
9684         Message::SendFail() << "Syntax error at " << anArg;
9685         return 1;
9686       }
9687       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
9688     }
9689     else if (anArg == "-AUTOTR"
9690           || anArg == "-AUTOTRIANG"
9691           || anArg == "-AUTOTRIANGULATION")
9692     {
9693       ++anArgIter;
9694       bool toTurnOn = true;
9695       if (anArgIter >= theArgsNb
9696       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
9697       {
9698         Message::SendFail() << "Syntax error at '" << anArg << "'";
9699         return 1;
9700       }
9701       aDefParams->SetAutoTriangulation (toTurnOn);
9702     }
9703     else
9704     {
9705       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
9706       return 1;
9707     }
9708   }
9709
9710   return 0;
9711 }
9712
9713 //! Parse light source type from string.
9714 static bool parseLightSourceType (const TCollection_AsciiString& theTypeName,
9715                                   Graphic3d_TypeOfLightSource& theType)
9716 {
9717   TCollection_AsciiString aType (theTypeName);
9718   aType.LowerCase();
9719   if (aType == "amb"
9720    || aType == "ambient"
9721    || aType == "amblight")
9722   {
9723     theType = Graphic3d_TypeOfLightSource_Ambient;
9724   }
9725   else if (aType == "directional"
9726         || aType == "dirlight")
9727   {
9728     theType = Graphic3d_TypeOfLightSource_Directional;
9729   }
9730   else if (aType == "spot"
9731         || aType == "spotlight")
9732   {
9733     theType = Graphic3d_TypeOfLightSource_Spot;
9734   }
9735   else if (aType == "poslight"
9736         || aType == "positional"
9737         || aType == "point"
9738         || aType == "pnt")
9739   {
9740     theType = Graphic3d_TypeOfLightSource_Positional;
9741   }
9742   else
9743   {
9744     return false;
9745   }
9746   return true;
9747 }
9748
9749 //! Find existing light by name or index.
9750 static Handle(V3d_Light) findLightSource (const TCollection_AsciiString& theName)
9751 {
9752   Handle(V3d_Light) aLight;
9753   Standard_Integer aLightIndex = -1;
9754   Draw::ParseInteger (theName.ToCString(), aLightIndex);
9755   Standard_Integer aLightIt = 0;
9756   Handle(V3d_View) aView = ViewerTest::CurrentView();
9757   for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
9758   {
9759     if (aLightIndex != -1)
9760     {
9761       if (aLightIt == aLightIndex)
9762       {
9763         return aLightIter.Value();
9764       }
9765     }
9766     else if (aLightIter.Value()->GetId() == theName
9767           || aLightIter.Value()->Name()  == theName)
9768     {
9769       if (!aLight.IsNull())
9770       {
9771         Message::SendWarning() << "Warning: ambiguous light name '" << theName << "'";
9772         break;
9773       }
9774       aLight = aLightIter.Value();
9775     }
9776   }
9777   return aLight;
9778 }
9779
9780 //===============================================================================================
9781 //function : VLight
9782 //purpose  :
9783 //===============================================================================================
9784 static int VLight (Draw_Interpretor& theDi,
9785                    Standard_Integer  theArgsNb,
9786                    const char**      theArgVec)
9787 {
9788   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
9789   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
9790   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9791   if (aView.IsNull()
9792    || aViewer.IsNull())
9793   {
9794     Message::SendFail ("Error: no active viewer");
9795     return 1;
9796   }
9797
9798   if (theArgsNb < 2)
9799   {
9800     // print lights info
9801     Standard_Integer aLightId = 0;
9802     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
9803     {
9804       Handle(V3d_Light) aLight = aLightIter.Value();
9805       const Quantity_Color aColor = aLight->Color();
9806       theDi << "Light #" << aLightId
9807             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
9808             << " [" << aLight->GetId() << "] "
9809             << (aLight->IsEnabled() ? "ON" : "OFF") << "\n";
9810       switch (aLight->Type())
9811       {
9812         case V3d_AMBIENT:
9813         {
9814           theDi << "  Type:       Ambient\n"
9815                 << "  Intensity:  " << aLight->Intensity() << "\n";
9816           break;
9817         }
9818         case V3d_DIRECTIONAL:
9819         {
9820           theDi << "  Type:       Directional\n"
9821                 << "  Intensity:  " << aLight->Intensity() << "\n"
9822                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9823                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9824                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9825                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n";
9826           break;
9827         }
9828         case V3d_POSITIONAL:
9829         {
9830           theDi << "  Type:       Positional\n"
9831                 << "  Intensity:  " << aLight->Intensity() << "\n"
9832                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9833                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9834                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9835                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9836                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9837                 << "  Range:      " << aLight->Range() << "\n";
9838           break;
9839         }
9840         case V3d_SPOT:
9841         {
9842           theDi << "  Type:       Spot\n"
9843                 << "  Intensity:  " << aLight->Intensity() << "\n"
9844                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9845                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9846                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9847                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n"
9848                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9849                 << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n"
9850                 << "  Exponent:   " << aLight->Concentration() << "\n"
9851                 << "  Range:      " << aLight->Range() << "\n";
9852           break;
9853         }
9854         default:
9855         {
9856           theDi << "  Type:       UNKNOWN\n";
9857           break;
9858         }
9859       }
9860       theDi << "  Color:      " << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
9861     }
9862   }
9863
9864   Handle(V3d_Light) aLightOld, aLightNew;
9865   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
9866   bool isGlobal = true;
9867   ViewerTest_AutoUpdater anUpdateTool (aCtx, aView);
9868   Handle(AIS_LightSource) aLightPrs;
9869   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
9870   {
9871     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
9872     TCollection_AsciiString anArgCase (anArg);
9873     anArgCase.LowerCase();
9874     if (anUpdateTool.parseRedrawMode (anArg))
9875     {
9876       continue;
9877     }
9878     else if (anArgCase == "-new"
9879           || anArgCase == "-add"
9880           || anArgCase == "-create"
9881           || anArgCase == "-type"
9882           || (anArgCase == "-reset"
9883           && !aLightNew.IsNull())
9884           || (anArgCase == "-defaults"
9885           && !aLightNew.IsNull())
9886           || anArgCase == "add"
9887           || anArgCase == "new"
9888           || anArgCase == "create")
9889     {
9890       Graphic3d_TypeOfLightSource aType = Graphic3d_TypeOfLightSource_Ambient;
9891       if (anArgCase == "-reset")
9892       {
9893         aType = aLightNew->Type();
9894       }
9895       else if (anArgIt + 1 >= theArgsNb
9896            || !parseLightSourceType (theArgVec[++anArgIt], aType))
9897       {
9898         theDi << "Syntax error at '" << theArgVec[anArgIt] << "'\n";
9899         return 1;
9900       }
9901
9902       TCollection_AsciiString aName;
9903       if (!aLightNew.IsNull())
9904       {
9905         aName = aLightNew->Name();
9906       }
9907       switch (aType)
9908       {
9909         case Graphic3d_TypeOfLightSource_Ambient:
9910         {
9911           aLightNew = new V3d_AmbientLight();
9912           break;
9913         }
9914         case Graphic3d_TypeOfLightSource_Directional:
9915         {
9916           aLightNew = new V3d_DirectionalLight();
9917           break;
9918         }
9919         case Graphic3d_TypeOfLightSource_Spot:
9920         {
9921           aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
9922           break;
9923         }
9924         case Graphic3d_TypeOfLightSource_Positional:
9925         {
9926           aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
9927           break;
9928         }
9929       }
9930
9931       if (anArgCase == "-type"
9932       && !aLightOld.IsNull())
9933       {
9934         aLightNew->CopyFrom (aLightOld);
9935       }
9936       aLightNew->SetName (aName);
9937     }
9938     else if ((anArgCase == "-layer"
9939            || anArgCase == "-zlayer")
9940           && anArgIt + 1 < theArgsNb)
9941     {
9942       if (!ViewerTest::ParseZLayer (theArgVec[++anArgIt], aLayer)
9943       ||  aLayer == Graphic3d_ZLayerId_UNKNOWN)
9944       {
9945         Message::SendFail() << "Error: wrong syntax at '" << theArgVec[anArgIt] << "'";
9946         return 1;
9947       }
9948     }
9949     else if (anArgCase == "-glob"
9950           || anArgCase == "-global"
9951           || anArgCase == "-loc"
9952           || anArgCase == "-local")
9953     {
9954       isGlobal = anArgCase.StartsWith ("-glob");
9955     }
9956     else if (anArgCase == "-def"
9957           || anArgCase == "-defaults"
9958           || anArgCase == "-reset")
9959     {
9960       aViewer->SetDefaultLights();
9961       aLightOld.Nullify();
9962       aLightNew.Nullify();
9963       aLightPrs.Nullify();
9964     }
9965     else if (anArgCase == "-clr"
9966           || anArgCase == "-clear"
9967           || anArgCase == "clear")
9968     {
9969       TColStd_SequenceOfInteger aLayers;
9970       aViewer->GetAllZLayers (aLayers);
9971       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
9972       {
9973         if (aLayeriter.Value() == aLayer
9974          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
9975         {
9976           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
9977           aSettings.SetLights (Handle(Graphic3d_LightSet)());
9978           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
9979           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
9980           {
9981             break;
9982           }
9983         }
9984       }
9985
9986       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
9987       {
9988         ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
9989         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
9990         {
9991           Handle(V3d_Light) aLight = aLightIter.Value();
9992           Handle(AIS_InteractiveObject) aPrsObject;
9993           GetMapOfAIS().Find2 (aLight->Name(), aPrsObject);
9994           if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
9995           {
9996             aCtx->Remove (aLightSourceDel, false);
9997             aMap.UnBind1 (aLightSourceDel);
9998           }
9999           aViewer->DelLight (aLight);
10000           aLightIter = aView->ActiveLightIterator();
10001         }
10002       }
10003
10004       aLightOld.Nullify();
10005       aLightNew.Nullify();
10006       aLightPrs.Nullify();
10007     }
10008     else if (!aLightNew.IsNull()
10009           && (anArgCase == "-display"
10010            || anArgCase == "-disp"
10011            || anArgCase == "-presentation"
10012            || anArgCase == "-prs"))
10013     {
10014       TCollection_AsciiString aLightName = aLightNew->Name();
10015       if (anArgIt + 1 < theArgsNb
10016        && theArgVec[anArgIt + 1][0] != '-')
10017       {
10018         // old syntax
10019         aLightName = theArgVec[++anArgIt];
10020         if (aLightNew->Name() != aLightName)
10021         {
10022           if (Handle(V3d_Light) anOtherLight = findLightSource (aLightName))
10023           {
10024             theDi << "Syntax error: light with name '" << aLightName << "' is already defined";
10025             return 1;
10026           }
10027           aLightNew->SetName (aLightName);
10028         }
10029       }
10030       if (aLightName.IsEmpty())
10031       {
10032         Message::SendFail() << "Error: nameless light source cannot be displayed";
10033         return 1;
10034       }
10035       if (aLightPrs.IsNull())
10036       {
10037         aLightPrs = new AIS_LightSource (aLightNew);
10038       }
10039       theDi << aLightName << " ";
10040     }
10041     else if (!aLightNew.IsNull()
10042           && (anArgCase == "-disable"
10043            || anArgCase == "-disabled"
10044            || anArgCase == "-enable"
10045            || anArgCase == "-enabled"))
10046     {
10047       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10048       if (anArgCase == "-disable"
10049        || anArgCase == "-disabled")
10050       {
10051         toEnable = !toEnable;
10052       }
10053       aLightNew->SetEnabled (toEnable);
10054     }
10055     else if (!aLightNew.IsNull()
10056           && (anArgCase == "-color"
10057            || anArgCase == "-colour"
10058            || anArgCase == "color"))
10059     {
10060       Quantity_Color aColor;
10061       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
10062                                                      theArgVec + anArgIt + 1,
10063                                                      aColor);
10064       anArgIt += aNbParsed;
10065       if (aNbParsed == 0)
10066       {
10067         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10068         return 1;
10069       }
10070       aLightNew->SetColor (aColor);
10071     }
10072     else if (!aLightNew.IsNull()
10073           && (anArgCase == "-pos"
10074            || anArgCase == "-position"
10075            || anArgCase == "-prsposition"
10076            || anArgCase == "-prspos"
10077            || anArgCase == "pos"
10078            || anArgCase == "position")
10079           && (anArgIt + 3) < theArgsNb)
10080     {
10081       gp_XYZ aPosXYZ;
10082       if (!parseXYZ (theArgVec + anArgIt + 1, aPosXYZ))
10083       {
10084         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10085         return 1;
10086       }
10087
10088       anArgIt += 3;
10089       if (anArgCase == "-prsposition"
10090        || anArgCase == "-prspos")
10091       {
10092         aLightNew->SetDisplayPosition (aPosXYZ);
10093       }
10094       else
10095       {
10096         if (aLightNew->Type() != Graphic3d_TypeOfLightSource_Positional
10097          && aLightNew->Type() != Graphic3d_TypeOfLightSource_Spot)
10098         {
10099           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10100           return 1;
10101         }
10102
10103         aLightNew->SetPosition (aPosXYZ);
10104       }
10105     }
10106     else if (!aLightNew.IsNull()
10107           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional
10108            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10109           && (anArgCase == "-dir"
10110            || anArgCase == "-direction")
10111           && (anArgIt + 3) < theArgsNb)
10112     {
10113       gp_XYZ aDirXYZ;
10114       if (!parseXYZ (theArgVec + anArgIt + 1, aDirXYZ))
10115       {
10116         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10117         return 1;
10118       }
10119
10120       anArgIt += 3;
10121       aLightNew->SetDirection (gp_Dir (aDirXYZ));
10122     }
10123     else if (!aLightNew.IsNull()
10124           && (anArgCase == "-smoothangle"
10125            || anArgCase == "-smoothradius"
10126            || anArgCase == "-sm"
10127            || anArgCase == "-smoothness")
10128           && anArgIt + 1 < theArgsNb)
10129     {
10130       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10131       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10132       {
10133         aSmoothness = Standard_ShortReal(aSmoothness * M_PI / 180.0);
10134       }
10135       if (Abs (aSmoothness) <= ShortRealEpsilon())
10136       {
10137         aLightNew->SetIntensity (1.f);
10138       }
10139       else if (Abs (aLightNew->Smoothness()) <= ShortRealEpsilon())
10140       {
10141         aLightNew->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
10142       }
10143       else
10144       {
10145         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightNew->Smoothness());
10146         aLightNew->SetIntensity (aLightNew->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
10147       }
10148
10149       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10150       {
10151         aLightNew->SetSmoothRadius (aSmoothness);
10152       }
10153       else if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10154       {
10155         aLightNew->SetSmoothAngle (aSmoothness);
10156       }
10157     }
10158     else if (!aLightNew.IsNull()
10159           && (anArgCase == "-int"
10160            || anArgCase == "-intensity")
10161           && anArgIt + 1 < theArgsNb)
10162     {
10163       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10164       aLightNew->SetIntensity (aIntensity);
10165     }
10166     else if (!aLightNew.IsNull()
10167           &&  aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10168           && (anArgCase == "-spotangle"
10169            || anArgCase == "-ang"
10170            || anArgCase == "-angle")
10171           && anArgIt + 1 < theArgsNb)
10172     {
10173       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10174       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
10175       aLightNew->SetAngle (anAngle);
10176     }
10177     else if (!aLightNew.IsNull()
10178           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10179            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10180           && (anArgCase == "-constatten"
10181            || anArgCase == "-constattenuation")
10182           && anArgIt + 1 < theArgsNb)
10183     {
10184       const Standard_ShortReal aConstAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10185       aLightNew->SetAttenuation (aConstAtten, aLightNew->LinearAttenuation());
10186     }
10187     else if (!aLightNew.IsNull()
10188           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10189            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10190           && (anArgCase == "-linatten"
10191            || anArgCase == "-linearatten"
10192            || anArgCase == "-linearattenuation")
10193           && anArgIt + 1 < theArgsNb)
10194     {
10195       const Standard_ShortReal aLinAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10196       aLightNew->SetAttenuation (aLightNew->ConstAttenuation(), aLinAtten);
10197     }
10198     else if (!aLightNew.IsNull()
10199           && aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10200           && (anArgCase == "-spotexp"
10201            || anArgCase == "-spotexponent"
10202            || anArgCase == "-exp"
10203            || anArgCase == "-exponent")
10204           && anArgIt + 1 < theArgsNb)
10205     {
10206       aLightNew->SetConcentration ((Standard_ShortReal )Atof (theArgVec[++anArgIt]));
10207     }
10208     else if (!aLightNew.IsNull()
10209            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10210            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Directional
10211            && anArgCase == "-range"
10212            && anArgIt + 1 < theArgsNb)
10213     {
10214       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[++anArgIt]));
10215       aLightNew->SetRange (aRange);
10216     }
10217     else if (!aLightNew.IsNull()
10218           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10219           && (anArgCase == "-head"
10220            || anArgCase == "-headlight"))
10221     {
10222       Standard_Boolean isHeadLight = Standard_True;
10223       if (anArgIt + 1 < theArgsNb
10224        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
10225       {
10226         ++anArgIt;
10227       }
10228       aLightNew->SetHeadlight (isHeadLight);
10229     }
10230     else if (!aLightNew.IsNull()
10231            && anArgCase == "-name"
10232            && anArgIt + 1 < theArgsNb)
10233     {
10234       const TCollection_AsciiString aName = theArgVec[++anArgIt];
10235       if (aLightNew->Name() == aName)
10236       {
10237         continue;
10238       }
10239
10240       if (Handle(V3d_Light) anOtherLight = findLightSource (aName))
10241       {
10242         theDi << "Syntax error: light with name '" << aName << "' is already defined";
10243         return 1;
10244       }
10245       aLightNew->SetName (aName);
10246     }
10247     else if (!aLightPrs.IsNull()
10248           && (anArgCase == "-showzoomable"
10249            || anArgCase == "-prszoomable"
10250            || anArgCase == "-zoomable"))
10251     {
10252       const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10253       aLightPrs->SetZoomable (isZoomable);
10254     }
10255     else if (!aLightPrs.IsNull()
10256          && (anArgCase == "-showdraggable"
10257           || anArgCase == "-prsdraggable"
10258           || anArgCase == "-draggable"))
10259     {
10260       const bool isDraggable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10261       aLightPrs->SetDraggable (isDraggable);
10262     }
10263     else if (!aLightPrs.IsNull()
10264           && (anArgCase == "-showname"
10265            || anArgCase == "-prsname"))
10266     {
10267       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10268       aLightPrs->SetDisplayName (toDisplay);
10269     }
10270     else if (!aLightPrs.IsNull()
10271           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10272            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10273           && (anArgCase == "-showrange"
10274            || anArgCase == "-prsrange"))
10275     {
10276       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10277       aLightPrs->SetDisplayRange (toDisplay);
10278     }
10279     else if (!aLightPrs.IsNull()
10280           && (anArgCase == "-showsize"
10281            || anArgCase == "-prssize")
10282           && anArgIt + 1 < theArgsNb)
10283     {
10284       Standard_Real aSize = 0.0;
10285       if (!Draw::ParseReal (theArgVec[++anArgIt], aSize)
10286        || aSize <= 0.0
10287        || aLightPrs.IsNull())
10288       {
10289         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10290         return 1;
10291       }
10292
10293       aLightPrs->SetSize (aSize);
10294     }
10295     else if (!aLightPrs.IsNull()
10296           && (anArgCase == "-dirarcsize"
10297            || anArgCase == "-arcsize"
10298            || anArgCase == "-arc")
10299           && anArgIt + 1 < theArgsNb)
10300     {
10301       Standard_Integer aSize = 0;
10302       if (!Draw::ParseInteger (theArgVec[anArgIt + 1], aSize)
10303        || aSize <= 0
10304        || aLightPrs->Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
10305       {
10306         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10307         return 1;
10308       }
10309       ++anArgIt;
10310       aLightPrs->SetArcSize (aSize);
10311     }
10312     else if (!aLightNew.IsNull()
10313           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10314           && (anArgCase == "-castshadow"
10315            || anArgCase == "-castshadows"
10316            || anArgCase == "-shadows"))
10317     {
10318       bool toCastShadows = true;
10319       if (anArgIt + 1 < theArgsNb
10320        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
10321       {
10322         ++anArgIt;
10323       }
10324       aLightNew->SetCastShadows (toCastShadows);
10325     }
10326     else if (anArgCase == "-del"
10327           || anArgCase == "-delete"
10328           || anArgCase == "-remove"
10329           || anArgCase == "del"
10330           || anArgCase == "delete"
10331           || anArgCase == "remove")
10332     {
10333       if (aLightOld.IsNull())
10334       {
10335         if (!aLightNew.IsNull())
10336         {
10337           aLightNew.Nullify();
10338           continue;
10339         }
10340
10341         if (++anArgIt >= theArgsNb)
10342         {
10343           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10344           return 1;
10345         }
10346
10347         const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10348         aLightOld = findLightSource (anOldName);
10349         if (aLightOld.IsNull())
10350         {
10351           Message::SendWarning() << "Warning: light '" << anOldName << "' not found";
10352           continue;
10353         }
10354       }
10355
10356       aLightNew.Nullify();
10357       aLightPrs.Nullify();
10358     }
10359     else if (anArgCase == "-change"
10360           || anArgCase == "change")
10361     {
10362       // just skip old syntax
10363     }
10364     else if (aLightNew.IsNull()
10365          && !anArgCase.StartsWith ("-"))
10366     {
10367       if (!aLightNew.IsNull())
10368       {
10369         continue;
10370       }
10371
10372       const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10373       aLightOld = findLightSource (anOldName);
10374       if (!aLightOld.IsNull())
10375       {
10376         aLightNew = aLightOld;
10377
10378         Handle(AIS_InteractiveObject) aPrsObject;
10379         GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10380         aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsObject);
10381       }
10382       else
10383       {
10384         Standard_Integer aLightIndex = -1;
10385         Draw::ParseInteger (anOldName.ToCString(), aLightIndex);
10386         if (aLightIndex != -1)
10387         {
10388           Message::SendFail() << "Syntax error: light source with index '" << aLightIndex << "' is not found";
10389           return 1;
10390         }
10391
10392         aLightNew = new V3d_AmbientLight();
10393         aLightNew->SetName (anOldName);
10394       }
10395     }
10396     else
10397     {
10398       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
10399       return 1;
10400     }
10401   }
10402
10403   // delete old light source
10404   if (!aLightOld.IsNull()
10405     && aLightOld != aLightNew)
10406   {
10407     TColStd_SequenceOfInteger aLayers;
10408     aViewer->GetAllZLayers (aLayers);
10409     for (TColStd_SequenceOfInteger::Iterator aLayerIter (aLayers); aLayerIter.More(); aLayerIter.Next())
10410     {
10411       if (aLayerIter.Value() == aLayer
10412        || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10413       {
10414         Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerIter.Value());
10415         if (!aSettings.Lights().IsNull())
10416         {
10417           aSettings.Lights()->Remove (aLightOld);
10418           if (aSettings.Lights()->IsEmpty())
10419           {
10420             aSettings.SetLights (Handle(Graphic3d_LightSet)());
10421           }
10422         }
10423         aViewer->SetZLayerSettings (aLayerIter.Value(), aSettings);
10424         if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10425         {
10426           break;
10427         }
10428       }
10429     }
10430
10431     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10432     {
10433       Handle(AIS_InteractiveObject) aPrsObject;
10434       GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10435       if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10436       {
10437         aCtx->Remove (aLightSourceDel, false);
10438         GetMapOfAIS().UnBind1 (aLightSourceDel);
10439       }
10440       aViewer->DelLight (aLightOld);
10441     }
10442     aLightOld.Nullify();
10443   }
10444
10445   // add new light source
10446   if (!aLightNew.IsNull())
10447   {
10448     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10449     {
10450       aViewer->AddLight (aLightNew);
10451       if (isGlobal)
10452       {
10453         aViewer->SetLightOn (aLightNew);
10454       }
10455       else
10456       {
10457         aView->SetLightOn (aLightNew);
10458       }
10459     }
10460     else
10461     {
10462       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayer);
10463       if (aSettings.Lights().IsNull())
10464       {
10465         aSettings.SetLights (new Graphic3d_LightSet());
10466       }
10467       aSettings.Lights()->Add (aLightNew);
10468       aViewer->SetZLayerSettings (aLayer, aSettings);
10469     }
10470
10471     if (!aLightPrs.IsNull())
10472     {
10473       aLightPrs->SetLight (aLightNew);
10474       ViewerTest::Display (aLightNew->Name(), aLightPrs, false);
10475     }
10476   }
10477
10478   // manage presentations
10479   struct LightPrsSort
10480   {
10481     bool operator() (const Handle(AIS_LightSource)& theLeft,
10482                      const Handle(AIS_LightSource)& theRight)
10483     {
10484       return theLeft->Light()->GetId() < theRight->Light()->GetId();
10485     }
10486   };
10487
10488   AIS_ListOfInteractive aPrsList;
10489   aCtx->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
10490   if (!aPrsList.IsEmpty())
10491   {
10492     // update light source presentations
10493     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
10494     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
10495     {
10496       if (Handle(AIS_LightSource) aLightPrs2 = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
10497       {
10498         aLightPrsVec.push_back (aLightPrs2);
10499       }
10500     }
10501
10502     // sort objects by id as AIS_InteractiveContext stores them in unordered map
10503     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
10504
10505     Standard_Integer aTopStack = 0;
10506     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
10507     {
10508       Handle(AIS_LightSource) aLightPrs2 = *aPrsIter;
10509       if (!aLightPrs2->TransformPersistence().IsNull()
10510         && aLightPrs2->TransformPersistence()->IsTrihedronOr2d())
10511       {
10512         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs2->Size();
10513         aLightPrs2->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
10514         aTopStack += aPrsSize + aPrsSize / 2;
10515       }
10516       aCtx->Redisplay (aLightPrs2, false);
10517       aCtx->SetTransformPersistence (aLightPrs2, aLightPrs2->TransformPersistence());
10518     }
10519   }
10520   return 0;
10521 }
10522
10523 //===============================================================================================
10524 //function : VPBREnvironment
10525 //purpose  :
10526 //===============================================================================================
10527 static int VPBREnvironment (Draw_Interpretor&,
10528                             Standard_Integer theArgsNb,
10529                             const char**     theArgVec)
10530 {
10531   if (theArgsNb > 2)
10532   {
10533     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
10534     return 1;
10535   }
10536
10537   Handle(V3d_View) aView = ViewerTest::CurrentView();
10538   if (aView.IsNull())
10539   {
10540     Message::SendFail ("Error: no active viewer");
10541     return 1;
10542   }
10543
10544   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
10545   anArg.LowerCase();
10546
10547   if (anArg == "-generate"
10548    || anArg == "-gen")
10549   {
10550     aView->GeneratePBREnvironment (Standard_True);
10551   }
10552   else if (anArg == "-clear")
10553   {
10554     aView->ClearPBREnvironment (Standard_True);
10555   }
10556   else
10557   {
10558     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
10559     return 1;
10560   }
10561
10562   return 0;
10563 }
10564
10565 //! Read Graphic3d_RenderingParams::PerfCounters flag.
10566 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
10567                                             Standard_Boolean& theToReset,
10568                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
10569                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
10570 {
10571   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
10572   TCollection_AsciiString aVal = theValue;
10573   Standard_Boolean toReverse = Standard_False;
10574   if (aVal == "none")
10575   {
10576     theToReset = Standard_True;
10577     return Standard_True;
10578   }
10579   else if (aVal.StartsWith ("-"))
10580   {
10581     toReverse = Standard_True;
10582     aVal = aVal.SubString (2, aVal.Length());
10583   }
10584   else if (aVal.StartsWith ("no"))
10585   {
10586     toReverse = Standard_True;
10587     aVal = aVal.SubString (3, aVal.Length());
10588   }
10589   else if (aVal.StartsWith ("+"))
10590   {
10591     aVal = aVal.SubString (2, aVal.Length());
10592   }
10593   else
10594   {
10595     theToReset = Standard_True;
10596   }
10597
10598   if (     aVal == "fps"
10599         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
10600   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
10601   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
10602   else if (aVal == "structs"
10603         || aVal == "structures"
10604         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
10605   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
10606   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
10607   else if (aVal == "tris"
10608         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
10609   else if (aVal == "pnts"
10610         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
10611   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
10612   else if (aVal == "mem"
10613         || aVal == "gpumem"
10614         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
10615   else if (aVal == "skipimmediate"
10616         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
10617   else if (aVal == "frametime"
10618         || aVal == "frametimers"
10619         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
10620   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
10621   else if (aVal == "extended"
10622         || aVal == "verbose"
10623         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
10624   else if (aVal == "full"
10625         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
10626   else
10627   {
10628     return Standard_False;
10629   }
10630
10631   if (toReverse)
10632   {
10633     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
10634   }
10635   else
10636   {
10637     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
10638   }
10639   return Standard_True;
10640 }
10641
10642 //! Read Graphic3d_RenderingParams::PerfCounters flags.
10643 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
10644                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
10645 {
10646   TCollection_AsciiString aValue = theValue;
10647   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
10648   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
10649   Standard_Boolean toReset = Standard_False;
10650   for (;;)
10651   {
10652     Standard_Integer aSplitPos = aValue.Search ("|");
10653     if (aSplitPos <= 0)
10654     {
10655       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
10656       {
10657         return Standard_False;
10658       }
10659       if (toReset)
10660       {
10661         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
10662       }
10663       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
10664       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
10665       return Standard_True;
10666     }
10667
10668     if (aSplitPos > 1)
10669     {
10670       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
10671       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
10672       {
10673         return Standard_False;
10674       }
10675     }
10676     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
10677   }
10678 }
10679
10680 //=======================================================================
10681 //function : VRenderParams
10682 //purpose  : Enables/disables rendering features
10683 //=======================================================================
10684
10685 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
10686                                        Standard_Integer  theArgNb,
10687                                        const char**      theArgVec)
10688 {
10689   Handle(V3d_View) aView = ViewerTest::CurrentView();
10690   if (aView.IsNull())
10691   {
10692     Message::SendFail ("Error: no active viewer");
10693     return 1;
10694   }
10695
10696   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
10697   TCollection_AsciiString aCmdName (theArgVec[0]);
10698   aCmdName.LowerCase();
10699   if (aCmdName == "vraytrace")
10700   {
10701     if (theArgNb == 1)
10702     {
10703       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
10704       return 0;
10705     }
10706     else if (theArgNb == 2)
10707     {
10708       TCollection_AsciiString aValue (theArgVec[1]);
10709       aValue.LowerCase();
10710       if (aValue == "on"
10711        || aValue == "1")
10712       {
10713         aParams.Method = Graphic3d_RM_RAYTRACING;
10714         aView->Redraw();
10715         return 0;
10716       }
10717       else if (aValue == "off"
10718             || aValue == "0")
10719       {
10720         aParams.Method = Graphic3d_RM_RASTERIZATION;
10721         aView->Redraw();
10722         return 0;
10723       }
10724       else
10725       {
10726         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
10727         return 1;
10728       }
10729     }
10730     else
10731     {
10732       Message::SendFail ("Syntax error: wrong number of arguments");
10733       return 1;
10734     }
10735   }
10736
10737   if (theArgNb < 2)
10738   {
10739     theDI << "renderMode:  ";
10740     switch (aParams.Method)
10741     {
10742       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10743       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
10744     }
10745     theDI << "\n";
10746     theDI << "transparency:  ";
10747     switch (aParams.TransparencyMethod)
10748     {
10749       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
10750       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
10751                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
10752       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
10753                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
10754     }
10755     theDI << "\n";
10756     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
10757     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
10758     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
10759     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
10760     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
10761     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
10762     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
10763     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
10764     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
10765     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
10766     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
10767     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
10768     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
10769     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
10770     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
10771     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
10772     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
10773     theDI << "shadingModel: ";
10774     switch (aView->ShadingModel())
10775     {
10776       case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
10777       case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit";     break;
10778       case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat";      break;
10779       case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud";   break;
10780       case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong";     break;
10781       case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
10782       case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
10783     }
10784     theDI << "\n";
10785     {
10786       theDI << "perfCounters:";
10787       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
10788       {
10789         theDI << " fps";
10790       }
10791       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
10792       {
10793         theDI << " cpu";
10794       }
10795       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
10796       {
10797         theDI << " structs";
10798       }
10799       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
10800       {
10801         theDI << " groups";
10802       }
10803       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
10804       {
10805         theDI << " arrays";
10806       }
10807       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
10808       {
10809         theDI << " tris";
10810       }
10811       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
10812       {
10813         theDI << " lines";
10814       }
10815       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
10816       {
10817         theDI << " pnts";
10818       }
10819       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
10820       {
10821         theDI << " gpumem";
10822       }
10823       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
10824       {
10825         theDI << " frameTime";
10826       }
10827       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
10828       {
10829         theDI << " skipimmediate";
10830       }
10831       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
10832       {
10833         theDI << " none";
10834       }
10835       theDI << "\n";
10836     }
10837     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
10838     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
10839     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
10840                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
10841                                                                                                                     "noUpdate") << "\n";
10842     theDI << "\n";
10843     return 0;
10844   }
10845
10846   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
10847   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10848   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10849   {
10850     Standard_CString        anArg (theArgVec[anArgIter]);
10851     TCollection_AsciiString aFlag (anArg);
10852     aFlag.LowerCase();
10853     if (anUpdateTool.parseRedrawMode (aFlag))
10854     {
10855       continue;
10856     }
10857     else if (aFlag == "-echo"
10858           || aFlag == "-print")
10859     {
10860       toPrint = Standard_True;
10861       anUpdateTool.Invalidate();
10862     }
10863     else if (aFlag == "-reset")
10864     {
10865       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
10866     }
10867     else if (aFlag == "-sync"
10868           && (anArgIter + 1 < theArgNb))
10869     {
10870       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
10871       aSyncFlag.LowerCase();
10872       if (aSyncFlag == "default"
10873        || aSyncFlag == "defaults"
10874        || aSyncFlag == "viewer")
10875       {
10876         toSyncDefaults = true;
10877       }
10878       else if (aSyncFlag == "allviews"
10879             || aSyncFlag == "views")
10880       {
10881         toSyncAllViews = true;
10882       }
10883       else
10884       {
10885         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
10886         return 1;
10887       }
10888     }
10889     else if (aFlag == "-mode"
10890           || aFlag == "-rendermode"
10891           || aFlag == "-render_mode")
10892     {
10893       if (toPrint)
10894       {
10895         switch (aParams.Method)
10896         {
10897           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10898           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
10899         }
10900         continue;
10901       }
10902       else
10903       {
10904         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10905         return 1;
10906       }
10907     }
10908     else if (aFlag == "-ray"
10909           || aFlag == "-raytrace")
10910     {
10911       if (toPrint)
10912       {
10913         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
10914         continue;
10915       }
10916
10917       bool isRayTrace = true;
10918       if (anArgIter + 1 < theArgNb
10919        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
10920       {
10921         ++anArgIter;
10922       }
10923       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
10924     }
10925     else if (aFlag == "-rast"
10926           || aFlag == "-raster"
10927           || aFlag == "-rasterization")
10928     {
10929       if (toPrint)
10930       {
10931         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
10932         continue;
10933       }
10934
10935       bool isRaster = true;
10936       if (anArgIter + 1 < theArgNb
10937        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
10938       {
10939         ++anArgIter;
10940       }
10941       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
10942     }
10943     else if (aFlag == "-msaa")
10944     {
10945       if (toPrint)
10946       {
10947         theDI << aParams.NbMsaaSamples << " ";
10948         continue;
10949       }
10950       else if (++anArgIter >= theArgNb)
10951       {
10952         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10953         return 1;
10954       }
10955
10956       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
10957       if (aNbSamples < 0)
10958       {
10959         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
10960         return 1;
10961       }
10962       else
10963       {
10964         aParams.NbMsaaSamples = aNbSamples;
10965       }
10966     }
10967     else if (aFlag == "-linefeather"
10968           || aFlag == "-edgefeather"
10969           || aFlag == "-feather")
10970     {
10971       if (toPrint)
10972       {
10973         theDI << " " << aParams.LineFeather << " ";
10974         continue;
10975       }
10976       else if (++anArgIter >= theArgNb)
10977       {
10978         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10979         return 1;
10980       }
10981
10982       TCollection_AsciiString aParam = theArgVec[anArgIter];
10983       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
10984       if (aFeather <= 0.0f)
10985       {
10986         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
10987         return 1;
10988       }
10989       aParams.LineFeather = aFeather;
10990     }
10991     else if (aFlag == "-oit")
10992     {
10993       if (toPrint)
10994       {
10995         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
10996         {
10997           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
10998         }
10999         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
11000         {
11001           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
11002         }
11003         else
11004         {
11005           theDI << "off" << " ";
11006         }
11007         continue;
11008       }
11009       else if (++anArgIter >= theArgNb)
11010       {
11011         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11012         return 1;
11013       }
11014
11015       TCollection_AsciiString aParam = theArgVec[anArgIter];
11016       aParam.LowerCase();
11017       if (aParam == "peeling"
11018        || aParam == "peel")
11019       {
11020         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
11021         if (anArgIter + 1 < theArgNb
11022          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
11023         {
11024           ++anArgIter;
11025           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11026           if (aNbLayers < 2)
11027           {
11028             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
11029             return 1;
11030           }
11031           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11032         }
11033       }
11034       else if (aParam == "weighted"
11035             || aParam == "weight")
11036       {
11037         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11038         if (anArgIter + 1 < theArgNb
11039          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
11040         {
11041           ++anArgIter;
11042           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
11043           if (aWeight < 0.f || aWeight > 1.f)
11044           {
11045             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11046             return 1;
11047           }
11048           aParams.OitDepthFactor = aWeight;
11049         }
11050       }
11051       else if (aParam.IsRealValue())
11052       {
11053         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11054         if (aWeight < 0.f || aWeight > 1.f)
11055         {
11056           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11057           return 1;
11058         }
11059
11060         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11061         aParams.OitDepthFactor     = aWeight;
11062       }
11063       else if (aParam == "off")
11064       {
11065         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
11066       }
11067       else
11068       {
11069         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11070         return 1;
11071       }
11072     }
11073     else if (aFlag == "-fonthinting"
11074           || aFlag == "-fonthint")
11075     {
11076       if (toPrint)
11077       {
11078         if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11079         {
11080           theDI << "normal" << " ";
11081         }
11082         else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11083         {
11084           theDI << "light" << " ";
11085         }
11086         else
11087         {
11088           theDI << "off" << " ";
11089         }
11090         continue;
11091       }
11092       else if (anArgIter + 1 >= theArgNb)
11093       {
11094         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11095         return 1;
11096       }
11097
11098       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11099       aHintStyle.LowerCase();
11100       if (aHintStyle == "normal"
11101        || aHintStyle == "on"
11102        || aHintStyle == "1")
11103       {
11104         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11105         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Normal);
11106       }
11107       else if (aHintStyle == "light")
11108       {
11109         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11110         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Light);
11111       }
11112       else if (aHintStyle == "no"
11113             || aHintStyle == "off"
11114             || aHintStyle == "0")
11115       {
11116         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11117         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11118       }
11119       else
11120       {
11121         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11122         return 1;
11123       }
11124     }
11125     else if (aFlag == "-fontautohinting"
11126           || aFlag == "-fontautohint")
11127     {
11128       if (toPrint)
11129       {
11130         if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
11131         {
11132           theDI << "force" << " ";
11133         }
11134         else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
11135         {
11136           theDI << "disallow" << " ";
11137         }
11138         else
11139         {
11140           theDI << "auto" << " ";
11141         }
11142         continue;
11143       }
11144       else if (anArgIter + 1 >= theArgNb)
11145       {
11146         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11147         return 1;
11148       }
11149
11150       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11151       aHintStyle.LowerCase();
11152       if (aHintStyle == "force")
11153       {
11154         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11155         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_ForceAutohint);
11156       }
11157       else if (aHintStyle == "disallow"
11158             || aHintStyle == "no")
11159       {
11160         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11161         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_NoAutohint);
11162       }
11163       else if (aHintStyle == "auto")
11164       {
11165         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11166         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11167       }
11168       else
11169       {
11170         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11171         return 1;
11172       }
11173     }
11174     else if (aFlag == "-depthprepass")
11175     {
11176       if (toPrint)
11177       {
11178         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11179         continue;
11180       }
11181       aParams.ToEnableDepthPrepass = Standard_True;
11182       if (anArgIter + 1 < theArgNb
11183        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11184       {
11185         ++anArgIter;
11186       }
11187     }
11188     else if (aFlag == "-samplealphatocoverage"
11189           || aFlag == "-alphatocoverage")
11190     {
11191       if (toPrint)
11192       {
11193         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11194         continue;
11195       }
11196       aParams.ToEnableAlphaToCoverage = Standard_True;
11197       if (anArgIter + 1 < theArgNb
11198        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11199       {
11200         ++anArgIter;
11201       }
11202     }
11203     else if (aFlag == "-rendscale"
11204           || aFlag == "-renderscale"
11205           || aFlag == "-renderresolutionscale")
11206     {
11207       if (toPrint)
11208       {
11209         theDI << aParams.RenderResolutionScale << " ";
11210         continue;
11211       }
11212       else if (++anArgIter >= theArgNb)
11213       {
11214         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11215         return 1;
11216       }
11217
11218       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11219       if (aScale < 0.01)
11220       {
11221         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11222         return 1;
11223       }
11224       else
11225       {
11226         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11227       }
11228     }
11229     else if (aFlag == "-raydepth"
11230           || aFlag == "-ray_depth")
11231     {
11232       if (toPrint)
11233       {
11234         theDI << aParams.RaytracingDepth << " ";
11235         continue;
11236       }
11237       else if (++anArgIter >= theArgNb)
11238       {
11239         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11240         return 1;
11241       }
11242
11243       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11244
11245       // We allow RaytracingDepth be more than 10 in case of GI enabled
11246       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11247       {
11248         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11249         return 1;
11250       }
11251       else
11252       {
11253         aParams.RaytracingDepth = aDepth;
11254       }
11255     }
11256     else if (aFlag == "-shad"
11257           || aFlag == "-shadows")
11258     {
11259       if (toPrint)
11260       {
11261         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11262         continue;
11263       }
11264
11265       Standard_Boolean toEnable = Standard_True;
11266       if (++anArgIter < theArgNb
11267       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11268       {
11269         --anArgIter;
11270       }
11271       aParams.IsShadowEnabled = toEnable;
11272     }
11273     else if (aFlag == "-shadowmapresolution"
11274           || aFlag == "-shadowmap")
11275     {
11276       if (toPrint)
11277       {
11278         theDI << aParams.ShadowMapResolution << " ";
11279         continue;
11280       }
11281       else if (++anArgIter >= theArgNb)
11282       {
11283         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11284         return 1;
11285       }
11286
11287       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
11288     }
11289     else if (aFlag == "-shadowmapbias")
11290     {
11291       if (toPrint)
11292       {
11293         theDI << aParams.ShadowMapBias << " ";
11294         continue;
11295       }
11296       else if (++anArgIter >= theArgNb)
11297       {
11298         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11299         return 1;
11300       }
11301
11302       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
11303     }
11304     else if (aFlag == "-refl"
11305           || aFlag == "-reflections")
11306     {
11307       if (toPrint)
11308       {
11309         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11310         continue;
11311       }
11312
11313       Standard_Boolean toEnable = Standard_True;
11314       if (++anArgIter < theArgNb
11315       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11316       {
11317         --anArgIter;
11318       }
11319       aParams.IsReflectionEnabled = toEnable;
11320     }
11321     else if (aFlag == "-fsaa")
11322     {
11323       if (toPrint)
11324       {
11325         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11326         continue;
11327       }
11328
11329       Standard_Boolean toEnable = Standard_True;
11330       if (++anArgIter < theArgNb
11331       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11332       {
11333         --anArgIter;
11334       }
11335       aParams.IsAntialiasingEnabled = toEnable;
11336     }
11337     else if (aFlag == "-gleam")
11338     {
11339       if (toPrint)
11340       {
11341         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11342         continue;
11343       }
11344
11345       Standard_Boolean toEnable = Standard_True;
11346       if (++anArgIter < theArgNb
11347       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11348       {
11349         --anArgIter;
11350       }
11351       aParams.IsTransparentShadowEnabled = toEnable;
11352     }
11353     else if (aFlag == "-gi")
11354     {
11355       if (toPrint)
11356       {
11357         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11358         continue;
11359       }
11360
11361       Standard_Boolean toEnable = Standard_True;
11362       if (++anArgIter < theArgNb
11363       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11364       {
11365         --anArgIter;
11366       }
11367       aParams.IsGlobalIlluminationEnabled = toEnable;
11368       if (!toEnable)
11369       {
11370         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11371       }
11372     }
11373     else if (aFlag == "-blockedrng"
11374           || aFlag == "-brng")
11375     {
11376       if (toPrint)
11377       {
11378         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
11379         continue;
11380       }
11381
11382       Standard_Boolean toEnable = Standard_True;
11383       if (++anArgIter < theArgNb
11384         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11385       {
11386         --anArgIter;
11387       }
11388       aParams.CoherentPathTracingMode = toEnable;
11389     }
11390     else if (aFlag == "-maxrad")
11391     {
11392       if (toPrint)
11393       {
11394         theDI << aParams.RadianceClampingValue << " ";
11395         continue;
11396       }
11397       else if (++anArgIter >= theArgNb)
11398       {
11399         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11400         return 1;
11401       }
11402
11403       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11404       if (!aMaxRadStr.IsRealValue (Standard_True))
11405       {
11406         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11407         return 1;
11408       }
11409
11410       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11411       if (aMaxRadiance <= 0.0)
11412       {
11413         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
11414         return 1;
11415       }
11416       else
11417       {
11418         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
11419       }
11420     }
11421     else if (aFlag == "-iss")
11422     {
11423       if (toPrint)
11424       {
11425         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
11426         continue;
11427       }
11428
11429       Standard_Boolean toEnable = Standard_True;
11430       if (++anArgIter < theArgNb
11431         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11432       {
11433         --anArgIter;
11434       }
11435       aParams.AdaptiveScreenSampling = toEnable;
11436     }
11437     else if (aFlag == "-issatomic")
11438     {
11439       if (toPrint)
11440       {
11441         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
11442         continue;
11443       }
11444
11445       Standard_Boolean toEnable = Standard_True;
11446       if (++anArgIter < theArgNb
11447       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11448       {
11449         --anArgIter;
11450       }
11451       aParams.AdaptiveScreenSamplingAtomic = toEnable;
11452     }
11453     else if (aFlag == "-issd")
11454     {
11455       if (toPrint)
11456       {
11457         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
11458         continue;
11459       }
11460
11461       Standard_Boolean toEnable = Standard_True;
11462       if (++anArgIter < theArgNb
11463         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11464       {
11465         --anArgIter;
11466       }
11467       aParams.ShowSamplingTiles = toEnable;
11468     }
11469     else if (aFlag == "-tilesize")
11470     {
11471       if (toPrint)
11472       {
11473         theDI << aParams.RayTracingTileSize << " ";
11474         continue;
11475       }
11476       else if (++anArgIter >= theArgNb)
11477       {
11478         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11479         return 1;
11480       }
11481
11482       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
11483       if (aTileSize < 1)
11484       {
11485         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
11486         return 1;
11487       }
11488       aParams.RayTracingTileSize = aTileSize;
11489     }
11490     else if (aFlag == "-nbtiles")
11491     {
11492       if (toPrint)
11493       {
11494         theDI << aParams.NbRayTracingTiles << " ";
11495         continue;
11496       }
11497       else if (++anArgIter >= theArgNb)
11498       {
11499         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11500         return 1;
11501       }
11502
11503       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
11504       if (aNbTiles < -1)
11505       {
11506         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
11507         return 1;
11508       }
11509       else if (aNbTiles > 0
11510             && (aNbTiles < 64
11511              || aNbTiles > 1024))
11512       {
11513         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
11514       }
11515       aParams.NbRayTracingTiles = aNbTiles;
11516     }
11517     else if (aFlag == "-env")
11518     {
11519       if (toPrint)
11520       {
11521         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
11522         continue;
11523       }
11524
11525       Standard_Boolean toEnable = Standard_True;
11526       if (++anArgIter < theArgNb
11527         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11528       {
11529         --anArgIter;
11530       }
11531       aParams.UseEnvironmentMapBackground = toEnable;
11532     }
11533     else if (aFlag == "-ignorenormalmap")
11534     {
11535       if (toPrint)
11536       {
11537         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
11538         continue;
11539       }
11540
11541       Standard_Boolean toEnable = Standard_True;
11542       if (++anArgIter < theArgNb
11543         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11544       {
11545         --anArgIter;
11546       }
11547       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
11548     }
11549     else if (aFlag == "-twoside")
11550     {
11551       if (toPrint)
11552       {
11553         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
11554         continue;
11555       }
11556
11557       Standard_Boolean toEnable = Standard_True;
11558       if (++anArgIter < theArgNb
11559         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11560       {
11561         --anArgIter;
11562       }
11563       aParams.TwoSidedBsdfModels = toEnable;
11564     }
11565     else if (aFlag == "-shademodel"
11566           || aFlag == "-shadingmodel"
11567           || aFlag == "-shading")
11568     {
11569       if (toPrint)
11570       {
11571         switch (aView->ShadingModel())
11572         {
11573           case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
11574           case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit ";    break;
11575           case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat ";     break;
11576           case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud ";  break;
11577           case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong ";    break;
11578           case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
11579           case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
11580         }
11581         continue;
11582       }
11583
11584       if (++anArgIter >= theArgNb)
11585       {
11586         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11587       }
11588
11589       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TypeOfShadingModel_DEFAULT;
11590       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
11591        && aModel != Graphic3d_TypeOfShadingModel_DEFAULT)
11592       {
11593         aView->SetShadingModel (aModel);
11594       }
11595       else
11596       {
11597         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
11598         return 1;
11599       }
11600     }
11601     else if (aFlag == "-pbrenvpow2size"
11602           || aFlag == "-pbrenvp2s"
11603           || aFlag == "-pep2s")
11604     {
11605       if (++anArgIter >= theArgNb)
11606       {
11607         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11608         return 1;
11609       }
11610
11611       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
11612       if (aPbrEnvPow2Size < 1)
11613       {
11614         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
11615         return 1;
11616       }
11617       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
11618     }
11619     else if (aFlag == "-pbrenvspecmaplevelsnumber"
11620           || aFlag == "-pbrenvspecmapnblevels"
11621           || aFlag == "-pbrenvspecmaplevels"
11622           || aFlag == "-pbrenvsmln"
11623           || aFlag == "-pesmln")
11624     {
11625       if (++anArgIter >= theArgNb)
11626       {
11627         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11628         return 1;
11629       }
11630
11631       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
11632       if (aPbrEnvSpecMapNbLevels < 2)
11633       {
11634         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
11635         return 1;
11636       }
11637       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
11638     }
11639     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
11640           || aFlag == "-pbrenvbakingdiffsamples"
11641           || aFlag == "-pbrenvbdsn")
11642     {
11643       if (++anArgIter >= theArgNb)
11644       {
11645         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11646         return 1;
11647       }
11648
11649       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11650       if (aPbrEnvBakingDiffNbSamples < 1)
11651       {
11652         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
11653         return 1;
11654       }
11655       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
11656     }
11657     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
11658           || aFlag == "-pbrenvbakingspecsamples"
11659           || aFlag == "-pbrenvbssn")
11660     {
11661     if (++anArgIter >= theArgNb)
11662     {
11663       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11664       return 1;
11665     }
11666
11667     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
11668     if (aPbrEnvBakingSpecNbSamples < 1)
11669     {
11670       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
11671       return 1;
11672     }
11673     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
11674     }
11675     else if (aFlag == "-pbrenvbakingprobability"
11676           || aFlag == "-pbrenvbp")
11677     {
11678       if (++anArgIter >= theArgNb)
11679       {
11680         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11681         return 1;
11682       }
11683       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
11684       if (aPbrEnvBakingProbability < 0.f
11685        || aPbrEnvBakingProbability > 1.f)
11686       {
11687         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
11688         return 1;
11689       }
11690       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
11691     }
11692     else if (aFlag == "-resolution")
11693     {
11694       if (++anArgIter >= theArgNb)
11695       {
11696         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11697         return 1;
11698       }
11699
11700       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
11701       if (aResolution.IsIntegerValue())
11702       {
11703         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
11704       }
11705       else
11706       {
11707         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
11708         return 1;
11709       }
11710     }
11711     else if (aFlag == "-rebuildglsl"
11712           || aFlag == "-rebuild")
11713     {
11714       if (toPrint)
11715       {
11716         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
11717         continue;
11718       }
11719
11720       Standard_Boolean toEnable = Standard_True;
11721       if (++anArgIter < theArgNb
11722           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11723       {
11724         --anArgIter;
11725       }
11726       aParams.RebuildRayTracingShaders = toEnable;
11727     }
11728     else if (aFlag == "-focal")
11729     {
11730       if (++anArgIter >= theArgNb)
11731       {
11732         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11733         return 1;
11734       }
11735
11736       TCollection_AsciiString aParam (theArgVec[anArgIter]);
11737       if (aParam.IsRealValue (Standard_True))
11738       {
11739         float aFocalDist = static_cast<float> (aParam.RealValue());
11740         if (aFocalDist < 0)
11741         {
11742           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11743           return 1;
11744         }
11745         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
11746       }
11747       else
11748       {
11749         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11750         return 1;
11751       }
11752     }
11753     else if (aFlag == "-aperture")
11754     {
11755       if (++anArgIter >= theArgNb)
11756       {
11757         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11758         return 1;
11759       }
11760
11761       TCollection_AsciiString aParam(theArgVec[anArgIter]);
11762       if (aParam.IsRealValue (Standard_True))
11763       {
11764         float aApertureSize = static_cast<float> (aParam.RealValue());
11765         if (aApertureSize < 0)
11766         {
11767           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11768           return 1;
11769         }
11770         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
11771       }
11772       else
11773       {
11774         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11775         return 1;
11776       }
11777     }
11778     else if (aFlag == "-exposure")
11779     {
11780       if (++anArgIter >= theArgNb)
11781       {
11782         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11783         return 1;
11784       }
11785
11786       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
11787       if (anExposure.IsRealValue (Standard_True))
11788       {
11789         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
11790       }
11791       else
11792       {
11793         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11794         return 1;
11795       }
11796     }
11797     else if (aFlag == "-whitepoint")
11798     {
11799       if (++anArgIter >= theArgNb)
11800       {
11801         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11802         return 1;
11803       }
11804
11805       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
11806       if (aWhitePoint.IsRealValue (Standard_True))
11807       {
11808         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
11809       }
11810       else
11811       {
11812         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11813         return 1;
11814       }
11815     }
11816     else if (aFlag == "-tonemapping")
11817     {
11818       if (++anArgIter >= theArgNb)
11819       {
11820         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11821         return 1;
11822       }
11823
11824       TCollection_AsciiString aMode (theArgVec[anArgIter]);
11825       aMode.LowerCase();
11826
11827       if (aMode == "disabled")
11828       {
11829         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
11830       }
11831       else if (aMode == "filmic")
11832       {
11833         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
11834       }
11835       else
11836       {
11837         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11838         return 1;
11839       }
11840     }
11841     else if (aFlag == "-performancestats"
11842           || aFlag == "-performancecounters"
11843           || aFlag == "-perfstats"
11844           || aFlag == "-perfcounters"
11845           || aFlag == "-stats")
11846     {
11847       if (++anArgIter >= theArgNb)
11848       {
11849         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11850         return 1;
11851       }
11852
11853       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
11854       aFlagsStr.LowerCase();
11855       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
11856       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
11857       {
11858         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11859         return 1;
11860       }
11861       aView->ChangeRenderingParams().CollectedStats = aFlags;
11862       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
11863     }
11864     else if (aFlag == "-perfupdateinterval"
11865           || aFlag == "-statsupdateinterval")
11866     {
11867       if (++anArgIter >= theArgNb)
11868       {
11869         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11870         return 1;
11871       }
11872       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11873     }
11874     else if (aFlag == "-perfchart"
11875           || aFlag == "-statschart")
11876     {
11877       if (++anArgIter >= theArgNb)
11878       {
11879         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11880         return 1;
11881       }
11882       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
11883     }
11884     else if (aFlag == "-perfchartmax"
11885           || aFlag == "-statschartmax")
11886     {
11887       if (++anArgIter >= theArgNb)
11888       {
11889         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11890         return 1;
11891       }
11892       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11893     }
11894     else if (aFlag == "-frustumculling"
11895           || aFlag == "-culling")
11896     {
11897       if (toPrint)
11898       {
11899         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
11900                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
11901                                                                                                    "noUpdate") << " ";
11902         continue;
11903       }
11904
11905       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
11906       if (++anArgIter < theArgNb)
11907       {
11908         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
11909         aStateStr.LowerCase();
11910         bool toEnable = true;
11911         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
11912         {
11913           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
11914         }
11915         else if (aStateStr == "noupdate"
11916               || aStateStr == "freeze")
11917         {
11918           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
11919         }
11920         else
11921         {
11922           --anArgIter;
11923         }
11924       }
11925       aParams.FrustumCullingState = aState;
11926     }
11927     else
11928     {
11929       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
11930       return 1;
11931     }
11932   }
11933
11934   // set current view parameters as defaults
11935   if (toSyncDefaults)
11936   {
11937     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
11938   }
11939   if (toSyncAllViews)
11940   {
11941     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
11942     {
11943       aViewIter.Value()->ChangeRenderingParams() = aParams;
11944     }
11945   }
11946   return 0;
11947 }
11948
11949 //=======================================================================
11950 //function : searchInfo
11951 //purpose  :
11952 //=======================================================================
11953 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
11954                                            const TCollection_AsciiString&              theKey)
11955 {
11956   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
11957   {
11958     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
11959     {
11960       return anIter.Value();
11961     }
11962   }
11963   return TCollection_AsciiString();
11964 }
11965
11966 //=======================================================================
11967 //function : VStatProfiler
11968 //purpose  :
11969 //=======================================================================
11970 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
11971                                        Standard_Integer  theArgNb,
11972                                        const char**      theArgVec)
11973 {
11974   Handle(V3d_View) aView = ViewerTest::CurrentView();
11975   if (aView.IsNull())
11976   {
11977     Message::SendFail ("Error: no active viewer");
11978     return 1;
11979   }
11980
11981   Standard_Boolean toRedraw = Standard_True;
11982   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
11983   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
11984   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
11985   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11986   {
11987     Standard_CString        anArg (theArgVec[anArgIter]);
11988     TCollection_AsciiString aFlag (anArg);
11989     aFlag.LowerCase();
11990     if (aFlag == "-noredraw")
11991     {
11992       toRedraw = Standard_False;
11993     }
11994     else
11995     {
11996       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
11997       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11998       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
11999       else if (aFlag == "alllayers"
12000             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12001       else if (aFlag == "allstructs"
12002             || aFlag == "allstructures"
12003             || aFlag == "structs"
12004             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12005       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12006       else if (aFlag == "allarrays"
12007             || aFlag == "fillarrays"
12008             || aFlag == "linearrays"
12009             || aFlag == "pointarrays"
12010             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12011       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12012       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12013       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12014       else if (aFlag == "geommem"
12015             || aFlag == "texturemem"
12016             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12017       else if (aFlag == "elapsedframe"
12018             || aFlag == "cpuframeaverage"
12019             || aFlag == "cpupickingaverage"
12020             || aFlag == "cpucullingaverage"
12021             || aFlag == "cpudynaverage"
12022             || aFlag == "cpuframemax"
12023             || aFlag == "cpupickingmax"
12024             || aFlag == "cpucullingmax"
12025             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12026       else
12027       {
12028         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12029         continue;
12030       }
12031
12032       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12033     }
12034   }
12035
12036   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12037   {
12038     aView->ChangeRenderingParams().CollectedStats =
12039       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12040
12041     if (toRedraw)
12042     {
12043       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12044       aView->Redraw();
12045       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12046     }
12047
12048     TColStd_IndexedDataMapOfStringString aDict;
12049     aView->StatisticInformation (aDict);
12050
12051     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12052
12053     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12054     {
12055       Standard_CString        anArg(theArgVec[anArgIter]);
12056       TCollection_AsciiString aFlag(anArg);
12057       aFlag.LowerCase();
12058       if (aFlag == "fps")
12059       {
12060         theDI << searchInfo (aDict, "FPS") << " ";
12061       }
12062       else if (aFlag == "cpu")
12063       {
12064         theDI << searchInfo (aDict, "CPU FPS") << " ";
12065       }
12066       else if (aFlag == "alllayers")
12067       {
12068         theDI << searchInfo (aDict, "Layers") << " ";
12069       }
12070       else if (aFlag == "layers")
12071       {
12072         theDI << searchInfo (aDict, "Rendered layers") << " ";
12073       }
12074       else if (aFlag == "allstructs"
12075             || aFlag == "allstructures")
12076       {
12077         theDI << searchInfo (aDict, "Structs") << " ";
12078       }
12079       else if (aFlag == "structs"
12080             || aFlag == "structures")
12081       {
12082         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
12083         if (aRend.IsEmpty()) // all structures rendered
12084         {
12085           aRend = searchInfo (aDict, "Structs");
12086         }
12087         theDI << aRend << " ";
12088       }
12089       else if (aFlag == "groups")
12090       {
12091         theDI << searchInfo (aDict, "Rendered groups") << " ";
12092       }
12093       else if (aFlag == "allarrays")
12094       {
12095         theDI << searchInfo (aDict, "Rendered arrays") << " ";
12096       }
12097       else if (aFlag == "fillarrays")
12098       {
12099         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
12100       }
12101       else if (aFlag == "linearrays")
12102       {
12103         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
12104       }
12105       else if (aFlag == "pointarrays")
12106       {
12107         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
12108       }
12109       else if (aFlag == "textarrays")
12110       {
12111         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
12112       }
12113       else if (aFlag == "triangles")
12114       {
12115         theDI << searchInfo (aDict, "Rendered triangles") << " ";
12116       }
12117       else if (aFlag == "points")
12118       {
12119         theDI << searchInfo (aDict, "Rendered points") << " ";
12120       }
12121       else if (aFlag == "geommem")
12122       {
12123         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12124       }
12125       else if (aFlag == "texturemem")
12126       {
12127         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12128       }
12129       else if (aFlag == "framemem")
12130       {
12131         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12132       }
12133       else if (aFlag == "elapsedframe")
12134       {
12135         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12136       }
12137       else if (aFlag == "cpuframe_average")
12138       {
12139         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12140       }
12141       else if (aFlag == "cpupicking_average")
12142       {
12143         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12144       }
12145       else if (aFlag == "cpuculling_average")
12146       {
12147         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12148       }
12149       else if (aFlag == "cpudyn_average")
12150       {
12151         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12152       }
12153       else if (aFlag == "cpuframe_max")
12154       {
12155         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12156       }
12157       else if (aFlag == "cpupicking_max")
12158       {
12159         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12160       }
12161       else if (aFlag == "cpuculling_max")
12162       {
12163         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12164       }
12165       else if (aFlag == "cpudyn_max")
12166       {
12167         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12168       }
12169     }
12170   }
12171   else
12172   {
12173     if (toRedraw)
12174     {
12175       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12176       aView->Redraw();
12177       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12178     }
12179     theDI << "Statistic info:\n" << aView->StatisticInformation();
12180   }
12181   return 0;
12182 }
12183
12184 //=======================================================================
12185 //function : VXRotate
12186 //purpose  :
12187 //=======================================================================
12188 static Standard_Integer VXRotate (Draw_Interpretor& di,
12189                                    Standard_Integer argc,
12190                                    const char ** argv)
12191 {
12192   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12193   if (aContext.IsNull())
12194   {
12195     di << argv[0] << "ERROR : use 'vinit' command before \n";
12196     return 1;
12197   }
12198
12199   if (argc != 3)
12200   {
12201     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12202     return 1;
12203   }
12204
12205   TCollection_AsciiString aName (argv[1]);
12206   Standard_Real anAngle = Draw::Atof (argv[2]);
12207
12208   // find object
12209   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12210   Handle(AIS_InteractiveObject) anIObj;
12211   if (!aMap.Find2 (aName, anIObj))
12212   {
12213     di << "Use 'vdisplay' before\n";
12214     return 1;
12215   }
12216
12217   gp_Trsf aTransform;
12218   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12219   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12220
12221   aContext->SetLocation (anIObj, aTransform);
12222   aContext->UpdateCurrentViewer();
12223   return 0;
12224 }
12225
12226 namespace
12227 {
12228   //! Structure for setting AIS_Manipulator::SetPart() property.
12229   struct ManipAxisModeOnOff
12230   {
12231     Standard_Integer    Axis;
12232     AIS_ManipulatorMode Mode;
12233     Standard_Boolean    ToEnable;
12234
12235     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
12236   };
12237
12238   enum ManipAjustPosition
12239   {
12240     ManipAjustPosition_Off,
12241     ManipAjustPosition_Center,
12242     ManipAjustPosition_Location,
12243     ManipAjustPosition_ShapeLocation,
12244   };
12245 }
12246
12247 //===============================================================================================
12248 //function : VManipulator
12249 //purpose  :
12250 //===============================================================================================
12251 static int VManipulator (Draw_Interpretor& theDi,
12252                          Standard_Integer  theArgsNb,
12253                          const char**      theArgVec)
12254 {
12255   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12256   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12257   if (aCurrentView.IsNull()
12258    || aViewer.IsNull())
12259   {
12260     Message::SendFail ("Error: no active viewer");
12261     return 1;
12262   }
12263
12264   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12265   Standard_Integer anArgIter = 1;
12266   Handle(AIS_Manipulator) aManipulator;
12267   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12268   TCollection_AsciiString aName;
12269   // parameters
12270   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
12271   Standard_Real aGap = -1.0, aSize = -1.0;
12272   NCollection_Sequence<ManipAxisModeOnOff> aParts;
12273   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
12274   //
12275   bool toDetach = false;
12276   AIS_Manipulator::OptionsForAttach anAttachOptions;
12277   Handle(AIS_InteractiveObject) anAttachObject;
12278   Handle(V3d_View) aViewAffinity;
12279   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
12280   //
12281   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
12282   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
12283   Standard_Integer toStopMouseTransform = -1;
12284   // explicit transformation
12285   gp_Trsf aTrsf;
12286   gp_XYZ aTmpXYZ;
12287   Standard_Real aTmpReal = 0.0;
12288   gp_XYZ aRotPnt, aRotAxis;
12289   for (; anArgIter < theArgsNb; ++anArgIter)
12290   {
12291     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12292     anArg.LowerCase();
12293     if (anUpdateTool.parseRedrawMode (anArg))
12294     {
12295       continue;
12296     }
12297     else if (anArg == "-help")
12298     {
12299       theDi.PrintHelp (theArgVec[0]);
12300       return 0;
12301     }
12302     //
12303     else if (anArg == "-autoactivate"
12304           || anArg == "-noautoactivate")
12305     {
12306       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12307     }
12308     else if (anArg == "-followtranslation"
12309           || anArg == "-nofollowtranslation")
12310     {
12311       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12312     }
12313     else if (anArg == "-followrotation"
12314           || anArg == "-nofollowrotation")
12315     {
12316       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12317     }
12318     else if (anArg == "-followdragging"
12319           || anArg == "-nofollowdragging")
12320     {
12321       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12322     }
12323     else if (anArg == "-gap"
12324           && anArgIter + 1 < theArgsNb
12325           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
12326           && aGap >= 0.0)
12327     {
12328       ++anArgIter;
12329     }
12330     else if (anArg == "-size"
12331           && anArgIter + 1 < theArgsNb
12332           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
12333           && aSize > 0.0)
12334     {
12335       ++anArgIter;
12336     }
12337     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
12338           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
12339     {
12340       ManipAxisModeOnOff aPart;
12341       Standard_Integer aMode = 0;
12342       if (anArg == "-part")
12343       {
12344         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
12345           || aPart.Axis < 0 || aPart.Axis > 3)
12346         {
12347           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
12348           return 1;
12349         }
12350       }
12351       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
12352         || aMode < 1 || aMode > 4)
12353       {
12354         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
12355         return 1;
12356       }
12357       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
12358       {
12359         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
12360         return 1;
12361       }
12362       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
12363       aParts.Append (aPart);
12364     }
12365     else if (anArg == "-pos"
12366           && anArgIter + 3 < theArgsNb
12367           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
12368     {
12369       anArgIter += 3;
12370       if (anArgIter + 3 < theArgsNb
12371        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
12372        && aVDir.Modulus() > Precision::Confusion())
12373       {
12374         anArgIter += 3;
12375       }
12376       if (anArgIter + 3 < theArgsNb
12377        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
12378        && anXDir.Modulus() > Precision::Confusion())
12379       {
12380         anArgIter += 3;
12381       }
12382     }
12383     else if (anArg == "-zoomable"
12384           || anArg == "-notzoomable")
12385     {
12386       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12387     }
12388     //
12389     else if (anArg == "-adjustposition"
12390           || anArg == "-noadjustposition")
12391     {
12392       anAttachPos = ManipAjustPosition_Center;
12393       if (anArgIter + 1 < theArgsNb)
12394       {
12395         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
12396         aPosName.LowerCase();
12397         if (aPosName == "0")
12398         {
12399           anAttachPos = ManipAjustPosition_Off;
12400         }
12401         else if (aPosName == "1"
12402               || aPosName == "center")
12403         {
12404           anAttachPos = ManipAjustPosition_Center;
12405         }
12406         else if (aPosName == "transformation"
12407               || aPosName == "trsf"
12408               || aPosName == "location"
12409               || aPosName == "loc")
12410         {
12411           anAttachPos = ManipAjustPosition_Location;
12412         }
12413         else if (aPosName == "shapelocation"
12414               || aPosName == "shapeloc")
12415         {
12416           anAttachPos = ManipAjustPosition_ShapeLocation;
12417         }
12418         else
12419         {
12420           --anArgIter;
12421         }
12422       }
12423       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
12424     }
12425     else if (anArg == "-adjustsize"
12426           || anArg == "-noadjustsize")
12427     {
12428       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12429     }
12430     else if (anArg == "-enablemodes"
12431           || anArg == "-enablemodes")
12432     {
12433       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12434     }
12435     //
12436     else if (anArg == "-starttransform"
12437           && anArgIter + 2 < theArgsNb
12438           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
12439           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
12440     {
12441       anArgIter += 2;
12442     }
12443     else if (anArg == "-transform"
12444           && anArgIter + 2 < theArgsNb
12445           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
12446           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
12447     {
12448       anArgIter += 2;
12449     }
12450     else if (anArg == "-stoptransform")
12451     {
12452       toStopMouseTransform = 1;
12453       if (anArgIter + 1 < theArgsNb
12454        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
12455       {
12456         ++anArgIter;
12457         toStopMouseTransform = 0;
12458       }
12459     }
12460     //
12461     else if (anArg == "-move"
12462           && anArgIter + 3 < theArgsNb
12463           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
12464     {
12465       anArgIter += 3;
12466       aTrsf.SetTranslationPart (aTmpXYZ);
12467     }
12468     else if (anArg == "-scale"
12469           && anArgIter + 1 < theArgsNb
12470           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
12471     {
12472       ++anArgIter;
12473       aTrsf.SetScale (gp_Pnt(), aTmpReal);
12474     }
12475     else if (anArg == "-rotate"
12476           && anArgIter + 7 < theArgsNb
12477           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
12478           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
12479           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
12480     {
12481       anArgIter += 7;
12482       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
12483     }
12484     //
12485     else if (anArg == "-detach")
12486     {
12487       toDetach = true;
12488     }
12489     else if (anArg == "-attach"
12490           && anArgIter + 1 < theArgsNb)
12491     {
12492       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
12493       if (!aMapAIS.Find2 (anObjName, anAttachObject))
12494       {
12495         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
12496         return 1;
12497       }
12498
12499       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
12500       {
12501         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
12502         if (!aManip.IsNull()
12503           && aManip->IsAttached()
12504           && aManip->Object() == anAttachObject)
12505         {
12506           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
12507           return 1;
12508         }
12509       }
12510     }
12511     else if (anArg == "-view"
12512           && anArgIter + 1 < theArgsNb
12513           && aViewAffinity.IsNull())
12514     {
12515       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
12516       if (aViewString == "active")
12517       {
12518         aViewAffinity = ViewerTest::CurrentView();
12519       }
12520       else // Check view name
12521       {
12522         ViewerTest_Names aViewNames (aViewString);
12523         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
12524         {
12525           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
12526           return 1;
12527         }
12528         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
12529         if (aViewAffinity.IsNull())
12530         {
12531           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
12532           return 1;
12533         }
12534       }
12535     }
12536     else if (aName.IsEmpty())
12537     {
12538       aName = theArgVec[anArgIter];
12539       if (!aMapAIS.IsBound2 (aName))
12540       {
12541         aManipulator = new AIS_Manipulator();
12542         aManipulator->SetModeActivationOnDetection (true);
12543         aMapAIS.Bind (aManipulator, aName);
12544       }
12545       else
12546       {
12547         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12548         if (aManipulator.IsNull())
12549         {
12550           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12551           return 1;
12552         }
12553       }
12554     }
12555     else
12556     {
12557       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
12558     }
12559   }
12560
12561   if (aName.IsEmpty())
12562   {
12563     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
12564     return 1;
12565   }
12566   if (!toDetach
12567     && aManipulator.IsNull())
12568   {
12569     aManipulator = new AIS_Manipulator();
12570     aManipulator->SetModeActivationOnDetection (true);
12571     aMapAIS.Bind (aManipulator, aName);
12572   }
12573
12574   // -----------------------------------------
12575   // change properties of manipulator instance
12576   // -----------------------------------------
12577
12578   if (toAutoActivate != -1)
12579   {
12580     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
12581   }
12582   if (toFollowTranslation != -1)
12583   {
12584     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
12585   }
12586   if (toFollowRotation != -1)
12587   {
12588     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
12589   }
12590   if (toFollowDragging != -1)
12591   {
12592     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
12593   }
12594   if (aGap >= 0.0f)
12595   {
12596     aManipulator->SetGap ((float )aGap);
12597   }
12598
12599   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
12600   {
12601     const ManipAxisModeOnOff& aPart = aPartIter.Value();
12602     if (aPart.Axis == -1)
12603     {
12604       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
12605     }
12606     else
12607     {
12608       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
12609     }
12610   }
12611
12612   if (aSize > 0.0)
12613   {
12614     aManipulator->SetSize ((float )aSize);
12615   }
12616   if (isZoomable != -1)
12617   {
12618     aManipulator->SetZoomPersistence (isZoomable == 0);
12619
12620     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12621     {
12622       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
12623       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
12624     }
12625   }
12626
12627   // ----------------------------------
12628   // detach existing manipulator object
12629   // ----------------------------------
12630
12631   if (toDetach)
12632   {
12633     aManipulator->Detach();
12634     aMapAIS.UnBind2 (aName);
12635     ViewerTest::GetAISContext()->Remove (aManipulator, false);
12636   }
12637
12638   // ---------------------------------------------------
12639   // attach, detach or access manipulator from an object
12640   // ---------------------------------------------------
12641
12642   if (!anAttachObject.IsNull())
12643   {
12644     aManipulator->Attach (anAttachObject, anAttachOptions);
12645   }
12646   if (!aViewAffinity.IsNull())
12647   {
12648     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
12649          anIter.More(); anIter.Next())
12650     {
12651       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
12652     }
12653     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
12654   }
12655
12656   if (anAttachPos != ManipAjustPosition_Off
12657    && aManipulator->IsAttached()
12658    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
12659   {
12660     gp_Ax2 aPosition = gp::XOY();
12661     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
12662     switch (anAttachPos)
12663     {
12664       case ManipAjustPosition_Off:
12665       {
12666         break;
12667       }
12668       case ManipAjustPosition_Location:
12669       {
12670         aPosition = gp::XOY().Transformed (aBaseTrsf);
12671         break;
12672       }
12673       case ManipAjustPosition_ShapeLocation:
12674       {
12675         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
12676         {
12677           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
12678         }
12679         else
12680         {
12681           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
12682           return 1;
12683         }
12684         break;
12685       }
12686       case ManipAjustPosition_Center:
12687       {
12688         Bnd_Box aBox;
12689         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
12690         {
12691           Bnd_Box anObjBox;
12692           anObjIter.Value()->BoundingBox (anObjBox);
12693           aBox.Add (anObjBox);
12694         }
12695         aBox = aBox.FinitePart();
12696         if (!aBox.IsVoid())
12697         {
12698           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
12699           aPosition.SetLocation (aCenter);
12700         }
12701         break;
12702       }
12703     }
12704     aManipulator->SetPosition (aPosition);
12705   }
12706   if (!Precision::IsInfinite (aLocation.X()))
12707   {
12708     if (aVDir.Modulus() <= Precision::Confusion())
12709     {
12710       aVDir = aManipulator->Position().Direction().XYZ();
12711     }
12712     if (anXDir.Modulus() <= Precision::Confusion())
12713     {
12714       anXDir = aManipulator->Position().XDirection().XYZ();
12715     }
12716     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
12717   }
12718
12719   // --------------------------------------
12720   // apply transformation using manipulator
12721   // --------------------------------------
12722
12723   if (aMousePosFrom.x() != IntegerLast())
12724   {
12725     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
12726   }
12727   if (aMousePosTo.x() != IntegerLast())
12728   {
12729     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
12730   }
12731   if (toStopMouseTransform != -1)
12732   {
12733     aManipulator->StopTransform (toStopMouseTransform == 1);
12734   }
12735
12736   if (aTrsf.Form() != gp_Identity)
12737   {
12738     aManipulator->Transform (aTrsf);
12739   }
12740
12741   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12742   {
12743     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
12744   }
12745   return 0;
12746 }
12747
12748 //===============================================================================================
12749 //function : VSelectionProperties
12750 //purpose  :
12751 //===============================================================================================
12752 static int VSelectionProperties (Draw_Interpretor& theDi,
12753                                  Standard_Integer  theArgsNb,
12754                                  const char**      theArgVec)
12755 {
12756   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
12757   if (aCtx.IsNull())
12758   {
12759     Message::SendFail ("Error: no active viewer");
12760     return 1;
12761   }
12762
12763   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
12764   {
12765     // handle obsolete alias
12766     bool toEnable = true;
12767     if (theArgsNb < 2)
12768     {
12769       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
12770       return 0;
12771     }
12772     else if (theArgsNb != 2
12773          || !Draw::ParseOnOff (theArgVec[1], toEnable))
12774     {
12775       Message::SendFail ("Syntax error: wrong number of parameters");
12776       return 1;
12777     }
12778     if (toEnable != aCtx->ToHilightSelected())
12779     {
12780       aCtx->ClearDetected();
12781       aCtx->SetToHilightSelected (toEnable);
12782     }
12783     return 0;
12784   }
12785
12786   Standard_Boolean toPrint  = theArgsNb == 1;
12787   Standard_Boolean toRedraw = Standard_False;
12788   Standard_Integer anArgIter = 1;
12789   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
12790   if (anArgIter < theArgsNb)
12791   {
12792     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
12793     anArgFirst.LowerCase();
12794     ++anArgIter;
12795     if (anArgFirst == "dynhighlight"
12796      || anArgFirst == "dynhilight"
12797      || anArgFirst == "dynamichighlight"
12798      || anArgFirst == "dynamichilight")
12799     {
12800       aType = Prs3d_TypeOfHighlight_Dynamic;
12801     }
12802     else if (anArgFirst == "localdynhighlight"
12803           || anArgFirst == "localdynhilight"
12804           || anArgFirst == "localdynamichighlight"
12805           || anArgFirst == "localdynamichilight")
12806     {
12807       aType = Prs3d_TypeOfHighlight_LocalDynamic;
12808     }
12809     else if (anArgFirst == "selhighlight"
12810           || anArgFirst == "selhilight"
12811           || anArgFirst == "selectedhighlight"
12812           || anArgFirst == "selectedhilight")
12813     {
12814       aType = Prs3d_TypeOfHighlight_Selected;
12815     }
12816     else if (anArgFirst == "localselhighlight"
12817           || anArgFirst == "localselhilight"
12818           || anArgFirst == "localselectedhighlight"
12819           || anArgFirst == "localselectedhilight")
12820     {
12821       aType = Prs3d_TypeOfHighlight_LocalSelected;
12822     }
12823     else
12824     {
12825       --anArgIter;
12826     }
12827   }
12828   for (; anArgIter < theArgsNb; ++anArgIter)
12829   {
12830     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12831     anArg.LowerCase();
12832     if (anArg == "-help")
12833     {
12834       theDi.PrintHelp (theArgVec[0]);
12835       return 0;
12836     }
12837     else if (anArg == "-print")
12838     {
12839       toPrint = Standard_True;
12840     }
12841     else if (anArg == "-autoactivate")
12842     {
12843       Standard_Boolean toEnable = Standard_True;
12844       if (anArgIter + 1 < theArgsNb
12845        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12846       {
12847         ++anArgIter;
12848       }
12849       aCtx->SetAutoActivateSelection (toEnable);
12850     }
12851     else if (anArg == "-automatichighlight"
12852           || anArg == "-automatichilight"
12853           || anArg == "-autohighlight"
12854           || anArg == "-autohilight")
12855     {
12856       Standard_Boolean toEnable = Standard_True;
12857       if (anArgIter + 1 < theArgsNb
12858        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12859       {
12860         ++anArgIter;
12861       }
12862       aCtx->ClearSelected (false);
12863       aCtx->ClearDetected();
12864       aCtx->SetAutomaticHilight (toEnable);
12865       toRedraw = true;
12866     }
12867     else if (anArg == "-highlightselected"
12868           || anArg == "-hilightselected")
12869     {
12870       Standard_Boolean toEnable = Standard_True;
12871       if (anArgIter + 1 < theArgsNb
12872        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12873       {
12874         ++anArgIter;
12875       }
12876       aCtx->ClearDetected();
12877       aCtx->SetToHilightSelected (toEnable);
12878       toRedraw = true;
12879     }
12880     else if (anArg == "-pickstrategy"
12881           || anArg == "-pickingstrategy")
12882     {
12883       if (++anArgIter >= theArgsNb)
12884       {
12885         Message::SendFail ("Syntax error: type of highlighting is undefined");
12886         return 1;
12887       }
12888
12889       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
12890       TCollection_AsciiString aVal (theArgVec[anArgIter]);
12891       aVal.LowerCase();
12892       if (aVal == "first"
12893        || aVal == "firstaccepted"
12894        || aVal == "firstacceptable")
12895       {
12896         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
12897       }
12898       else if (aVal == "topmost"
12899             || aVal == "onlyTopmost")
12900       {
12901         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
12902       }
12903       else
12904       {
12905         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
12906         return 1;
12907       }
12908
12909       aCtx->SetPickingStrategy (aStrategy);
12910     }
12911     else if (anArg == "-pixtol"
12912           && anArgIter + 1 < theArgsNb)
12913     {
12914       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
12915     }
12916     else if (anArg == "-preferclosest")
12917     {
12918       bool toPreferClosest = true;
12919       if (anArgIter + 1 < theArgsNb
12920        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
12921       {
12922         ++anArgIter;
12923       }
12924       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
12925     }
12926     else if ((anArg == "-depthtol"
12927            || anArg == "-depthtolerance")
12928           && anArgIter + 1 < theArgsNb)
12929     {
12930       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
12931       aTolType.LowerCase();
12932       if (aTolType == "uniform")
12933       {
12934         if (anArgIter + 1 >= theArgsNb)
12935         {
12936           Message::SendFail() << "Syntax error: wrong number of arguments";
12937           return 1;
12938         }
12939         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
12940                                                  Draw::Atof (theArgVec[++anArgIter]));
12941       }
12942       else if (aTolType == "uniformpx")
12943       {
12944         if (anArgIter + 1 >= theArgsNb)
12945         {
12946           Message::SendFail() << "Syntax error: wrong number of arguments";
12947           return 1;
12948         }
12949         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
12950                                                  Draw::Atof (theArgVec[++anArgIter]));
12951       }
12952       else if (aTolType == "sensfactor")
12953       {
12954         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
12955       }
12956       else
12957       {
12958         Message::SendFail() << "Syntax error at '" << aTolType << "'";
12959         return 1;
12960       }
12961     }
12962     else if ((anArg == "-mode"
12963            || anArg == "-dispmode")
12964           && anArgIter + 1 < theArgsNb)
12965     {
12966       if (aType == Prs3d_TypeOfHighlight_None)
12967       {
12968         Message::SendFail ("Syntax error: type of highlighting is undefined");
12969         return 1;
12970       }
12971
12972       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
12973       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12974       aStyle->SetDisplayMode (aDispMode);
12975       toRedraw = Standard_True;
12976     }
12977     else if (anArg == "-layer"
12978           && anArgIter + 1 < theArgsNb)
12979     {
12980       if (aType == Prs3d_TypeOfHighlight_None)
12981       {
12982         Message::SendFail ("Syntax error: type of highlighting is undefined");
12983         return 1;
12984       }
12985
12986       ++anArgIter;
12987       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
12988       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
12989       {
12990         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
12991         return 1;
12992       }
12993
12994       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12995       aStyle->SetZLayer (aNewLayer);
12996       toRedraw = Standard_True;
12997     }
12998     else if (anArg == "-hicolor"
12999           || anArg == "-selcolor"
13000           || anArg == "-color")
13001     {
13002       if (anArg.StartsWith ("-hi"))
13003       {
13004         aType = Prs3d_TypeOfHighlight_Dynamic;
13005       }
13006       else if (anArg.StartsWith ("-sel"))
13007       {
13008         aType = Prs3d_TypeOfHighlight_Selected;
13009       }
13010       else if (aType == Prs3d_TypeOfHighlight_None)
13011       {
13012         Message::SendFail ("Syntax error: type of highlighting is undefined");
13013         return 1;
13014       }
13015
13016       Quantity_Color aColor;
13017       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13018                                                      theArgVec + anArgIter + 1,
13019                                                      aColor);
13020       if (aNbParsed == 0)
13021       {
13022         Message::SendFail ("Syntax error: need more arguments");
13023         return 1;
13024       }
13025       anArgIter += aNbParsed;
13026
13027       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13028       aStyle->SetColor (aColor);
13029       toRedraw = Standard_True;
13030     }
13031     else if ((anArg == "-transp"
13032            || anArg == "-transparency"
13033            || anArg == "-hitransp"
13034            || anArg == "-seltransp"
13035            || anArg == "-hitransplocal"
13036            || anArg == "-seltransplocal")
13037           && anArgIter + 1 < theArgsNb)
13038     {
13039       if (anArg.StartsWith ("-hi"))
13040       {
13041         aType = Prs3d_TypeOfHighlight_Dynamic;
13042       }
13043       else if (anArg.StartsWith ("-sel"))
13044       {
13045         aType = Prs3d_TypeOfHighlight_Selected;
13046       }
13047       else if (aType == Prs3d_TypeOfHighlight_None)
13048       {
13049         Message::SendFail ("Syntax error: type of highlighting is undefined");
13050         return 1;
13051       }
13052
13053       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13054       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13055       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13056       toRedraw = Standard_True;
13057     }
13058     else if ((anArg == "-mat"
13059            || anArg == "-material")
13060           && anArgIter + 1 < theArgsNb)
13061     {
13062       if (aType == Prs3d_TypeOfHighlight_None)
13063       {
13064         Message::SendFail ("Syntax error: type of highlighting is undefined");
13065         return 1;
13066       }
13067
13068       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13069       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13070       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
13071       {
13072         ++anArgIter;
13073         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13074         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13075         Graphic3d_MaterialAspect aMat (aMatName);
13076         aMat.SetColor (aStyle->Color());
13077         aMat.SetTransparency (aStyle->Transparency());
13078         anAspect->SetFrontMaterial (aMat);
13079         anAspect->SetInteriorColor (aStyle->Color());
13080         aStyle->SetBasicFillAreaAspect (anAspect);
13081       }
13082       else
13083       {
13084         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
13085       }
13086       toRedraw = Standard_True;
13087     }
13088     else
13089     {
13090       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
13091       return 1;
13092     }
13093   }
13094
13095   if (toPrint)
13096   {
13097     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
13098     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
13099     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
13100     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
13101     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
13102     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
13103     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
13104     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
13105     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
13106     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
13107     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
13108     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
13109     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
13110     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
13111   }
13112
13113   if (aCtx->NbSelected() != 0 && toRedraw)
13114   {
13115     aCtx->HilightSelected (Standard_True);
13116   }
13117
13118   return 0;
13119 }
13120
13121 //===============================================================================================
13122 //function : VDumpSelectionImage
13123 //purpose  :
13124 //===============================================================================================
13125 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13126                                 Standard_Integer  theArgsNb,
13127                                 const char**      theArgVec)
13128 {
13129   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13130   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13131   if (aContext.IsNull())
13132   {
13133     Message::SendFail ("Error: no active viewer");
13134     return 1;
13135   }
13136
13137   TCollection_AsciiString aFile;
13138   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13139   Handle(Graphic3d_Camera) aCustomCam;
13140   Image_Format anImgFormat = Image_Format_BGR;
13141   Standard_Integer aPickedIndex = 1;
13142   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13143   {
13144     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13145     aParam.LowerCase();
13146     if (aParam == "-type")
13147     {
13148       if (++anArgIter >= theArgsNb)
13149       {
13150         Message::SendFail ("Syntax error: wrong number parameters of flag '-type'");
13151         return 1;
13152       }
13153
13154       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13155       aValue.LowerCase();
13156       if (aValue == "depth"
13157        || aValue == "normdepth"
13158        || aValue == "normalizeddepth")
13159       {
13160         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13161         anImgFormat = Image_Format_GrayF;
13162       }
13163       else if (aValue == "depthinverted"
13164             || aValue == "normdepthinverted"
13165             || aValue == "normalizeddepthinverted"
13166             || aValue == "inverted")
13167       {
13168         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13169         anImgFormat = Image_Format_GrayF;
13170       }
13171       else if (aValue == "unnormdepth"
13172             || aValue == "unnormalizeddepth")
13173       {
13174         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13175         anImgFormat = Image_Format_GrayF;
13176       }
13177       else if (aValue == "objectcolor"
13178             || aValue == "object"
13179             || aValue == "color")
13180       {
13181         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13182       }
13183       else if (aValue == "entitycolor"
13184             || aValue == "entity")
13185       {
13186         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13187       }
13188       else if (aValue == "entitytypecolor"
13189             || aValue == "entitytype")
13190       {
13191         aType = StdSelect_TypeOfSelectionImage_ColoredEntityType;
13192       }
13193       else if (aValue == "ownercolor"
13194             || aValue == "owner")
13195       {
13196         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13197       }
13198       else if (aValue == "selectionmodecolor"
13199             || aValue == "selectionmode"
13200             || aValue == "selmodecolor"
13201             || aValue == "selmode")
13202       {
13203         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13204       }
13205       else if (aValue == "surfnormal"
13206             || aValue == "surfacenormal"
13207             || aValue == "normal")
13208       {
13209         aType = StdSelect_TypeOfSelectionImage_SurfaceNormal;
13210       }
13211       else
13212       {
13213         Message::SendFail() << "Syntax error: unknown type '" << aValue << "'";
13214         return 1;
13215       }
13216     }
13217     else if (aParam == "-picked"
13218           || aParam == "-pickeddepth"
13219           || aParam == "-pickedindex")
13220     {
13221       if (++anArgIter >= theArgsNb)
13222       {
13223         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13224         return 1;
13225       }
13226
13227       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13228     }
13229     else if (anArgIter + 1 < theArgsNb
13230           && aParam == "-xrpose")
13231     {
13232       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13233       anXRArg.LowerCase();
13234       if (anXRArg == "base")
13235       {
13236         aCustomCam = aView->View()->BaseXRCamera();
13237       }
13238       else if (anXRArg == "head")
13239       {
13240         aCustomCam = aView->View()->PosedXRCamera();
13241       }
13242       else
13243       {
13244         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13245         return 1;
13246       }
13247       if (aCustomCam.IsNull())
13248       {
13249         Message::SendFail() << "Error: undefined XR pose";
13250         return 0;
13251       }
13252     }
13253     else if (aFile.IsEmpty())
13254     {
13255       aFile = theArgVec[anArgIter];
13256     }
13257     else
13258     {
13259       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13260       return 1;
13261     }
13262   }
13263   if (aFile.IsEmpty())
13264   {
13265     Message::SendFail ("Syntax error: image file name is missing");
13266     return 1;
13267   }
13268
13269   Standard_Integer aWidth = 0, aHeight = 0;
13270   aView->Window()->Size (aWidth, aHeight);
13271
13272   Image_AlienPixMap aPixMap;
13273   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13274   {
13275     Message::SendFail ("Error: can't allocate image");
13276     return 1;
13277   }
13278
13279   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13280   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13281   if (!aCustomCam.IsNull())
13282   {
13283     aView->SetCamera (aCustomCam);
13284   }
13285   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13286   {
13287     Message::SendFail ("Error: can't generate selection image");
13288     return 1;
13289   }
13290   if (!aCustomCam.IsNull())
13291   {
13292     aView->SetCamera (aCamBack);
13293   }
13294   aView->SetImmediateUpdate (wasImmUpdate);
13295
13296   if (!aPixMap.Save (aFile))
13297   {
13298     Message::SendFail ("Error: can't save selection image");
13299     return 0;
13300   }
13301   return 0;
13302 }
13303
13304 //===============================================================================================
13305 //function : VViewCube
13306 //purpose  :
13307 //===============================================================================================
13308 static int VViewCube (Draw_Interpretor& ,
13309                       Standard_Integer  theNbArgs,
13310                       const char**      theArgVec)
13311 {
13312   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13313   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13314   if (aContext.IsNull() || aView.IsNull())
13315   {
13316     Message::SendFail ("Error: no active viewer");
13317     return 1;
13318   }
13319   else if (theNbArgs < 2)
13320   {
13321     Message::SendFail ("Syntax error: wrong number arguments");
13322     return 1;
13323   }
13324
13325   Handle(AIS_ViewCube) aViewCube;
13326   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13327   Quantity_Color aColorRgb;
13328   TCollection_AsciiString aName;
13329   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13330   {
13331     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13332     anArg.LowerCase();
13333     if (anUpdateTool.parseRedrawMode (anArg))
13334     {
13335       //
13336     }
13337     else if (aViewCube.IsNull())
13338     {
13339       aName = theArgVec[anArgIter];
13340       if (aName.StartsWith ("-"))
13341       {
13342         Message::SendFail ("Syntax error: object name should be specified");
13343         return 1;
13344       }
13345       Handle(AIS_InteractiveObject) aPrs;
13346       GetMapOfAIS().Find2 (aName, aPrs);
13347       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13348       if (aViewCube.IsNull())
13349       {
13350         aViewCube = new AIS_ViewCube();
13351         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13352         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13353         aViewCube->SetFixedAnimationLoop (false);
13354       }
13355     }
13356     else if (anArg == "-reset")
13357     {
13358       aViewCube->ResetStyles();
13359     }
13360     else if (anArg == "-color"
13361           || anArg == "-boxcolor"
13362           || anArg == "-boxsidecolor"
13363           || anArg == "-sidecolor"
13364           || anArg == "-boxedgecolor"
13365           || anArg == "-edgecolor"
13366           || anArg == "-boxcornercolor"
13367           || anArg == "-cornercolor"
13368           || anArg == "-innercolor"
13369           || anArg == "-textcolor"
13370           || anArg == "-xaxistextcolor"
13371           || anArg == "-yaxistextcolor"
13372           || anArg == "-zaxistextcolor")
13373     {
13374       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
13375                                                      theArgVec + anArgIter + 1,
13376                                                      aColorRgb);
13377       if (aNbParsed == 0)
13378       {
13379         Message::SendFail() << "Syntax error at '" << anArg << "'";
13380         return 1;
13381       }
13382       anArgIter += aNbParsed;
13383       if (anArg == "-boxcolor")
13384       {
13385         aViewCube->SetBoxColor (aColorRgb);
13386       }
13387       else if (anArg == "-boxsidecolor"
13388             || anArg == "-sidecolor")
13389       {
13390         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13391         aViewCube->SynchronizeAspects();
13392       }
13393       else if (anArg == "-boxedgecolor"
13394             || anArg == "-edgecolor")
13395       {
13396         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13397         aViewCube->SynchronizeAspects();
13398       }
13399       else if (anArg == "-boxcornercolor"
13400             || anArg == "-cornercolor")
13401       {
13402         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13403         aViewCube->SynchronizeAspects();
13404       }
13405       else if (anArg == "-innercolor")
13406       {
13407         aViewCube->SetInnerColor (aColorRgb);
13408       }
13409       else if (anArg == "-textcolor")
13410       {
13411         aViewCube->SetTextColor (aColorRgb);
13412       }
13413       else if (anArg == "-xaxistextcolor"
13414             || anArg == "-yaxistextcolor"
13415             || anArg == "-zaxistextcolor")
13416       {
13417         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
13418                                 ? Prs3d_DatumParts_XAxis
13419                                 : (anArg.Value (2) == 'y'
13420                                  ? Prs3d_DatumParts_YAxis
13421                                  : Prs3d_DatumParts_ZAxis);
13422         aViewCube->Attributes()->SetOwnDatumAspects();
13423         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
13424       }
13425       else
13426       {
13427         aViewCube->SetColor (aColorRgb);
13428       }
13429     }
13430     else if (anArgIter + 1 < theNbArgs
13431           && (anArg == "-transparency"
13432            || anArg == "-boxtransparency"))
13433     {
13434       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13435       if (aValue < 0.0 || aValue > 1.0)
13436       {
13437         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13438         return 1;
13439       }
13440
13441       if (anArg == "-boxtransparency")
13442       {
13443         aViewCube->SetBoxTransparency (aValue);
13444       }
13445       else
13446       {
13447         aViewCube->SetTransparency (aValue);
13448       }
13449     }
13450     else if (anArg == "-axes"
13451           || anArg == "-edges"
13452           || anArg == "-vertices"
13453           || anArg == "-vertexes"
13454           || anArg == "-fixedanimation")
13455     {
13456       bool toShow = true;
13457       if (anArgIter + 1 < theNbArgs
13458        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
13459       {
13460         ++anArgIter;
13461       }
13462       if (anArg == "-fixedanimation")
13463       {
13464         aViewCube->SetFixedAnimationLoop (toShow);
13465       }
13466       else if (anArg == "-axes")
13467       {
13468         aViewCube->SetDrawAxes (toShow);
13469       }
13470       else if (anArg == "-edges")
13471       {
13472         aViewCube->SetDrawEdges (toShow);
13473       }
13474       else
13475       {
13476         aViewCube->SetDrawVertices (toShow);
13477       }
13478     }
13479     else if (anArg == "-yup"
13480           || anArg == "-zup")
13481     {
13482       bool isOn = true;
13483       if (anArgIter + 1 < theNbArgs
13484        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
13485       {
13486         ++anArgIter;
13487       }
13488       if (anArg == "-yup")
13489       {
13490         aViewCube->SetYup (isOn);
13491       }
13492       else
13493       {
13494         aViewCube->SetYup (!isOn);
13495       }
13496     }
13497     else if (anArgIter + 1 < theNbArgs
13498           && anArg == "-font")
13499     {
13500       aViewCube->SetFont (theArgVec[++anArgIter]);
13501     }
13502     else if (anArgIter + 1 < theNbArgs
13503           && anArg == "-fontheight")
13504     {
13505       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
13506     }
13507     else if (anArgIter + 1 < theNbArgs
13508           && (anArg == "-size"
13509            || anArg == "-boxsize"))
13510     {
13511       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
13512                           anArg != "-boxsize");
13513     }
13514     else if (anArgIter + 1 < theNbArgs
13515           && (anArg == "-boxfacet"
13516            || anArg == "-boxfacetextension"
13517            || anArg == "-facetextension"
13518            || anArg == "-extension"))
13519     {
13520       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
13521     }
13522     else if (anArgIter + 1 < theNbArgs
13523           && (anArg == "-boxedgegap"
13524            || anArg == "-edgegap"))
13525     {
13526       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
13527     }
13528     else if (anArgIter + 1 < theNbArgs
13529           && (anArg == "-boxedgeminsize"
13530            || anArg == "-edgeminsize"))
13531     {
13532       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
13533     }
13534     else if (anArgIter + 1 < theNbArgs
13535           && (anArg == "-boxcornerminsize"
13536            || anArg == "-cornerminsize"))
13537     {
13538       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
13539     }
13540     else if (anArgIter + 1 < theNbArgs
13541           && anArg == "-axespadding")
13542     {
13543       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
13544     }
13545     else if (anArgIter + 1 < theNbArgs
13546           && anArg == "-roundradius")
13547     {
13548       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
13549     }
13550     else if (anArgIter + 1 < theNbArgs
13551           && anArg == "-duration")
13552     {
13553       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
13554     }
13555     else if (anArgIter + 1 < theNbArgs
13556           && anArg == "-axesradius")
13557     {
13558       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
13559     }
13560     else if (anArgIter + 1 < theNbArgs
13561           && anArg == "-axesconeradius")
13562     {
13563       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
13564     }
13565     else if (anArgIter + 1 < theNbArgs
13566           && anArg == "-axessphereradius")
13567     {
13568       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
13569     }
13570     else
13571     {
13572       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13573       return 1;
13574     }
13575   }
13576   if (aViewCube.IsNull())
13577   {
13578     Message::SendFail ("Syntax error: wrong number of arguments");
13579     return 1;
13580   }
13581
13582   ViewerTest::Display (aName, aViewCube, false);
13583   return 0;
13584 }
13585
13586 //===============================================================================================
13587 //function : VColorConvert
13588 //purpose  :
13589 //===============================================================================================
13590 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13591 {
13592   if (theNbArgs != 6)
13593   {
13594     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13595     return 1;
13596   }
13597
13598   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
13599   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
13600   {
13601     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
13602     return 1;
13603   }
13604
13605   const char* aTypeStr = theArgVec[2];
13606   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
13607   if (! strcasecmp (aTypeStr, "srgb"))
13608   {
13609     aType = Quantity_TOC_sRGB;
13610   }
13611   else if (! strcasecmp (aTypeStr, "hls"))
13612   {
13613     aType = Quantity_TOC_HLS;
13614   }
13615   else if (! strcasecmp (aTypeStr, "lab"))
13616   {
13617     aType = Quantity_TOC_CIELab;
13618   }
13619   else if (! strcasecmp (aTypeStr, "lch"))
13620   {
13621     aType = Quantity_TOC_CIELch;
13622   }
13623   else
13624   {
13625     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
13626     return 1;
13627   }
13628
13629   double aC1 = Draw::Atof (theArgVec[3]);
13630   double aC2 = Draw::Atof (theArgVec[4]);
13631   double aC3 = Draw::Atof (theArgVec[5]);
13632
13633   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
13634   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
13635
13636   // print values with 6 decimal digits
13637   char buffer[1024];
13638   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
13639   theDI << buffer;
13640
13641   return 0;
13642 }
13643  
13644 //===============================================================================================
13645 //function : VColorDiff
13646 //purpose  :
13647 //===============================================================================================
13648 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13649 {
13650   if (theNbArgs != 7)
13651   {
13652     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13653     return 1;
13654   }
13655
13656   double aR1 = Draw::Atof (theArgVec[1]);
13657   double aG1 = Draw::Atof (theArgVec[2]);
13658   double aB1 = Draw::Atof (theArgVec[3]);
13659   double aR2 = Draw::Atof (theArgVec[4]);
13660   double aG2 = Draw::Atof (theArgVec[5]);
13661   double aB2 = Draw::Atof (theArgVec[6]);
13662
13663   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
13664   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
13665
13666   theDI << aColor1.DeltaE2000 (aColor2);
13667
13668   return 0;
13669 }
13670  
13671 //===============================================================================================
13672 //function : VSelBvhBuild
13673 //purpose  :
13674 //===============================================================================================
13675 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
13676 {
13677   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
13678   if (aCtx.IsNull())
13679   {
13680     Message::SendFail ("Error: no active viewer");
13681     return 1;
13682   }
13683
13684   if (theNbArgs < 2)
13685   {
13686     Message::SendFail ("Error: command syntax is incorrect, see help");
13687     return 1;
13688   }
13689
13690   Standard_Integer toEnable = -1;
13691   Standard_Integer aThreadsNb = -1;
13692   Standard_Boolean toWait = Standard_False;
13693
13694   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13695   {
13696     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13697     anArg.LowerCase();
13698
13699     if (anArg == "-nbthreads"
13700         && anArgIter + 1 < theNbArgs)
13701     {
13702       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
13703       if (aThreadsNb < 1)
13704       {
13705         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
13706       }
13707     }
13708     else if (anArg == "-wait")
13709     {
13710       toWait = Standard_True;
13711     }
13712     else if (toEnable == -1)
13713     {
13714       Standard_Boolean toEnableValue = Standard_True;
13715       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
13716       {
13717         toEnable = toEnableValue ? 1 : 0;
13718       }
13719       else
13720       {
13721         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13722         return 1;
13723       }
13724     }
13725     else
13726     {
13727       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13728       return 1;
13729     }
13730   }
13731
13732   if (aThreadsNb == -1)
13733   {
13734     aThreadsNb = 1;
13735   }
13736   if (toEnable != -1)
13737   {
13738     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
13739   }
13740   if (toWait)
13741   {
13742     aCtx->MainSelector()->WaitForBVHBuild();
13743   }
13744
13745   return 0;
13746 }
13747
13748 //=======================================================================
13749 //function : ViewerTest_ExitProc
13750 //purpose  :
13751 //=======================================================================
13752 static void ViewerTest_ExitProc (ClientData )
13753 {
13754   NCollection_List<TCollection_AsciiString> aViewList;
13755   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
13756        anIter.More(); anIter.Next())
13757   {
13758     aViewList.Append (anIter.Key1());
13759   }
13760
13761   for (NCollection_List<TCollection_AsciiString>::Iterator anIter (aViewList);
13762        anIter.More(); anIter.Next())
13763   {
13764     ViewerTest::RemoveView (anIter.Value(), true);
13765   }
13766 }
13767
13768 //=======================================================================
13769 //function : ViewerCommands
13770 //purpose  :
13771 //=======================================================================
13772
13773 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
13774 {
13775   static bool TheIsInitialized = false;
13776   if (TheIsInitialized)
13777   {
13778     return;
13779   }
13780
13781   TheIsInitialized = true;
13782   // define destruction callback to destroy views in a well-defined order
13783   Tcl_CreateExitHandler (ViewerTest_ExitProc, 0);
13784
13785   const char* aGroup = "AIS Viewer";
13786   const char* aFileName = __FILE__;
13787   auto addCmd = [&](const char* theName, Draw_Interpretor::CommandFunction theFunc, const char* theHelp)
13788   {
13789     theCommands.Add (theName, theHelp, aFileName, theFunc, aGroup);
13790   };
13791
13792   addCmd ("vdriver", VDriver, /* [vdriver] */ R"(
13793 vdriver [-list] [-default DriverName] [-load DriverName]
13794 Manages active graphic driver factory.
13795 Prints current active driver when called without arguments.
13796 Makes specified driver active when ActiveName argument is specified.
13797  -list    print registered factories
13798  -default define which factory should be used by default (to be used by next vinit call)
13799  -load    try loading factory plugin and set it as default one
13800 )" /* [vdriver] */);
13801
13802   addCmd ("vinit", VInit, /* [vinit] */ R"(
13803 vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]
13804       [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {on|off}=off] [-2d_mode {on|off}=off]
13805       [-display displayName] [-dpiAware {on|off}]
13806 Creates new View window with specified name viewName.
13807 By default the new view is created in the viewer and in graphic driver shared with active view.
13808  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}
13809        if driverName isn't specified the driver will be shared with active view;
13810        if viewerName isn't specified the viewer will be shared with active view.
13811  -display HostName.DisplayNumber[:ScreenNumber]
13812
13813 Display name will be used within creation of graphic driver, when specified.
13814  -left,  -top    pixel position of left top corner of the window.
13815  -width, -height width and height of window respectively.
13816  -cloneActive flag to copy camera and dimensions of active view.
13817  -exitOnClose when specified, closing the view will exit application.
13818  -closeOnEscape when specified, view will be closed on pressing Escape.
13819  -virtual create an offscreen window within interactive session
13820  -2d_mode when on, view will not react on rotate scene events
13821  -dpiAware override dpi aware hint (Windows platform)
13822 Additional commands for operations with views: vclose, vactivate, vviewlist.
13823 )" /* [vinit] */);
13824
13825   addCmd ("vclose", VClose, /* [vclose] */ R"(
13826 vclose [view_id [keep_context=0|1]]
13827 or vclose ALL - to remove all created views
13828  - removes view(viewer window) defined by its view_id.
13829  - keep_context: by default 0; if 1 and the last view is deleted the current context is not removed.
13830 )" /* [vclose] */);
13831
13832   addCmd ("vactivate", VActivate, /* [vactivate] */ R"(
13833 vactivate view_id [-noUpdate]
13834 Activates view(viewer window) defined by its view_id.
13835 )" /* [vactivate] */);
13836
13837   addCmd ("vviewlist", VViewList, /* [vviewlist] */ R"(
13838 vviewlist [format={tree, long}]=tree
13839 Prints current list of views per viewer and graphic_driver ID shared between viewers
13840  - format: format of result output, if tree the output is a tree view;
13841            otherwise it's a list of full view names.
13842 )" /* [vviewlist] */);
13843
13844   addCmd ("vhelp", VHelp, /* [vhelp] */ R"(
13845 vhelp : display help on the viewer commands and list of hotkeys.
13846 )" /* [vhelp] */);
13847
13848   addCmd ("vviewproj", VViewProj, /* [vviewproj] */ R"(
13849 vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]
13850           [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]
13851 Setup view direction
13852  -Yup      use Y-up convention instead of Zup (which is default).
13853  +-X+-Y+-Z define direction as combination of DX, DY and DZ;
13854            for example '+Z' will show front of the model,
13855            '-X-Y+Z' will define left axonometric view.
13856  -frame    define camera Up and Right directions (regardless Up convention);
13857            for example '+X+Z' will show front of the model with Z-up.
13858 )" /* [vviewproj] */);
13859
13860   addCmd ("vtop", VViewProj, /* [vtop] */ R"(
13861 vtop or <T> : Display top view (+X+Y) in the 3D viewer window.
13862 )" /* [vtop] */);
13863
13864   addCmd ("vbottom", VViewProj, /* [vbottom] */ R"(
13865 vbottom : Display bottom view (+X-Y) in the 3D viewer window.
13866 )" /* [vbottom] */);
13867
13868   addCmd ("vleft", VViewProj, /* [vleft] */ R"(
13869 vleft : Display left view (-Y+Z) in the 3D viewer window.
13870 )" /* [vleft] */);
13871
13872   addCmd ("vright", VViewProj, /* [vright] */ R"(
13873 vright : Display right view (+Y+Z) in the 3D viewer window.
13874 )" /* [vright] */);
13875
13876   addCmd ("vaxo", VViewProj, /* [vaxo] */ R"(
13877 vaxo or <A> : Display axonometric view (+X-Y+Z) in the 3D viewer window.
13878 )" /* [vaxo] */);
13879
13880   addCmd ("vfront", VViewProj, /* [vfront] */ R"(
13881 vfront : Display front view (+X+Z) in the 3D viewer window.
13882 )" /* [vfront] */);
13883
13884   addCmd ("vback", VViewProj, /* [vfront] */ R"(
13885 vback : Display back view (-X+Z) in the 3D viewer window.
13886 )" /* [vback] */);
13887
13888   addCmd ("vpick", VPick, /* [vpick] */ R"(
13889 vpick X Y Z [shape subshape]
13890 )" /* [vpick] */);
13891
13892   addCmd ("vfit", VFit, /* [vfit] */ R"(
13893 vfit or <F> [-selected] [-noupdate]
13894 Fit all / selected. Objects in the view are visualized to occupy the maximum surface.
13895 )" /* [vfit] */);
13896
13897   addCmd ("vfitarea", VFitArea, /* [vfitarea] */ R"(
13898 vfitarea [x1 y1 x2 y2] [x1 y1 z1 x2 y2 z2]
13899 Fit view to show area located between two points
13900 given in world 2D or 3D coordinates.
13901 )" /* [vfitarea] */);
13902
13903   addCmd ("vzfit", VZFit, /* [vzfit] */ R"(
13904 vzfit [scale]
13905 Automatic depth panning.
13906 Matches Z near, Z far view volume planes to the displayed objects.
13907  - "scale" specifies factor to scale computed z range.
13908 )" /* [vzfit] */);
13909
13910   addCmd ("vrepaint", VRepaint, /* [vrepaint] */ R"(
13911 vrepaint [-immediate] [-continuous FPS]
13912 Force redraw of active View.
13913  -immediate  flag performs redraw of immediate layers only;
13914  -continuous activates/deactivates continuous redraw of active View,
13915              0 means no continuous rendering,
13916             -1 means non-stop redraws,
13917             >0 specifies target framerate.
13918 )" /* [vrepaint] */);
13919
13920   addCmd ("vclear", VClear, /* [vclear] */ R"(
13921 vclear : Remove all the object from the viewer
13922 )" /* [vclear] */);
13923
13924   addCmd ("vbackground", VBackground, /* [vbackground] */ R"(
13925 vbackground [-color Color [-default]]
13926     [-gradient Color1 Color2 [-default]
13927     [-gradientMode {NONE|HORIZONTAL|VERTICAL|DIAG1|DIAG2|CORNER1|CORNER2|CORNER3|ELLIPTICAL}]=VERT]
13928     [-imageFile ImageFile [-imageMode {CENTERED|TILED|STRETCH|NONE}]=CENTERED [-srgb {0|1}]=1]
13929     [-cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]=0]
13930     [-skydome [-sunDir X Y Z=0 1 0] [-cloud Cloudy=0.2] [-time Time=0.0]
13931               [-fog Haze=0.0] [-size SizePx=512]]
13932     [-pbrEnv {ibl|noibl|keep}]
13933 Changes background or some background settings.
13934  -color        sets background color
13935  -gradient     sets background gradient starting and ending colors
13936  -gradientMode sets gradient fill method
13937  -default      sets background default gradient or color
13938  -imageFile    sets filename of image used as background
13939  -imageMode    sets image fill type
13940  -cubemap      sets environment cubemap as background
13941  -invertedz    sets inversion of Z axis for background cubemap rendering; FALSE when unspecified
13942  -pbrEnv       sets on/off Image Based Lighting (IBL) from background cubemap for PBR
13943  -srgb         prefer sRGB texture format when applicable; TRUE when unspecified"
13944  -order        defines order of tiles in one image cubemap
13945                TileIndexi defubes an index in range [0, 5] for i tile of one image packed cubemap
13946                (has no effect in case of multi-image cubemaps).
13947 Skydome background parameters (generated cubemap):
13948  -skydome      sets procedurally generated skydome as background
13949  -sunDir       sets direction to the sun, direction with negative y component represents moon direction (-x, -y, -z)
13950  -cloud        sets cloud intensity (0.0 - clear sky, 1.0 - very high cloudy)
13951  -time         might be tweaked to slightly change appearance of clouds
13952  -fog          sets mist intensity (0.0 - no mist at all, 1.0 - high mist)
13953  -size         sets size in pixels of cubemap side
13954 )" /* [vbackground] */);
13955
13956   addCmd ("vsetbg", VBackground, /* [vsetbg] */ R"(
13957 Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.
13958 )" /* [vsetbg] */);
13959
13960   addCmd ("vsetbgmode", VBackground, /* [vsetbgmode] */ R"(
13961 Alias for 'vbackground -imageMode FillType'.
13962 )" /* [vsetbgmode] */);
13963
13964   addCmd ("vsetgradientbg", VBackground, /* [vsetgradientbg] */ R"(
13965 Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.
13966 )" /* [vsetgradientbg] */);
13967
13968   addCmd ("vsetgrbgmode", VBackground, /* [vsetgrbgmode] */ R"(
13969 Alias for 'vbackground -gradientMode FillMethod'.
13970 )" /* [vsetgrbgmode] */);
13971
13972   addCmd ("vsetcolorbg", VBackground, /* [vsetcolorbg] */ R"(
13973 Alias for 'vbackground -color Color'.
13974 )" /* [vsetcolorbg] */);
13975
13976   addCmd ("vsetdefaultbg", VBackground, /* [vsetdefaultbg] */ R"(
13977 Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'
13978   and for 'vbackground -default -color Color'.
13979 )" /* [vsetdefaultbg] */);
13980
13981   addCmd ("vscale", VScale, /* [vscale] */ R"(
13982 vscale X Y Z
13983 )" /* [vscale] */);
13984
13985   addCmd ("vzbufftrihedron", VZBuffTrihedron, /* [vzbufftrihedron] */ R"(
13986 vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]
13987        [-position center|left_lower|left_upper|right_lower|right_upper]
13988        [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]
13989        [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]
13990        [-nbfacets value=12] [-colorLabels color=WHITE]
13991        [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]
13992 Displays a trihedron.
13993 )" /* [vzbufftrihedron] */);
13994
13995   addCmd ("vrotate", VRotate, /* [vrotate] */ R"(
13996 vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]
13997  -mouseStart start rotation according to the mouse position;
13998  -mouseMove  continue rotation with angle computed
13999              from last and new mouse position.
14000 )" /* [vrotate] */);
14001
14002   addCmd ("vzoom", VZoom, /* [vzoom] */ R"(
14003 vzoom coef
14004 )" /* [vzoom] */);
14005
14006   addCmd ("vpan", VPan, /* [vpan] */ R"(
14007 vpan dx dy
14008 )" /* [vpan] */);
14009
14010   addCmd ("vcolorscale", VColorScale, /* [vcolorscale] */ R"(
14011 vcolorscale name [-noupdate|-update] [-demo]
14012       [-range RangeMin=0 RangeMax=1 NbIntervals=10]
14013       [-font HeightFont=20]
14014       [-logarithmic {on|off}=off] [-reversed {on|off}=off]
14015       [-smoothTransition {on|off}=off]
14016       [-hueRange MinAngle=230 MaxAngle=0]
14017       [-colorRange MinColor=BLUE1 MaxColor=RED]
14018       [-textPos {left|right|center|none}=right]
14019       [-labelAtBorder {on|off}=on]
14020       [-colors Color1 Color2 ...] [-color Index Color]
14021       [-labels Label1 Label2 ...] [-label Index Label]
14022       [-freeLabels NbOfLabels Label1 Label2 ...]
14023       [-xy Left=0 Bottom=0]
14024       [-uniform lightness hue_from hue_to]
14025  -demo       display a color scale with demonstration values
14026  -colors     set colors for all intervals
14027  -color      set color for specific interval
14028  -uniform    generate colors with the same lightness
14029  -textpos    horizontal label position relative to color scale bar
14030  -labelAtBorder vertical label position relative to color interval;
14031              at border means the value inbetween neighbor intervals,
14032              at center means the center value within current interval
14033  -labels     set labels for all intervals
14034  -freeLabels same as -labels but does not require
14035              matching the number of intervals
14036  -label      set label for specific interval
14037  -title      set title
14038  -reversed   setup smooth color transition between intervals
14039  -smoothTransition swap colorscale direction
14040  -hueRange   set hue angles corresponding to minimum and maximum values
14041 )" /* [vcolorscale] */);
14042
14043   addCmd ("vgraduatedtrihedron", VGraduatedTrihedron, /* [vgraduatedtrihedron] */ R"(
14044 vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]
14045     [-namefont Name] [-valuesfont Name]
14046     [-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]
14047     [-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]
14048     [-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]
14049     [-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]
14050     [-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]
14051     [-xcolor Color] [-ycolor Color] [-zcolor Color]
14052     [-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]
14053     [-xticks Number] [-yticks Number] [-zticks Number]
14054     [-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]
14055     [-drawgrid on/off] [-drawaxes on/off]
14056 Display or erase graduated trihedron
14057  - xname, yname, zname - names of axes, default: X, Y, Z
14058  - namefont - font of axes names. Default: Arial
14059  - xnameoffset, ynameoffset, znameoffset - offset of name
14060    from values or tickmarks or axis. Default: 30
14061  - xnamecolor, ynamecolor, znamecolor - colors of axes names
14062  - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values
14063    from tickmarks or axis. Default: 10
14064  - valuesfont - font of axes values. Default: Arial
14065  - xcolor, ycolor, zcolor - color of axis and values
14066  - xticks, yticks, xzicks - number of tickmark on axes. Default: 5
14067  - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10
14068 )" /* [vgraduatedtrihedron] */);
14069
14070   addCmd ("vtile", VTile, /* [vtile] */ R"(
14071 vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]
14072 Setup view to draw a tile (a part of virtual bigger viewport).
14073  -totalSize the size of virtual bigger viewport
14074  -tileSize  tile size (the view size will be used if omitted)
14075  -lowerLeft tile offset as lower left corner
14076  -upperLeft tile offset as upper left corner
14077 )" /* [vtile] */);
14078
14079   addCmd ("vzlayer", VZLayer, /* [vzlayer] */ R"(
14080 vzlayer [layerId]
14081         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]
14082         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]
14083         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]
14084         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]
14085 ZLayer list management
14086  -add      add new z layer to viewer and print its id
14087  -insertBefore add new z layer and insert it before existing one
14088  -insertAfter  add new z layer and insert it after  existing one
14089  -delete   delete z layer
14090  -get      print sequence of z layers
14091  -settings print status of z layer settings
14092  -disable  disables given setting
14093  -enable   enables  given setting
14094 )" /* [vzlayer] */);
14095
14096   addCmd ("vlayerline", VLayerLine, /* [vlayerline] */ R"(
14097 vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]
14098 )" /* [vlayerline] */);
14099
14100   addCmd ("vgrid", VGrid, /* [vgrid] */ R"(
14101 vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]
14102       [-step X Y] [-size DX DY]
14103       [-step StepRadius NbDivisions] [-radius Radius]
14104 )" /* [vgrid] */);
14105
14106   addCmd ("vpriviledgedplane", VPriviledgedPlane, /* [vpriviledgedplane] */ R"(
14107 vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]
14108 Sets or prints viewer's priviledged plane geometry:
14109   Ox, Oy, Oz - plane origin;
14110   Nx, Ny, Nz - plane normal direction;
14111   Xx, Xy, Xz - plane x-reference axis direction.
14112 )" /* [vpriviledgedplane] */);
14113
14114   addCmd ("vconvert", VConvert, /* [vconvert] */ R"(
14115 vconvert v [Mode={window|view}]
14116 vconvert x y [Mode={window|view|grid|ray}]
14117 vconvert x y z [Mode={window|grid}]
14118 Convert the given coordinates to window/view/model space:
14119  - window - convert to window coordinates, pixels;
14120  - view   - convert to view projection plane;
14121  - grid   - convert to model coordinates, given on grid;
14122  - ray    - convert projection ray to model coordinates.
14123 )" /* [vconvert] */);
14124
14125   addCmd ("vfps", VFps, /* [vfps] */ R"(
14126 vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view.
14127 )" /* [vfps] */);
14128
14129   addCmd ("vstereo", VStereo, /* [vstereo] */ R"(
14130 vstereo [0|1] [-mode Mode] [-reverse {0|1}]
14131         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]
14132         [-anaglyph Filter] [-smoothInterlacing]
14133 Control stereo output mode. Available modes for -mode:
14134   quadBuffer       OpenGL QuadBuffer stereo;
14135     requires driver support;
14136     should be called BEFORE vinit!
14137   anaglyph         Anaglyph glasses, filters for -anaglyph:
14138     redCyan, redCyanSimple, yellowBlue, yellowBlueSimple, greenMagentaSimple.
14139   rowInterlaced    row-interlaced display
14140     smooth         smooth interlaced output for better text readability
14141   columnInterlaced column-interlaced display
14142   chessBoard       chess-board output
14143   sideBySide       horizontal pair
14144   overUnder        vertical   pair
14145   openVR           OpenVR (HMD), extra options:
14146     -mirrorComposer flag to mirror VR frame in the window (debug);
14147     -unitFactor     specifies meters scale factor for mapping VR input.
14148 )" /* [vstereo] */);
14149
14150   addCmd ("vmemgpu", VMemGpu, /* [vmemgpu] */ R"(
14151 vmemgpu [f]: print system-dependent GPU memory information if available;
14152 with f option returns free memory in bytes.
14153 )" /* [vmemgpu] */);
14154
14155   addCmd ("vreadpixel", VReadPixel, /* [vreadpixel] */ R"(
14156 vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]
14157 Read pixel value for active view.
14158 )" /* [vreadpixel] */);
14159
14160   addCmd ("diffimage", VDiffImage, /* [diffimage] */ R"(
14161 diffimage imageFile1 imageFile2 [diffImageFile]
14162           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]
14163           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]
14164 Compare two images by content and generate difference image.
14165 When -exitOnClose is specified, closing the view will exit application.
14166 When -closeOnEscape is specified, view will be closed on pressing Escape.
14167 )" /* [diffimage] */);
14168
14169   addCmd ("vselect", VSelect, /* [vselect] */ R"(
14170 vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1]
14171         [-replace|-replaceextra|-xor|-add|-remove]
14172 Emulate different types of selection:
14173  1) Single click selection.
14174  2) Selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2).
14175  3) Selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn).
14176  4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.
14177     If the flag is set to 1, both sensitives that were included completely
14178     and overlapped partially by defined rectangle or polygon will be detected,
14179     otherwise algorithm will chose only fully included sensitives.
14180     Default behavior is to detect only full inclusion
14181     (partial inclusion - overlap - is not allowed by default).
14182  5) Selection scheme replace, replaceextra, xor, add or remove (replace by default).
14183 )" /* [vselect] */);
14184
14185   addCmd ("vmoveto", VMoveTo, /* [vmoveto] */ R"(
14186 vmoveto [x y] [-reset]
14187 Emulate cursor movement to pixel position (x,y).
14188  -reset resets current highlighting.
14189 )" /* [vmoveto] */);
14190
14191   addCmd ("vselaxis", VSelectByAxis, /* [vselaxis] */ R"(
14192 vselaxis x y z dx dy dz [-onlyTop 0|1] [-display Name] [-showNormal 0|1]"
14193 Provides intersection by given axis and print result intersection points.
14194  -onlyTop       switches On/Off mode to find only top point or all;
14195  -display Name  displays intersecting axis and result intersection points for debug goals;
14196  -showNormal    adds displaying of normal in intersection point or not.
14197 )" /* [vselaxis] */);
14198
14199   addCmd ("vviewparams", VViewParams, /* [vviewparams] */ R"(
14200 vviewparams [-args] [-scale [s]]
14201             [-eye [x y z]] [-at [x y z]] [-up [x y z]]
14202             [-proj [x y z]] [-center x y] [-size sx]
14203 Manage current view parameters (camera orientation) or prints all
14204 current values when called without argument.
14205  -scale [s]    prints or sets viewport relative scale
14206  -eye  [x y z] prints or sets eye location
14207  -at   [x y z] prints or sets center of look
14208  -up   [x y z] prints or sets direction of up vector
14209  -proj [x y z] prints or sets direction of look
14210  -center x y   sets location of center of the screen in pixels
14211  -size [sx]    prints viewport projection width and height sizes
14212                or changes the size of its maximum dimension
14213  -args         prints vviewparams arguments for restoring current view
14214 )" /* [vviewparams] */);
14215
14216   addCmd ("v2dmode", V2DMode, /* [v2dmode] */ R"(
14217 v2dmode [-name viewName] [-mode {-on|-off}=-on]
14218   name - name of existing view, if not defined, the active view is changed;
14219   mode - switches On/Off rotation mode.
14220 Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:
14221  - rotation of the view by 3rd mouse button with Ctrl active
14222  - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right
14223 View camera position might be changed only by commands.
14224 )" /* [v2dmode] */);
14225
14226   addCmd ("vanimation", VAnimation, /* [vanimation] */ R"(
14227 Alias for vanim
14228 )" /* [vanimation] */);
14229
14230   addCmd ("vanim", VAnimation, /* [vanim] */ R"(
14231 List existing animations:
14232   vanim
14233
14234 Animation playback:
14235   vanim name {-play|-resume|-pause|-stop} [playFrom [playDuration]]
14236              [-speed Coeff] [-freeLook] [-noPauseOnClick] [-lockLoop]
14237
14238   -speed    playback speed (1.0 is normal speed)
14239   -freeLook skip camera animations
14240   -noPauseOnClick do not pause animation on mouse click
14241   -lockLoop disable any interactions
14242
14243 Animation definition:
14244   vanim Name/sub/name [-clear] [-delete]
14245         [-start TimeSec] [-duration TimeSec] [-end TimeSec]
14246
14247 Animation name defined in path-style (anim/name or anim.name)
14248 specifies nested animations.
14249 There is no syntax to explicitly add new animation,
14250 and all non-existing animations within the name will be
14251 implicitly created on first use (including parents).
14252
14253 Each animation might define the SINGLE action (see below),
14254 like camera transition, object transformation or custom callback.
14255 Child animations can be used for defining concurrent actions.
14256
14257 Camera animation:
14258   vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]
14259                    [-at1  X Y Z] [-at2  X Y Z]
14260                    [-up1  X Y Z] [-up2  X Y Z]
14261                    [-scale1 Scale] [-scale2 Scale]
14262   -eyeX   camera Eye positions pair (start and end)
14263   -atX    camera Center positions pair
14264   -upX    camera Up directions pair
14265   -scaleX camera Scale factors pair
14266
14267 Object animation:
14268   vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]
14269                      [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]
14270                      [-scale1 Scale] [-scale2 Scale]
14271  -locX   object Location points pair (translation)
14272  -rotX   object Orientations pair (quaternions)
14273  -scaleX object Scale factors pair (quaternions)
14274
14275 Custom callback:
14276   vanim name -invoke "Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN"
14277
14278   %Pts        overall animation presentation timestamp
14279   %LocalPts   local animation timestamp
14280   %Normalized local animation normalized value in range 0..1
14281
14282 Video recording:
14283   vanim name -record FileName [Width Height] [-fps FrameRate=24]
14284         [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]
14285         [-crf Value] [-preset Preset]
14286   -fps     video framerate
14287   -format  file format, container (matroska, etc.)
14288   -vcodec  video codec identifier (ffv1, mjpeg, etc.)
14289   -pix_fmt image pixel format (yuv420p, rgb24, etc.)
14290   -crf     constant rate factor (specific to codec)
14291   -preset  codec parameters preset (specific to codec)
14292 )" /* [vanim] */);
14293
14294   addCmd ("vchangeselected", VChangeSelected, /* [vchangeselected] */ R"(
14295 vchangeselected shape : Add shape to selection or remove one from it.
14296 )" /* [vchangeselected] */);
14297
14298   addCmd ("vnbselected", VNbSelected, /* [vnbselected] */ R"(
14299 vnbselected : Returns number of selected objects in the interactive context.
14300 )" /* [vnbselected] */);
14301
14302   addCmd ("vcamera", VCamera, /* [vcamera] */ R"(
14303 vcamera [PrsName] [-ortho] [-projtype]
14304         [-persp]
14305         [-fovy   [Angle]] [-distance [Distance]]
14306         [-stereo] [-leftEye] [-rightEye]
14307         [-iod [Distance]] [-iodType    [absolute|relative]]
14308         [-zfocus [Value]] [-zfocusType [absolute|relative]]
14309         [-fov2d  [Angle]] [-lockZup {0|1}]
14310         [-rotationMode {active|pick|pickCenter|cameraAt|scene}]
14311         [-navigationMode {orbit|walk|flight}]
14312         [-xrPose base|head=base]
14313 Manages camera parameters.
14314 Displays frustum when presentation name PrsName is specified.
14315 Prints current value when option called without argument.
14316
14317 Orthographic camera:
14318  -ortho      activate orthographic projection.
14319
14320 Perspective camera:
14321  -persp      activate perspective  projection (mono);
14322  -fovy       field of view in y axis, in degrees;
14323  -fov2d      field of view limit for 2d on-screen elements;
14324  -distance   distance of eye from camera center;
14325  -lockZup    lock Z up (turntable mode);
14326  -rotationMode rotation mode (gravity point);
14327  -navigationMode navigation mode.
14328
14329 Stereoscopic camera:
14330  -stereo     perspective  projection (stereo);
14331  -leftEye    perspective  projection (left  eye);
14332  -rightEye   perspective  projection (right eye);
14333  -iod        intraocular distance value;
14334  -iodType    distance type, absolute or relative;
14335  -zfocus     stereographic focus value;
14336  -zfocusType focus type, absolute or relative.
14337 )" /* [vcamera] */);
14338
14339   addCmd ("vautozfit", VAutoZFit, /* [vautozfit] */ R"(
14340 vautozfit [on={1|0}] [scale]
14341 Prints or changes parameters of automatic z-fit mode:
14342  "on" - turns automatic z-fit on or off;
14343  "scale" - specifies factor to scale computed z range.
14344 )" /* [vautozfit] */);
14345
14346   addCmd ("vzrange", VZRange, /* [vzrange] */ R"(
14347 vzrange [znear] [zfar]
14348 Applies provided znear/zfar to view or prints current values.
14349 )" /* [vzrange] */);
14350
14351   addCmd ("vsetviewsize", VSetViewSize, /* [vsetviewsize] */ R"(
14352 vsetviewsize size
14353 )" /* [vsetviewsize] */);
14354
14355   addCmd ("vmoveview", VMoveView, /* [vmoveview] */ R"(
14356 vmoveview Dx Dy Dz [Start = 1|0]
14357 )" /* [vmoveview] */);
14358
14359   addCmd ("vtranslateview", VTranslateView, /* [vtranslateview] */ R"(
14360 vtranslateview Dx Dy Dz [Start = 1|0)]
14361 )" /* [vtranslateview] */);
14362
14363   addCmd ("vturnview", VTurnView, /* [vturnview] */ R"(
14364 vturnview Ax Ay Az [Start = 1|0]
14365 )" /* [vturnview] */);
14366
14367   addCmd ("vtextureenv", VTextureEnv, /* [vtextureenv] */ R"(
14368 vtextureenv {on|off} {image_file}
14369             [{clamp|repeat} {decal|modulate} {nearest|bilinear|trilinear} ss st ts tt rot]
14370 Enables or disables environment mapping in the 3D view, loading the texture from the given standard
14371 or user-defined file and optionally applying texture mapping parameters.
14372  ss, st - scale factors for s and t texture coordinates;
14373  ts, tt - translation for s and t texture coordinates;
14374  rot    - texture rotation angle in degrees.
14375 )" /* [vtextureenv] */);
14376
14377   addCmd ("vhlr", VHLR, /* [vhlr] */ R"(
14378 vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]
14379 Hidden Line Removal algorithm.
14380  -showHidden if set ON, hidden lines are drawn as dotted ones;
14381  -algoType   type of HLR algorithm:
14382             'algo' - exact HLR algorithm is applied;
14383             'polyAlgo' - polygonal HLR algorithm is applied.
14384 )" /* [vhlr] */);
14385
14386   addCmd ("vhlrtype", VHLRType, /* [vhlrtype] */ R"(
14387 vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]
14388 Changes the type of HLR algorithm using for shapes:
14389  'algo' - exact HLR algorithm is applied;
14390  'polyAlgo' - polygonal HLR algorithm is applied.
14391 If shapes are not given - option is applied to all shapes in the view.
14392 )" /* [vhlrtype] */);
14393
14394   addCmd ("vclipplane", VClipPlane, /* [vclipplane] */ R"(
14395 vclipplane planeName [{0|1}]
14396     [-equation1 A B C D]
14397     [-equation2 A B C D]
14398     [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]
14399     [-set|-unset|-setOverrideGlobal [objects|views]]
14400     [-maxPlanes]
14401     [-capping {0|1}]
14402       [-color R G B] [-transparency Value] [-hatch {on|off|ID}]
14403       [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]
14404         [-texRotate Angle]
14405       [-useObjMaterial {0|1}] [-useObjTexture {0|1}]
14406         [-useObjShader {0|1}]
14407
14408 Clipping planes management:
14409  -maxPlanes   print plane limit for view;
14410  -delete      delete plane with given name;
14411  {off|on|0|1} turn clipping on/off;
14412  -set|-unset  set/unset plane for Object or View list;
14413               applied to active View when list is omitted;
14414  -equation A B C D change plane equation;
14415  -clone SourcePlane NewPlane clone the plane definition.
14416
14417 Capping options:
14418  -capping {off|on|0|1} turn capping on/off;
14419  -color R G B          set capping color;
14420  -transparency Value   set capping transparency 0..1;
14421  -texName Texture      set capping texture;
14422  -texScale SX SY       set capping tex scale;
14423  -texOrigin TX TY      set capping tex origin;
14424  -texRotate Angle      set capping tex rotation;
14425  -hatch {on|off|ID}    set capping hatching mask;
14426  -useObjMaterial {off|on|0|1} use material of clipped object;
14427  -useObjTexture  {off|on|0|1} use texture of clipped object;
14428  -useObjShader   {off|on|0|1} use shader program of object.
14429 )" /* [vclipplane] */);
14430
14431   addCmd ("vdefaults", VDefaults, /* [vdefaults] */ R"(
14432 vdefaults [-absDefl value] [-devCoeff value] [-angDefl value]
14433           [-autoTriang {off/on | 0/1}]
14434 )" /* [vdefaults] */);
14435
14436   addCmd ("vlight", VLight, /* [vlight] */ R"(
14437 vlight [lightName] [-noupdate]
14438        [-clear|-defaults] [-layer Id] [-local|-global] [-disable|-enable]
14439        [-type {ambient|directional|spotlight|positional}] [-name value]
14440        [-position X Y Z] [-direction X Y Z] [-color colorName] [-intensity value]
14441        [-headlight 0|1] [-castShadows 0|1]
14442        [-range value] [-constAttenuation value] [-linearAttenuation value]
14443        [-spotExponent value] [-spotAngle angleDeg]
14444        [-smoothAngle value] [-smoothRadius value]
14445        [-display] [-showName 1|0] [-showRange 1|0] [-prsZoomable 1|0] [-prsSize Value]
14446        [-arcSize Value]
14447
14448 Command manages light sources. Without arguments shows list of lights.
14449 Arguments affecting the list of defined/active lights:
14450  -clear       remove all light sources;
14451  -defaults    defines two standard light sources;
14452  -reset       resets light source parameters to default values;
14453  -type        sets type of light source;
14454  -name        sets new name to light source;
14455  -global      assigns light source to all views (default state);
14456  -local       assigns light source to active view;
14457  -zlayer      assigns light source to specified Z-Layer.
14458
14459 Ambient light parameters:
14460  -color       sets (normalized) light color;
14461  -intensity   sets intensity of light source, 1.0 by default;
14462               affects also environment cubemap intensity.
14463
14464 Point light parameters:
14465  -color       sets (normalized) light color;
14466  -intensity   sets PBR intensity;
14467  -range       sets clamping distance;
14468  -constAtten  (obsolete) sets constant attenuation factor;
14469  -linearAtten (obsolete) sets linear   attenuation factor;
14470  -smoothRadius sets PBR smoothing radius.
14471
14472 Directional light parameters:
14473  -color       sets (normalized) light color;
14474  -intensity   sets PBR intensity;
14475  -direction   sets direction;
14476  -headlight   sets headlight flag;
14477  -castShadows enables/disables shadow casting;
14478  -smoothAngle sets PBR smoothing angle (in degrees) within 0..90 range.
14479
14480 Spot light parameters:
14481  -color       sets (normalized) light color;
14482  -intensity   sets PBR intensity;
14483  -range       sets clamping distance;
14484  -position    sets position;
14485  -direction   sets direction;
14486  -spotAngle   sets spotlight angle;
14487  -spotExp     sets spotlight exponenta;
14488  -headlight   sets headlight flag;
14489  -constAtten  (obsolete) sets constant attenuation factor;
14490  -linearAtten (obsolete) sets linear   attenuation factor.
14491
14492 Light presentation parameters:
14493  -display     adds light source presentation;
14494  -showName    shows/hides the name of light source; 1 by default;
14495  -showRange   shows/hides the range of spot/positional light source; 1 by default;
14496  -prsZoomable makes light presentation zoomable/non-zoomable;
14497  -prsDraggable makes light presentation draggable/non-draggable;
14498  -prsSize     sets light presentation size;
14499  -arcSize     sets arc presentation size(in pixels)
14500               for rotation directional light source; 25 by default.
14501
14502 Examples:
14503  vlight redlight -type POSITIONAL -headlight 1 -pos 0 1 1 -color RED
14504  vlight redlight -delete
14505 )" /* [vlight] */);
14506
14507   addCmd ("vpbrenv", VPBREnvironment, /* [vpbrenv] */ R"(
14508 vpbrenv -clear|-generate
14509 Clears or generates PBR environment map of active view.
14510  -clear clears PBR environment (fills by white color);
14511  -generate generates PBR environment from current background cubemap.
14512 )" /* [vpbrenv] */);
14513
14514   addCmd ("vraytrace", VRenderParams, /* [vraytrace] */ R"(
14515 vraytrace [0|1] : Turns on/off ray-tracing renderer.
14516  'vraytrace 0' alias for 'vrenderparams -raster'.
14517  'vraytrace 1' alias for 'vrenderparams -rayTrace'.
14518 )" /* [vraytrace] */);
14519
14520   addCmd ("vrenderparams", VRenderParams, /* [vrenderparams] */ R"(
14521 Manages rendering parameters, affecting visual appearance, quality and performance.
14522 Should be applied taking into account GPU hardware capabilities and performance.
14523
14524 Common parameters:
14525 vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]
14526               [-msaa 0..8=0] [-rendScale scale=1]
14527               [-resolution value=72] [-fontHinting {off|normal|light}=off]
14528               [-fontAutoHinting {auto|force|disallow}=auto]
14529               [-oit {off|weight|peel}] [-oit weighted [depthFactor=0.0]] [-oit peeling [nbLayers=4]]
14530               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]
14531               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]
14532               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]
14533               [-sync {default|views}] [-reset]
14534  -raster          Disables GPU ray-tracing.
14535  -shadingModel    Controls shading model.
14536  -msaa            Specifies number of samples for MSAA.
14537  -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA).
14538  -resolution      Sets new pixels density (PPI) used as text scaling factor.
14539  -fontHinting     Enables/disables font hinting for better readability on low-resolution screens.
14540  -fontAutoHinting Manages font autohinting.
14541  -lineFeather     Sets line feather factor while displaying mesh edges.
14542  -alphaToCoverage Enables/disables alpha to coverage (needs MSAA).
14543  -oit             Enables/disables order-independent transparency (OIT) rendering;
14544       off         unordered transparency (but opaque objects implicitly draw first);
14545       weighted    weight OIT is managed by depth weight factor 0.0..1.0;
14546       peeling     depth peeling OIT is managed by number of peeling layers.
14547   -shadows         Enables/disables shadows rendering.
14548   -shadowMapResolution Shadow texture map resolution.
14549   -shadowMapBias   Shadow map bias.
14550   -depthPrePass    Enables/disables depth pre-pass.
14551   -frustumCulling  Enables/disables objects frustum clipping or
14552                    sets state to check structures culled previously.
14553   -sync            Sets active View parameters as Viewer defaults / to other Views.
14554   -reset           Resets active View parameters to Viewer defaults.
14555
14556 Diagnostic output (on-screen overlay):
14557 vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points
14558                                  |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]
14559               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]
14560  -perfCounters       Show/hide performance counters (flags can be combined).
14561  -perfUpdateInterval Performance counters update interval.
14562  -perfChart          Show frame timers chart limited by specified number of frames.
14563  -perfChartMax       Maximum time in seconds with the chart.
14564
14565 Ray-Tracing options:
14566 vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]
14567               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]
14568               [-gi {on|off}=off] [-brng {on|off}=off]
14569               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]
14570               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]
14571               [-maxRad {value>0}=30.0]
14572               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]
14573               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]
14574  -rayTrace     Enables  GPU ray-tracing.
14575  -rayDepth     Defines maximum ray-tracing depth.
14576  -reflections  Enables/disables specular reflections.
14577  -fsaa         Enables/disables adaptive anti-aliasing.
14578  -gleam        Enables/disables transparency shadow effects.
14579  -gi           Enables/disables global illumination effects (Path-Tracing).
14580  -env          Enables/disables environment map background.
14581  -ignoreNormalMap Enables/disables normal map ignoring during path tracing.
14582  -twoSide      Enables/disables two-sided BSDF models (PT mode).
14583  -iss          Enables/disables adaptive screen sampling (PT mode).
14584  -maxRad       Value used for clamping radiance estimation (PT mode).
14585  -tileSize     Specifies   size of screen tiles in ISS mode (32 by default).
14586  -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default).
14587  -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF).
14588  -focal        Focal distance of perspective camera for depth-of-field effect.
14589  -exposure     Exposure value for tone mapping (0.0 value disables the effect).
14590  -whitePoint   White point value for filmic tone mapping.
14591  -toneMapping  Tone mapping mode (disabled, filmic).
14592
14593 PBR environment baking parameters (advanced/debug):
14594 vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]
14595               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]
14596  -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size).
14597  -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map.
14598  -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during
14599                  diffuse IBL map's sherical harmonics calculation.
14600  -pbrEnvBSSN     Controls maximum number of samples per mipmap level
14601                  in Monte-Carlo integration during specular IBL maps generation.
14602  -pbrEnvBP       Controls strength of samples number reducing
14603                  during specular IBL maps generation (1 disables reducing).
14604
14605 Debug options:
14606 vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]
14607  -issd         Shows screen sampling distribution in ISS mode.
14608  -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging).
14609  -brng         Enables/disables blocked RNG (fast coherent PT).
14610 )" /* [vrenderparams] */);
14611
14612   addCmd ("vstatprofiler", VStatProfiler, /* [vstatprofiler] */ R"(
14613 vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups
14614                 |allArrays|fillArrays|lineArrays|pointArrays|textArrays
14615                 |triangles|points|geomMem|textureMem|frameMem
14616                 |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage
14617                 |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]
14618               [-noredraw]
14619 Prints rendering statistics for specified counters or for all when unspecified.
14620 Set '-noredraw' flag to avoid additional redraw call and use already collected values.
14621 )" /* [vstatprofiler] */);
14622
14623   addCmd ("vplace", VPlace, /* [vplace] */ R"(
14624 vplace dx dy : Places the point (in pixels) at the center of the window
14625 )" /* [vplace] */);
14626
14627   addCmd ("vxrotate", VXRotate, /* [vxrotate] */ R"(
14628 vxrotate
14629 )" /* [vxrotate] */);
14630
14631   addCmd ("vmanipulator", VManipulator, /* [vmanipulator] */ R"(
14632 vmanipulator Name [-attach AISObject | -detach | ...]
14633 Tool to create and manage AIS manipulators.
14634 Options:
14635  '-attach AISObject'                 attach manipulator to AISObject
14636  '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching
14637  '-adjustSize     {0|1}'             adjust size when attaching
14638  '-enableModes    {0|1}'             enable modes when attaching
14639  '-view  {active | [name of view]}'  display manipulator only in defined view,
14640                                      by default it is displayed in all views of the current viewer
14641  '-detach'                           detach manipulator
14642  '-startTransform mouse_x mouse_y' - invoke start of transformation
14643  '-transform      mouse_x mouse_y' - invoke transformation
14644  '-stopTransform  [abort]'         - invoke stop of transformation
14645  '-move x y z'                     - move attached object
14646  '-rotate x y z dx dy dz angle'    - rotate attached object
14647  '-scale factor'                   - scale attached object
14648  '-autoActivate      {0|1}'        - set activation on detection
14649  '-followTranslation {0|1}'        - set following translation transform
14650  '-followRotation    {0|1}'        - set following rotation transform
14651  '-followDragging    {0|1}'        - set following dragging transform
14652  '-gap value'                      - set gap between sub-parts
14653  '-part axis mode    {0|1}'        - set visual part
14654  '-parts axis mode   {0|1}'        - set visual part
14655  '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator
14656  '-size value'                     - set size of manipulator
14657  '-zoomable {0|1}'                 - set zoom persistence
14658 )" /* [vmanipulator] */);
14659
14660   addCmd ("vselprops", VSelectionProperties, /* [vselprops] */ R"(
14661 vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]
14662 Customizes selection and dynamic highlight parameters for the whole interactive context:
14663  -autoActivate {0|1}     disables|enables default computation
14664                          and activation of global selection mode
14665  -autoHighlight {0|1}    disables|enables automatic highlighting in 3D Viewer
14666  -highlightSelected {0|1} disables|enables highlighting of detected object in selected state
14667  -pickStrategy {first|topmost} : defines picking strategy
14668                'first'   to pick first acceptable (default)
14669                'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)
14670  -pixTol    value        sets up pixel tolerance
14671  -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth
14672  -depthTol {sensfactor}  use sensitive factor for sorting results by depth
14673  -preferClosest {0|1}    sets if depth should take precedence over priority while sorting results
14674  -dispMode  dispMode     sets display mode for highlighting
14675  -layer     ZLayer       sets ZLayer for highlighting
14676  -color     {name|r g b} sets highlight color
14677  -transp    value        sets transparency coefficient for highlight
14678  -material  material     sets highlight material
14679  -print                  prints current state of all mentioned parameters
14680 )" /* [vselprops] */);
14681
14682   addCmd ("vhighlightselected", VSelectionProperties, /* [vhighlightselected] */ R"(
14683 vhighlightselected [0|1] : alias for vselprops -highlightSelected.
14684 )" /* [vhighlightselected] */);
14685
14686   addCmd ("vseldump", VDumpSelectionImage, /* [vseldump] */ R"(
14687 vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|entityType|surfNormal}=depth
14688          -pickedIndex Index=1
14689          [-xrPose base|head=base]
14690 Generate an image based on detection results:
14691   depth       normalized depth values
14692   unnormDepth unnormalized depth values
14693   object      color of detected object
14694   owner       color of detected owner
14695   selMode     color of selection mode
14696   entity      color of detected entity
14697   entityType  color of detected entity type
14698   surfNormal  normal direction values
14699 )" /* [vseldump] */);
14700
14701   addCmd ("vviewcube", VViewCube, /* [vviewcube] */ R"(
14702 vviewcube name
14703 Displays interactive view manipulation object. Options:
14704  -reset                   reset geometric and visual attributes
14705  -size Size               adapted size of View Cube
14706  -boxSize Size            box size
14707  -axes  {0|1}             show/hide axes (trihedron)
14708  -edges {0|1}             show/hide edges of View Cube
14709  -vertices {0|1}          show/hide vertices of View Cube
14710  -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation
14711  -color Color             color of View Cube
14712  -boxColor Color          box color
14713  -boxSideColor Color      box sides color
14714  -boxEdgeColor Color      box edges color
14715  -boxCornerColor Color    box corner color
14716  -textColor Color         color of side text of view cube
14717  -innerColor Color        inner box color
14718  -transparency Value      transparency of object within [0, 1] range
14719  -boxTransparency Value   transparency of box    within [0, 1] range
14720  -xAxisTextColor Color    color of X axis label
14721  -yAxisTextColor Color    color of Y axis label
14722  -zAxisTextColor Color    color of Z axis label
14723  -font Name               font name
14724  -fontHeight Value        font height
14725  -boxFacetExtension Value box facet extension
14726  -boxEdgeGap Value        gap between box edges and box sides
14727  -boxEdgeMinSize Value    minimal box edge size
14728  -boxCornerMinSize Value  minimal box corner size
14729  -axesPadding Value       padding between box and arrows
14730  -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range
14731  -axesRadius Value        radius of axes of the trihedron
14732  -axesConeRadius Value    radius of the cone (arrow) of the trihedron
14733  -axesSphereRadius Value  radius of the sphere (central point) of trihedron
14734  -fixedAnimation {0|1}    uninterruptible animation loop
14735  -duration Seconds        animation duration in seconds
14736 )" /* [vviewcube] */);
14737
14738   addCmd ("vcolorconvert", VColorConvert, /* [vcolorconvert] */ R"(
14739 vcolorconvert {from|to} type C1 C2 C2
14740 vcolorconvert from type C1 C2 C2 : Converts color from specified color space to linear RGB
14741 vcolorconvert to   type R  G  B  : Converts linear RGB color to specified color space
14742 Type can be sRGB, HLS, Lab, or Lch.
14743 )" /* [vcolorconvert] */);
14744
14745   addCmd ("vcolordiff", VColorDiff, /* [vcolordiff] */ R"(
14746 vcolordiff R1 G1 B1 R2 G2 B2 : returns CIEDE2000 color difference between two RGB colors.
14747 )" /* [vcolordiff] */);
14748
14749   addCmd ("vselbvhbuild", VSelBvhBuild, /* [vselbvhbuild] */ R"(
14750 vselbvhbuild [{0|1}] [-nbThreads value] [-wait]
14751 Turns on/off prebuilding of BVH within background thread(s).
14752  -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1);
14753  -wait        waits for building all of BVH.
14754 )" /* [vselbvhbuild] */);
14755 }