0032694: Documentation, Draw Harness Guide - update ViewerTest commands
[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;
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 (!ViewerTest::CurrentView().IsNull()
1043           &&  aCopyFrom.IsNull()
1044           && (anArgCase == "-copy"
1045            || anArgCase == "-clone"
1046            || anArgCase == "-cloneactive"
1047            || anArgCase == "-cloneactiveview"))
1048     {
1049       aCopyFrom = ViewerTest::CurrentView();
1050     }
1051     // old syntax
1052     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
1053     {
1054       aName.LowerCase();
1055       if (aName == "name")
1056       {
1057         aViewName = aValue;
1058       }
1059       else if (aName == "l"
1060             || aName == "left")
1061       {
1062         aPxLeft = aValue.IntegerValue();
1063       }
1064       else if (aName == "t"
1065             || aName == "top")
1066       {
1067         aPxTop = aValue.IntegerValue();
1068       }
1069       else if (aName == "disp"
1070             || aName == "display")
1071       {
1072         aDisplayName = aValue;
1073       }
1074       else if (aName == "w"
1075             || aName == "width")
1076       {
1077         aPxWidth = aValue.IntegerValue();
1078       }
1079       else if (aName == "h"
1080             || aName == "height")
1081       {
1082         aPxHeight = aValue.IntegerValue();
1083       }
1084       else
1085       {
1086         Message::SendFail() << "Syntax error: unknown argument " << anArg;
1087         return 1;
1088       }
1089     }
1090     else if (aViewName.IsEmpty())
1091     {
1092       aViewName = anArg;
1093     }
1094     else
1095     {
1096       Message::SendFail() << "Syntax error: unknown argument " << anArg;
1097       return 1;
1098     }
1099   }
1100
1101 #if !defined(HAVE_XLIB)
1102   if (!aDisplayName.IsEmpty())
1103   {
1104     aDisplayName.Clear();
1105     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
1106   }
1107 #endif
1108
1109   ViewerTest_Names aViewNames (aViewName);
1110   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1111   {
1112     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
1113     theDi.Eval (aCommand.ToCString());
1114     if (is2dMode != -1)
1115     {
1116       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1117     }
1118     return 0;
1119   }
1120
1121   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
1122                                                             aViewName, aDisplayName, aCopyFrom, isVirtual);
1123   if (is2dMode != -1)
1124   {
1125     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1126   }
1127   theDi << aViewId;
1128   return 0;
1129 }
1130
1131 //! Parse HLR algo type.
1132 static Standard_Boolean parseHlrAlgoType (const char* theName,
1133                                           Prs3d_TypeOfHLR& theType)
1134 {
1135   TCollection_AsciiString aName (theName);
1136   aName.LowerCase();
1137   if (aName == "polyalgo")
1138   {
1139     theType = Prs3d_TOH_PolyAlgo;
1140   }
1141   else if (aName == "algo")
1142   {
1143     theType = Prs3d_TOH_Algo;
1144   }
1145   else
1146   {
1147     return Standard_False;
1148   }
1149   return Standard_True;
1150 }
1151
1152 //==============================================================================
1153 //function : VHLR
1154 //purpose  : hidden lines removal algorithm
1155 //==============================================================================
1156
1157 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
1158 {
1159   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1160   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1161   if (aView.IsNull())
1162   {
1163     Message::SendFail ("Error: no active viewer");
1164     return 1;
1165   }
1166
1167   Standard_Boolean hasHlrOnArg = Standard_False;
1168   Standard_Boolean hasShowHiddenArg = Standard_False;
1169   Standard_Boolean isHLROn = Standard_False;
1170   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
1171   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
1172   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1173   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1174   {
1175     TCollection_AsciiString anArg (argv[anArgIter]);
1176     anArg.LowerCase();
1177     if (anUpdateTool.parseRedrawMode (anArg))
1178     {
1179       continue;
1180     }
1181     else if (anArg == "-showhidden"
1182           && anArgIter + 1 < argc
1183           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
1184     {
1185       ++anArgIter;
1186       hasShowHiddenArg = Standard_True;
1187       continue;
1188     }
1189     else if ((anArg == "-type"
1190            || anArg == "-algo"
1191            || anArg == "-algotype")
1192           && anArgIter + 1 < argc
1193           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1194     {
1195       ++anArgIter;
1196       continue;
1197     }
1198     else if (!hasHlrOnArg
1199           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
1200     {
1201       hasHlrOnArg = Standard_True;
1202       continue;
1203     }
1204     // old syntax
1205     else if (!hasShowHiddenArg
1206           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
1207     {
1208       hasShowHiddenArg = Standard_True;
1209       continue;
1210     }
1211     else
1212     {
1213       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
1214       return 1;
1215     }
1216   }
1217   if (!hasHlrOnArg)
1218   {
1219     di << "HLR:        " << aView->ComputedMode() << "\n";
1220     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
1221     di << "HlrAlgo:    ";
1222     switch (aCtx->DefaultDrawer()->TypeOfHLR())
1223     {
1224       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
1225       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
1226       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
1227     }
1228     anUpdateTool.Invalidate();
1229     return 0;
1230   }
1231
1232   Standard_Boolean toRecompute = Standard_False;
1233   if (aTypeOfHLR != Prs3d_TOH_NotSet
1234    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
1235   {
1236     toRecompute = Standard_True;
1237     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1238   }
1239   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
1240   {
1241     toRecompute = Standard_True;
1242     if (toShowHidden)
1243     {
1244       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
1245     }
1246     else
1247     {
1248       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
1249     }
1250   }
1251
1252   // redisplay shapes
1253   if (aView->ComputedMode() && isHLROn && toRecompute)
1254   {
1255     AIS_ListOfInteractive aListOfShapes;
1256     aCtx->DisplayedObjects (aListOfShapes);
1257     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
1258     {
1259       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
1260       {
1261         aCtx->Redisplay (aShape, Standard_False);
1262       }
1263     }
1264   }
1265
1266   aView->SetComputedMode (isHLROn);
1267   return 0;
1268 }
1269
1270 //==============================================================================
1271 //function : VHLRType
1272 //purpose  : change type of using HLR algorithm
1273 //==============================================================================
1274
1275 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
1276 {
1277   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1278   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1279   if (aView.IsNull())
1280   {
1281     Message::SendFail ("Error: no active viewer");
1282     return 1;
1283   }
1284
1285   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
1286   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1287   AIS_ListOfInteractive aListOfShapes;
1288   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1289   {
1290     TCollection_AsciiString anArg (argv[anArgIter]);
1291     anArg.LowerCase();
1292     if (anUpdateTool.parseRedrawMode (anArg))
1293     {
1294       continue;
1295     }
1296     else if ((anArg == "-type"
1297            || anArg == "-algo"
1298            || anArg == "-algotype")
1299           && anArgIter + 1 < argc
1300           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1301     {
1302       ++anArgIter;
1303       continue;
1304     }
1305     // old syntax
1306     else if (aTypeOfHLR == Prs3d_TOH_NotSet
1307           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
1308     {
1309       continue;
1310     }
1311     else
1312     {
1313       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
1314       TCollection_AsciiString aName (argv[anArgIter]);
1315       if (!aMap.IsBound2 (aName))
1316       {
1317         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
1318         return 1;
1319       }
1320
1321       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
1322       if (aShape.IsNull())
1323       {
1324         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
1325         return 1;
1326       }
1327       aListOfShapes.Append (aShape);
1328       continue;
1329     }
1330   }
1331   if (aTypeOfHLR == Prs3d_TOH_NotSet)
1332   {
1333     Message::SendFail ("Syntax error: wrong number of arguments");
1334     return 1;
1335   }
1336
1337   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
1338   if (isGlobal)
1339   {
1340     aCtx->DisplayedObjects (aListOfShapes);
1341     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1342   }
1343
1344   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
1345   {
1346     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
1347     if (aShape.IsNull())
1348     {
1349       continue;
1350     }
1351
1352     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
1353                             && aView->ComputedMode();
1354     if (!isGlobal
1355      || aShape->TypeOfHLR() != aTypeOfHLR)
1356     {
1357       aShape->SetTypeOfHLR (aTypeOfHLR);
1358     }
1359     if (toUpdateShape)
1360     {
1361       aCtx->Redisplay (aShape, Standard_False);
1362     }
1363   }
1364   return 0;
1365 }
1366
1367 //==============================================================================
1368 //function : FindViewIdByWindowHandle
1369 //purpose  : Find theView Id in the map of views by window handle
1370 //==============================================================================
1371 #if defined(_WIN32) || defined(HAVE_XLIB)
1372 static TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
1373 {
1374   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
1375        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1376   {
1377     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
1378     if (aWindowHandle == theWindowHandle)
1379       return anIter.Key1();
1380   }
1381   return TCollection_AsciiString("");
1382 }
1383 #endif
1384
1385 //! Make the view active
1386 void ActivateView (const TCollection_AsciiString& theViewName,
1387                    Standard_Boolean theToUpdate = Standard_True)
1388 {
1389   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1390   if (aView.IsNull())
1391   {
1392     return;
1393   }
1394
1395   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
1396   if (!anAISContext.IsNull())
1397   {
1398     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1399     {
1400       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1401     }
1402
1403     ViewerTest::CurrentView (aView);
1404     ViewerTest::SetAISContext (anAISContext);
1405     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
1406     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(ViewerTest::CurrentView()->Window());
1407     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
1408     if (theToUpdate)
1409     {
1410       ViewerTest::CurrentView()->Redraw();
1411     }
1412   }
1413 }
1414
1415 //==============================================================================
1416 //function : RemoveView
1417 //purpose  :
1418 //==============================================================================
1419 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
1420                              const Standard_Boolean  theToRemoveContext)
1421 {
1422   if (!ViewerTest_myViews.IsBound2 (theView))
1423   {
1424     return;
1425   }
1426
1427   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
1428   RemoveView (aViewName, theToRemoveContext);
1429 }
1430
1431 //==============================================================================
1432 //function : RemoveView
1433 //purpose  : Close and remove view from display, clear maps if necessary
1434 //==============================================================================
1435 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
1436 {
1437   if (!ViewerTest_myViews.IsBound1(theViewName))
1438   {
1439     Message::SendFail() << "Wrong view name";
1440     return;
1441   }
1442
1443   // Activate another view if it's active now
1444   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
1445   {
1446     if (ViewerTest_myViews.Extent() > 1)
1447     {
1448       TCollection_AsciiString aNewViewName;
1449       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1450            anIter.More(); anIter.Next())
1451       {
1452         if (anIter.Key1() != theViewName)
1453         {
1454           aNewViewName = anIter.Key1();
1455           break;
1456         }
1457       }
1458       ActivateView (aNewViewName);
1459     }
1460     else
1461     {
1462       VT_GetWindow().Nullify();
1463       ViewerTest::CurrentView (Handle(V3d_View)());
1464       if (isContextRemoved)
1465       {
1466         Handle(AIS_InteractiveContext) anEmptyContext;
1467         ViewerTest::SetAISContext(anEmptyContext);
1468       }
1469     }
1470   }
1471
1472   // Delete view
1473   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1474   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
1475   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
1476   aRedrawer.Stop (aView);
1477
1478   // Remove view resources
1479   ViewerTest_myViews.UnBind1(theViewName);
1480   aView->Window()->Unmap();
1481   aView->Remove();
1482
1483 #if defined(HAVE_XLIB)
1484   XFlush ((::Display* )GetDisplayConnection()->GetDisplayAspect());
1485 #endif
1486
1487   // Keep context opened only if the closed view is last to avoid
1488   // unused empty contexts
1489   if (!aCurrentContext.IsNull())
1490   {
1491     // Check if there are more defined views in the viewer
1492     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
1493      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
1494     {
1495       // Remove driver if there is no viewers that use it
1496       Standard_Boolean isRemoveDriver = Standard_True;
1497       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1498           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
1499       {
1500         if (aCurrentContext != anIter.Key2() &&
1501           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
1502         {
1503           isRemoveDriver = Standard_False;
1504           break;
1505         }
1506       }
1507
1508       aCurrentContext->RemoveAll (Standard_False);
1509       if(isRemoveDriver)
1510       {
1511         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
1512       #if defined(HAVE_XLIB)
1513         Tcl_DeleteFileHandler (XConnectionNumber ((::Display* )aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplayAspect()));
1514       #endif
1515       }
1516
1517       ViewerTest_myContexts.UnBind2(aCurrentContext);
1518     }
1519   }
1520   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
1521   if (ViewerTest_EventManager::ToExitOnCloseView())
1522   {
1523     Draw_Interprete ("exit");
1524   }
1525 }
1526
1527 //==============================================================================
1528 //function : VClose
1529 //purpose  : Remove the view defined by its name
1530 //==============================================================================
1531
1532 static int VClose (Draw_Interpretor& /*theDi*/,
1533                    Standard_Integer  theArgsNb,
1534                    const char**      theArgVec)
1535 {
1536   NCollection_List<TCollection_AsciiString> aViewList;
1537   if (theArgsNb > 1)
1538   {
1539     TCollection_AsciiString anArg (theArgVec[1]);
1540     anArg.UpperCase();
1541     if (anArg.IsEqual ("ALL")
1542      || anArg.IsEqual ("*"))
1543     {
1544       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1545            anIter.More(); anIter.Next())
1546       {
1547         aViewList.Append (anIter.Key1());
1548       }
1549       if (aViewList.IsEmpty())
1550       {
1551         std::cout << "No view to close\n";
1552         return 0;
1553       }
1554     }
1555     else
1556     {
1557       ViewerTest_Names aViewName (theArgVec[1]);
1558       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
1559       {
1560         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
1561         return 1;
1562       }
1563       aViewList.Append (aViewName.GetViewName());
1564     }
1565   }
1566   else
1567   {
1568     // close active view
1569     if (ViewerTest::CurrentView().IsNull())
1570     {
1571       Message::SendFail ("Error: no active view");
1572       return 1;
1573     }
1574     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1575   }
1576
1577   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
1578   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
1579        anIter.More(); anIter.Next())
1580   {
1581     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
1582   }
1583
1584   return 0;
1585 }
1586
1587 //==============================================================================
1588 //function : VActivate
1589 //purpose  : Activate the view defined by its ID
1590 //==============================================================================
1591
1592 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1593 {
1594   if (theArgsNb == 1)
1595   {
1596     theDi.Eval("vviewlist");
1597     return 0;
1598   }
1599
1600   TCollection_AsciiString aNameString;
1601   Standard_Boolean toUpdate = Standard_True;
1602   Standard_Boolean toActivate = Standard_True;
1603   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
1604   {
1605     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1606     anArg.LowerCase();
1607     if (toUpdate
1608      && anArg == "-noupdate")
1609     {
1610       toUpdate = Standard_False;
1611     }
1612     else if (toActivate
1613           && aNameString.IsEmpty()
1614           && anArg == "none")
1615     {
1616       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1617       VT_GetWindow().Nullify();
1618       ViewerTest::CurrentView (Handle(V3d_View)());
1619       ViewerTest::ResetEventManager();
1620       theDi << theArgVec[0] << ": all views are inactive\n";
1621       toActivate = Standard_False;
1622     }
1623     else if (toActivate
1624           && aNameString.IsEmpty())
1625     {
1626       aNameString = theArgVec[anArgIter];
1627     }
1628     else
1629     {
1630       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
1631       return 1;
1632     }
1633   }
1634
1635   if (!toActivate)
1636   {
1637     return 0;
1638   }
1639   else if (aNameString.IsEmpty())
1640   {
1641     Message::SendFail ("Syntax error: wrong number of arguments");
1642     return 1;
1643   }
1644
1645   // Check if this view exists in the viewer with the driver
1646   ViewerTest_Names aViewNames (aNameString);
1647   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
1648   {
1649     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
1650     return 1;
1651   }
1652
1653   // Check if it is active already
1654   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
1655   {
1656     theDi << theArgVec[0] << ": the view is active already\n";
1657     return 0;
1658   }
1659
1660   ActivateView (aViewNames.GetViewName(), toUpdate);
1661   return 0;
1662 }
1663
1664 //==============================================================================
1665 //function : VViewList
1666 //purpose  : Print current list of views per viewer and graphic driver ID
1667 //           shared between viewers
1668 //==============================================================================
1669
1670 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1671 {
1672   if (theArgsNb > 2)
1673   {
1674     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
1675           << "Usage: " << theArgVec[0] << " name";
1676     return 1;
1677   }
1678   if (ViewerTest_myContexts.Size() < 1)
1679     return 0;
1680
1681   Standard_Boolean isTreeView =
1682     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
1683
1684   if (isTreeView)
1685   {
1686     theDi << theArgVec[0] <<":\n";
1687   }
1688
1689   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
1690        aDriverIter.More(); aDriverIter.Next())
1691   {
1692     if (isTreeView)
1693       theDi << aDriverIter.Key1() << ":\n";
1694
1695     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1696       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
1697     {
1698       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
1699       {
1700         if (isTreeView)
1701         {
1702           TCollection_AsciiString aContextName(aContextIter.Key1());
1703           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
1704         }
1705
1706         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
1707              aViewIter.More(); aViewIter.Next())
1708         {
1709           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
1710           {
1711             TCollection_AsciiString aViewName(aViewIter.Key1());
1712             if (isTreeView)
1713             {
1714               if (aViewIter.Value() == ViewerTest::CurrentView())
1715                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
1716               else
1717                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
1718             }
1719             else
1720             {
1721               theDi << aViewName << " ";
1722             }
1723           }
1724         }
1725       }
1726     }
1727   }
1728   return 0;
1729 }
1730
1731 //==============================================================================
1732 //function : GetMousePosition
1733 //purpose  :
1734 //==============================================================================
1735 void ViewerTest::GetMousePosition (Standard_Integer& theX,
1736                                    Standard_Integer& theY)
1737 {
1738   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
1739   {
1740     theX = aViewCtrl->LastMousePosition().x();
1741     theY = aViewCtrl->LastMousePosition().y();
1742   }
1743 }
1744
1745 //==============================================================================
1746 //function : VViewProj
1747 //purpose  : Switch view projection
1748 //==============================================================================
1749 static int VViewProj (Draw_Interpretor& ,
1750                       Standard_Integer theNbArgs,
1751                       const char** theArgVec)
1752 {
1753   static Standard_Boolean isYup = Standard_False;
1754   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
1755   if (aView.IsNull())
1756   {
1757     Message::SendFail ("Error: no active viewer");
1758     return 1;
1759   }
1760
1761   TCollection_AsciiString aCmdName (theArgVec[0]);
1762   Standard_Boolean isGeneralCmd = Standard_False;
1763   if (aCmdName == "vfront")
1764   {
1765     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1766   }
1767   else if (aCmdName == "vback")
1768   {
1769     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1770   }
1771   else if (aCmdName == "vtop")
1772   {
1773     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1774   }
1775   else if (aCmdName == "vbottom")
1776   {
1777     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1778   }
1779   else if (aCmdName == "vleft")
1780   {
1781     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1782   }
1783   else if (aCmdName == "vright")
1784   {
1785     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1786   }
1787   else if (aCmdName == "vaxo")
1788   {
1789     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1790   }
1791   else
1792   {
1793     isGeneralCmd = Standard_True;
1794     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
1795     {
1796       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
1797       anArgCase.LowerCase();
1798       if (anArgCase == "-zup")
1799       {
1800         isYup = Standard_False;
1801       }
1802       else if (anArgCase == "-yup")
1803       {
1804         isYup = Standard_True;
1805       }
1806       else if (anArgCase == "-front"
1807             || anArgCase == "front"
1808             || anArgCase == "-f"
1809             || anArgCase == "f")
1810       {
1811         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
1812       }
1813       else if (anArgCase == "-back"
1814             || anArgCase == "back"
1815             || anArgCase == "-b"
1816             || anArgCase == "b")
1817       {
1818         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
1819       }
1820       else if (anArgCase == "-top"
1821             || anArgCase == "top"
1822             || anArgCase == "-t"
1823             || anArgCase == "t")
1824       {
1825         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
1826       }
1827       else if (anArgCase == "-bottom"
1828             || anArgCase == "bottom"
1829             || anArgCase == "-bot"
1830             || anArgCase == "bot"
1831             || anArgCase == "-b"
1832             || anArgCase == "b")
1833       {
1834         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
1835       }
1836       else if (anArgCase == "-left"
1837             || anArgCase == "left"
1838             || anArgCase == "-l"
1839             || anArgCase == "l")
1840       {
1841         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
1842       }
1843       else if (anArgCase == "-right"
1844             || anArgCase == "right"
1845             || anArgCase == "-r"
1846             || anArgCase == "r")
1847       {
1848         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
1849       }
1850       else if (anArgCase == "-axoleft"
1851             || anArgCase == "-leftaxo"
1852             || anArgCase == "axoleft"
1853             || anArgCase == "leftaxo")
1854       {
1855         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
1856       }
1857       else if (anArgCase == "-axo"
1858             || anArgCase == "axo"
1859             || anArgCase == "-a"
1860             || anArgCase == "a"
1861             || anArgCase == "-axoright"
1862             || anArgCase == "-rightaxo"
1863             || anArgCase == "axoright"
1864             || anArgCase == "rightaxo")
1865       {
1866         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
1867       }
1868       else if (anArgCase == "+x")
1869       {
1870         aView->SetProj (V3d_Xpos, isYup);
1871       }
1872       else if (anArgCase == "-x")
1873       {
1874         aView->SetProj (V3d_Xneg, isYup);
1875       }
1876       else if (anArgCase == "+y")
1877       {
1878         aView->SetProj (V3d_Ypos, isYup);
1879       }
1880       else if (anArgCase == "-y")
1881       {
1882         aView->SetProj (V3d_Yneg, isYup);
1883       }
1884       else if (anArgCase == "+z")
1885       {
1886         aView->SetProj (V3d_Zpos, isYup);
1887       }
1888       else if (anArgCase == "-z")
1889       {
1890         aView->SetProj (V3d_Zneg, isYup);
1891       }
1892       else if (anArgCase == "+x+y+z")
1893       {
1894         aView->SetProj (V3d_XposYposZpos, isYup);
1895       }
1896       else if (anArgCase == "+x+y-z")
1897       {
1898         aView->SetProj (V3d_XposYposZneg, isYup);
1899       }
1900       else if (anArgCase == "+x-y+z")
1901       {
1902         aView->SetProj (V3d_XposYnegZpos, isYup);
1903       }
1904       else if (anArgCase == "+x-y-z")
1905       {
1906         aView->SetProj (V3d_XposYnegZneg, isYup);
1907       }
1908       else if (anArgCase == "-x+y+z")
1909       {
1910         aView->SetProj (V3d_XnegYposZpos, isYup);
1911       }
1912       else if (anArgCase == "-x+y-z")
1913       {
1914         aView->SetProj (V3d_XnegYposZneg, isYup);
1915       }
1916       else if (anArgCase == "-x-y+z")
1917       {
1918         aView->SetProj (V3d_XnegYnegZpos, isYup);
1919       }
1920       else if (anArgCase == "-x-y-z")
1921       {
1922         aView->SetProj (V3d_XnegYnegZneg, isYup);
1923       }
1924       else if (anArgCase == "+x+y")
1925       {
1926         aView->SetProj (V3d_XposYpos, isYup);
1927       }
1928       else if (anArgCase == "+x-y")
1929       {
1930         aView->SetProj (V3d_XposYneg, isYup);
1931       }
1932       else if (anArgCase == "-x+y")
1933       {
1934         aView->SetProj (V3d_XnegYpos, isYup);
1935       }
1936       else if (anArgCase == "-x-y")
1937       {
1938         aView->SetProj (V3d_XnegYneg, isYup);
1939       }
1940       else if (anArgCase == "+x+z")
1941       {
1942         aView->SetProj (V3d_XposZpos, isYup);
1943       }
1944       else if (anArgCase == "+x-z")
1945       {
1946         aView->SetProj (V3d_XposZneg, isYup);
1947       }
1948       else if (anArgCase == "-x+z")
1949       {
1950         aView->SetProj (V3d_XnegZpos, isYup);
1951       }
1952       else if (anArgCase == "-x-z")
1953       {
1954         aView->SetProj (V3d_XnegZneg, isYup);
1955       }
1956       else if (anArgCase == "+y+z")
1957       {
1958         aView->SetProj (V3d_YposZpos, isYup);
1959       }
1960       else if (anArgCase == "+y-z")
1961       {
1962         aView->SetProj (V3d_YposZneg, isYup);
1963       }
1964       else if (anArgCase == "-y+z")
1965       {
1966         aView->SetProj (V3d_YnegZpos, isYup);
1967       }
1968       else if (anArgCase == "-y-z")
1969       {
1970         aView->SetProj (V3d_YnegZneg, isYup);
1971       }
1972       else if (anArgIter + 1 < theNbArgs
1973             && anArgCase == "-frame"
1974             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
1975       {
1976         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
1977         aFrameDef.LowerCase();
1978         gp_Dir aRight, anUp;
1979         if (aFrameDef.Value (2) == aFrameDef.Value (4))
1980         {
1981           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
1982           return 1;
1983         }
1984
1985         if (aFrameDef.Value (2) == 'x')
1986         {
1987           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
1988         }
1989         else if (aFrameDef.Value (2) == 'y')
1990         {
1991           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
1992         }
1993         else if (aFrameDef.Value (2) == 'z')
1994         {
1995           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
1996         }
1997         else
1998         {
1999           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2000           return 1;
2001         }
2002
2003         if (aFrameDef.Value (4) == 'x')
2004         {
2005           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2006         }
2007         else if (aFrameDef.Value (4) == 'y')
2008         {
2009           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2010         }
2011         else if (aFrameDef.Value (4) == 'z')
2012         {
2013           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2014         }
2015         else
2016         {
2017           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2018           return 1;
2019         }
2020
2021         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2022         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2023         const gp_Dir aDir = anUp.Crossed (aRight);
2024         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2025         aCamera->SetDirection (aDir);
2026         aCamera->SetUp (anUp);
2027         aCamera->OrthogonalizeUp();
2028
2029         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2030         aView->Update();
2031       }
2032       else
2033       {
2034         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2035         return 1;
2036       }
2037     }
2038   }
2039
2040   if (!isGeneralCmd
2041     && theNbArgs != 1)
2042   {
2043     Message::SendFail ("Syntax error: wrong number of arguments");
2044     return 1;
2045   }
2046   return 0;
2047 }
2048
2049 //==============================================================================
2050 //function : VHelp
2051 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
2052 //Draw arg : No args
2053 //==============================================================================
2054
2055 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
2056 {
2057   di << "=========================\n";
2058   di << "F : FitAll\n";
2059   di << "T : TopView\n";
2060   di << "B : BottomView\n";
2061   di << "R : RightView\n";
2062   di << "L : LeftView\n";
2063   di << "Backspace : AxonometricView\n";
2064
2065   di << "=========================\n";
2066   di << "W, S : Fly   forward/backward\n";
2067   di << "A, D : Slide left/right\n";
2068   di << "Q, E : Bank  left/right\n";
2069   di << "-, + : Change flying speed\n";
2070   di << "Arrows : look left/right/up/down\n";
2071   di << "Arrows+Shift : slide left/right/up/down\n";
2072
2073   di << "=========================\n";
2074   di << "S + Ctrl : Shading\n";
2075   di << "W + Ctrl : Wireframe\n";
2076   di << "H : HiddenLineRemoval\n";
2077   di << "U : Unset display mode\n";
2078   di << "Delete : Remove selection from viewer\n";
2079
2080   di << "=========================\n";
2081   di << "Selection mode \n";
2082   di << "0 : Shape\n";
2083   di << "1 : Vertex\n";
2084   di << "2 : Edge\n";
2085   di << "3 : Wire\n";
2086   di << "4 : Face\n";
2087   di << "5 : Shell\n";
2088   di << "6 : Solid\n";
2089   di << "7 : Compound\n";
2090
2091   di << "=========================\n";
2092   di << "< : Hilight next detected\n";
2093   di << "> : Hilight previous detected\n";
2094
2095   return 0;
2096 }
2097
2098 #ifdef _WIN32
2099
2100 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
2101                                            UINT theMsg,
2102                                            WPARAM wParam,
2103                                            LPARAM lParam )
2104 {
2105   if (ViewerTest_myViews.IsEmpty())
2106   {
2107     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2108   }
2109
2110   switch (theMsg)
2111   {
2112     case WM_CLOSE:
2113     {
2114       // Delete view from map of views
2115       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
2116       return 0;
2117     }
2118     case WM_ACTIVATE:
2119     {
2120       if (LOWORD(wParam) == WA_CLICKACTIVE
2121        || LOWORD(wParam) == WA_ACTIVE
2122        || ViewerTest::CurrentView().IsNull())
2123       {
2124         // Activate inactive window
2125         if (VT_GetWindow().IsNull()
2126          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
2127         {
2128           ActivateView (FindViewIdByWindowHandle (theWinHandle));
2129         }
2130       }
2131       return 0;
2132     }
2133     default:
2134     {
2135       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2136       if (!aView.IsNull()
2137        && !VT_GetWindow().IsNull())
2138       {
2139         MSG aMsg = {};
2140         aMsg.hwnd = theWinHandle;
2141         aMsg.message = theMsg;
2142         aMsg.wParam = wParam;
2143         aMsg.lParam = lParam;
2144         if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg))
2145         {
2146           return 0;
2147         }
2148       }
2149     }
2150   }
2151   return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
2152 }
2153
2154 //==============================================================================
2155 //function : ViewerMainLoop
2156 //purpose  : Get a Event on the view and dispatch it
2157 //==============================================================================
2158
2159 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2160 {
2161   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
2162   if (aViewCtrl.IsNull()
2163    || theNbArgs < 4)
2164   {
2165     return 0;
2166   }
2167
2168   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2169
2170   std::cout << "Start picking\n";
2171
2172   MSG aMsg;
2173   aMsg.wParam = 1;
2174   while (aViewCtrl->ToPickPoint())
2175   {
2176     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
2177     if (GetMessageW (&aMsg, NULL, 0, 0))
2178     {
2179       TranslateMessage (&aMsg);
2180       DispatchMessageW (&aMsg);
2181     }
2182   }
2183
2184   std::cout << "Picking done\n";
2185   return 0;
2186 }
2187
2188 #elif defined(HAVE_XLIB)
2189
2190 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
2191 {
2192   static XEvent aReport;
2193   const Standard_Boolean toPick = theNbArgs > 0;
2194   if (theNbArgs > 0)
2195   {
2196     if (ViewerTest::CurrentEventManager().IsNull())
2197     {
2198       return 0;
2199     }
2200     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
2201   }
2202
2203   Display* aDisplay = (Display* )GetDisplayConnection()->GetDisplayAspect();
2204   XNextEvent (aDisplay, &aReport);
2205
2206   // Handle event for the chosen display connection
2207   switch (aReport.type)
2208   {
2209     case ClientMessage:
2210     {
2211       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
2212       {
2213         // Close the window
2214         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
2215         return toPick ? 0 : 1;
2216       }
2217       break;
2218     }
2219     case FocusIn:
2220     {
2221       // Activate inactive view
2222       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
2223       if (aWindow != aReport.xfocus.window)
2224       {
2225         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
2226       }
2227       break;
2228     }
2229     default:
2230     {
2231       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2232       if (!aView.IsNull()
2233        && !VT_GetWindow().IsNull())
2234       {
2235         VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aReport);
2236       }
2237       break;
2238     }
2239   }
2240   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
2241 }
2242
2243 //==============================================================================
2244 //function : VProcessEvents
2245 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
2246 //==============================================================================
2247 static void VProcessEvents (ClientData theDispX, int)
2248 {
2249   Display* aDispX = (Display* )theDispX;
2250   Handle(Aspect_DisplayConnection) aDispConn;
2251   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
2252        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
2253   {
2254     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
2255     if ((Display* )aDispConnTmp->GetDisplayAspect() == aDispX)
2256     {
2257       aDispConn = aDispConnTmp;
2258       break;
2259     }
2260   }
2261   if (aDispConn.IsNull())
2262   {
2263     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
2264     return;
2265   }
2266
2267   // process new events in queue
2268   SetDisplayConnection (aDispConn);
2269   int aNbRemain = 0;
2270   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
2271   {
2272     const int anEventResult = ViewerMainLoop (0, NULL);
2273     if (anEventResult == 0)
2274     {
2275       return;
2276     }
2277
2278     aNbRemain = XPending (aDispX);
2279     if (++anEventIter >= aNbEventsMax
2280      || aNbRemain <= 0)
2281     {
2282       break;
2283     }
2284   }
2285
2286   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
2287   // it is possible that new events will arrive to queue before the end of this callback
2288   // so that either this callback should go into an infinite loop (blocking processing of other events)
2289   // or to keep unprocessed events till the next queue update (which can arrive not soon).
2290   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
2291   if (aNbRemain != 0)
2292   {
2293     XEvent aDummyEvent;
2294     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
2295     aDummyEvent.type = ClientMessage;
2296     aDummyEvent.xclient.format = 32;
2297     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
2298     XFlush (aDispX);
2299   }
2300
2301   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
2302   {
2303     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
2304   }
2305 }
2306 #elif !defined(__APPLE__)
2307 // =======================================================================
2308 // function : ViewerMainLoop
2309 // purpose  :
2310 // =======================================================================
2311 int ViewerMainLoop (Standard_Integer , const char** )
2312 {
2313   // unused
2314   return 0;
2315 }
2316 #endif
2317
2318 //==============================================================================
2319 //function : VFit
2320 //purpose  :
2321 //==============================================================================
2322
2323 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
2324 {
2325   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2326   if (aView.IsNull())
2327   {
2328     Message::SendFail ("Error: no active viewer");
2329     return 1;
2330   }
2331
2332   Standard_Boolean toFit = Standard_True;
2333   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2334   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2335   {
2336     TCollection_AsciiString anArg (theArgv[anArgIter]);
2337     anArg.LowerCase();
2338     if (anUpdateTool.parseRedrawMode (anArg))
2339     {
2340       continue;
2341     }
2342     else if (anArg == "-selected")
2343     {
2344       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
2345       toFit = Standard_False;
2346     }
2347     else
2348     {
2349       Message::SendFail() << "Syntax error at '" << anArg << "'";
2350     }
2351   }
2352
2353   if (toFit)
2354   {
2355     aView->FitAll (0.01, Standard_False);
2356   }
2357   return 0;
2358 }
2359
2360 //=======================================================================
2361 //function : VFitArea
2362 //purpose  : Fit view to show area located between two points
2363 //         : given in world 2D or 3D coordinates.
2364 //=======================================================================
2365 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
2366 {
2367   Handle(V3d_View) aView = ViewerTest::CurrentView();
2368   if (aView.IsNull())
2369   {
2370     Message::SendFail ("Error: No active viewer");
2371     return 1;
2372   }
2373
2374   // Parse arguments.
2375   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
2376   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
2377
2378   if (theArgNb == 5)
2379   {
2380     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2381     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2382     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
2383     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
2384   }
2385   else if (theArgNb == 7)
2386   {
2387     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
2388     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
2389     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
2390     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
2391     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
2392     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
2393   }
2394   else
2395   {
2396     Message::SendFail ("Syntax error: Invalid number of arguments");
2397     theDI.PrintHelp(theArgVec[0]);
2398     return 1;
2399   }
2400
2401   // Convert model coordinates to view space
2402   Handle(Graphic3d_Camera) aCamera = aView->Camera();
2403   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
2404   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
2405
2406   // Determine fit area
2407   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
2408   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
2409
2410   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
2411
2412   if (aDiagonal < Precision::Confusion())
2413   {
2414     Message::SendFail ("Error: view area is too small");
2415     return 1;
2416   }
2417
2418   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
2419   return 0;
2420 }
2421
2422 //==============================================================================
2423 //function : VZFit
2424 //purpose  : ZFitall, no DRAW arguments
2425 //Draw arg : No args
2426 //==============================================================================
2427 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
2428 {
2429   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
2430
2431   if (aCurrentView.IsNull())
2432   {
2433     Message::SendFail ("Error: no active viewer");
2434     return 1;
2435   }
2436
2437   if (theArgsNb == 1)
2438   {
2439     aCurrentView->ZFitAll();
2440     aCurrentView->Redraw();
2441     return 0;
2442   }
2443
2444   Standard_Real aScale = 1.0;
2445
2446   if (theArgsNb >= 2)
2447   {
2448     aScale = Draw::Atoi (theArgVec[1]);
2449   }
2450
2451   aCurrentView->ZFitAll (aScale);
2452   aCurrentView->Redraw();
2453
2454   return 0;
2455 }
2456
2457 //==============================================================================
2458 //function : VRepaint
2459 //purpose  :
2460 //==============================================================================
2461 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
2462 {
2463   Handle(V3d_View) aView = ViewerTest::CurrentView();
2464   if (aView.IsNull())
2465   {
2466     Message::SendFail ("Error: no active viewer");
2467     return 1;
2468   }
2469
2470   Standard_Boolean isImmediateUpdate = Standard_False;
2471   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
2472   {
2473     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2474     anArg.LowerCase();
2475     if (anArg == "-immediate"
2476      || anArg == "-imm")
2477     {
2478       isImmediateUpdate = Standard_True;
2479       if (anArgIter + 1 < theArgNb
2480        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
2481       {
2482         ++anArgIter;
2483       }
2484     }
2485     else if (anArg == "-continuous"
2486           || anArg == "-cont"
2487           || anArg == "-fps"
2488           || anArg == "-framerate")
2489     {
2490       Standard_Real aFps = -1.0;
2491       if (anArgIter + 1 < theArgNb
2492        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
2493       {
2494         aFps = Draw::Atof (theArgVec[++anArgIter]);
2495       }
2496
2497       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2498       ViewerTest::CurrentEventManager()->SetContinuousRedraw (false);
2499       if (aFps >= 1.0)
2500       {
2501         aRedrawer.Start (aView, aFps);
2502       }
2503       else if (aFps < 0.0)
2504       {
2505         if (ViewerTest::GetViewerFromContext()->ActiveViews().Extent() == 1)
2506         {
2507           aRedrawer.Stop();
2508           ViewerTest::CurrentEventManager()->SetContinuousRedraw (true);
2509           ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
2510           continue;
2511         }
2512         aRedrawer.Start (aView, aFps);
2513       }
2514       else
2515       {
2516         aRedrawer.Stop();
2517       }
2518     }
2519     else
2520     {
2521       Message::SendFail() << "Syntax error at '" << anArg << "'";
2522       return 1;
2523     }
2524   }
2525
2526   if (isImmediateUpdate)
2527   {
2528     aView->RedrawImmediate();
2529   }
2530   else
2531   {
2532     aView->Redraw();
2533   }
2534   return 0;
2535 }
2536
2537 //==============================================================================
2538 //function : VClear
2539 //purpose  : Remove all the object from the viewer
2540 //Draw arg : No args
2541 //==============================================================================
2542
2543 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
2544 {
2545   Handle(V3d_View) V = ViewerTest::CurrentView();
2546   if(!V.IsNull())
2547     ViewerTest::Clear();
2548   return 0;
2549 }
2550
2551 //==============================================================================
2552 //function : VPick
2553 //purpose  :
2554 //==============================================================================
2555
2556 static int VPick (Draw_Interpretor& ,
2557                   Standard_Integer theNbArgs,
2558                   const char** theArgVec)
2559 {
2560   if (ViewerTest::CurrentView().IsNull())
2561   {
2562     return 1;
2563   }
2564
2565   if (theNbArgs < 4)
2566   {
2567     Message::SendFail ("Syntax error: wrong number of arguments");
2568     return 1;
2569   }
2570
2571   while (ViewerMainLoop (theNbArgs, theArgVec))
2572   {
2573     //
2574   }
2575
2576   return 0;
2577 }
2578
2579 //! Parse image fill method.
2580 static bool parseImageMode (const TCollection_AsciiString& theName,
2581                             Aspect_FillMethod& theMode)
2582 {
2583   TCollection_AsciiString aName = theName;
2584   aName.LowerCase();
2585   if (aName == "none")
2586   {
2587     theMode = Aspect_FM_NONE;
2588   }
2589   else if (aName == "centered")
2590   {
2591     theMode = Aspect_FM_CENTERED;
2592   }
2593   else if (aName == "tiled")
2594   {
2595     theMode = Aspect_FM_TILED;
2596   }
2597   else if (aName == "stretch")
2598   {
2599     theMode = Aspect_FM_STRETCH;
2600   }
2601   else
2602   {
2603     return false;
2604   }
2605   return true;
2606 }
2607
2608 //! Parse gradient fill method.
2609 static bool parseGradientMode (const TCollection_AsciiString& theName,
2610                                Aspect_GradientFillMethod& theMode)
2611 {
2612   TCollection_AsciiString aName = theName;
2613   aName.LowerCase();
2614   if (aName == "none")
2615   {
2616     theMode = Aspect_GradientFillMethod_None;
2617   }
2618   else if (aName == "hor"
2619         || aName == "horizontal")
2620   {
2621     theMode = Aspect_GradientFillMethod_Horizontal;
2622   }
2623   else if (aName == "ver"
2624         || aName == "vert"
2625         || aName == "vertical")
2626   {
2627     theMode = Aspect_GradientFillMethod_Vertical;
2628   }
2629   else if (aName == "diag"
2630         || aName == "diagonal"
2631         || aName == "diag1"
2632         || aName == "diagonal1")
2633   {
2634     theMode = Aspect_GradientFillMethod_Diagonal1;
2635   }
2636   else if (aName == "diag2"
2637         || aName == "diagonal2")
2638   {
2639     theMode = Aspect_GradientFillMethod_Diagonal2;
2640   }
2641   else if (aName == "corner1")
2642   {
2643     theMode = Aspect_GradientFillMethod_Corner1;
2644   }
2645   else if (aName == "corner2")
2646   {
2647     theMode = Aspect_GradientFillMethod_Corner2;
2648   }
2649   else if (aName == "corner3")
2650   {
2651     theMode = Aspect_GradientFillMethod_Corner3;
2652   }
2653   else if (aName == "corner4")
2654   {
2655     theMode = Aspect_GradientFillMethod_Corner4;
2656   }
2657   else if (aName == "ellip"
2658         || aName == "elliptical")
2659   {
2660     theMode = Aspect_GradientFillMethod_Elliptical;
2661   }
2662   else
2663   {
2664     return false;
2665   }
2666   return true;
2667 }
2668
2669 //==============================================================================
2670 //function : VBackground
2671 //purpose  :
2672 //==============================================================================
2673 static int VBackground (Draw_Interpretor& theDI,
2674                         Standard_Integer  theNbArgs,
2675                         const char**      theArgVec)
2676 {
2677   if (theNbArgs < 2)
2678   {
2679     theDI << "Syntax error: wrong number of arguments";
2680     return 1;
2681   }
2682
2683   const TCollection_AsciiString aCmdName (theArgVec[0]);
2684   bool isDefault = aCmdName == "vsetdefaultbg";
2685   Standard_Integer aNbColors = 0;
2686   Quantity_ColorRGBA aColors[2];
2687
2688   Aspect_GradientFillMethod aGradientMode = Aspect_GradientFillMethod_None;
2689   bool hasGradientMode = false;
2690
2691   TCollection_AsciiString anImagePath;
2692   Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
2693   bool hasImageMode = false;
2694
2695   NCollection_Sequence<TCollection_AsciiString> aCubeMapSeq;
2696   Graphic3d_CubeMapOrder aCubeOrder = Graphic3d_CubeMapOrder::Default();
2697   bool isCubeZInverted = false;
2698   bool isSRgb = true;
2699
2700   int toUseIBL = 1;
2701
2702   Handle(V3d_View) aView = ViewerTest::CurrentView();
2703   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
2704   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2705   {
2706     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2707     anArg.LowerCase();
2708     if (anUpdateTool.parseRedrawMode (anArg))
2709     {
2710       continue;
2711     }
2712     else if (anArg == "-default"
2713           || anArg == "-def")
2714     {
2715       isDefault = true;
2716     }
2717     else if (anArgIter + 1 < theNbArgs
2718           && (anArg == "-imagefile"
2719            || anArg == "-imgfile"
2720            || anArg == "-image"
2721            || anArg == "-img"))
2722     {
2723       anImagePath = theArgVec[++anArgIter];
2724     }
2725     else if (anArgIter + 1 < theNbArgs
2726           && aCubeMapSeq.IsEmpty()
2727           && (anArg == "-cubemap"
2728            || anArg == "-cmap"
2729            || anArg == "-cm"))
2730     {
2731       aCubeMapSeq.Append (theArgVec[++anArgIter]);
2732       for (Standard_Integer aCubeSideIter = 1; anArgIter + aCubeSideIter < theNbArgs; ++aCubeSideIter)
2733       {
2734         TCollection_AsciiString aSideArg (theArgVec[anArgIter + aCubeSideIter]);
2735         if (!aSideArg.IsEmpty()
2736           && aSideArg.Value (1) == '-')
2737         {
2738           break;
2739         }
2740
2741         aCubeMapSeq.Append (aSideArg);
2742         if (aCubeMapSeq.Size() == 6)
2743         {
2744           anArgIter += 5;
2745           break;
2746         }
2747       }
2748
2749       if (aCubeMapSeq.Size() > 1
2750        && aCubeMapSeq.Size() < 6)
2751       {
2752         aCubeMapSeq.Remove (2, aCubeMapSeq.Size());
2753       }
2754     }
2755     else if (anArgIter + 6 < theNbArgs
2756           && anArg == "-order")
2757     {
2758       for (Standard_Integer aCubeSideIter = 0; aCubeSideIter < 6; ++aCubeSideIter)
2759       {
2760         Standard_Integer aSideArg = 0;
2761         if (!Draw::ParseInteger (theArgVec[anArgIter + aCubeSideIter + 1], aSideArg)
2762          || aSideArg < 0
2763          || aSideArg > 5)
2764         {
2765           theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2766           return 1;
2767         }
2768         aCubeOrder.Set ((Graphic3d_CubeMapSide )aCubeSideIter, (unsigned char )aSideArg);
2769       }
2770       if (!aCubeOrder.IsValid())
2771       {
2772         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2773         return 1;
2774       }
2775       anArgIter += 6;
2776     }
2777     else if (anArg == "-invertedz"
2778           || anArg == "-noinvertedz"
2779           || anArg == "-invz"
2780           || anArg == "-noinvz")
2781     {
2782       isCubeZInverted = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2783     }
2784     else if (anArg == "-pbrenv"
2785           || anArg == "-nopbrenv"
2786           || anArg == "-ibl"
2787           || anArg == "-noibl")
2788     {
2789       toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2790       if (anArgIter + 1 < theNbArgs)
2791       {
2792         TCollection_AsciiString anIblArg (theArgVec[anArgIter + 1]);
2793         anIblArg.LowerCase();
2794         if (anIblArg == "keep"
2795          || anIblArg == "-1")
2796         {
2797           toUseIBL = -1;
2798           ++anArgIter;
2799         }
2800         else if (anIblArg == "ibl"
2801               || anIblArg == "1"
2802               || anIblArg == "on")
2803         {
2804           toUseIBL = !anArg.StartsWith ("-no") ? 1 : 0;
2805           ++anArgIter;
2806         }
2807         else if (anIblArg == "noibl"
2808               || anIblArg == "0"
2809               || anIblArg == "off")
2810         {
2811           toUseIBL = !anArg.StartsWith ("-no") ? 0 : 1;
2812           ++anArgIter;
2813         }
2814       }
2815     }
2816     else if (anArg == "-srgb"
2817           || anArg == "-nosrgb")
2818     {
2819       isSRgb = Draw::ParseOnOffNoIterator (theNbArgs, theArgVec, anArgIter);
2820     }
2821     else if (aNbColors < 2
2822           && (anArg == "-color"
2823            || anArg == "-col"))
2824     {
2825       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - (anArgIter + 1),
2826                                                      theArgVec + (anArgIter + 1),
2827                                                      aColors[aNbColors].ChangeRGB());
2828       if (aNbParsed == 0)
2829       {
2830         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2831         return 1;
2832       }
2833       anArgIter += aNbParsed;
2834       ++aNbColors;
2835     }
2836     else if (anArgIter + 1 < theNbArgs
2837           && (anArg == "-gradientmode"
2838            || anArg == "-gradmode"
2839            || anArg == "-gradmd"
2840            || anArg == "-grmode"
2841            || anArg == "-grmd")
2842           && parseGradientMode (theArgVec[anArgIter + 1], aGradientMode))
2843     {
2844       ++anArgIter;
2845       hasGradientMode = true;
2846     }
2847     else if (anArgIter + 1 < theNbArgs
2848           && (anArg == "-imagemode"
2849            || anArg == "-imgmode"
2850            || anArg == "-imagemd"
2851            || anArg == "-imgmd")
2852           && parseImageMode (theArgVec[anArgIter + 1], anImageMode))
2853     {
2854       ++anArgIter;
2855       hasImageMode = true;
2856     }
2857     else if (aNbColors == 0
2858           && anArgIter + 2 < theNbArgs
2859           && (anArg == "-gradient"
2860            || anArg == "-grad"
2861            || anArg == "-gr"))
2862     {
2863       Standard_Integer aNbParsed1 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
2864                                                       theArgVec + (anArgIter + 1),
2865                                                       aColors[aNbColors].ChangeRGB());
2866       anArgIter += aNbParsed1;
2867       ++aNbColors;
2868       if (aNbParsed1 == 0)
2869       {
2870         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2871         return 1;
2872       }
2873       Standard_Integer aNbParsed2 = Draw::ParseColor (theNbArgs - (anArgIter + 1),
2874                                                       theArgVec + (anArgIter + 1),
2875                                                       aColors[aNbColors].ChangeRGB());
2876       anArgIter += aNbParsed2;
2877       ++aNbColors;
2878       if (aNbParsed2 == 0)
2879       {
2880         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2881         return 1;
2882       }
2883     }
2884     else if (parseGradientMode (theArgVec[anArgIter], aGradientMode))
2885     {
2886       hasGradientMode = true;
2887     }
2888     else if (aNbColors < 2
2889           && (Quantity_ColorRGBA::ColorFromName(theArgVec[anArgIter], aColors[aNbColors])
2890            || Quantity_ColorRGBA::ColorFromHex (theArgVec[anArgIter], aColors[aNbColors])))
2891     {
2892       ++aNbColors;
2893     }
2894     else if (anImagePath.IsEmpty()
2895          &&  aNbColors == 0
2896          && !hasGradientMode
2897          &&  aCubeMapSeq.IsEmpty())
2898     {
2899       anImagePath = theArgVec[anArgIter];
2900     }
2901     else
2902     {
2903       theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
2904       return 1;
2905     }
2906   }
2907
2908   if (!isDefault
2909    && aView.IsNull())
2910   {
2911     theDI << "Error: no active viewer";
2912     return 1;
2913   }
2914   else if (isDefault
2915        &&  aNbColors == 0
2916        && !hasGradientMode)
2917   {
2918     theDI << "Syntax error at '-default'";
2919     return 1;
2920   }
2921
2922   if (aNbColors == 1)
2923   {
2924     if (isDefault)
2925     {
2926       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
2927       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
2928       ViewerTest_DefaultBackground.FillMethod     = Aspect_GradientFillMethod_None;
2929       ViewerTest_DefaultBackground.FlatColor      = aColors[0].GetRGB();
2930       ViewerTest_DefaultBackground.SetDefaultGradient();
2931       ViewerTest_DefaultBackground.SetDefaultColor();
2932     }
2933     else
2934     {
2935       aView->SetBgGradientStyle (hasGradientMode ? aGradientMode : Aspect_GradientFillMethod_None);
2936       aView->SetBackgroundColor (aColors[0].GetRGB());
2937       if (toUseIBL != -1)
2938       {
2939         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
2940       }
2941     }
2942   }
2943   else if (aNbColors == 2)
2944   {
2945     if (isDefault)
2946     {
2947       ViewerTest_DefaultBackground.GradientColor1 = aColors[0].GetRGB();
2948       ViewerTest_DefaultBackground.GradientColor2 = aColors[1].GetRGB();
2949       if (hasGradientMode)
2950       {
2951         ViewerTest_DefaultBackground.FillMethod = aGradientMode;
2952       }
2953       else if (ViewerTest_DefaultBackground.FillMethod == Aspect_GradientFillMethod_None)
2954       {
2955         ViewerTest_DefaultBackground.FillMethod = Aspect_GradientFillMethod_Vertical;
2956       }
2957       ViewerTest_DefaultBackground.SetDefaultGradient();
2958     }
2959     else
2960     {
2961       if (!hasGradientMode)
2962       {
2963         aGradientMode = aView->GradientBackground().BgGradientFillMethod();
2964         if (aGradientMode == Aspect_GradientFillMethod_None)
2965         {
2966           aGradientMode = Aspect_GradientFillMethod_Vertical;
2967         }
2968       }
2969       aView->SetBgGradientColors (aColors[0].GetRGB(), aColors[1].GetRGB(), aGradientMode);
2970       if (toUseIBL != -1)
2971       {
2972         aView->SetBackgroundCubeMap (Handle(Graphic3d_CubeMap)(), true);
2973       }
2974     }
2975   }
2976   else if (hasGradientMode)
2977   {
2978     if (isDefault)
2979     {
2980       ViewerTest_DefaultBackground.FillMethod = aGradientMode;
2981       ViewerTest_DefaultBackground.SetDefaultGradient();
2982     }
2983     else
2984     {
2985       aView->SetBgGradientStyle (aGradientMode);
2986     }
2987   }
2988
2989   if (!anImagePath.IsEmpty())
2990   {
2991     Handle(Graphic3d_Texture2D) aTextureMap = new Graphic3d_Texture2Dmanual (anImagePath);
2992     aTextureMap->DisableModulate();
2993     aTextureMap->SetColorMap (isSRgb);
2994     if (!aTextureMap->IsDone())
2995     {
2996       theDI << "Syntax error at '" << anImagePath << "'";
2997       return 1;
2998     }
2999     aView->SetBackgroundImage (aTextureMap, anImageMode);
3000   }
3001   else if (hasImageMode)
3002   {
3003     aView->SetBgImageStyle (anImageMode);
3004   }
3005
3006   if (!aCubeMapSeq.IsEmpty())
3007   {
3008     Handle(Graphic3d_CubeMap) aCubeMap;
3009     if (aCubeMapSeq.Size() == 1)
3010     {
3011       aCubeMap = new Graphic3d_CubeMapPacked (aCubeMapSeq.First(), aCubeOrder.Validated());
3012     }
3013     else
3014     {
3015       NCollection_Array1<TCollection_AsciiString> aCubeMapArr (0, 5);
3016       Standard_Integer aCubeSide = 0;
3017       for (NCollection_Sequence<TCollection_AsciiString>::Iterator aFileIter (aCubeMapSeq); aFileIter.More(); aFileIter.Next(), ++aCubeSide)
3018       {
3019         aCubeMapArr[aCubeSide] = aFileIter.Value();
3020       }
3021       aCubeMap = new Graphic3d_CubeMapSeparate (aCubeMapArr);
3022     }
3023
3024     aCubeMap->SetZInversion (isCubeZInverted);
3025     aCubeMap->SetColorMap (isSRgb);
3026
3027     aCubeMap->GetParams()->SetFilter (Graphic3d_TOTF_BILINEAR);
3028     aCubeMap->GetParams()->SetRepeat (false);
3029     aCubeMap->GetParams()->SetTextureUnit (Graphic3d_TextureUnit_EnvMap);
3030
3031     aView->SetBackgroundCubeMap (aCubeMap, toUseIBL != -1);
3032   }
3033   if (toUseIBL != -1
3034   && !aView.IsNull())
3035   {
3036     aView->SetImageBasedLighting (toUseIBL == 1);
3037   }
3038
3039   return 0;
3040 }
3041
3042 //==============================================================================
3043 //function : VScale
3044 //purpose  : View Scaling
3045 //==============================================================================
3046
3047 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3048 {
3049   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3050   if ( V3dView.IsNull() ) return 1;
3051
3052   if ( argc != 4 ) {
3053     di << argv[0] << "Invalid number of arguments\n";
3054     return 1;
3055   }
3056   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3057   return 0;
3058 }
3059 //==============================================================================
3060 //function : VZBuffTrihedron
3061 //purpose  :
3062 //==============================================================================
3063
3064 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3065                             Standard_Integer  theArgNb,
3066                             const char**      theArgVec)
3067 {
3068   Handle(V3d_View) aView = ViewerTest::CurrentView();
3069   if (aView.IsNull())
3070   {
3071     Message::SendFail ("Error: no active viewer");
3072     return 1;
3073   }
3074
3075   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3076
3077   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3078   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3079   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
3080   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
3081   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
3082   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3083   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3084   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3085   Standard_Real                 aScale        = 0.1;
3086   Standard_Real                 aSizeRatio    = 0.8;
3087   Standard_Real                 anArrowDiam   = 0.05;
3088   Standard_Integer              aNbFacets     = 12;
3089   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3090   {
3091     Standard_CString        anArg = theArgVec[anArgIter];
3092     TCollection_AsciiString aFlag (anArg);
3093     aFlag.LowerCase();
3094     if (anUpdateTool.parseRedrawMode (aFlag))
3095     {
3096       continue;
3097     }
3098     else if (aFlag == "-on")
3099     {
3100       continue;
3101     }
3102     else if (aFlag == "-off")
3103     {
3104       aView->TriedronErase();
3105       return 0;
3106     }
3107     else if (aFlag == "-pos"
3108           || aFlag == "-position"
3109           || aFlag == "-corner")
3110     {
3111       if (++anArgIter >= theArgNb)
3112       {
3113         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3114         return 1;
3115       }
3116
3117       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
3118       aPosName.LowerCase();
3119       if (aPosName == "center")
3120       {
3121         aPosition = Aspect_TOTP_CENTER;
3122       }
3123       else if (aPosName == "left_lower"
3124             || aPosName == "lower_left"
3125             || aPosName == "leftlower"
3126             || aPosName == "lowerleft")
3127       {
3128         aPosition = Aspect_TOTP_LEFT_LOWER;
3129       }
3130       else if (aPosName == "left_upper"
3131             || aPosName == "upper_left"
3132             || aPosName == "leftupper"
3133             || aPosName == "upperleft")
3134       {
3135         aPosition = Aspect_TOTP_LEFT_UPPER;
3136       }
3137       else if (aPosName == "right_lower"
3138             || aPosName == "lower_right"
3139             || aPosName == "rightlower"
3140             || aPosName == "lowerright")
3141       {
3142         aPosition = Aspect_TOTP_RIGHT_LOWER;
3143       }
3144       else if (aPosName == "right_upper"
3145             || aPosName == "upper_right"
3146             || aPosName == "rightupper"
3147             || aPosName == "upperright")
3148       {
3149         aPosition = Aspect_TOTP_RIGHT_UPPER;
3150       }
3151       else
3152       {
3153         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
3154         return 1;
3155       }
3156     }
3157     else if (aFlag == "-type")
3158     {
3159       if (++anArgIter >= theArgNb)
3160       {
3161         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3162         return 1;
3163       }
3164
3165       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
3166       aTypeName.LowerCase();
3167       if (aTypeName == "wireframe"
3168        || aTypeName == "wire")
3169       {
3170         aVisType = V3d_WIREFRAME;
3171       }
3172       else if (aTypeName == "zbuffer"
3173             || aTypeName == "shaded")
3174       {
3175         aVisType = V3d_ZBUFFER;
3176       }
3177       else
3178       {
3179         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
3180       }
3181     }
3182     else if (aFlag == "-scale")
3183     {
3184       if (++anArgIter >= theArgNb)
3185       {
3186         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3187         return 1;
3188       }
3189
3190       aScale = Draw::Atof (theArgVec[anArgIter]);
3191     }
3192     else if (aFlag == "-size"
3193           || aFlag == "-sizeratio")
3194     {
3195       if (++anArgIter >= theArgNb)
3196       {
3197         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3198         return 1;
3199       }
3200
3201       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
3202     }
3203     else if (aFlag == "-arrowdiam"
3204           || aFlag == "-arrowdiameter")
3205     {
3206       if (++anArgIter >= theArgNb)
3207       {
3208         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3209         return 1;
3210       }
3211
3212       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
3213     }
3214     else if (aFlag == "-nbfacets")
3215     {
3216       if (++anArgIter >= theArgNb)
3217       {
3218         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3219         return 1;
3220       }
3221
3222       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
3223     }
3224     else if (aFlag == "-colorlabel"
3225           || aFlag == "-colorlabels"
3226           || aFlag == "-colorlabelx"
3227           || aFlag == "-colorlabely"
3228           || aFlag == "-colorlabelz"
3229           || aFlag == "-colorarrowx"
3230           || aFlag == "-colorarrowy"
3231           || aFlag == "-colorarrowz")
3232     {
3233       Quantity_Color aColor;
3234       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
3235                                                      theArgVec + anArgIter + 1,
3236                                                      aColor);
3237       if (aNbParsed == 0)
3238       {
3239         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3240         return 1;
3241       }
3242
3243       if (aFlag == "-colorarrowx")
3244       {
3245         anArrowColorX = aColor;
3246       }
3247       else if (aFlag == "-colorarrowy")
3248       {
3249         anArrowColorY = aColor;
3250       }
3251       else if (aFlag == "-colorarrowz")
3252       {
3253         anArrowColorZ = aColor;
3254       }
3255       else if (aFlag == "-colorlabelx")
3256       {
3257         aLabelsColorX = aColor;
3258       }
3259       else if (aFlag == "-colorlabely")
3260       {
3261         aLabelsColorY = aColor;
3262       }
3263       else if (aFlag == "-colorlabelz")
3264       {
3265         aLabelsColorZ = aColor;
3266       }
3267       else
3268       {
3269         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
3270       }
3271       anArgIter += aNbParsed;
3272     }
3273     else
3274     {
3275       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3276       return 1;
3277     }
3278   }
3279
3280   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
3281   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
3282   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
3283   aTrihedron->SetSizeRatio    (aSizeRatio);
3284   aTrihedron->SetNbFacets     (aNbFacets);
3285   aTrihedron->SetArrowDiameter(anArrowDiam);
3286   aTrihedron->SetScale        (aScale);
3287   aTrihedron->SetPosition     (aPosition);
3288   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
3289   aTrihedron->Display (aView);
3290
3291   aView->ZFitAll();
3292   return 0;
3293 }
3294
3295 //==============================================================================
3296 //function : VRotate
3297 //purpose  : Camera Rotating
3298 //==============================================================================
3299
3300 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
3301 {
3302   Handle(V3d_View) aView = ViewerTest::CurrentView();
3303   if (aView.IsNull())
3304   {
3305     Message::SendFail ("Error: no active viewer");
3306     return 1;
3307   }
3308
3309   Standard_Boolean hasFlags = Standard_False;
3310   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3311   {
3312     Standard_CString        anArg (theArgVec[anArgIter]);
3313     TCollection_AsciiString aFlag (anArg);
3314     aFlag.LowerCase();
3315     if (aFlag == "-mousestart"
3316      || aFlag == "-mousefrom")
3317     {
3318       hasFlags = Standard_True;
3319       if (anArgIter + 2 >= theArgNb)
3320       {
3321         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3322         return 1;
3323       }
3324
3325       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3326       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3327       aView->StartRotation (anX, anY);
3328     }
3329     else if (aFlag == "-mousemove")
3330     {
3331       hasFlags = Standard_True;
3332       if (anArgIter + 2 >= theArgNb)
3333       {
3334         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3335         return 1;
3336       }
3337
3338       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
3339       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
3340       aView->Rotation (anX, anY);
3341     }
3342     else if (theArgNb != 4
3343           && theArgNb != 7)
3344     {
3345       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3346       return 1;
3347     }
3348   }
3349
3350   if (hasFlags)
3351   {
3352     return 0;
3353   }
3354   else if (theArgNb == 4)
3355   {
3356     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3357     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3358     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3359     aView->Rotate (anAX, anAY, anAZ);
3360     return 0;
3361   }
3362   else if (theArgNb == 7)
3363   {
3364     Standard_Real anAX = Draw::Atof (theArgVec[1]);
3365     Standard_Real anAY = Draw::Atof (theArgVec[2]);
3366     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
3367
3368     Standard_Real anX = Draw::Atof (theArgVec[4]);
3369     Standard_Real anY = Draw::Atof (theArgVec[5]);
3370     Standard_Real anZ = Draw::Atof (theArgVec[6]);
3371
3372     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
3373     return 0;
3374   }
3375
3376   Message::SendFail ("Error: Invalid number of arguments");
3377   return 1;
3378 }
3379
3380 //==============================================================================
3381 //function : VZoom
3382 //purpose  : View zoom in / out (relative to current zoom)
3383 //==============================================================================
3384
3385 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3386   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3387   if ( V3dView.IsNull() ) {
3388     return 1;
3389   }
3390
3391   if ( argc == 2 ) {
3392     Standard_Real coef = Draw::Atof(argv[1]);
3393     if ( coef <= 0.0 ) {
3394       di << argv[1] << "Invalid value\n";
3395       return 1;
3396     }
3397     V3dView->SetZoom( Draw::Atof(argv[1]) );
3398     return 0;
3399   } else {
3400     di << argv[0] << " Invalid number of arguments\n";
3401     return 1;
3402   }
3403 }
3404
3405 //==============================================================================
3406 //function : VPan
3407 //purpose  : View panning (in pixels)
3408 //==============================================================================
3409
3410 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
3411   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3412   if ( V3dView.IsNull() ) return 1;
3413
3414   if ( argc == 3 ) {
3415     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
3416     return 0;
3417   } else {
3418     di << argv[0] << " Invalid number of arguments\n";
3419     return 1;
3420   }
3421 }
3422
3423 //==============================================================================
3424 //function : VPlace
3425 //purpose  : Place the point (in pixels) at the center of the window
3426 //==============================================================================
3427 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
3428 {
3429   Handle(V3d_View) aView = ViewerTest::CurrentView();
3430   if (aView.IsNull())
3431   {
3432     Message::SendFail ("Error: no active viewer");
3433     return 1;
3434   }
3435
3436   if (theArgNb != 3)
3437   {
3438     Message::SendFail ("Syntax error: wrong number of arguments");
3439     return 1;
3440   }
3441
3442   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
3443
3444   return 0;
3445 }
3446
3447 static int VColorScale (Draw_Interpretor& theDI,
3448                         Standard_Integer  theArgNb,
3449                         const char**      theArgVec)
3450 {
3451   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
3452   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
3453   if (aContext.IsNull())
3454   {
3455     Message::SendFail ("Error: no active viewer");
3456     return 1;
3457   }
3458   if (theArgNb <= 1)
3459   {
3460     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
3461     return 1;
3462   }
3463
3464   Handle(AIS_ColorScale) aColorScale;
3465   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
3466   {
3467     // find existing object
3468     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
3469     if (aColorScale.IsNull())
3470     {
3471       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
3472       return 1;
3473     }
3474   }
3475
3476   if (theArgNb <= 2)
3477   {
3478     if (aColorScale.IsNull())
3479     {
3480       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
3481       return 1;
3482     }
3483
3484     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
3485           << "Min range: "            << aColorScale->GetMin() << "\n"
3486           << "Max range: "            << aColorScale->GetMax() << "\n"
3487           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
3488           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
3489           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
3490           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
3491           << "Label position: ";
3492     switch (aColorScale->GetLabelPosition())
3493     {
3494       case Aspect_TOCSP_NONE:
3495         theDI << "None\n";
3496         break;
3497       case Aspect_TOCSP_LEFT:
3498         theDI << "Left\n";
3499         break;
3500       case Aspect_TOCSP_RIGHT:
3501         theDI << "Right\n";
3502         break;
3503       case Aspect_TOCSP_CENTER:
3504         theDI << "Center\n";
3505         break;
3506     }
3507     return 0;
3508   }
3509
3510   if (aColorScale.IsNull())
3511   {
3512     aColorScale = new AIS_ColorScale();
3513     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
3514     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
3515   }
3516
3517   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
3518   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
3519   {
3520     Standard_CString        anArg = theArgVec[anArgIter];
3521     TCollection_AsciiString aFlag (anArg);
3522     aFlag.LowerCase();
3523     if (anUpdateTool.parseRedrawMode (aFlag))
3524     {
3525       continue;
3526     }
3527     else if (aFlag == "-range")
3528     {
3529       if (anArgIter + 3 >= theArgNb)
3530       {
3531         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
3532         return 1;
3533       }
3534
3535       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
3536       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
3537       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
3538       if (!aRangeMin.IsRealValue (Standard_True)
3539        || !aRangeMax.IsRealValue (Standard_True))
3540       {
3541         Message::SendFail ("Syntax error: the range values should be real");
3542         return 1;
3543       }
3544       else if (!aNbIntervals.IsIntegerValue())
3545       {
3546         Message::SendFail ("Syntax error: the number of intervals should be integer");
3547         return 1;
3548       }
3549
3550       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
3551       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
3552     }
3553     else if (aFlag == "-font")
3554     {
3555       if (anArgIter + 1 >= theArgNb)
3556       {
3557         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3558         return 1;
3559       }
3560       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
3561       if (!aFontArg.IsIntegerValue())
3562       {
3563         Message::SendFail ("Syntax error: HeightFont value should be integer");
3564         return 1;
3565       }
3566
3567       aColorScale->SetTextHeight (aFontArg.IntegerValue());
3568       anArgIter += 1;
3569     }
3570     else if (aFlag == "-textpos")
3571     {
3572       if (anArgIter + 1 >= theArgNb)
3573       {
3574         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3575         return 1;
3576       }
3577
3578       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
3579       aTextPosArg.LowerCase();
3580       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
3581       if (aTextPosArg == "none")
3582       {
3583         aLabPosition = Aspect_TOCSP_NONE;
3584       }
3585       else if (aTextPosArg == "left")
3586       {
3587         aLabPosition = Aspect_TOCSP_LEFT;
3588       }
3589       else if (aTextPosArg == "right")
3590       {
3591         aLabPosition = Aspect_TOCSP_RIGHT;
3592       }
3593       else if (aTextPosArg == "center")
3594       {
3595         aLabPosition = Aspect_TOCSP_CENTER;
3596       }
3597       else
3598       {
3599         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
3600         return 1;
3601       }
3602       aColorScale->SetLabelPosition (aLabPosition);
3603     }
3604     else if (aFlag == "-logarithmic"
3605           || aFlag == "-log")
3606     {
3607       if (anArgIter + 1 >= theArgNb)
3608       {
3609         Message::SendFail() << "Synta error at argument '" << anArg << "'";
3610         return 1;
3611       }
3612
3613       Standard_Boolean IsLog;
3614       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
3615       {
3616         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3617         return 1;
3618       }
3619       aColorScale->SetLogarithmic (IsLog);
3620     }
3621     else if (aFlag == "-huerange"
3622           || aFlag == "-hue")
3623     {
3624       if (anArgIter + 2 >= theArgNb)
3625       {
3626         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3627         return 1;
3628       }
3629
3630       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
3631       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
3632       aColorScale->SetHueRange (aHueMin, aHueMax);
3633     }
3634     else if (aFlag == "-colorrange")
3635     {
3636       Quantity_Color aColorMin, aColorMax;
3637       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3638                                                       theArgVec + (anArgIter + 1),
3639                                                       aColorMin);
3640       anArgIter += aNbParsed1;
3641       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3642                                                       theArgVec + (anArgIter + 1),
3643                                                       aColorMax);
3644       anArgIter += aNbParsed2;
3645       if (aNbParsed1 == 0
3646        || aNbParsed2 == 0)
3647       {
3648         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3649         return 1;
3650       }
3651
3652       aColorScale->SetColorRange (aColorMin, aColorMax);
3653     }
3654     else if (aFlag == "-reversed"
3655           || aFlag == "-inverted"
3656           || aFlag == "-topdown"
3657           || aFlag == "-bottomup")
3658     {
3659       Standard_Boolean toEnable = Standard_True;
3660       if (anArgIter + 1 < theArgNb
3661        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
3662       {
3663         ++anArgIter;
3664       }
3665       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
3666     }
3667     else if (aFlag == "-smooth"
3668           || aFlag == "-smoothtransition")
3669     {
3670       Standard_Boolean toEnable = Standard_True;
3671       if (anArgIter + 1 < theArgNb
3672        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3673       {
3674         ++anArgIter;
3675       }
3676       aColorScale->SetSmoothTransition (toEnable);
3677     }
3678     else if (aFlag == "-xy")
3679     {
3680       if (anArgIter + 2 >= theArgNb)
3681       {
3682         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3683         return 1;
3684       }
3685
3686       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
3687       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
3688       if (!anX.IsIntegerValue()
3689        || !anY.IsIntegerValue())
3690       {
3691         Message::SendFail ("Syntax error: coordinates should be integer values");
3692         return 1;
3693       }
3694
3695       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
3696     }
3697     else if (aFlag == "-width"
3698           || aFlag == "-w"
3699           || aFlag == "-breadth")
3700     {
3701       if (anArgIter + 1 >= theArgNb)
3702       {
3703         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3704         return 1;
3705       }
3706
3707       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
3708       if (!aBreadth.IsIntegerValue())
3709       {
3710         Message::SendFail ("Syntax error: a width should be an integer value");
3711         return 1;
3712       }
3713       aColorScale->SetBreadth (aBreadth.IntegerValue());
3714     }
3715     else if (aFlag == "-height"
3716           || aFlag == "-h")
3717     {
3718       if (anArgIter + 1 >= theArgNb)
3719       {
3720         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3721         return 1;
3722       }
3723
3724       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
3725       if (!aHeight.IsIntegerValue())
3726       {
3727         Message::SendFail ("Syntax error: a width should be an integer value");
3728         return 1;
3729       }
3730       aColorScale->SetHeight (aHeight.IntegerValue());
3731     }
3732     else if (aFlag == "-color")
3733     {
3734       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3735       {
3736         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
3737         return 1;
3738       }
3739       else if (anArgIter + 2 >= theArgNb)
3740       {
3741         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3742         return 1;
3743       }
3744
3745       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
3746       if (!anInd.IsIntegerValue())
3747       {
3748         Message::SendFail ("Syntax error: Index value should be integer");
3749         return 1;
3750       }
3751       const Standard_Integer anIndex = anInd.IntegerValue();
3752       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
3753       {
3754         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
3755         return 1;
3756       }
3757
3758       Quantity_Color aColor;
3759       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3760                                                      theArgVec + (anArgIter + 1),
3761                                                      aColor);
3762       if (aNbParsed == 0)
3763       {
3764         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3765         return 1;
3766       }
3767       aColorScale->SetIntervalColor (aColor, anIndex);
3768       aColorScale->SetColorType (Aspect_TOCSD_USER);
3769       anArgIter += aNbParsed;
3770     }
3771     else if (aFlag == "-label")
3772     {
3773       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
3774       {
3775         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
3776         return 1;
3777       }
3778       else if (anArgIter + 2 >= theArgNb)
3779       {
3780         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3781         return 1;
3782       }
3783
3784       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
3785       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
3786       {
3787         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
3788         return 1;
3789       }
3790
3791       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
3792       aColorScale->SetLabel     (aText, anIndex);
3793       aColorScale->SetLabelType (Aspect_TOCSD_USER);
3794       anArgIter += 2;
3795     }
3796     else if (aFlag == "-labelat"
3797           || aFlag == "-labat"
3798           || aFlag == "-labelatborder"
3799           || aFlag == "-labatborder"
3800           || aFlag == "-labelatcenter"
3801           || aFlag == "-labatcenter")
3802     {
3803       Standard_Boolean toEnable = Standard_True;
3804       if (aFlag == "-labelat"
3805        || aFlag == "-labat")
3806       {
3807         Standard_Integer aLabAtBorder = -1;
3808         if (++anArgIter >= theArgNb)
3809         {
3810           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
3811           anAtBorder.LowerCase();
3812           if (anAtBorder == "border")
3813           {
3814             aLabAtBorder = 1;
3815           }
3816           else if (anAtBorder == "center")
3817           {
3818             aLabAtBorder = 0;
3819           }
3820         }
3821         if (aLabAtBorder == -1)
3822         {
3823           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3824           return 1;
3825         }
3826         toEnable = (aLabAtBorder == 1);
3827       }
3828       else if (anArgIter + 1 < theArgNb
3829             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
3830       {
3831         ++anArgIter;
3832       }
3833       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
3834                                   || aFlag == "-labatcenter"
3835                                    ? !toEnable
3836                                    :  toEnable);
3837     }
3838     else if (aFlag == "-colors")
3839     {
3840       Aspect_SequenceOfColor aSeq;
3841       for (;;)
3842       {
3843         Quantity_Color aColor;
3844         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
3845                                                        theArgVec + (anArgIter + 1),
3846                                                        aColor);
3847         if (aNbParsed == 0)
3848         {
3849           break;
3850         }
3851         anArgIter += aNbParsed;
3852         aSeq.Append (aColor);
3853       }
3854       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
3855       {
3856         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
3857                             << aColorScale->GetNumberOfIntervals() << " intervals";
3858         return 1;
3859       }
3860
3861       aColorScale->SetColors    (aSeq);
3862       aColorScale->SetColorType (Aspect_TOCSD_USER);
3863     }
3864     else if (aFlag == "-uniform")
3865     {
3866       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
3867       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
3868       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
3869       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
3870       aColorScale->SetColorType (Aspect_TOCSD_USER);
3871     }
3872     else if (aFlag == "-labels"
3873           || aFlag == "-freelabels")
3874     {
3875       if (anArgIter + 1 >= theArgNb)
3876       {
3877         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3878         return 1;
3879       }
3880
3881       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
3882                                  ? aColorScale->GetNumberOfIntervals() + 1
3883                                  : aColorScale->GetNumberOfIntervals();
3884       if (aFlag == "-freelabels")
3885       {
3886         ++anArgIter;
3887         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
3888       }
3889       if (anArgIter + aNbLabels >= theArgNb)
3890       {
3891         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
3892         return 1;
3893       }
3894
3895       TColStd_SequenceOfExtendedString aSeq;
3896       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
3897       {
3898         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
3899       }
3900       aColorScale->SetLabels (aSeq);
3901       aColorScale->SetLabelType (Aspect_TOCSD_USER);
3902     }
3903     else if (aFlag == "-title")
3904     {
3905       if (anArgIter + 1 >= theArgNb)
3906       {
3907         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3908         return 1;
3909       }
3910
3911       Standard_Boolean isTwoArgs = Standard_False;
3912       if (anArgIter + 2 < theArgNb)
3913       {
3914         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
3915         aSecondArg.LowerCase();
3916       Standard_DISABLE_DEPRECATION_WARNINGS
3917         if (aSecondArg == "none")
3918         {
3919           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
3920           isTwoArgs = Standard_True;
3921         }
3922         else if (aSecondArg == "left")
3923         {
3924           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
3925           isTwoArgs = Standard_True;
3926         }
3927         else if (aSecondArg == "right")
3928         {
3929           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
3930           isTwoArgs = Standard_True;
3931         }
3932         else if (aSecondArg == "center")
3933         {
3934           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
3935           isTwoArgs = Standard_True;
3936         }
3937       Standard_ENABLE_DEPRECATION_WARNINGS
3938       }
3939
3940       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
3941       aColorScale->SetTitle (aTitle);
3942       if (isTwoArgs)
3943       {
3944         anArgIter += 1;
3945       }
3946       anArgIter += 1;
3947     }
3948     else if (aFlag == "-demoversion"
3949           || aFlag == "-demo")
3950     {
3951       aColorScale->SetPosition (0, 0);
3952       aColorScale->SetTextHeight (16);
3953       aColorScale->SetRange (0.0, 100.0);
3954       aColorScale->SetNumberOfIntervals (10);
3955       aColorScale->SetBreadth (0);
3956       aColorScale->SetHeight  (0);
3957       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
3958       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
3959       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
3960     }
3961     else if (aFlag == "-findcolor")
3962     {
3963       if (anArgIter + 1 >= theArgNb)
3964       {
3965         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
3966         return 1;
3967       }
3968
3969       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
3970
3971       if (!anArg1.IsRealValue (Standard_True))
3972       {
3973         Message::SendFail ("Syntax error: the value should be real");
3974         return 1;
3975       }
3976
3977       Quantity_Color aColor;
3978       aColorScale->FindColor (anArg1.RealValue(), aColor);
3979       theDI << Quantity_Color::StringName (aColor.Name());
3980       return 0;
3981     }
3982     else
3983     {
3984       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
3985       return 1;
3986     }
3987   }
3988
3989   Standard_Integer aWinWidth = 0, aWinHeight = 0;
3990   aView->Window()->Size (aWinWidth, aWinHeight);
3991   if (aColorScale->GetBreadth() == 0)
3992   {
3993     aColorScale->SetBreadth (aWinWidth);
3994   }
3995   if (aColorScale->GetHeight() == 0)
3996   {
3997     aColorScale->SetHeight (aWinHeight);
3998   }
3999   aColorScale->SetToUpdate();
4000   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4001   return 0;
4002 }
4003
4004 //==============================================================================
4005 //function : VGraduatedTrihedron
4006 //purpose  : Displays or hides a graduated trihedron
4007 //==============================================================================
4008 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4009                                   Quantity_Color& theColor)
4010 {
4011   Quantity_NameOfColor aColorName;
4012   TCollection_AsciiString aVal = theValue;
4013   aVal.UpperCase();
4014   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4015   {
4016     return Standard_False;
4017   }
4018   theColor = Quantity_Color (aColorName);
4019   return Standard_True;
4020 }
4021
4022 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4023 {
4024   if (theArgNum < 2)
4025   {
4026     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4027                         << theArgs[0] <<"' for more information";
4028     return 1;
4029   }
4030
4031   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4032   TCollection_AsciiString aParseKey;
4033   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4034   {
4035     TCollection_AsciiString anArg (theArgs [anArgIt]);
4036
4037     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4038     {
4039       aParseKey = anArg;
4040       aParseKey.Remove (1);
4041       aParseKey.LowerCase();
4042       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4043       continue;
4044     }
4045
4046     if (aParseKey.IsEmpty())
4047     {
4048       continue;
4049     }
4050
4051     aMapOfArgs(aParseKey)->Append (anArg);
4052   }
4053
4054   // Check parameters
4055   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4056        aMapIt.More(); aMapIt.Next())
4057   {
4058     const TCollection_AsciiString& aKey = aMapIt.Key();
4059     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4060
4061     // Bool key, without arguments
4062     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4063         && anArgs->IsEmpty())
4064     {
4065       continue;
4066     }
4067
4068     // One argument
4069     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4070           && anArgs->Length() == 1)
4071     {
4072       continue;
4073     }
4074
4075     // On/off arguments
4076     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4077         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4078         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4079         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4080         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4081     {
4082       continue;
4083     }
4084
4085     // One string argument
4086     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4087           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4088           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4089     {
4090       continue;
4091     }
4092
4093     // One integer argument
4094     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4095           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4096           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4097           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4098          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4099     {
4100       continue;
4101     }
4102
4103     // One real argument
4104     if ( aKey.IsEqual ("arrowlength")
4105          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
4106     {
4107       continue;
4108     }
4109
4110     // Two string arguments
4111     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
4112          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4113     {
4114       continue;
4115     }
4116
4117     TCollection_AsciiString aLowerKey;
4118     aLowerKey  = "-";
4119     aLowerKey += aKey;
4120     aLowerKey.LowerCase();
4121     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
4122                         << "Type help for more information";
4123     return 1;
4124   }
4125
4126   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
4127   if (anAISContext.IsNull())
4128   {
4129     Message::SendFail ("Error: no active viewer");
4130     return 1;
4131   }
4132
4133   Standard_Boolean toDisplay = Standard_True;
4134   Quantity_Color aColor;
4135   Graphic3d_GraduatedTrihedron aTrihedronData;
4136   // Process parameters
4137   Handle(TColStd_HSequenceOfAsciiString) aValues;
4138   if (aMapOfArgs.Find ("off", aValues))
4139   {
4140     toDisplay = Standard_False;
4141   }
4142
4143   // AXES NAMES
4144   if (aMapOfArgs.Find ("xname", aValues))
4145   {
4146     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
4147   }
4148   if (aMapOfArgs.Find ("yname", aValues))
4149   {
4150     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
4151   }
4152   if (aMapOfArgs.Find ("zname", aValues))
4153   {
4154     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
4155   }
4156   if (aMapOfArgs.Find ("xdrawname", aValues))
4157   {
4158     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4159   }
4160   if (aMapOfArgs.Find ("ydrawname", aValues))
4161   {
4162     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4163   }
4164   if (aMapOfArgs.Find ("zdrawname", aValues))
4165   {
4166     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4167   }
4168   if (aMapOfArgs.Find ("xnameoffset", aValues))
4169   {
4170     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4171   }
4172   if (aMapOfArgs.Find ("ynameoffset", aValues))
4173   {
4174     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4175   }
4176   if (aMapOfArgs.Find ("znameoffset", aValues))
4177   {
4178     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4179   }
4180
4181   // COLORS
4182   if (aMapOfArgs.Find ("xnamecolor", aValues))
4183   {
4184     if (!GetColor (aValues->Value(1), aColor))
4185     {
4186       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
4187       return 1;
4188     }
4189     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
4190   }
4191   if (aMapOfArgs.Find ("ynamecolor", aValues))
4192   {
4193     if (!GetColor (aValues->Value(1), aColor))
4194     {
4195       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
4196       return 1;
4197     }
4198     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
4199   }
4200   if (aMapOfArgs.Find ("znamecolor", aValues))
4201   {
4202     if (!GetColor (aValues->Value(1), aColor))
4203     {
4204       Message::SendFail ("Syntax error: -znamecolor wrong color name");
4205       return 1;
4206     }
4207     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
4208   }
4209   if (aMapOfArgs.Find ("xcolor", aValues))
4210   {
4211     if (!GetColor (aValues->Value(1), aColor))
4212     {
4213       Message::SendFail ("Syntax error: -xcolor wrong color name");
4214       return 1;
4215     }
4216     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
4217   }
4218   if (aMapOfArgs.Find ("ycolor", aValues))
4219   {
4220     if (!GetColor (aValues->Value(1), aColor))
4221     {
4222       Message::SendFail ("Syntax error: -ycolor wrong color name");
4223       return 1;
4224     }
4225     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
4226   }
4227   if (aMapOfArgs.Find ("zcolor", aValues))
4228   {
4229     if (!GetColor (aValues->Value(1), aColor))
4230     {
4231       Message::SendFail ("Syntax error: -zcolor wrong color name");
4232       return 1;
4233     }
4234     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
4235   }
4236
4237   // TICKMARKS
4238   if (aMapOfArgs.Find ("xticks", aValues))
4239   {
4240     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4241   }
4242   if (aMapOfArgs.Find ("yticks", aValues))
4243   {
4244     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4245   }
4246   if (aMapOfArgs.Find ("zticks", aValues))
4247   {
4248     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
4249   }
4250   if (aMapOfArgs.Find ("xticklength", aValues))
4251   {
4252     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4253   }
4254   if (aMapOfArgs.Find ("yticklength", aValues))
4255   {
4256     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4257   }
4258   if (aMapOfArgs.Find ("zticklength", aValues))
4259   {
4260     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
4261   }
4262   if (aMapOfArgs.Find ("xdrawticks", aValues))
4263   {
4264     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4265   }
4266   if (aMapOfArgs.Find ("ydrawticks", aValues))
4267   {
4268     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4269   }
4270   if (aMapOfArgs.Find ("zdrawticks", aValues))
4271   {
4272     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
4273   }
4274
4275   // VALUES
4276   if (aMapOfArgs.Find ("xdrawvalues", aValues))
4277   {
4278     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4279   }
4280   if (aMapOfArgs.Find ("ydrawvalues", aValues))
4281   {
4282     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4283   }
4284   if (aMapOfArgs.Find ("zdrawvalues", aValues))
4285   {
4286     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
4287   }
4288   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
4289   {
4290     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4291   }
4292   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
4293   {
4294     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4295   }
4296   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
4297   {
4298     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
4299   }
4300
4301   // ARROWS
4302   if (aMapOfArgs.Find ("arrowlength", aValues))
4303   {
4304     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
4305   }
4306
4307   // FONTS
4308   if (aMapOfArgs.Find ("namefont", aValues))
4309   {
4310     aTrihedronData.SetNamesFont (aValues->Value(1));
4311   }
4312   if (aMapOfArgs.Find ("valuesfont", aValues))
4313   {
4314     aTrihedronData.SetValuesFont (aValues->Value(1));
4315   }
4316
4317   if (aMapOfArgs.Find ("drawgrid", aValues))
4318   {
4319     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
4320   }
4321   if (aMapOfArgs.Find ("drawaxes", aValues))
4322   {
4323     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
4324   }
4325
4326   // The final step: display of erase trihedron
4327   if (toDisplay)
4328   {
4329     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
4330   }
4331   else
4332   {
4333     ViewerTest::CurrentView()->GraduatedTrihedronErase();
4334   }
4335
4336   ViewerTest::GetAISContext()->UpdateCurrentViewer();
4337   ViewerTest::CurrentView()->Redraw();
4338
4339   return 0;
4340 }
4341
4342 //==============================================================================
4343 //function : VTile
4344 //purpose  :
4345 //==============================================================================
4346 static int VTile (Draw_Interpretor& theDI,
4347                   Standard_Integer  theArgNb,
4348                   const char**      theArgVec)
4349 {
4350   Handle(V3d_View) aView = ViewerTest::CurrentView();
4351   if (aView.IsNull())
4352   {
4353     Message::SendFail ("Error: no active viewer");
4354     return 1;
4355   }
4356
4357   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
4358   if (theArgNb < 2)
4359   {
4360     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
4361           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
4362           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
4363     return 0;
4364   }
4365
4366   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
4367   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4368   {
4369     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4370     anArg.LowerCase();
4371     if (anArg == "-lowerleft"
4372      || anArg == "-upperleft")
4373     {
4374       if (anArgIter + 3 < theArgNb)
4375       {
4376         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4377         return 1;
4378       }
4379       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
4380       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4381       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4382     }
4383     else if (anArg == "-total"
4384           || anArg == "-totalsize"
4385           || anArg == "-viewsize")
4386     {
4387       if (anArgIter + 3 < theArgNb)
4388       {
4389         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4390         return 1;
4391       }
4392       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4393       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4394       if (aTile.TotalSize.x() < 1
4395        || aTile.TotalSize.y() < 1)
4396       {
4397         Message::SendFail ("Error: total size is incorrect");
4398         return 1;
4399       }
4400     }
4401     else if (anArg == "-tilesize")
4402     {
4403       if (anArgIter + 3 < theArgNb)
4404       {
4405         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
4406         return 1;
4407       }
4408
4409       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
4410       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
4411       if (aTile.TileSize.x() < 1
4412        || aTile.TileSize.y() < 1)
4413       {
4414         Message::SendFail ("Error: tile size is incorrect");
4415         return 1;
4416       }
4417     }
4418     else if (anArg == "-unset")
4419     {
4420       aView->Camera()->SetTile (Graphic3d_CameraTile());
4421       aView->Redraw();
4422       return 0;
4423     }
4424   }
4425
4426   if (aTile.TileSize.x() < 1
4427    || aTile.TileSize.y() < 1)
4428   {
4429     Message::SendFail ("Error: tile size is undefined");
4430     return 1;
4431   }
4432   else if (aTile.TotalSize.x() < 1
4433         || aTile.TotalSize.y() < 1)
4434   {
4435     Message::SendFail ("Error: total size is undefined");
4436     return 1;
4437   }
4438
4439   aView->Camera()->SetTile (aTile);
4440   aView->Redraw();
4441   return 0;
4442 }
4443
4444 //! Format ZLayer ID.
4445 inline const char* formZLayerId (const Standard_Integer theLayerId)
4446 {
4447   switch (theLayerId)
4448   {
4449     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
4450     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
4451     case Graphic3d_ZLayerId_Top:     return "[TOP]";
4452     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
4453     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
4454     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
4455   }
4456   return "";
4457 }
4458
4459 //! Print the ZLayer information.
4460 inline void printZLayerInfo (Draw_Interpretor& theDI,
4461                              const Graphic3d_ZLayerSettings& theLayer)
4462 {
4463   if (!theLayer.Name().IsEmpty())
4464   {
4465     theDI << "  Name: " << theLayer.Name() << "\n";
4466   }
4467   if (theLayer.IsImmediate())
4468   {
4469     theDI << "  Immediate: TRUE\n";
4470   }
4471   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
4472   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
4473   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
4474   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
4475   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
4476   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
4477   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
4478   {
4479     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
4480   }
4481 }
4482
4483 //==============================================================================
4484 //function : VZLayer
4485 //purpose  : Test z layer operations for v3d viewer
4486 //==============================================================================
4487 static int VZLayer (Draw_Interpretor& theDI,
4488                     Standard_Integer  theArgNb,
4489                     const char**      theArgVec)
4490 {
4491   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
4492   if (aContextAIS.IsNull())
4493   {
4494     Message::SendFail ("Error: no active viewer");
4495     return 1;
4496   }
4497
4498   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
4499   if (theArgNb < 2)
4500   {
4501     TColStd_SequenceOfInteger aLayers;
4502     aViewer->GetAllZLayers (aLayers);
4503     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4504     {
4505       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
4506       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
4507       printZLayerInfo (theDI, aSettings);
4508     }
4509     return 0;
4510   }
4511
4512   Standard_Integer anArgIter = 1;
4513   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4514   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
4515   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
4516   {
4517     ++anArgIter;
4518   }
4519
4520   {
4521     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
4522     if (aFirstArg.IsIntegerValue())
4523     {
4524       ++anArgIter;
4525       aLayerId = aFirstArg.IntegerValue();
4526     }
4527     else
4528     {
4529       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
4530       {
4531         ++anArgIter;
4532       }
4533     }
4534   }
4535
4536   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
4537   for (; anArgIter < theArgNb; ++anArgIter)
4538   {
4539     // perform operation
4540     TCollection_AsciiString anArg (theArgVec[anArgIter]);
4541     anArg.LowerCase();
4542     if (anUpdateTool.parseRedrawMode (anArg))
4543     {
4544       //
4545     }
4546     else if (anArg == "-add"
4547           || anArg == "add")
4548     {
4549       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4550       if (!aViewer->AddZLayer (aLayerId))
4551       {
4552         Message::SendFail ("Error: can not add a new z layer");
4553         return 0;
4554       }
4555
4556       theDI << aLayerId;
4557     }
4558     else if (anArg == "-insertbefore"
4559           && anArgIter + 1 < theArgNb
4560           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4561     {
4562       ++anArgIter;
4563       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4564       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4565       {
4566         Message::SendFail ("Error: can not add a new z layer");
4567         return 0;
4568       }
4569
4570       theDI << aLayerId;
4571     }
4572     else if (anArg == "-insertafter"
4573           && anArgIter + 1 < theArgNb
4574           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
4575     {
4576       ++anArgIter;
4577       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
4578       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
4579       {
4580         Message::SendFail ("Error: can not add a new z layer");
4581         return 0;
4582       }
4583
4584       theDI << aLayerId;
4585     }
4586     else if (anArg == "-del"
4587           || anArg == "-delete"
4588           || anArg == "del")
4589     {
4590       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4591       {
4592         if (++anArgIter >= theArgNb)
4593         {
4594           Message::SendFail ("Syntax error: id of z layer to remove is missing");
4595           return 1;
4596         }
4597
4598         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4599       }
4600
4601       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
4602        || aLayerId == Graphic3d_ZLayerId_Default
4603        || aLayerId == Graphic3d_ZLayerId_Top
4604        || aLayerId == Graphic3d_ZLayerId_Topmost
4605        || aLayerId == Graphic3d_ZLayerId_TopOSD
4606        || aLayerId == Graphic3d_ZLayerId_BotOSD)
4607       {
4608         Message::SendFail ("Syntax error: standard Z layer can not be removed");
4609         return 1;
4610       }
4611
4612       // move all object displayed in removing layer to default layer
4613       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
4614            anObjIter.More(); anObjIter.Next())
4615       {
4616         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
4617         if (aPrs.IsNull()
4618          || aPrs->ZLayer() != aLayerId)
4619         {
4620           continue;
4621         }
4622         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
4623       }
4624
4625       if (!aViewer->RemoveZLayer (aLayerId))
4626       {
4627         Message::SendFail ("Z layer can not be removed");
4628       }
4629       else
4630       {
4631         theDI << aLayerId << " ";
4632       }
4633     }
4634     else if (anArg == "-get"
4635           || anArg == "get")
4636     {
4637       TColStd_SequenceOfInteger aLayers;
4638       aViewer->GetAllZLayers (aLayers);
4639       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
4640       {
4641         theDI << aLayeriter.Value() << " ";
4642       }
4643
4644       theDI << "\n";
4645     }
4646     else if (anArg == "-name")
4647     {
4648       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4649       {
4650         Message::SendFail ("Syntax error: id of Z layer is missing");
4651         return 1;
4652       }
4653
4654       if (++anArgIter >= theArgNb)
4655       {
4656         Message::SendFail ("Syntax error: name is missing");
4657         return 1;
4658       }
4659
4660       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4661       aSettings.SetName (theArgVec[anArgIter]);
4662       aViewer->SetZLayerSettings (aLayerId, aSettings);
4663     }
4664     else if (anArg == "-origin")
4665     {
4666       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4667       {
4668         Message::SendFail ("Syntax error: id of Z layer is missing");
4669         return 1;
4670       }
4671
4672       if (anArgIter + 2 >= theArgNb)
4673       {
4674         Message::SendFail ("Syntax error: origin coordinates are missing");
4675         return 1;
4676       }
4677
4678       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4679       gp_XYZ anOrigin;
4680       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
4681       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
4682       anOrigin.SetZ (0.0);
4683       if (anArgIter + 3 < theArgNb)
4684       {
4685         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
4686         anArgIter += 3;
4687       }
4688       else
4689       {
4690         anArgIter += 2;
4691       }
4692       aSettings.SetOrigin (anOrigin);
4693       aViewer->SetZLayerSettings (aLayerId, aSettings);
4694     }
4695     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4696           && anArgIter + 1 < theArgNb
4697           && (anArg == "-cullingdistance"
4698            || anArg == "-cullingdist"
4699            || anArg == "-culldistance"
4700            || anArg == "-culldist"
4701            || anArg == "-distcull"
4702            || anArg == "-distculling"
4703            || anArg == "-distanceculling"))
4704     {
4705       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4706       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
4707       aSettings.SetCullingDistance (aDist);
4708       aViewer->SetZLayerSettings (aLayerId, aSettings);
4709     }
4710     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
4711           && anArgIter + 1 < theArgNb
4712           && (anArg == "-cullingsize"
4713            || anArg == "-cullsize"
4714            || anArg == "-sizecull"
4715            || anArg == "-sizeculling"))
4716     {
4717       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4718       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
4719       aSettings.SetCullingSize (aSize);
4720       aViewer->SetZLayerSettings (aLayerId, aSettings);
4721     }
4722     else if (anArg == "-settings"
4723           || anArg == "settings")
4724     {
4725       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4726       {
4727         if (++anArgIter >= theArgNb)
4728         {
4729           Message::SendFail ("Syntax error: id of Z layer is missing");
4730           return 1;
4731         }
4732
4733         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4734       }
4735
4736       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4737       printZLayerInfo (theDI, aSettings);
4738     }
4739     else if (anArg == "-enable"
4740           || anArg == "enable"
4741           || anArg == "-disable"
4742           || anArg == "disable")
4743     {
4744       const Standard_Boolean toEnable = anArg == "-enable"
4745                                      || anArg == "enable";
4746       if (++anArgIter >= theArgNb)
4747       {
4748         Message::SendFail ("Syntax error: option name is missing");
4749         return 1;
4750       }
4751
4752       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
4753       aSubOp.LowerCase();
4754       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
4755       {
4756         if (++anArgIter >= theArgNb)
4757         {
4758           Message::SendFail ("Syntax error: id of Z layer is missing");
4759           return 1;
4760         }
4761
4762         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
4763       }
4764
4765       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
4766       if (aSubOp == "depthtest"
4767        || aSubOp == "test")
4768       {
4769         aSettings.SetEnableDepthTest (toEnable);
4770       }
4771       else if (aSubOp == "depthwrite"
4772             || aSubOp == "write")
4773       {
4774         aSettings.SetEnableDepthWrite (toEnable);
4775       }
4776       else if (aSubOp == "depthclear"
4777             || aSubOp == "clear")
4778       {
4779         aSettings.SetClearDepth (toEnable);
4780       }
4781       else if (aSubOp == "depthoffset"
4782             || aSubOp == "offset")
4783       {
4784         Graphic3d_PolygonOffset aParams;
4785         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
4786         if (toEnable)
4787         {
4788           if (anArgIter + 2 >= theArgNb)
4789           {
4790             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
4791             return 1;
4792           }
4793
4794           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4795           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
4796         }
4797         aSettings.SetPolygonOffset (aParams);
4798       }
4799       else if (aSubOp == "positiveoffset"
4800             || aSubOp == "poffset")
4801       {
4802         if (toEnable)
4803         {
4804           aSettings.SetDepthOffsetPositive();
4805         }
4806         else
4807         {
4808           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
4809         }
4810       }
4811       else if (aSubOp == "negativeoffset"
4812             || aSubOp == "noffset")
4813       {
4814         if (toEnable)
4815         {
4816           aSettings.SetDepthOffsetNegative();
4817         }
4818         else
4819         {
4820           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
4821         }
4822       }
4823       else if (aSubOp == "textureenv")
4824       {
4825         aSettings.SetEnvironmentTexture (toEnable);
4826       }
4827       else if (aSubOp == "raytracing")
4828       {
4829         aSettings.SetRaytracable (toEnable);
4830       }
4831
4832       aViewer->SetZLayerSettings (aLayerId, aSettings);
4833     }
4834     else
4835     {
4836       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
4837       return 1;
4838     }
4839   }
4840
4841   return 0;
4842 }
4843
4844 // The interactive presentation of 2d layer item
4845 // for "vlayerline" command it provides a presentation of
4846 // line with user-defined linewidth, linetype and transparency.
4847 class V3d_LineItem : public AIS_InteractiveObject
4848 {
4849 public:
4850   // CASCADE RTTI
4851   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
4852
4853   // constructor
4854   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
4855                                Standard_Real X2, Standard_Real Y2,
4856                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
4857                                Standard_Real theWidth    = 0.5,
4858                                Standard_Real theTransp   = 1.0);
4859
4860 private:
4861
4862   virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
4863                         const Handle(Prs3d_Presentation)& thePrs,
4864                         const Standard_Integer theMode) Standard_OVERRIDE;
4865
4866   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& ,
4867                                  const Standard_Integer ) Standard_OVERRIDE
4868   {}
4869
4870 private:
4871
4872   Standard_Real       myX1, myY1, myX2, myY2;
4873   Aspect_TypeOfLine   myType;
4874   Standard_Real       myWidth;
4875 };
4876
4877 // default constructor for line item
4878 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
4879                            Standard_Real X2, Standard_Real Y2,
4880                            Aspect_TypeOfLine theType,
4881                            Standard_Real theWidth,
4882                            Standard_Real theTransp) :
4883   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
4884   myType(theType), myWidth(theWidth)
4885 {
4886   SetTransparency (1-theTransp);
4887 }
4888
4889 // render line
4890 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager)& ,
4891                             const Handle(Prs3d_Presentation)& thePresentation,
4892                             const Standard_Integer )
4893 {
4894   thePresentation->Clear();
4895   Quantity_Color aColor (Quantity_NOC_RED);
4896   Standard_Integer aWidth, aHeight;
4897   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
4898   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
4899   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
4900   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
4901   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
4902   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
4903   aGroup->SetPrimitivesAspect (anAspect->Aspect());
4904   aGroup->AddPrimitiveArray (aPrim);
4905 }
4906
4907 //=============================================================================
4908 //function : VLayerLine
4909 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
4910 //         : linewidth, transparency coefficient
4911 //============================================================================
4912 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
4913 {
4914   // get the active view
4915   Handle(V3d_View) aView = ViewerTest::CurrentView();
4916   if (aView.IsNull())
4917   {
4918     di << "Call vinit before!\n";
4919     return 1;
4920   }
4921   else if (argc < 5)
4922   {
4923     di << "Use: " << argv[0];
4924     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
4925     di << " linetype : { 0 | 1 | 2 | 3 } \n";
4926     di << "              0 - solid  \n";
4927     di << "              1 - dashed \n";
4928     di << "              2 - dot    \n";
4929     di << "              3 - dashdot\n";
4930     di << " transparency : { 0.0 - 1.0 } \n";
4931     di << "                  0.0 - transparent\n";
4932     di << "                  1.0 - visible    \n";
4933     return 1;
4934   }
4935
4936   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4937   // get the input params
4938   Standard_Real X1 = Draw::Atof(argv[1]);
4939   Standard_Real Y1 = Draw::Atof(argv[2]);
4940   Standard_Real X2 = Draw::Atof(argv[3]);
4941   Standard_Real Y2 = Draw::Atof(argv[4]);
4942
4943   Standard_Real aWidth = 0.5;
4944   Standard_Real aTransparency = 1.0;
4945
4946   // has width
4947   if (argc > 5)
4948     aWidth = Draw::Atof(argv[5]);
4949
4950   // select appropriate line type
4951   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
4952   if (argc > 6
4953   && !ViewerTest::ParseLineType (argv[6], aLineType))
4954   {
4955     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
4956     return 1;
4957   }
4958
4959   // has transparency
4960   if (argc > 7)
4961   {
4962     aTransparency = Draw::Atof(argv[7]);
4963     if (aTransparency < 0 || aTransparency > 1.0)
4964       aTransparency = 1.0;
4965   }
4966
4967   static Handle (V3d_LineItem) aLine;
4968   if (!aLine.IsNull())
4969   {
4970     aContext->Erase (aLine, Standard_False);
4971   }
4972   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
4973                             aLineType, aWidth,
4974                             aTransparency);
4975
4976   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4977   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4978   aLine->SetToUpdate();
4979   aContext->Display (aLine, Standard_True);
4980
4981   return 0;
4982 }
4983
4984
4985 //==============================================================================
4986 //function : VGrid
4987 //purpose  :
4988 //==============================================================================
4989
4990 static int VGrid (Draw_Interpretor& /*theDI*/,
4991                   Standard_Integer  theArgNb,
4992                   const char**      theArgVec)
4993 {
4994   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
4995   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
4996   if (aView.IsNull() || aViewer.IsNull())
4997   {
4998     Message::SendFail ("Error: no active viewer");
4999     return 1;
5000   }
5001
5002   Aspect_GridType     aType = aViewer->GridType();
5003   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5004   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5005   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5006   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5007   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5008   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5009   {
5010     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5011     anArg.LowerCase();
5012     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5013     {
5014       continue;
5015     }
5016     else if (anArgIter + 1 < theArgNb
5017           && anArg == "-type")
5018     {
5019       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5020       anArgNext.LowerCase();
5021       if (anArgNext == "r"
5022        || anArgNext == "rect"
5023        || anArgNext == "rectangular")
5024       {
5025         aType = Aspect_GT_Rectangular;
5026       }
5027       else if (anArgNext == "c"
5028             || anArgNext == "circ"
5029             || anArgNext == "circular")
5030       {
5031         aType = Aspect_GT_Circular;
5032       }
5033       else
5034       {
5035         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5036         return 1;
5037       }
5038     }
5039     else if (anArgIter + 1 < theArgNb
5040           && anArg == "-mode")
5041     {
5042       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5043       anArgNext.LowerCase();
5044       if (anArgNext == "l"
5045        || anArgNext == "line"
5046        || anArgNext == "lines")
5047       {
5048         aMode = Aspect_GDM_Lines;
5049       }
5050       else if (anArgNext == "p"
5051             || anArgNext == "point"
5052             || anArgNext == "points")
5053       {
5054         aMode = Aspect_GDM_Points;
5055       }
5056       else
5057       {
5058         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5059         return 1;
5060       }
5061     }
5062     else if (anArgIter + 2 < theArgNb
5063           && (anArg == "-origin"
5064            || anArg == "-orig"))
5065     {
5066       hasOrigin = true;
5067       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5068                               Draw::Atof (theArgVec[anArgIter + 2]));
5069       anArgIter += 2;
5070     }
5071     else if (anArgIter + 2 < theArgNb
5072           && anArg == "-step")
5073     {
5074       hasStep = true;
5075       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5076                             Draw::Atof (theArgVec[anArgIter + 2]));
5077       if (aNewStepXY.x() <= 0.0
5078        || aNewStepXY.y() <= 0.0)
5079       {
5080         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5081         return 1;
5082       }
5083       anArgIter += 2;
5084     }
5085     else if (anArgIter + 1 < theArgNb
5086           && (anArg == "-angle"
5087            || anArg == "-rotangle"
5088            || anArg == "-rotationangle"))
5089     {
5090       hasRotAngle = true;
5091       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5092     }
5093     else if (anArgIter + 1 < theArgNb
5094           && (anArg == "-zoffset"
5095            || anArg == "-dz"))
5096     {
5097       hasZOffset = true;
5098       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5099     }
5100     else if (anArgIter + 1 < theArgNb
5101           && anArg == "-radius")
5102     {
5103       hasSize = true;
5104       ++anArgIter;
5105       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
5106       if (aNewStepXY.x() <= 0.0)
5107       {
5108         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
5109         return 1;
5110       }
5111     }
5112     else if (anArgIter + 2 < theArgNb
5113           && anArg == "-size")
5114     {
5115       hasSize = true;
5116       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5117                             Draw::Atof (theArgVec[anArgIter + 2]));
5118       if (aNewStepXY.x() <= 0.0
5119        || aNewStepXY.y() <= 0.0)
5120       {
5121         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5122         return 1;
5123       }
5124       anArgIter += 2;
5125     }
5126     else if (anArg == "r"
5127           || anArg == "rect"
5128           || anArg == "rectangular")
5129     {
5130       aType = Aspect_GT_Rectangular;
5131     }
5132     else if (anArg == "c"
5133           || anArg == "circ"
5134           || anArg == "circular")
5135     {
5136       aType = Aspect_GT_Circular;
5137     }
5138     else if (anArg == "l"
5139           || anArg == "line"
5140           || anArg == "lines")
5141     {
5142       aMode = Aspect_GDM_Lines;
5143     }
5144     else if (anArg == "p"
5145           || anArg == "point"
5146           || anArg == "points")
5147     {
5148       aMode = Aspect_GDM_Points;
5149     }
5150     else if (anArgIter + 1 >= theArgNb
5151           && anArg == "off")
5152     {
5153       aViewer->DeactivateGrid();
5154       return 0;
5155     }
5156     else
5157     {
5158       Message::SendFail() << "Syntax error at '" << anArg << "'";
5159       return 1;
5160     }
5161   }
5162
5163   if (aType == Aspect_GT_Rectangular)
5164   {
5165     Graphic3d_Vec2d anOrigXY, aStepXY;
5166     Standard_Real aRotAngle = 0.0;
5167     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5168     if (hasOrigin)
5169     {
5170       anOrigXY = aNewOriginXY;
5171     }
5172     if (hasStep)
5173     {
5174       aStepXY = aNewStepXY;
5175     }
5176     if (hasRotAngle)
5177     {
5178       aRotAngle = aNewRotAngle;
5179     }
5180     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5181     if (hasSize || hasZOffset)
5182     {
5183       Graphic3d_Vec3d aSize;
5184       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5185       if (hasSize)
5186       {
5187         aSize.x() = aNewSizeXY.x();
5188         aSize.y() = aNewSizeXY.y();
5189       }
5190       if (hasZOffset)
5191       {
5192         aSize.z() = aNewZOffset;
5193       }
5194       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5195     }
5196   }
5197   else if (aType == Aspect_GT_Circular)
5198   {
5199     Graphic3d_Vec2d anOrigXY;
5200     Standard_Real aRadiusStep;
5201     Standard_Integer aDivisionNumber;
5202     Standard_Real aRotAngle = 0.0;
5203     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5204     if (hasOrigin)
5205     {
5206       anOrigXY = aNewOriginXY;
5207     }
5208     if (hasStep)
5209     {
5210       aRadiusStep     = aNewStepXY[0];
5211       aDivisionNumber = (int )aNewStepXY[1];
5212       if (aDivisionNumber < 1)
5213       {
5214         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
5215         return 1;
5216       }
5217     }
5218     if (hasRotAngle)
5219     {
5220       aRotAngle = aNewRotAngle;
5221     }
5222
5223     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5224     if (hasSize || hasZOffset)
5225     {
5226       Standard_Real aRadius = 0.0, aZOffset = 0.0;
5227       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
5228       if (hasSize)
5229       {
5230         aRadius = aNewSizeXY.x();
5231         if (aNewSizeXY.y() != 0.0)
5232         {
5233           Message::SendFail ("Syntax error: circular size should be specified as radius");
5234           return 1;
5235         }
5236       }
5237       if (hasZOffset)
5238       {
5239         aZOffset = aNewZOffset;
5240       }
5241       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
5242     }
5243   }
5244   aViewer->ActivateGrid (aType, aMode);
5245   return 0;
5246 }
5247
5248 //==============================================================================
5249 //function : VPriviledgedPlane
5250 //purpose  :
5251 //==============================================================================
5252
5253 static int VPriviledgedPlane (Draw_Interpretor& theDI,
5254                               Standard_Integer  theArgNb,
5255                               const char**      theArgVec)
5256 {
5257   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
5258   {
5259     Message::SendFail ("Error: wrong number of arguments! See usage:");
5260     theDI.PrintHelp (theArgVec[0]);
5261     return 1;
5262   }
5263
5264   // get the active viewer
5265   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5266   if (aViewer.IsNull())
5267   {
5268     Message::SendFail ("Error: no active viewer");
5269     return 1;
5270   }
5271
5272   if (theArgNb == 1)
5273   {
5274     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
5275     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
5276     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
5277     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
5278     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
5279           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
5280           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
5281     return 0;
5282   }
5283
5284   Standard_Integer anArgIdx = 1;
5285   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
5286   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
5287   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
5288   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
5289   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
5290   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
5291
5292   gp_Ax3 aPriviledgedPlane;
5293   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
5294   gp_Dir aNorm (aNormX, aNormY, aNormZ);
5295   if (theArgNb > 7)
5296   {
5297     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
5298     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
5299     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
5300     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
5301     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
5302   }
5303   else
5304   {
5305     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
5306   }
5307
5308   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
5309
5310   return 0;
5311 }
5312
5313 //==============================================================================
5314 //function : VConvert
5315 //purpose  :
5316 //==============================================================================
5317
5318 static int VConvert (Draw_Interpretor& theDI,
5319                      Standard_Integer  theArgNb,
5320                      const char**      theArgVec)
5321 {
5322   // get the active view
5323   Handle(V3d_View) aView = ViewerTest::CurrentView();
5324   if (aView.IsNull())
5325   {
5326     Message::SendFail ("Error: no active viewer");
5327     return 1;
5328   }
5329
5330   enum { Model, Ray, View, Window, Grid } aMode = Model;
5331
5332   // access coordinate arguments
5333   TColStd_SequenceOfReal aCoord;
5334   Standard_Integer anArgIdx = 1;
5335   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
5336   {
5337     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5338     if (!anArg.IsRealValue (Standard_True))
5339     {
5340       break;
5341     }
5342     aCoord.Append (anArg.RealValue());
5343   }
5344
5345   // non-numeric argument too early
5346   if (aCoord.IsEmpty())
5347   {
5348     Message::SendFail ("Error: wrong number of arguments! See usage:");
5349     theDI.PrintHelp (theArgVec[0]);
5350     return 1;
5351   }
5352
5353   // collect all other arguments and options
5354   for (; anArgIdx < theArgNb; ++anArgIdx)
5355   {
5356     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
5357     anArg.LowerCase();
5358     if      (anArg == "window") aMode = Window;
5359     else if (anArg == "view")   aMode = View;
5360     else if (anArg == "grid")   aMode = Grid;
5361     else if (anArg == "ray")    aMode = Ray;
5362     else
5363     {
5364       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
5365       theDI.PrintHelp (theArgVec[0]);
5366       return 1;
5367     }
5368   }
5369
5370   // complete input checks
5371   if ((aCoord.Length() == 1 && theArgNb > 3) ||
5372       (aCoord.Length() == 2 && theArgNb > 4) ||
5373       (aCoord.Length() == 3 && theArgNb > 5))
5374   {
5375     Message::SendFail ("Error: wrong number of arguments! See usage:");
5376     theDI.PrintHelp (theArgVec[0]);
5377     return 1;
5378   }
5379
5380   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
5381   Standard_Integer aXYp[2] = {0, 0};
5382
5383   // convert one-dimensional coordinate
5384   if (aCoord.Length() == 1)
5385   {
5386     switch (aMode)
5387     {
5388       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
5389       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
5390       default:
5391         Message::SendFail ("Error: wrong arguments! See usage:");
5392         theDI.PrintHelp (theArgVec[0]);
5393         return 1;
5394     }
5395   }
5396
5397   // convert 2D coordinates from projection or view reference space
5398   if (aCoord.Length() == 2)
5399   {
5400     switch (aMode)
5401     {
5402       case Model :
5403         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5404         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5405         return 0;
5406
5407       case View :
5408         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
5409         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
5410         return 0;
5411
5412       case Window :
5413         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
5414         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5415         return 0;
5416
5417       case Grid :
5418         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
5419         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
5420         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5421         return 0;
5422
5423       case Ray :
5424         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
5425                                 (Standard_Integer) aCoord (2),
5426                                 aXYZ[0], aXYZ[1], aXYZ[2],
5427                                 aXYZ[3], aXYZ[4], aXYZ[5]);
5428         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
5429         return 0;
5430
5431       default:
5432         Message::SendFail ("Error: wrong arguments! See usage:");
5433         theDI.PrintHelp (theArgVec[0]);
5434         return 1;
5435     }
5436   }
5437
5438   // convert 3D coordinates from view reference space
5439   else if (aCoord.Length() == 3)
5440   {
5441     switch (aMode)
5442     {
5443       case Window :
5444         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
5445         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
5446         return 0;
5447
5448       case Grid :
5449         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
5450         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
5451         return 0;
5452
5453       default:
5454         Message::SendFail ("Error: wrong arguments! See usage:");
5455         theDI.PrintHelp (theArgVec[0]);
5456         return 1;
5457     }
5458   }
5459
5460   return 0;
5461 }
5462
5463 //==============================================================================
5464 //function : VFps
5465 //purpose  :
5466 //==============================================================================
5467
5468 static int VFps (Draw_Interpretor& theDI,
5469                  Standard_Integer  theArgNb,
5470                  const char**      theArgVec)
5471 {
5472   // get the active view
5473   Handle(V3d_View) aView = ViewerTest::CurrentView();
5474   if (aView.IsNull())
5475   {
5476     Message::SendFail ("Error: no active viewer");
5477     return 1;
5478   }
5479
5480   Standard_Integer aFramesNb = -1;
5481   Standard_Real aDuration = -1.0;
5482   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5483   {
5484     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5485     anArg.LowerCase();
5486     if (aDuration < 0.0
5487      && anArgIter + 1 < theArgNb
5488      && (anArg == "-duration"
5489       || anArg == "-dur"
5490       || anArg == "-time"))
5491     {
5492       aDuration = Draw::Atof (theArgVec[++anArgIter]);
5493     }
5494     else if (aFramesNb < 0
5495           && anArg.IsIntegerValue())
5496     {
5497       aFramesNb = anArg.IntegerValue();
5498       if (aFramesNb <= 0)
5499       {
5500         Message::SendFail() << "Syntax error at '" << anArg << "'";
5501         return 1;
5502       }
5503     }
5504     else
5505     {
5506       Message::SendFail() << "Syntax error at '" << anArg << "'";
5507       return 1;
5508     }
5509   }
5510   if (aFramesNb < 0 && aDuration < 0.0)
5511   {
5512     aFramesNb = 100;
5513   }
5514
5515   // the time is meaningless for first call
5516   // due to async OpenGl rendering
5517   aView->Redraw();
5518
5519   // redraw view in loop to estimate average values
5520   OSD_Timer aTimer;
5521   aTimer.Start();
5522   Standard_Integer aFrameIter = 1;
5523   for (;; ++aFrameIter)
5524   {
5525     aView->Redraw();
5526     if ((aFramesNb > 0
5527       && aFrameIter >= aFramesNb)
5528      || (aDuration > 0.0
5529       && aTimer.ElapsedTime() >= aDuration))
5530     {
5531       break;
5532     }
5533   }
5534   aTimer.Stop();
5535   Standard_Real aCpu;
5536   const Standard_Real aTime = aTimer.ElapsedTime();
5537   aTimer.OSD_Chronometer::Show (aCpu);
5538
5539   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
5540   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
5541
5542   // return statistics
5543   theDI << "FPS: " << aFpsAver << "\n"
5544         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
5545
5546   // compute additional statistics in ray-tracing mode
5547   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
5548   if (aParams.Method == Graphic3d_RM_RAYTRACING)
5549   {
5550     Graphic3d_Vec2i aWinSize (0, 0);
5551     aView->Window()->Size (aWinSize.x(), aWinSize.y());
5552
5553     // 1 shadow ray and 1 secondary ray pew each bounce
5554     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
5555     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
5556   }
5557
5558   return 0;
5559 }
5560
5561
5562 //==============================================================================
5563 //function : VMemGpu
5564 //purpose  :
5565 //==============================================================================
5566
5567 static int VMemGpu (Draw_Interpretor& theDI,
5568                     Standard_Integer  theArgNb,
5569                     const char**      theArgVec)
5570 {
5571   // get the context
5572   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5573   if (aContextAIS.IsNull())
5574   {
5575     Message::SendFail ("Error: no active viewer");
5576     return 1;
5577   }
5578
5579   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
5580   if (aDriver.IsNull())
5581   {
5582     Message::SendFail ("Error: graphic driver not available");
5583     return 1;
5584   }
5585
5586   Standard_Size aFreeBytes = 0;
5587   TCollection_AsciiString anInfo;
5588   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
5589   {
5590     Message::SendFail ("Error: information not available");
5591     return 1;
5592   }
5593
5594   if (theArgNb > 1 && *theArgVec[1] == 'f')
5595   {
5596     theDI << Standard_Real (aFreeBytes);
5597   }
5598   else
5599   {
5600     theDI << anInfo;
5601   }
5602
5603   return 0;
5604 }
5605
5606 // ==============================================================================
5607 // function : VReadPixel
5608 // purpose  :
5609 // ==============================================================================
5610 static int VReadPixel (Draw_Interpretor& theDI,
5611                        Standard_Integer  theArgNb,
5612                        const char**      theArgVec)
5613 {
5614   // get the active view
5615   Handle(V3d_View) aView = ViewerTest::CurrentView();
5616   if (aView.IsNull())
5617   {
5618     Message::SendFail ("Error: no active viewer");
5619     return 1;
5620   }
5621   else if (theArgNb < 3)
5622   {
5623     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
5624                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
5625     return 1;
5626   }
5627
5628   Image_Format         aFormat     = Image_Format_RGBA;
5629   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
5630
5631   Standard_Integer aWidth, aHeight;
5632   aView->Window()->Size (aWidth, aHeight);
5633   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
5634   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
5635   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
5636   {
5637     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
5638     return 1;
5639   }
5640
5641   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
5642   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
5643   {
5644     TCollection_AsciiString aParam (theArgVec[anIter]);
5645     aParam.LowerCase();
5646     if (aParam == "-rgb"
5647      || aParam == "rgb"
5648      || aParam == "-srgb"
5649      || aParam == "srgb")
5650     {
5651       aFormat     = Image_Format_RGB;
5652       aBufferType = Graphic3d_BT_RGB;
5653       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
5654     }
5655     else if (aParam == "-hls"
5656           || aParam == "hls")
5657     {
5658       aFormat     = Image_Format_RGB;
5659       aBufferType = Graphic3d_BT_RGB;
5660       toShowHls   = Standard_True;
5661     }
5662     else if (aParam == "-rgbf"
5663           || aParam == "rgbf")
5664     {
5665       aFormat     = Image_Format_RGBF;
5666       aBufferType = Graphic3d_BT_RGB;
5667     }
5668     else if (aParam == "-rgba"
5669           || aParam == "rgba"
5670           || aParam == "-srgba"
5671           || aParam == "srgba")
5672     {
5673       aFormat     = Image_Format_RGBA;
5674       aBufferType = Graphic3d_BT_RGBA;
5675       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
5676     }
5677     else if (aParam == "-rgbaf"
5678           || aParam == "rgbaf")
5679     {
5680       aFormat     = Image_Format_RGBAF;
5681       aBufferType = Graphic3d_BT_RGBA;
5682     }
5683     else if (aParam == "-depth"
5684           || aParam == "depth")
5685     {
5686       aFormat     = Image_Format_GrayF;
5687       aBufferType = Graphic3d_BT_Depth;
5688     }
5689     else if (aParam == "-name"
5690           || aParam == "name")
5691     {
5692       toShowName = Standard_True;
5693     }
5694     else if (aParam == "-hex"
5695           || aParam == "hex")
5696     {
5697       toShowHex = Standard_True;
5698     }
5699     else
5700     {
5701       Message::SendFail() << "Syntax error at '" << aParam << "'";
5702       return 1;
5703     }
5704   }
5705
5706   Image_PixMap anImage;
5707   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
5708   {
5709     Message::SendFail ("Error: image allocation failed");
5710     return 1;
5711   }
5712   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
5713   {
5714     Message::SendFail ("Error: image dump failed");
5715     return 1;
5716   }
5717
5718   // redirect possible warning messages that could have been added by ToPixMap
5719   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
5720   // contaminate result of the command
5721   Standard_CString aWarnLog = theDI.Result();
5722   if (aWarnLog != NULL && aWarnLog[0] != '\0')
5723   {
5724     std::cout << aWarnLog << std::endl;
5725   }
5726   theDI.Reset();
5727
5728   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
5729   if (toShowName)
5730   {
5731     if (aBufferType == Graphic3d_BT_RGBA)
5732     {
5733       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
5734     }
5735     else
5736     {
5737       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
5738     }
5739   }
5740   else if (toShowHex)
5741   {
5742     if (aBufferType == Graphic3d_BT_RGBA)
5743     {
5744       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
5745     }
5746     else
5747     {
5748       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
5749     }
5750   }
5751   else
5752   {
5753     switch (aBufferType)
5754     {
5755       default:
5756       case Graphic3d_BT_RGB:
5757       {
5758         if (toShowHls)
5759         {
5760           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
5761         }
5762         else if (toShow_sRGB)
5763         {
5764           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
5765           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
5766         }
5767         else
5768         {
5769           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
5770         }
5771         break;
5772       }
5773       case Graphic3d_BT_RGBA:
5774       {
5775         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
5776         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
5777         break;
5778       }
5779       case Graphic3d_BT_Depth:
5780       {
5781         theDI << aColor.GetRGB().Red();
5782         break;
5783       }
5784     }
5785   }
5786
5787   return 0;
5788 }
5789
5790 //! Auxiliary presentation for an image plane.
5791 class ViewerTest_ImagePrs : public AIS_InteractiveObject
5792 {
5793 public:
5794   //! Main constructor.
5795   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
5796                        const Standard_Real theWidth,
5797                        const Standard_Real theHeight,
5798                        const TCollection_AsciiString& theLabel)
5799   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
5800   {
5801     SetDisplayMode (0);
5802     SetHilightMode (1);
5803     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
5804     {
5805       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
5806       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
5807       Graphic3d_MaterialAspect aMat;
5808       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
5809       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
5810       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
5811       aMat.SetSpecularColor (Quantity_NOC_BLACK);
5812       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
5813       aFillAspect->SetFrontMaterial (aMat);
5814       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
5815       aFillAspect->SetTextureMapOn();
5816     }
5817     {
5818       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
5819       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
5820       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
5821       myDrawer->SetTextAspect (aTextAspect);
5822     }
5823     {
5824       const gp_Dir aNorm (0.0, 0.0, 1.0);
5825       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
5826       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
5827       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
5828       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
5829       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
5830       myTris->AddEdge (1);
5831       myTris->AddEdge (2);
5832       myTris->AddEdge (3);
5833       myTris->AddEdge (3);
5834       myTris->AddEdge (2);
5835       myTris->AddEdge (4);
5836
5837       myRect = new Graphic3d_ArrayOfPolylines (4);
5838       myRect->AddVertex (myTris->Vertice (1));
5839       myRect->AddVertex (myTris->Vertice (3));
5840       myRect->AddVertex (myTris->Vertice (4));
5841       myRect->AddVertex (myTris->Vertice (2));
5842     }
5843   }
5844
5845   //! Returns TRUE for accepted display modes.
5846   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
5847
5848   //! Compute presentation.
5849   virtual void Compute (const Handle(PrsMgr_PresentationManager)& ,
5850                         const Handle(Prs3d_Presentation)& thePrs,
5851                         const Standard_Integer theMode) Standard_OVERRIDE
5852   {
5853     switch (theMode)
5854     {
5855       case 0:
5856       {
5857         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
5858         aGroup->AddPrimitiveArray (myTris);
5859         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
5860         aGroup->AddPrimitiveArray (myRect);
5861         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
5862         return;
5863       }
5864       case 1:
5865       {
5866         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
5867         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
5868         aGroup->AddPrimitiveArray (myRect);
5869         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
5870         return;
5871       }
5872     }
5873   }
5874
5875   //! Compute selection.
5876   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
5877   {
5878     if (theMode == 0)
5879     {
5880       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
5881       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
5882       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
5883       theSel->Add (aSensitive);
5884     }
5885   }
5886
5887 private:
5888   Handle(Graphic3d_ArrayOfTriangles) myTris;
5889   Handle(Graphic3d_ArrayOfPolylines) myRect;
5890   TCollection_AsciiString myLabel;
5891   Standard_Real myWidth;
5892   Standard_Real myHeight;
5893 };
5894
5895 //==============================================================================
5896 //function : VDiffImage
5897 //purpose  : The draw-command compares two images.
5898 //==============================================================================
5899
5900 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
5901 {
5902   if (theArgNb < 3)
5903   {
5904     Message::SendFail ("Syntax error: not enough arguments");
5905     return 1;
5906   }
5907
5908   Standard_Integer anArgIter = 1;
5909   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
5910   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
5911   TCollection_AsciiString aDiffImagePath;
5912   Standard_Real    aTolColor        = -1.0;
5913   Standard_Integer toBlackWhite     = -1;
5914   Standard_Integer isBorderFilterOn = -1;
5915   Standard_Boolean isOldSyntax = Standard_False;
5916   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
5917   for (; anArgIter < theArgNb; ++anArgIter)
5918   {
5919     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5920     anArg.LowerCase();
5921     if (anArgIter + 1 < theArgNb
5922      && (anArg == "-toleranceofcolor"
5923       || anArg == "-tolerancecolor"
5924       || anArg == "-tolerance"
5925       || anArg == "-toler"))
5926     {
5927       aTolColor = Atof (theArgVec[++anArgIter]);
5928       if (aTolColor < 0.0 || aTolColor > 1.0)
5929       {
5930         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
5931         return 1;
5932       }
5933     }
5934     else if (anArg == "-blackwhite")
5935     {
5936       Standard_Boolean toEnable = Standard_True;
5937       if (anArgIter + 1 < theArgNb
5938        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
5939       {
5940         ++anArgIter;
5941       }
5942       toBlackWhite = toEnable ? 1 : 0;
5943     }
5944     else if (anArg == "-borderfilter")
5945     {
5946       Standard_Boolean toEnable = Standard_True;
5947       if (anArgIter + 1 < theArgNb
5948        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
5949       {
5950         ++anArgIter;
5951       }
5952       isBorderFilterOn = toEnable ? 1 : 0;
5953     }
5954     else if (anArg == "-exitonclose")
5955     {
5956       ViewerTest_EventManager::ToExitOnCloseView() = true;
5957       if (anArgIter + 1 < theArgNb
5958        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
5959       {
5960         ++anArgIter;
5961       }
5962     }
5963     else if (anArg == "-closeonescape"
5964           || anArg == "-closeonesc")
5965     {
5966       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
5967       if (anArgIter + 1 < theArgNb
5968        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
5969       {
5970         ++anArgIter;
5971       }
5972     }
5973     else if (anArgIter + 3 < theArgNb
5974           && anArg == "-display")
5975     {
5976       aViewName   = theArgVec[++anArgIter];
5977       aPrsNameRef = theArgVec[++anArgIter];
5978       aPrsNameNew = theArgVec[++anArgIter];
5979       if (anArgIter + 1 < theArgNb
5980       && *theArgVec[anArgIter + 1] != '-')
5981       {
5982         aPrsNameDiff = theArgVec[++anArgIter];
5983       }
5984     }
5985     else if (aTolColor < 0.0
5986           && anArg.IsRealValue (Standard_True))
5987     {
5988       isOldSyntax = Standard_True;
5989       aTolColor = anArg.RealValue();
5990       if (aTolColor < 0.0 || aTolColor > 1.0)
5991       {
5992         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
5993         return 1;
5994       }
5995     }
5996     else if (isOldSyntax
5997           && toBlackWhite == -1
5998           && (anArg == "0" || anArg == "1"))
5999     {
6000       toBlackWhite = anArg == "1" ? 1 : 0;
6001     }
6002     else if (isOldSyntax
6003           && isBorderFilterOn == -1
6004           && (anArg == "0" || anArg == "1"))
6005     {
6006       isBorderFilterOn = anArg == "1" ? 1 : 0;
6007     }
6008     else if (aDiffImagePath.IsEmpty())
6009     {
6010       aDiffImagePath = theArgVec[anArgIter];
6011     }
6012     else
6013     {
6014       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6015       return 1;
6016     }
6017   }
6018
6019   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
6020   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
6021   if (!anImgRef->Load (anImgPathRef))
6022   {
6023     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
6024     return 1;
6025   }
6026   if (!anImgNew->Load (anImgPathNew))
6027   {
6028     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
6029     return 1;
6030   }
6031
6032   // compare the images
6033   Image_Diff aComparer;
6034   Standard_Integer aDiffColorsNb = -1;
6035   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
6036   {
6037     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
6038     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
6039     aDiffColorsNb = aComparer.Compare();
6040     theDI << aDiffColorsNb << "\n";
6041   }
6042
6043   // save image of difference
6044   Handle(Image_AlienPixMap) aDiff;
6045   if (aDiffColorsNb > 0
6046   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
6047   {
6048     aDiff = new Image_AlienPixMap();
6049     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
6050     {
6051       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
6052       return 1;
6053     }
6054     aComparer.SaveDiffImage (*aDiff);
6055     if (!aDiffImagePath.IsEmpty()
6056      && !aDiff->Save (aDiffImagePath))
6057     {
6058       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
6059       return 1;
6060     }
6061   }
6062
6063   if (aViewName.IsEmpty())
6064   {
6065     return 0;
6066   }
6067
6068   ViewerTest_Names aViewNames (aViewName);
6069   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
6070   {
6071     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
6072     theDI.Eval (aCommand.ToCString());
6073   }
6074
6075   Standard_Integer aPxLeft = 0;
6076   Standard_Integer aPxTop  = 0;
6077   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
6078   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
6079                               ? int(anImgRef->SizeY() * 2)
6080                               : int(anImgRef->SizeY());
6081   TCollection_AsciiString aDisplayName;
6082   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
6083                                                             aViewName, aDisplayName);
6084
6085   Standard_Real aRatio = anImgRef->Ratio();
6086   Standard_Real aSizeX = 1.0;
6087   Standard_Real aSizeY = aSizeX / aRatio;
6088   {
6089     OSD_Path aPath (anImgPathRef);
6090     TCollection_AsciiString aLabelRef;
6091     if (!aPath.Name().IsEmpty())
6092     {
6093       aLabelRef = aPath.Name() + aPath.Extension();
6094     }
6095     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
6096
6097     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
6098     gp_Trsf aTrsfRef;
6099     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
6100     anImgRefPrs->SetLocalTransformation (aTrsfRef);
6101     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
6102   }
6103   {
6104     OSD_Path aPath (anImgPathNew);
6105     TCollection_AsciiString aLabelNew;
6106     if (!aPath.Name().IsEmpty())
6107     {
6108       aLabelNew = aPath.Name() + aPath.Extension();
6109     }
6110     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
6111
6112     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
6113     gp_Trsf aTrsfRef;
6114     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
6115     anImgNewPrs->SetLocalTransformation (aTrsfRef);
6116     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
6117   }
6118   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
6119   if (!aDiff.IsNull())
6120   {
6121     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
6122     gp_Trsf aTrsfDiff;
6123     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
6124     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
6125   }
6126   if (!aPrsNameDiff.IsEmpty())
6127   {
6128     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
6129   }
6130   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
6131   ViewerTest::CurrentView()->FitAll();
6132   return 0;
6133 }
6134
6135 //=======================================================================
6136 //function : VSelect
6137 //purpose  : Emulates different types of selection by mouse:
6138 //           1) single click selection
6139 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
6140 //           3) selection with polygon having corners at
6141 //           pixel positions (x1,y1),...,(xn,yn)
6142 //           4) any of these selections with shift button pressed
6143 //=======================================================================
6144 static Standard_Integer VSelect (Draw_Interpretor& ,
6145                                  Standard_Integer theNbArgs,
6146                                  const char** theArgVec)
6147 {
6148   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
6149   if (aCtx.IsNull())
6150   {
6151     Message::SendFail ("Error: no active viewer");
6152     return 1;
6153   }
6154
6155   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
6156   bool toAllowOverlap = false;
6157   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
6158   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6159   {
6160     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6161     anArg.LowerCase();
6162     if (anArg == "-allowoverlap")
6163     {
6164       toAllowOverlap = true;
6165       if (anArgIter + 1 < theNbArgs
6166        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
6167       {
6168         ++anArgIter;
6169       }
6170     }
6171     else if (anArg == "-replace")
6172     {
6173       aSelScheme = AIS_SelectionScheme_Replace;
6174     }
6175     else if (anArg == "-replaceextra")
6176     {
6177       aSelScheme = AIS_SelectionScheme_ReplaceExtra;
6178     }
6179     else if (anArg == "-xor"
6180           || anArg == "-shift")
6181     {
6182       aSelScheme = AIS_SelectionScheme_XOR;
6183     }
6184     else if (anArg == "-add")
6185     {
6186       aSelScheme = AIS_SelectionScheme_Add;
6187     }
6188     else if (anArg == "-remove")
6189     {
6190       aSelScheme = AIS_SelectionScheme_Remove;
6191     }
6192     else if (anArgIter + 1 < theNbArgs
6193           && anArg.IsIntegerValue()
6194           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
6195     {
6196       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
6197       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
6198     }
6199     else if (anArgIter + 1 == theNbArgs
6200           && anArg.IsIntegerValue())
6201     {
6202       if (anArg.IntegerValue() == 1)
6203       {
6204         aSelScheme = AIS_SelectionScheme_XOR;
6205       }
6206     }
6207     else
6208     {
6209       Message::SendFail() << "Syntax error at '" << anArg << "'";
6210       return 1;
6211     }
6212   }
6213
6214   if (toAllowOverlap)
6215   {
6216     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
6217   }
6218
6219   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
6220   if (aPnts.IsEmpty())
6221   {
6222     aCtx->SelectDetected (aSelScheme);
6223     aCtx->CurrentViewer()->Invalidate();
6224   }
6225   else if (aPnts.Length() == 2)
6226   {
6227     if (toAllowOverlap
6228      && aPnts.First().y() < aPnts.Last().y())
6229     {
6230       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6231     }
6232     else if (!toAllowOverlap
6233            && aPnts.First().y() > aPnts.Last().y())
6234     {
6235       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6236     }
6237
6238     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6239   }
6240   else
6241   {
6242     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
6243   }
6244   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
6245   return 0;
6246 }
6247
6248 //=======================================================================
6249 //function : VMoveTo
6250 //purpose  : Emulates cursor movement to defined pixel position
6251 //=======================================================================
6252 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
6253                                 Standard_Integer theNbArgs,
6254                                 const char**     theArgVec)
6255 {
6256   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6257   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6258   if (aContext.IsNull())
6259   {
6260     Message::SendFail ("Error: no active viewer");
6261     return 1;
6262   }
6263
6264   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
6265   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6266   {
6267     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6268     anArgStr.LowerCase();
6269     if (anArgStr == "-reset"
6270      || anArgStr == "-clear")
6271     {
6272       if (anArgIter + 1 < theNbArgs)
6273       {
6274         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
6275         return 1;
6276       }
6277
6278       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
6279                                        && aContext->CurrentViewer()->GridEcho();
6280       if (toEchoGrid)
6281       {
6282         aContext->CurrentViewer()->HideGridEcho (aView);
6283       }
6284       if (aContext->ClearDetected() || toEchoGrid)
6285       {
6286         aContext->CurrentViewer()->RedrawImmediate();
6287       }
6288       return 0;
6289     }
6290     else if (aMousePos.x() == IntegerLast()
6291           && anArgStr.IsIntegerValue())
6292     {
6293       aMousePos.x() = anArgStr.IntegerValue();
6294     }
6295     else if (aMousePos.y() == IntegerLast()
6296           && anArgStr.IsIntegerValue())
6297     {
6298       aMousePos.y() = anArgStr.IntegerValue();
6299     }
6300     else
6301     {
6302       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6303       return 1;
6304     }
6305   }
6306
6307   if (aMousePos.x() == IntegerLast()
6308    || aMousePos.y() == IntegerLast())
6309   {
6310     Message::SendFail ("Syntax error: wrong number of arguments");
6311     return 1;
6312   }
6313
6314   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
6315   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
6316   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
6317
6318   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
6319   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
6320   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
6321   {
6322     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
6323     {
6324       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
6325       break;
6326     }
6327   }
6328   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
6329   return 0;
6330 }
6331
6332 //=======================================================================
6333 //function : VSelectByAxis
6334 //purpose  :
6335 //=======================================================================
6336 static Standard_Integer VSelectByAxis (Draw_Interpretor& theDI,
6337                                        Standard_Integer theNbArgs,
6338                                        const char**     theArgVec)
6339 {
6340   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
6341   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
6342   if (aContext.IsNull())
6343   {
6344     Message::SendFail ("Error: no active viewer");
6345     return 1;
6346   }
6347
6348   TCollection_AsciiString aName;
6349   gp_XYZ anAxisLocation(RealLast(), RealLast(), RealLast());
6350   gp_XYZ anAxisDirection(RealLast(), RealLast(), RealLast());
6351   Standard_Boolean isOnlyTop = true;
6352   Standard_Boolean toShowNormal = false;
6353   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6354   {
6355     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
6356     anArgStr.LowerCase();
6357     if (anArgStr == "-display")
6358     {
6359       if (anArgIter + 1 >= theNbArgs)
6360       {
6361         Message::SendFail() << "Syntax error at argument '" << anArgStr << "'";
6362         return 1;
6363       }
6364       aName = theArgVec[++anArgIter];
6365     }
6366     else if (anArgStr == "-onlytop")
6367     {
6368       isOnlyTop = true;
6369       if (anArgIter + 1 < theNbArgs
6370         && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOnlyTop))
6371       {
6372         ++anArgIter;
6373       }
6374     }
6375     else if (anArgStr == "-shownormal")
6376     {
6377       toShowNormal = true;
6378       if (anArgIter + 1 < theNbArgs
6379         && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShowNormal))
6380       {
6381         ++anArgIter;
6382       }
6383     }
6384     else if (Precision::IsInfinite(anAxisLocation.X())
6385           && anArgStr.IsRealValue())
6386     {
6387       anAxisLocation.SetX (anArgStr.RealValue());
6388     }
6389     else if (Precision::IsInfinite(anAxisLocation.Y())
6390           && anArgStr.IsRealValue())
6391     {
6392       anAxisLocation.SetY (anArgStr.RealValue());
6393     }
6394     else if (Precision::IsInfinite(anAxisLocation.Z())
6395           && anArgStr.IsRealValue())
6396     {
6397       anAxisLocation.SetZ (anArgStr.RealValue());
6398     }
6399     else if (Precision::IsInfinite(anAxisDirection.X())
6400           && anArgStr.IsRealValue())
6401     {
6402       anAxisDirection.SetX (anArgStr.RealValue());
6403     }
6404     else if (Precision::IsInfinite(anAxisDirection.Y())
6405           && anArgStr.IsRealValue())
6406     {
6407       anAxisDirection.SetY (anArgStr.RealValue());
6408     }
6409     else if (Precision::IsInfinite(anAxisDirection.Z())
6410           && anArgStr.IsRealValue())
6411     {
6412       anAxisDirection.SetZ (anArgStr.RealValue());
6413     }
6414     else
6415     {
6416       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6417       return 1;
6418     }
6419   }
6420
6421   if (Precision::IsInfinite (anAxisLocation.X()) ||
6422       Precision::IsInfinite (anAxisLocation.Y()) ||
6423       Precision::IsInfinite (anAxisLocation.Z()) ||
6424       Precision::IsInfinite (anAxisDirection.X()) ||
6425       Precision::IsInfinite (anAxisDirection.Y()) ||
6426       Precision::IsInfinite (anAxisDirection.Z()))
6427   {
6428     Message::SendFail() << "Invalid axis location and direction";
6429     return 1;
6430   }
6431
6432   gp_Ax1 anAxis(anAxisLocation, anAxisDirection);
6433   gp_Pnt aTopPnt;
6434   if (!ViewerTest::CurrentEventManager()->PickAxis (aTopPnt, aContext, aView, anAxis))
6435   {
6436     theDI << "There are no any intersections with this axis.";
6437     return 0;
6438   }
6439   NCollection_Sequence<gp_Pnt> aPoints;
6440   NCollection_Sequence<Graphic3d_Vec3> aNormals;
6441   NCollection_Sequence<Standard_Real> aNormalLengths;
6442   for (Standard_Integer aPickIter = 1; aPickIter <= aContext->MainSelector()->NbPicked(); ++aPickIter)
6443   {
6444     const SelectMgr_SortCriterion& aPickedData = aContext->MainSelector()->PickedData (aPickIter);
6445     aPoints.Append (aPickedData.Point);
6446     aNormals.Append (aPickedData.Normal);
6447     Standard_Real aNormalLength = 1.0;
6448     if (!aPickedData.Entity.IsNull())
6449     {
6450       aNormalLength = 0.2 * aPickedData.Entity->BoundingBox().Size().maxComp();
6451     }
6452     aNormalLengths.Append (aNormalLength);
6453   }
6454   if (!aName.IsEmpty())
6455   {
6456     Standard_Boolean wasAuto = aContext->GetAutoActivateSelection();
6457     aContext->SetAutoActivateSelection (false);
6458
6459     // Display axis
6460     Quantity_Color anAxisColor = Quantity_NOC_GREEN;
6461     Handle(Geom_Axis2Placement) anAx2Axis =
6462       new Geom_Axis2Placement (gp_Ax2(anAxisLocation, anAxisDirection));
6463     Handle(AIS_Axis) anAISAxis = new AIS_Axis (gp_Ax1 (anAxisLocation, anAxisDirection));
6464     anAISAxis->SetColor (anAxisColor);
6465     ViewerTest::Display (TCollection_AsciiString (aName) + "_axis", anAISAxis, false);
6466
6467     // Display axis start point
6468     Handle(AIS_Point) anAISStartPnt = new AIS_Point (new Geom_CartesianPoint (anAxisLocation));
6469     anAISStartPnt->SetMarker (Aspect_TOM_O);
6470     anAISStartPnt->SetColor (anAxisColor);
6471     ViewerTest::Display (TCollection_AsciiString(aName) + "_start", anAISStartPnt, false);
6472
6473     Standard_Integer anIndex = 0;
6474     for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter(aPoints); aPntIter.More(); aPntIter.Next(), anIndex++)
6475     {
6476       const gp_Pnt& aPoint = aPntIter.Value();
6477
6478       // Display normals in intersection points
6479       if (toShowNormal)
6480       {
6481         const Graphic3d_Vec3& aNormal = aNormals.Value (anIndex + 1);
6482         Standard_Real aNormalLength = aNormalLengths.Value (anIndex + 1);
6483         if (aNormal.SquareModulus() > ShortRealEpsilon())
6484         {
6485           gp_Dir aNormalDir ((Standard_Real)aNormal.x(), (Standard_Real)aNormal.y(), (Standard_Real)aNormal.z());
6486           Handle(AIS_Axis) anAISNormal = new AIS_Axis (gp_Ax1 (aPoint, aNormalDir), aNormalLength);
6487           anAISNormal->SetColor (Quantity_NOC_BLUE);
6488           anAISNormal->SetInfiniteState (false);
6489           ViewerTest::Display (TCollection_AsciiString(aName) + "_normal_" + anIndex, anAISNormal, false);
6490         }
6491       }
6492
6493       // Display intersection points
6494       Handle(Geom_CartesianPoint) anIntersectPnt = new Geom_CartesianPoint (aPoint);
6495       Handle(AIS_Point) anAISIntersectPoint = new AIS_Point (anIntersectPnt);
6496       anAISIntersectPoint->SetMarker (Aspect_TOM_PLUS);
6497       anAISIntersectPoint->SetColor (Quantity_NOC_RED);
6498       ViewerTest::Display (TCollection_AsciiString(aName) + "_intersect_" + anIndex, anAISIntersectPoint, true);
6499     }
6500
6501     aContext->SetAutoActivateSelection (wasAuto);
6502   }
6503
6504   Standard_Integer anIndex = 0;
6505   for (NCollection_Sequence<gp_Pnt>::Iterator anIter(aPoints); anIter.More(); anIter.Next(), anIndex++)
6506   {
6507     const gp_Pnt& aPnt = anIter.Value();
6508     theDI << aPnt.X() << " " << aPnt.Y() << " " << aPnt.Z() << "\n";
6509   }
6510   return 0;
6511 }
6512
6513 namespace
6514 {
6515   //! Global map storing all animations registered in ViewerTest.
6516   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
6517
6518   //! The animation calling the Draw Harness command.
6519   class ViewerTest_AnimationProc : public AIS_Animation
6520   {
6521     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationProc, AIS_Animation)
6522   public:
6523
6524     //! Main constructor.
6525     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
6526                               Draw_Interpretor* theDI,
6527                               const TCollection_AsciiString& theCommand)
6528     : AIS_Animation (theAnimationName),
6529       myDrawInter(theDI),
6530       myCommand  (theCommand)
6531     {
6532       //
6533     }
6534
6535   protected:
6536
6537     //! Evaluate the command.
6538     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
6539     {
6540       TCollection_AsciiString aCmd = myCommand;
6541       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
6542       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
6543       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
6544       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
6545       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
6546       myDrawInter->Eval (aCmd.ToCString());
6547     }
6548
6549     //! Find the keyword in the command and replace it with value.
6550     //! @return the position of the keyword to pass value
6551     void replace (TCollection_AsciiString&       theCmd,
6552                   const TCollection_AsciiString& theKey,
6553                   const TCollection_AsciiString& theVal)
6554     {
6555       TCollection_AsciiString aCmd (theCmd);
6556       aCmd.LowerCase();
6557       const Standard_Integer aPos = aCmd.Search (theKey);
6558       if (aPos == -1)
6559       {
6560         return;
6561       }
6562
6563       TCollection_AsciiString aPart1, aPart2;
6564       Standard_Integer aPart1To = aPos - 1;
6565       if (aPart1To >= 1
6566        && aPart1To <= theCmd.Length())
6567       {
6568         aPart1 = theCmd.SubString (1, aPart1To);
6569       }
6570
6571       Standard_Integer aPart2From = aPos + theKey.Length();
6572       if (aPart2From >= 1
6573        && aPart2From <= theCmd.Length())
6574       {
6575         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
6576       }
6577
6578       theCmd = aPart1 + theVal + aPart2;
6579     }
6580
6581   protected:
6582
6583     Draw_Interpretor*       myDrawInter;
6584     TCollection_AsciiString myCommand;
6585
6586   };
6587
6588   //! Auxiliary animation holder.
6589   class ViewerTest_AnimationHolder : public AIS_AnimationCamera
6590   {
6591     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationHolder, AIS_AnimationCamera)
6592   public:
6593     ViewerTest_AnimationHolder (const Handle(AIS_Animation)& theAnim,
6594                                 const Handle(V3d_View)& theView,
6595                                 const Standard_Boolean theIsFreeView)
6596     : AIS_AnimationCamera ("ViewerTest_AnimationHolder", Handle(V3d_View)())
6597     {
6598       if (theAnim->Timer().IsNull())
6599       {
6600         theAnim->SetTimer (new Media_Timer());
6601       }
6602       myTimer = theAnim->Timer();
6603       myView = theView;
6604       if (theIsFreeView)
6605       {
6606         myCamStart = new Graphic3d_Camera (theView->Camera());
6607       }
6608       Add (theAnim);
6609     }
6610
6611     //! Start playback.
6612     virtual void StartTimer (const Standard_Real    theStartPts,
6613                              const Standard_Real    thePlaySpeed,
6614                              const Standard_Boolean theToUpdate,
6615                              const Standard_Boolean theToStopTimer) Standard_OVERRIDE
6616     {
6617       base_type::StartTimer (theStartPts, thePlaySpeed, theToUpdate, theToStopTimer);
6618       if (theToStopTimer)
6619       {
6620         abortPlayback();
6621       }
6622     }
6623
6624     //! Pause animation.
6625     virtual void Pause() Standard_OVERRIDE
6626     {
6627       myState = AnimationState_Paused;
6628       // default implementation would stop all children,
6629       // but we want to keep wrapped animation paused
6630       myAnimations.First()->Pause();
6631       abortPlayback();
6632     }
6633
6634     //! Stop animation.
6635     virtual void Stop() Standard_OVERRIDE
6636     {
6637       base_type::Stop();
6638       abortPlayback();
6639     }
6640
6641     //! Process one step of the animation according to the input time progress, including all children.
6642     virtual void updateWithChildren (const AIS_AnimationProgress& thePosition) Standard_OVERRIDE
6643     {
6644       Handle(V3d_View) aView = myView;
6645       if (!aView.IsNull()
6646        && !myCamStart.IsNull())
6647       {
6648         myCamStart->Copy (aView->Camera());
6649       }
6650       base_type::updateWithChildren (thePosition);
6651       if (!aView.IsNull()
6652        && !myCamStart.IsNull())
6653       {
6654         aView->Camera()->Copy (myCamStart);
6655       }
6656     }
6657   private:
6658     void abortPlayback()
6659     {
6660       if (!myView.IsNull())
6661       {
6662         myView.Nullify();
6663       }
6664     }
6665   };
6666
6667   //! Replace the animation with the new one.
6668   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
6669                                 Handle(AIS_Animation)&       theAnimation,
6670                                 const Handle(AIS_Animation)& theAnimationNew)
6671   {
6672     theAnimationNew->CopyFrom (theAnimation);
6673     if (!theParentAnimation.IsNull())
6674     {
6675       theParentAnimation->Replace (theAnimation, theAnimationNew);
6676     }
6677     else
6678     {
6679       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
6680       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
6681     }
6682     theAnimation = theAnimationNew;
6683   }
6684
6685   //! Parse the point.
6686   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
6687   {
6688     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
6689     if (!anXYZ[0].IsRealValue (Standard_True)
6690      || !anXYZ[1].IsRealValue (Standard_True)
6691      || !anXYZ[2].IsRealValue (Standard_True))
6692     {
6693       return Standard_False;
6694     }
6695
6696     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
6697     return Standard_True;
6698   }
6699
6700   //! Parse the quaternion.
6701   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
6702   {
6703     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
6704     if (!anXYZW[0].IsRealValue (Standard_True)
6705      || !anXYZW[1].IsRealValue (Standard_True)
6706      || !anXYZW[2].IsRealValue (Standard_True)
6707      || !anXYZW[3].IsRealValue (Standard_True))
6708     {
6709       return Standard_False;
6710     }
6711
6712     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
6713     return Standard_True;
6714   }
6715
6716   //! Auxiliary class for flipping image upside-down.
6717   class ImageFlipper
6718   {
6719   public:
6720
6721     //! Empty constructor.
6722     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
6723
6724     //! Perform flipping.
6725     Standard_Boolean FlipY (Image_PixMap& theImage)
6726     {
6727       if (theImage.IsEmpty()
6728        || theImage.SizeX() == 0
6729        || theImage.SizeY() == 0)
6730       {
6731         return Standard_False;
6732       }
6733
6734       const Standard_Size aRowSize = theImage.SizeRowBytes();
6735       if (myTmp.Size() < aRowSize
6736       && !myTmp.Allocate (aRowSize))
6737       {
6738         return Standard_False;
6739       }
6740
6741       // for odd height middle row should be left as is
6742       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
6743       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
6744       {
6745         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
6746         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
6747         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
6748         memcpy (aTop,               aBot,         aRowSize);
6749         memcpy (aBot,               myTmp.Data(), aRowSize);
6750       }
6751       return Standard_True;
6752     }
6753
6754   private:
6755     NCollection_Buffer myTmp;
6756   };
6757
6758 }
6759
6760 //=================================================================================================
6761 //function : VViewParams
6762 //purpose  : Gets or sets AIS View characteristics
6763 //=================================================================================================
6764 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
6765 {
6766   Handle(V3d_View) aView = ViewerTest::CurrentView();
6767   if (aView.IsNull())
6768   {
6769     Message::SendFail ("Error: no active viewer");
6770     return 1;
6771   }
6772
6773   Standard_Boolean toSetProj     = Standard_False;
6774   Standard_Boolean toSetUp       = Standard_False;
6775   Standard_Boolean toSetAt       = Standard_False;
6776   Standard_Boolean toSetEye      = Standard_False;
6777   Standard_Boolean toSetScale    = Standard_False;
6778   Standard_Boolean toSetSize     = Standard_False;
6779   Standard_Boolean toSetCenter2d = Standard_False;
6780   Standard_Real    aViewScale = aView->Scale();
6781   Standard_Real    aViewAspect = aView->Camera()->Aspect();
6782   Standard_Real    aViewSize  = 1.0;
6783   Graphic3d_Vec2i  aCenter2d;
6784   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
6785   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
6786   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
6787   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
6788   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
6789   const Graphic3d_Mat4d& anOrientMat = aView->Camera()->OrientationMatrix();
6790   const Graphic3d_Mat4d& aProjMat = aView->Camera()->ProjectionMatrix();
6791   if (theArgsNb == 1)
6792   {
6793     // print all of the available view parameters
6794     char aText[4096];
6795     Sprintf (aText,
6796              "Scale:  %g\n"
6797              "Aspect: %g\n"
6798              "Proj:   %12g %12g %12g\n"
6799              "Up:     %12g %12g %12g\n"
6800              "At:     %12g %12g %12g\n"
6801              "Eye:    %12g %12g %12g\n"
6802              "OrientMat:    %12g %12g %12g %12g\n"
6803              "              %12g %12g %12g %12g\n"
6804              "              %12g %12g %12g %12g\n"
6805              "              %12g %12g %12g %12g\n"
6806              "ProjMat:      %12g %12g %12g %12g\n"
6807              "              %12g %12g %12g %12g\n"
6808              "              %12g %12g %12g %12g\n"
6809              "              %12g %12g %12g %12g\n",
6810               aViewScale, aViewAspect,
6811               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6812               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6813               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
6814               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z(),
6815               anOrientMat.GetValue (0, 0), anOrientMat.GetValue (0, 1), anOrientMat.GetValue (0, 2), anOrientMat.GetValue (0, 3),
6816               anOrientMat.GetValue (1, 0), anOrientMat.GetValue (1, 1), anOrientMat.GetValue (1, 2), anOrientMat.GetValue (1, 3),
6817               anOrientMat.GetValue (2, 0), anOrientMat.GetValue (2, 1), anOrientMat.GetValue (2, 2), anOrientMat.GetValue (2, 3),
6818               anOrientMat.GetValue (3, 0), anOrientMat.GetValue (3, 1), anOrientMat.GetValue (3, 2), anOrientMat.GetValue (3, 3),
6819               aProjMat.GetValue (0, 0), aProjMat.GetValue (0, 1), aProjMat.GetValue (0, 2), aProjMat.GetValue (0, 3),
6820               aProjMat.GetValue (1, 0), aProjMat.GetValue (1, 1), aProjMat.GetValue (1, 2), aProjMat.GetValue (1, 3),
6821               aProjMat.GetValue (2, 0), aProjMat.GetValue (2, 1), aProjMat.GetValue (2, 2), aProjMat.GetValue (2, 3),
6822               aProjMat.GetValue (3, 0), aProjMat.GetValue (3, 1), aProjMat.GetValue (3, 2), aProjMat.GetValue (3, 3));
6823     theDi << aText;
6824     return 0;
6825   }
6826
6827   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
6828   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
6829   {
6830     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6831     anArg.LowerCase();
6832     if (anUpdateTool.parseRedrawMode (anArg))
6833     {
6834       continue;
6835     }
6836     else if (anArg == "-cmd"
6837           || anArg == "-command"
6838           || anArg == "-args")
6839     {
6840       char aText[4096];
6841       Sprintf (aText,
6842                "-scale %g "
6843                "-proj %g %g %g "
6844                "-up %g %g %g "
6845                "-at %g %g %g\n",
6846                 aViewScale,
6847                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
6848                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
6849                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
6850       theDi << aText;
6851     }
6852     else if (anArg == "-scale"
6853           || anArg == "-size")
6854     {
6855       if (anArgIter + 1 < theArgsNb
6856        && *theArgVec[anArgIter + 1] != '-')
6857       {
6858         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
6859         if (aValueArg.IsRealValue (Standard_True))
6860         {
6861           ++anArgIter;
6862           if (anArg == "-scale")
6863           {
6864             toSetScale = Standard_True;
6865             aViewScale = aValueArg.RealValue();
6866           }
6867           else if (anArg == "-size")
6868           {
6869             toSetSize = Standard_True;
6870             aViewSize = aValueArg.RealValue();
6871           }
6872           continue;
6873         }
6874       }
6875       if (anArg == "-scale")
6876       {
6877         theDi << "Scale: " << aView->Scale() << "\n";
6878       }
6879       else if (anArg == "-size")
6880       {
6881         Graphic3d_Vec2d aSizeXY;
6882         aView->Size (aSizeXY.x(), aSizeXY.y());
6883         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
6884       }
6885     }
6886     else if (anArg == "-eye"
6887           || anArg == "-at"
6888           || anArg == "-up"
6889           || anArg == "-proj")
6890     {
6891       if (anArgIter + 3 < theArgsNb)
6892       {
6893         gp_XYZ anXYZ;
6894         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
6895         {
6896           anArgIter += 3;
6897           if (anArg == "-eye")
6898           {
6899             toSetEye = Standard_True;
6900             aViewEye = anXYZ;
6901           }
6902           else if (anArg == "-at")
6903           {
6904             toSetAt = Standard_True;
6905             aViewAt = anXYZ;
6906           }
6907           else if (anArg == "-up")
6908           {
6909             toSetUp = Standard_True;
6910             aViewUp = anXYZ;
6911           }
6912           else if (anArg == "-proj")
6913           {
6914             toSetProj = Standard_True;
6915             aViewProj = anXYZ;
6916           }
6917           continue;
6918         }
6919       }
6920
6921       if (anArg == "-eye")
6922       {
6923         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
6924       }
6925       else if (anArg == "-at")
6926       {
6927         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
6928       }
6929       else if (anArg == "-up")
6930       {
6931         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
6932       }
6933       else if (anArg == "-proj")
6934       {
6935         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
6936       }
6937     }
6938     else if (anArg == "-center")
6939     {
6940       if (anArgIter + 2 < theArgsNb)
6941       {
6942         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
6943         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
6944         if (anX.IsIntegerValue()
6945          && anY.IsIntegerValue())
6946         {
6947           toSetCenter2d = Standard_True;
6948           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
6949         }
6950       }
6951     }
6952     else
6953     {
6954       Message::SendFail() << "Syntax error at '" << anArg << "'";
6955       return 1;
6956     }
6957   }
6958
6959   // change view parameters in proper order
6960   if (toSetScale)
6961   {
6962     aView->SetScale (aViewScale);
6963   }
6964   if (toSetSize)
6965   {
6966     aView->SetSize (aViewSize);
6967   }
6968   if (toSetEye)
6969   {
6970     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
6971   }
6972   if (toSetAt)
6973   {
6974     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
6975   }
6976   if (toSetProj)
6977   {
6978     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
6979   }
6980   if (toSetUp)
6981   {
6982     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
6983   }
6984   if (toSetCenter2d)
6985   {
6986     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
6987   }
6988
6989   return 0;
6990 }
6991
6992 //==============================================================================
6993 //function : V2DMode
6994 //purpose  :
6995 //==============================================================================
6996 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
6997 {
6998   bool is2dMode = true;
6999   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
7000   if (aV3dView.IsNull())
7001   {
7002     Message::SendFail ("Error: no active viewer");
7003     return 1;
7004   }
7005   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
7006   {
7007     const TCollection_AsciiString anArg = theArgVec[anArgIt];
7008     TCollection_AsciiString anArgCase = anArg;
7009     anArgCase.LowerCase();
7010     if (anArgIt + 1 < theArgsNb
7011      && anArgCase == "-name")
7012     {
7013       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
7014       TCollection_AsciiString aViewName = aViewNames.GetViewName();
7015       if (!ViewerTest_myViews.IsBound1 (aViewName))
7016       {
7017         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
7018         return 1;
7019       }
7020       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
7021     }
7022     else if (anArgCase == "-mode")
7023     {
7024       if (anArgIt + 1 < theArgsNb
7025        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
7026       {
7027         ++anArgIt;
7028       }
7029     }
7030     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
7031     {
7032       //
7033     }
7034     else
7035     {
7036       Message::SendFail() << "Syntax error: unknown argument " << anArg;
7037       return 1;
7038     }
7039   }
7040
7041   aV3dView->SetView2DMode (is2dMode);
7042   return 0;
7043 }
7044
7045 //==============================================================================
7046 //function : VAnimation
7047 //purpose  :
7048 //==============================================================================
7049 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
7050                                     Standard_Integer  theArgNb,
7051                                     const char**      theArgVec)
7052 {
7053   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
7054   if (theArgNb < 2)
7055   {
7056     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
7057          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
7058     {
7059       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
7060     }
7061     return 0;
7062   }
7063   if (aCtx.IsNull())
7064   {
7065     Message::SendFail ("Error: no active viewer");
7066     return 1;
7067   }
7068
7069   Standard_Integer anArgIter = 1;
7070   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
7071   if (aNameArg.IsEmpty())
7072   {
7073     Message::SendFail ("Syntax error: animation name is not defined");
7074     return 1;
7075   }
7076
7077   TCollection_AsciiString aNameArgLower = aNameArg;
7078   aNameArgLower.LowerCase();
7079   if (aNameArgLower == "-reset"
7080    || aNameArgLower == "-clear")
7081   {
7082     ViewerTest_AnimationTimelineMap.Clear();
7083     return 0;
7084   }
7085   else if (aNameArg.Value (1) == '-')
7086   {
7087     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
7088     return 1;
7089   }
7090
7091   const char* aNameSplitter = "/";
7092   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
7093   if (aSplitPos == -1)
7094   {
7095     aNameSplitter = ".";
7096     aSplitPos = aNameArg.Search (aNameSplitter);
7097   }
7098
7099   // find existing or create a new animation by specified name within syntax "parent.child".
7100   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
7101   for (; !aNameArg.IsEmpty();)
7102   {
7103     TCollection_AsciiString aNameParent;
7104     if (aSplitPos != -1)
7105     {
7106       if (aSplitPos == aNameArg.Length())
7107       {
7108         Message::SendFail ("Syntax error: animation name is not defined");
7109         return 1;
7110       }
7111
7112       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
7113       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
7114
7115       aSplitPos = aNameArg.Search (aNameSplitter);
7116     }
7117     else
7118     {
7119       aNameParent = aNameArg;
7120       aNameArg.Clear();
7121     }
7122
7123     if (anAnimation.IsNull())
7124     {
7125       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
7126       {
7127         anAnimation = new AIS_Animation (aNameParent);
7128         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
7129       }
7130       aRootAnimation = anAnimation;
7131     }
7132     else
7133     {
7134       aParentAnimation = anAnimation;
7135       anAnimation = aParentAnimation->Find (aNameParent);
7136       if (anAnimation.IsNull())
7137       {
7138         anAnimation = new AIS_Animation (aNameParent);
7139         aParentAnimation->Add (anAnimation);
7140       }
7141     }
7142   }
7143   if (anAnimation.IsNull())
7144   {
7145     Message::SendFail() << "Syntax error: wrong number of arguments";
7146     return 1;
7147   }
7148
7149   if (anArgIter >= theArgNb)
7150   {
7151     // just print the list of children
7152     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
7153     {
7154       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
7155     }
7156     return 0;
7157   }
7158
7159   // animation parameters
7160   Standard_Boolean toPlay = Standard_False;
7161   Standard_Real aPlaySpeed     = 1.0;
7162   Standard_Real aPlayStartTime = anAnimation->StartPts();
7163   Standard_Real aPlayDuration  = anAnimation->Duration();
7164   Standard_Boolean isFreeCamera = Standard_False;
7165   Standard_Boolean toPauseOnClick = Standard_True;
7166   Standard_Boolean isLockLoop   = Standard_False;
7167
7168   // video recording parameters
7169   TCollection_AsciiString aRecFile;
7170   Image_VideoParams aRecParams;
7171
7172   Handle(V3d_View) aView = ViewerTest::CurrentView();
7173   for (; anArgIter < theArgNb; ++anArgIter)
7174   {
7175     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7176     anArg.LowerCase();
7177     // general options
7178     if (anArg == "-reset"
7179      || anArg == "-clear")
7180     {
7181       anAnimation->Clear();
7182     }
7183     else if (anArg == "-remove"
7184           || anArg == "-del"
7185           || anArg == "-delete")
7186     {
7187       if (aParentAnimation.IsNull())
7188       {
7189         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
7190       }
7191       else
7192       {
7193         aParentAnimation->Remove (anAnimation);
7194       }
7195     }
7196     // playback options
7197     else if (anArg == "-play")
7198     {
7199       toPlay = Standard_True;
7200       if (++anArgIter < theArgNb)
7201       {
7202         if (*theArgVec[anArgIter] == '-')
7203         {
7204           --anArgIter;
7205           continue;
7206         }
7207         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
7208
7209         if (++anArgIter < theArgNb)
7210         {
7211           if (*theArgVec[anArgIter] == '-')
7212           {
7213             --anArgIter;
7214             continue;
7215           }
7216           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7217         }
7218       }
7219     }
7220     else if (anArg == "-resume")
7221     {
7222       toPlay = Standard_True;
7223       aPlayStartTime = anAnimation->ElapsedTime();
7224       if (++anArgIter < theArgNb)
7225       {
7226         if (*theArgVec[anArgIter] == '-')
7227         {
7228           --anArgIter;
7229           continue;
7230         }
7231
7232         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7233       }
7234     }
7235     else if (anArg == "-pause")
7236     {
7237       anAnimation->Pause();
7238     }
7239     else if (anArg == "-stop")
7240     {
7241       anAnimation->Stop();
7242     }
7243     else if (anArg == "-playspeed"
7244           || anArg == "-speed")
7245     {
7246       if (++anArgIter >= theArgNb)
7247       {
7248         Message::SendFail() << "Syntax error at " << anArg << "";
7249         return 1;
7250       }
7251       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
7252     }
7253     else if (anArg == "-lock"
7254           || anArg == "-lockloop"
7255           || anArg == "-playlockloop")
7256     {
7257       isLockLoop = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
7258     }
7259     else if (anArg == "-freecamera"
7260           || anArg == "-nofreecamera"
7261           || anArg == "-playfreecamera"
7262           || anArg == "-noplayfreecamera"
7263           || anArg == "-freelook"
7264           || anArg == "-nofreelook")
7265     {
7266       isFreeCamera = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7267     }
7268     else if (anArg == "-pauseonclick"
7269           || anArg == "-nopauseonclick"
7270           || anArg == "-nopause")
7271     {
7272       toPauseOnClick = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
7273     }
7274     // video recodring options
7275     else if (anArg == "-rec"
7276           || anArg == "-record")
7277     {
7278       if (++anArgIter >= theArgNb)
7279       {
7280         Message::SendFail() << "Syntax error at " << anArg;
7281         return 1;
7282       }
7283
7284       aRecFile = theArgVec[anArgIter];
7285       if (aRecParams.FpsNum <= 0)
7286       {
7287         aRecParams.FpsNum = 24;
7288       }
7289
7290       if (anArgIter + 2 < theArgNb
7291       && *theArgVec[anArgIter + 1] != '-'
7292       && *theArgVec[anArgIter + 2] != '-')
7293       {
7294         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
7295         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
7296         if (aWidthArg .IsIntegerValue()
7297          && aHeightArg.IsIntegerValue())
7298         {
7299           aRecParams.Width  = aWidthArg .IntegerValue();
7300           aRecParams.Height = aHeightArg.IntegerValue();
7301           anArgIter += 2;
7302         }
7303       }
7304     }
7305     else if (anArg == "-fps")
7306     {
7307       if (++anArgIter >= theArgNb)
7308       {
7309         Message::SendFail() << "Syntax error at " << anArg;
7310         return 1;
7311       }
7312
7313       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
7314       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
7315       if (aSplitIndex == 0)
7316       {
7317         aRecParams.FpsNum = aFpsArg.IntegerValue();
7318       }
7319       else
7320       {
7321         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
7322         aFpsArg.Split (aFpsArg.Length() - 1);
7323         const TCollection_AsciiString aNumStr = aFpsArg;
7324         aRecParams.FpsNum = aNumStr.IntegerValue();
7325         aRecParams.FpsDen = aDenStr.IntegerValue();
7326         if (aRecParams.FpsDen < 1)
7327         {
7328           Message::SendFail() << "Syntax error at " << anArg;
7329           return 1;
7330         }
7331       }
7332     }
7333     else if (anArg == "-format")
7334     {
7335       if (++anArgIter >= theArgNb)
7336       {
7337         Message::SendFail() << "Syntax error at " << anArg;
7338         return 1;
7339       }
7340       aRecParams.Format = theArgVec[anArgIter];
7341     }
7342     else if (anArg == "-pix_fmt"
7343           || anArg == "-pixfmt"
7344           || anArg == "-pixelformat")
7345     {
7346       if (++anArgIter >= theArgNb)
7347       {
7348         Message::SendFail() << "Syntax error at " << anArg;
7349         return 1;
7350       }
7351       aRecParams.PixelFormat = theArgVec[anArgIter];
7352     }
7353     else if (anArg == "-codec"
7354           || anArg == "-vcodec"
7355           || anArg == "-videocodec")
7356     {
7357       if (++anArgIter >= theArgNb)
7358       {
7359         Message::SendFail() << "Syntax error at " << anArg;
7360         return 1;
7361       }
7362       aRecParams.VideoCodec = theArgVec[anArgIter];
7363     }
7364     else if (anArg == "-crf"
7365           || anArg == "-preset"
7366           || anArg == "-qp")
7367     {
7368       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
7369       if (++anArgIter >= theArgNb)
7370       {
7371         Message::SendFail() << "Syntax error at " << anArg;
7372         return 1;
7373       }
7374
7375       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
7376     }
7377     // animation definition options
7378     else if (anArg == "-start"
7379           || anArg == "-starttime"
7380           || anArg == "-startpts")
7381     {
7382       if (++anArgIter >= theArgNb)
7383       {
7384         Message::SendFail() << "Syntax error at " << anArg;
7385         return 1;
7386       }
7387
7388       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
7389       aRootAnimation->UpdateTotalDuration();
7390     }
7391     else if (anArg == "-end"
7392           || anArg == "-endtime"
7393           || anArg == "-endpts")
7394     {
7395       if (++anArgIter >= theArgNb)
7396       {
7397         Message::SendFail() << "Syntax error at " << anArg;
7398         return 1;
7399       }
7400
7401       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
7402       aRootAnimation->UpdateTotalDuration();
7403     }
7404     else if (anArg == "-dur"
7405           || anArg == "-duration")
7406     {
7407       if (++anArgIter >= theArgNb)
7408       {
7409         Message::SendFail() << "Syntax error at " << anArg;
7410         return 1;
7411       }
7412
7413       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
7414       aRootAnimation->UpdateTotalDuration();
7415     }
7416     else if (anArg == "-command"
7417           || anArg == "-cmd"
7418           || anArg == "-invoke"
7419           || anArg == "-eval"
7420           || anArg == "-proc")
7421     {
7422       if (++anArgIter >= theArgNb)
7423       {
7424         Message::SendFail() << "Syntax error at " << anArg;
7425         return 1;
7426       }
7427
7428       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
7429       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
7430     }
7431     else if (anArg == "-objecttrsf"
7432           || anArg == "-objectransformation"
7433           || anArg == "-objtransformation"
7434           || anArg == "-objtrsf"
7435           || anArg == "-object"
7436           || anArg == "-obj")
7437     {
7438       if (++anArgIter >= theArgNb)
7439       {
7440         Message::SendFail() << "Syntax error at " << anArg;
7441         return 1;
7442       }
7443
7444       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
7445       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
7446       Handle(AIS_InteractiveObject) anObject;
7447       if (!aMapOfAIS.Find2 (anObjName, anObject))
7448       {
7449         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
7450         return 1;
7451       }
7452
7453       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
7454       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
7455       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
7456       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
7457       Standard_Boolean isTrsfSet = Standard_False;
7458       Standard_Integer aTrsfArgIter = anArgIter + 1;
7459       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
7460       {
7461         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
7462         aTrsfArg.LowerCase();
7463         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
7464         if (aTrsfArg.StartsWith ("-rotation")
7465          || aTrsfArg.StartsWith ("-rot"))
7466         {
7467           isTrsfSet = Standard_True;
7468           if (aTrsfArgIter + 4 >= theArgNb
7469           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
7470           {
7471             Message::SendFail() << "Syntax error at " << aTrsfArg;
7472             return 1;
7473           }
7474           aTrsfArgIter += 4;
7475         }
7476         else if (aTrsfArg.StartsWith ("-location")
7477               || aTrsfArg.StartsWith ("-loc"))
7478         {
7479           isTrsfSet = Standard_True;
7480           if (aTrsfArgIter + 3 >= theArgNb
7481           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
7482           {
7483             Message::SendFail() << "Syntax error at " << aTrsfArg;
7484             return 1;
7485           }
7486           aTrsfArgIter += 3;
7487         }
7488         else if (aTrsfArg.StartsWith ("-scale"))
7489         {
7490           isTrsfSet = Standard_True;
7491           if (++aTrsfArgIter >= theArgNb)
7492           {
7493             Message::SendFail() << "Syntax error at " << aTrsfArg;
7494             return 1;
7495           }
7496
7497           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
7498           if (!aScaleStr.IsRealValue (Standard_True))
7499           {
7500             Message::SendFail() << "Syntax error at " << aTrsfArg;
7501             return 1;
7502           }
7503           aScales[anIndex] = aScaleStr.RealValue();
7504         }
7505         else
7506         {
7507           anArgIter = aTrsfArgIter - 1;
7508           break;
7509         }
7510       }
7511       if (!isTrsfSet)
7512       {
7513         Message::SendFail() << "Syntax error at " << anArg;
7514         return 1;
7515       }
7516       else if (aTrsfArgIter >= theArgNb)
7517       {
7518         anArgIter = theArgNb;
7519       }
7520
7521       aTrsfs[0].SetRotation        (aRotQuats[0]);
7522       aTrsfs[1].SetRotation        (aRotQuats[1]);
7523       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
7524       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
7525       aTrsfs[0].SetScaleFactor     (aScales[0]);
7526       aTrsfs[1].SetScaleFactor     (aScales[1]);
7527
7528       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
7529       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
7530     }
7531     else if (anArg == "-viewtrsf"
7532           || anArg == "-view")
7533     {
7534       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
7535       if (aCamAnimation.IsNull())
7536       {
7537         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
7538         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
7539       }
7540
7541       Handle(Graphic3d_Camera) aCams[2] =
7542       {
7543         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
7544         new Graphic3d_Camera (aCamAnimation->View()->Camera())
7545       };
7546
7547       Standard_Boolean isTrsfSet = Standard_False;
7548       Standard_Integer aViewArgIter = anArgIter + 1;
7549       for (; aViewArgIter < theArgNb; ++aViewArgIter)
7550       {
7551         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
7552         aViewArg.LowerCase();
7553         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
7554         if (aViewArg.StartsWith ("-scale"))
7555         {
7556           isTrsfSet = Standard_True;
7557           if (++aViewArgIter >= theArgNb)
7558           {
7559             Message::SendFail() << "Syntax error at " << anArg;
7560             return 1;
7561           }
7562
7563           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
7564           if (!aScaleStr.IsRealValue (Standard_True))
7565           {
7566             Message::SendFail() << "Syntax error at " << aViewArg;
7567             return 1;
7568           }
7569           Standard_Real aScale = aScaleStr.RealValue();
7570           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
7571           aCams[anIndex]->SetScale (aScale);
7572         }
7573         else if (aViewArg.StartsWith ("-eye")
7574               || aViewArg.StartsWith ("-center")
7575               || aViewArg.StartsWith ("-at")
7576               || aViewArg.StartsWith ("-up"))
7577         {
7578           isTrsfSet = Standard_True;
7579           gp_XYZ anXYZ;
7580           if (aViewArgIter + 3 >= theArgNb
7581           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
7582           {
7583             Message::SendFail() << "Syntax error at " << aViewArg;
7584             return 1;
7585           }
7586           aViewArgIter += 3;
7587
7588           if (aViewArg.StartsWith ("-eye"))
7589           {
7590             aCams[anIndex]->SetEye (anXYZ);
7591           }
7592           else if (aViewArg.StartsWith ("-center")
7593                 || aViewArg.StartsWith ("-at"))
7594           {
7595             aCams[anIndex]->SetCenter (anXYZ);
7596           }
7597           else if (aViewArg.StartsWith ("-up"))
7598           {
7599             aCams[anIndex]->SetUp (anXYZ);
7600           }
7601         }
7602         else
7603         {
7604           anArgIter = aViewArgIter - 1;
7605           break;
7606         }
7607       }
7608       if (!isTrsfSet)
7609       {
7610         Message::SendFail() << "Syntax error at " << anArg;
7611         return 1;
7612       }
7613       else if (aViewArgIter >= theArgNb)
7614       {
7615         anArgIter = theArgNb;
7616       }
7617
7618       aCamAnimation->SetCameraStart(aCams[0]);
7619       aCamAnimation->SetCameraEnd  (aCams[1]);
7620     }
7621     else
7622     {
7623       Message::SendFail() << "Syntax error at " << anArg;
7624       return 1;
7625     }
7626   }
7627
7628   ViewerTest::CurrentEventManager()->AbortViewAnimation();
7629   ViewerTest::CurrentEventManager()->SetObjectsAnimation (Handle(AIS_Animation)());
7630   if (!toPlay && aRecFile.IsEmpty())
7631   {
7632     return 0;
7633   }
7634
7635   // Start animation timeline and process frame updating.
7636   if (aRecParams.FpsNum <= 0
7637   && !isLockLoop)
7638   {
7639     Handle(ViewerTest_AnimationHolder) aHolder = new ViewerTest_AnimationHolder (anAnimation, aView, isFreeCamera);
7640     aHolder->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7641     ViewerTest::CurrentEventManager()->SetPauseObjectsAnimation (toPauseOnClick);
7642     ViewerTest::CurrentEventManager()->SetObjectsAnimation (aHolder);
7643     ViewerTest::CurrentEventManager()->ProcessExpose();
7644     return 0;
7645   }
7646
7647   // Perform video recording
7648   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
7649   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
7650   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
7651
7652   OSD_Timer aPerfTimer;
7653   aPerfTimer.Start();
7654
7655   Handle(Image_VideoRecorder) aRecorder;
7656   ImageFlipper aFlipper;
7657   Handle(Draw_ProgressIndicator) aProgress;
7658   if (!aRecFile.IsEmpty())
7659   {
7660     if (aRecParams.Width  <= 0
7661      || aRecParams.Height <= 0)
7662     {
7663       aView->Window()->Size (aRecParams.Width, aRecParams.Height);
7664     }
7665
7666     aRecorder = new Image_VideoRecorder();
7667     if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
7668     {
7669       Message::SendFail ("Error: failed to open video file for recording");
7670       return 0;
7671     }
7672
7673     aProgress = new Draw_ProgressIndicator (theDI, 1);
7674   }
7675
7676   // Manage frame-rated animation here
7677   Standard_Real aPts = aPlayStartTime;
7678   int64_t aNbFrames = 0;
7679   Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
7680                             "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
7681   Standard_Integer aSecondsProgress = 0;
7682   for (; aPts <= anUpperPts && aPS.More();)
7683   {
7684     Standard_Real aRecPts = 0.0;
7685     if (aRecParams.FpsNum > 0)
7686     {
7687       aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
7688     }
7689     else
7690     {
7691       aRecPts = aPlaySpeed * aPerfTimer.ElapsedTime();
7692     }
7693
7694     aPts = aPlayStartTime + aRecPts;
7695     ++aNbFrames;
7696     if (!anAnimation->Update (aPts))
7697     {
7698       break;
7699     }
7700
7701     if (!aRecorder.IsNull())
7702     {
7703       V3d_ImageDumpOptions aDumpParams;
7704       aDumpParams.Width          = aRecParams.Width;
7705       aDumpParams.Height         = aRecParams.Height;
7706       aDumpParams.BufferType     = Graphic3d_BT_RGBA;
7707       aDumpParams.StereoOptions  = V3d_SDO_MONO;
7708       aDumpParams.ToAdjustAspect = Standard_True;
7709       if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
7710       {
7711         Message::SendFail ("Error: view dump is failed");
7712         return 0;
7713       }
7714       aFlipper.FlipY (aRecorder->ChangeFrame());
7715       if (!aRecorder->PushFrame())
7716       {
7717         return 0;
7718       }
7719     }
7720     else
7721     {
7722       aView->Redraw();
7723     }
7724
7725     while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
7726     {
7727       aPS.Next();
7728       ++aSecondsProgress;
7729     }
7730   }
7731
7732   aPerfTimer.Stop();
7733   anAnimation->Stop();
7734   const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
7735   theDI << "Average FPS: " << aRecFps << "\n"
7736         << "Nb. Frames: "  << Standard_Real(aNbFrames);
7737
7738   aView->Redraw();
7739   aView->SetImmediateUpdate (wasImmediateUpdate);
7740   return 0;
7741 }
7742
7743
7744 //=======================================================================
7745 //function : VChangeSelected
7746 //purpose  : Adds the shape to selection or remove one from it
7747 //=======================================================================
7748 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
7749                                 Standard_Integer argc,
7750                                 const char ** argv)
7751 {
7752   if(argc != 2)
7753   {
7754     di<<"Usage : " << argv[0] << " shape \n";
7755     return 1;
7756   }
7757   //get AIS_Shape:
7758   TCollection_AsciiString aName(argv[1]);
7759   Handle(AIS_InteractiveObject) anAISObject;
7760   if (!GetMapOfAIS().Find2 (aName, anAISObject)
7761     || anAISObject.IsNull())
7762   {
7763     di<<"Use 'vdisplay' before";
7764     return 1;
7765   }
7766
7767   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
7768   return 0;
7769 }
7770
7771 //=======================================================================
7772 //function : VNbSelected
7773 //purpose  : Returns number of selected objects
7774 //=======================================================================
7775 static Standard_Integer VNbSelected (Draw_Interpretor& di,
7776                                 Standard_Integer argc,
7777                                 const char ** argv)
7778 {
7779   if(argc != 1)
7780   {
7781     di << "Usage : " << argv[0] << "\n";
7782     return 1;
7783   }
7784   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7785   if(aContext.IsNull())
7786   {
7787     di << "use 'vinit' command before " << argv[0] << "\n";
7788     return 1;
7789   }
7790   di << aContext->NbSelected() << "\n";
7791   return 0;
7792 }
7793
7794 //=======================================================================
7795 //function : VSetViewSize
7796 //purpose  :
7797 //=======================================================================
7798 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
7799                                 Standard_Integer argc,
7800                                 const char ** argv)
7801 {
7802   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7803   if(aContext.IsNull())
7804   {
7805     di << "use 'vinit' command before " << argv[0] << "\n";
7806     return 1;
7807   }
7808   if(argc != 2)
7809   {
7810     di<<"Usage : " << argv[0] << " Size\n";
7811     return 1;
7812   }
7813   Standard_Real aSize = Draw::Atof (argv[1]);
7814   if (aSize <= 0.)
7815   {
7816     di<<"Bad Size value  : " << aSize << "\n";
7817     return 1;
7818   }
7819
7820   Handle(V3d_View) aView = ViewerTest::CurrentView();
7821   aView->SetSize(aSize);
7822   return 0;
7823 }
7824
7825 //=======================================================================
7826 //function : VMoveView
7827 //purpose  :
7828 //=======================================================================
7829 static Standard_Integer VMoveView (Draw_Interpretor& di,
7830                                 Standard_Integer argc,
7831                                 const char ** argv)
7832 {
7833   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7834   if(aContext.IsNull())
7835   {
7836     di << "use 'vinit' command before " << argv[0] << "\n";
7837     return 1;
7838   }
7839   if(argc < 4 || argc > 5)
7840   {
7841     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
7842     return 1;
7843   }
7844   Standard_Real Dx = Draw::Atof (argv[1]);
7845   Standard_Real Dy = Draw::Atof (argv[2]);
7846   Standard_Real Dz = Draw::Atof (argv[3]);
7847   Standard_Boolean aStart = Standard_True;
7848   if (argc == 5)
7849   {
7850       aStart = (Draw::Atoi (argv[4]) > 0);
7851   }
7852
7853   Handle(V3d_View) aView = ViewerTest::CurrentView();
7854   aView->Move(Dx,Dy,Dz,aStart);
7855   return 0;
7856 }
7857
7858 //=======================================================================
7859 //function : VTranslateView
7860 //purpose  :
7861 //=======================================================================
7862 static Standard_Integer VTranslateView (Draw_Interpretor& di,
7863                                 Standard_Integer argc,
7864                                 const char ** argv)
7865 {
7866   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7867   if(aContext.IsNull())
7868   {
7869     di << "use 'vinit' command before " << argv[0] << "\n";
7870     return 1;
7871   }
7872   if(argc < 4 || argc > 5)
7873   {
7874     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
7875     return 1;
7876   }
7877   Standard_Real Dx = Draw::Atof (argv[1]);
7878   Standard_Real Dy = Draw::Atof (argv[2]);
7879   Standard_Real Dz = Draw::Atof (argv[3]);
7880   Standard_Boolean aStart = Standard_True;
7881   if (argc == 5)
7882   {
7883       aStart = (Draw::Atoi (argv[4]) > 0);
7884   }
7885
7886   Handle(V3d_View) aView = ViewerTest::CurrentView();
7887   aView->Translate(Dx,Dy,Dz,aStart);
7888   return 0;
7889 }
7890
7891 //=======================================================================
7892 //function : VTurnView
7893 //purpose  :
7894 //=======================================================================
7895 static Standard_Integer VTurnView (Draw_Interpretor& di,
7896                                 Standard_Integer argc,
7897                                 const char ** argv)
7898 {
7899   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
7900   if(aContext.IsNull()) {
7901     di << "use 'vinit' command before " << argv[0] << "\n";
7902     return 1;
7903   }
7904   if(argc < 4 || argc > 5){
7905     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
7906     return 1;
7907   }
7908   Standard_Real Ax = Draw::Atof (argv[1]);
7909   Standard_Real Ay = Draw::Atof (argv[2]);
7910   Standard_Real Az = Draw::Atof (argv[3]);
7911   Standard_Boolean aStart = Standard_True;
7912   if (argc == 5)
7913   {
7914       aStart = (Draw::Atoi (argv[4]) > 0);
7915   }
7916
7917   Handle(V3d_View) aView = ViewerTest::CurrentView();
7918   aView->Turn(Ax,Ay,Az,aStart);
7919   return 0;
7920 }
7921
7922 //==============================================================================
7923 //function : VTextureEnv
7924 //purpose  : ENables or disables environment mapping
7925 //==============================================================================
7926 class OCC_TextureEnv : public Graphic3d_TextureEnv
7927 {
7928 public:
7929   OCC_TextureEnv(const Standard_CString FileName);
7930   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
7931   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
7932                             const Standard_Boolean theModulateFlag,
7933                             const Graphic3d_TypeOfTextureFilter theFilter,
7934                             const Standard_ShortReal theXScale,
7935                             const Standard_ShortReal theYScale,
7936                             const Standard_ShortReal theXShift,
7937                             const Standard_ShortReal theYShift,
7938                             const Standard_ShortReal theAngle);
7939   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
7940 };
7941 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
7942
7943 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
7944   : Graphic3d_TextureEnv(theFileName)
7945 {
7946 }
7947
7948 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
7949   : Graphic3d_TextureEnv(theTexId)
7950 {
7951 }
7952
7953 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
7954                                           const Standard_Boolean theModulateFlag,
7955                                           const Graphic3d_TypeOfTextureFilter theFilter,
7956                                           const Standard_ShortReal theXScale,
7957                                           const Standard_ShortReal theYScale,
7958                                           const Standard_ShortReal theXShift,
7959                                           const Standard_ShortReal theYShift,
7960                                           const Standard_ShortReal theAngle)
7961 {
7962   myParams->SetRepeat     (theRepeatFlag);
7963   myParams->SetModulate   (theModulateFlag);
7964   myParams->SetFilter     (theFilter);
7965   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
7966   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
7967   myParams->SetRotation   (theAngle);
7968 }
7969
7970 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
7971 {
7972   // get the active view
7973   Handle(V3d_View) aView = ViewerTest::CurrentView();
7974   if (aView.IsNull())
7975   {
7976     Message::SendFail ("Error: no active viewer");
7977     return 1;
7978   }
7979
7980   // Checking the input arguments
7981   Standard_Boolean anEnableFlag = Standard_False;
7982   Standard_Boolean isOk         = theArgNb >= 2;
7983   if (isOk)
7984   {
7985     TCollection_AsciiString anEnableOpt(theArgVec[1]);
7986     anEnableFlag = anEnableOpt.IsEqual("on");
7987     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
7988   }
7989   if (anEnableFlag)
7990   {
7991     isOk = (theArgNb == 3 || theArgNb == 11);
7992     if (isOk)
7993     {
7994       TCollection_AsciiString aTextureOpt(theArgVec[2]);
7995       isOk = (!aTextureOpt.IsIntegerValue() ||
7996              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
7997
7998       if (isOk && theArgNb == 11)
7999       {
8000         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
8001                                 aModulateOpt(theArgVec[4]),
8002                                 aFilterOpt  (theArgVec[5]),
8003                                 aSScaleOpt  (theArgVec[6]),
8004                                 aTScaleOpt  (theArgVec[7]),
8005                                 aSTransOpt  (theArgVec[8]),
8006                                 aTTransOpt  (theArgVec[9]),
8007                                 anAngleOpt  (theArgVec[10]);
8008         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
8009                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
8010                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
8011                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
8012                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
8013                 anAngleOpt.IsRealValue (Standard_True));
8014       }
8015     }
8016   }
8017
8018   if (!isOk)
8019   {
8020     Message::SendFail() << "Usage:\n"
8021                         << theArgVec[0] << " off\n"
8022                         << 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]";
8023     return 1;
8024   }
8025
8026   if (anEnableFlag)
8027   {
8028     TCollection_AsciiString aTextureOpt(theArgVec[2]);
8029     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
8030                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
8031                                      new OCC_TextureEnv(theArgVec[2]);
8032
8033     if (theArgNb == 11)
8034     {
8035       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
8036       aTexEnv->SetTextureParameters(
8037         aRepeatOpt.  IsEqual("repeat"),
8038         aModulateOpt.IsEqual("modulate"),
8039         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
8040                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
8041                                                                            Graphic3d_TOTF_TRILINEAR,
8042         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
8043         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
8044         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
8045         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
8046         (Standard_ShortReal)Draw::Atof(theArgVec[10])
8047         );
8048     }
8049     aView->SetTextureEnv(aTexEnv);
8050   }
8051   else // Disabling environment mapping
8052   {
8053     Handle(Graphic3d_TextureEnv) aTexture;
8054     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
8055   }
8056
8057   aView->Redraw();
8058   return 0;
8059 }
8060
8061 namespace
8062 {
8063   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
8064
8065   //! Remove registered clipping plane from all views and objects.
8066   static void removePlane (MapOfPlanes& theRegPlanes,
8067                            const TCollection_AsciiString& theName)
8068   {
8069     Handle(Graphic3d_ClipPlane) aClipPlane;
8070     if (!theRegPlanes.Find (theName, aClipPlane))
8071     {
8072       Message::SendWarning ("Warning: no such plane");
8073       return;
8074     }
8075
8076     theRegPlanes.UnBind (theName);
8077     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
8078          anIObjIt.More(); anIObjIt.Next())
8079     {
8080       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
8081       aPrs->RemoveClipPlane (aClipPlane);
8082     }
8083
8084     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
8085          aViewIt.More(); aViewIt.Next())
8086     {
8087       const Handle(V3d_View)& aView = aViewIt.Key2();
8088       aView->RemoveClipPlane(aClipPlane);
8089     }
8090
8091     ViewerTest::RedrawAllViews();
8092   }
8093 }
8094
8095 //===============================================================================================
8096 //function : VClipPlane
8097 //purpose  :
8098 //===============================================================================================
8099 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8100 {
8101   // use short-cut for created clip planes map of created (or "registered by name") clip planes
8102   static MapOfPlanes aRegPlanes;
8103
8104   if (theArgsNb < 2)
8105   {
8106     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
8107     {
8108       theDi << aPlaneIter.Key() << " ";
8109     }
8110     return 0;
8111   }
8112
8113   TCollection_AsciiString aCommand (theArgVec[1]);
8114   aCommand.LowerCase();
8115   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
8116   if (anActiveView.IsNull())
8117   {
8118     Message::SendFail ("Error: no active viewer");
8119     return 1;
8120   }
8121
8122   // print maximum number of planes for current viewer
8123   if (aCommand == "-maxplanes"
8124    || aCommand == "maxplanes")
8125   {
8126     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
8127           << " plane slots provided by driver.\n";
8128     return 0;
8129   }
8130
8131   // create / delete plane instance
8132   if (aCommand == "-create"
8133    || aCommand == "create"
8134    || aCommand == "-delete"
8135    || aCommand == "delete"
8136    || aCommand == "-clone"
8137    || aCommand == "clone")
8138   {
8139     if (theArgsNb < 3)
8140     {
8141       Message::SendFail ("Syntax error: plane name is required");
8142       return 1;
8143     }
8144
8145     Standard_Boolean toCreate = aCommand == "-create"
8146                              || aCommand == "create";
8147     Standard_Boolean toClone  = aCommand == "-clone"
8148                              || aCommand == "clone";
8149     Standard_Boolean toDelete = aCommand == "-delete"
8150                              || aCommand == "delete";
8151     TCollection_AsciiString aPlane (theArgVec[2]);
8152
8153     if (toCreate)
8154     {
8155       if (aRegPlanes.IsBound (aPlane))
8156       {
8157         std::cout << "Warning: existing plane has been overridden.\n";
8158         toDelete = true;
8159       }
8160       else
8161       {
8162         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8163         return 0;
8164       }
8165     }
8166     else if (toClone) // toClone
8167     {
8168       if (!aRegPlanes.IsBound (aPlane))
8169       {
8170         Message::SendFail ("Error: no such plane");
8171         return 1;
8172       }
8173       else if (theArgsNb < 4)
8174       {
8175         Message::SendFail ("Syntax error: enter name for new plane");
8176         return 1;
8177       }
8178
8179       TCollection_AsciiString aClone (theArgVec[3]);
8180       if (aRegPlanes.IsBound (aClone))
8181       {
8182         Message::SendFail ("Error: plane name is in use");
8183         return 1;
8184       }
8185
8186       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
8187
8188       aRegPlanes.Bind (aClone, aClipPlane->Clone());
8189       return 0;
8190     }
8191
8192     if (toDelete)
8193     {
8194       if (aPlane == "ALL"
8195        || aPlane == "all"
8196        || aPlane == "*")
8197       {
8198         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
8199         {
8200           aPlane = aPlaneIter.Key();
8201           removePlane (aRegPlanes, aPlane);
8202           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
8203         }
8204       }
8205       else
8206       {
8207         removePlane (aRegPlanes, aPlane);
8208       }
8209     }
8210
8211     if (toCreate)
8212     {
8213       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8214     }
8215     return 0;
8216   }
8217
8218   // set / unset plane command
8219   if (aCommand == "set"
8220    || aCommand == "unset")
8221   {
8222     if (theArgsNb < 5)
8223     {
8224       Message::SendFail ("Syntax error: need more arguments");
8225       return 1;
8226     }
8227
8228     // redirect to new syntax
8229     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
8230     anArgVec.SetValue (1, theArgVec[0]);
8231     anArgVec.SetValue (2, theArgVec[2]);
8232     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
8233     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
8234     {
8235       anArgVec.SetValue (anIt, theArgVec[anIt]);
8236     }
8237
8238     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
8239   }
8240
8241   // change plane command
8242   TCollection_AsciiString aPlaneName;
8243   Handle(Graphic3d_ClipPlane) aClipPlane;
8244   Standard_Integer anArgIter = 0;
8245   if (aCommand == "-change"
8246    || aCommand == "change")
8247   {
8248     // old syntax support
8249     if (theArgsNb < 3)
8250     {
8251       Message::SendFail ("Syntax error: need more arguments");
8252       return 1;
8253     }
8254
8255     anArgIter  = 3;
8256     aPlaneName = theArgVec[2];
8257     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
8258     {
8259       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
8260       return 1;
8261     }
8262   }
8263   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
8264   {
8265     anArgIter  = 2;
8266     aPlaneName = theArgVec[1];
8267   }
8268   else
8269   {
8270     anArgIter  = 2;
8271     aPlaneName = theArgVec[1];
8272     aClipPlane = new Graphic3d_ClipPlane();
8273     aRegPlanes.Bind (aPlaneName, aClipPlane);
8274     theDi << "Created new plane " << aPlaneName << ".\n";
8275   }
8276
8277   if (theArgsNb - anArgIter < 1)
8278   {
8279     Message::SendFail ("Syntax error: need more arguments");
8280     return 1;
8281   }
8282
8283   for (; anArgIter < theArgsNb; ++anArgIter)
8284   {
8285     const char**     aChangeArgs   = theArgVec + anArgIter;
8286     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
8287     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
8288     aChangeArg.LowerCase();
8289
8290     Standard_Boolean toEnable = Standard_True;
8291     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
8292     {
8293       aClipPlane->SetOn (toEnable);
8294     }
8295     else if (aChangeArg.StartsWith ("-equation")
8296           || aChangeArg.StartsWith ("equation"))
8297     {
8298       if (aNbChangeArgs < 5)
8299       {
8300         Message::SendFail ("Syntax error: need more arguments");
8301         return 1;
8302       }
8303
8304       Standard_Integer aSubIndex = 1;
8305       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
8306       if (aPrefixLen < aChangeArg.Length())
8307       {
8308         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
8309         if (!aSubStr.IsIntegerValue()
8310           || aSubStr.IntegerValue() <= 0)
8311         {
8312           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8313           return 1;
8314         }
8315         aSubIndex = aSubStr.IntegerValue();
8316       }
8317
8318       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
8319       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
8320       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
8321       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
8322       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8323       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
8324       {
8325         if (aSubPln->ChainNextPlane().IsNull())
8326         {
8327           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8328         }
8329         aSubPln = aSubPln->ChainNextPlane();
8330       }
8331       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8332       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
8333       anArgIter += 4;
8334     }
8335     else if ((aChangeArg == "-boxinterior"
8336            || aChangeArg == "-boxint"
8337            || aChangeArg == "-box")
8338             && aNbChangeArgs >= 7)
8339     {
8340       Graphic3d_BndBox3d aBndBox;
8341       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
8342       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
8343       anArgIter += 6;
8344
8345       Standard_Integer aNbSubPlanes = 6;
8346       const Graphic3d_Vec3d aDirArray[6] =
8347       {
8348         Graphic3d_Vec3d (-1, 0, 0),
8349         Graphic3d_Vec3d ( 1, 0, 0),
8350         Graphic3d_Vec3d ( 0,-1, 0),
8351         Graphic3d_Vec3d ( 0, 1, 0),
8352         Graphic3d_Vec3d ( 0, 0,-1),
8353         Graphic3d_Vec3d ( 0, 0, 1),
8354       };
8355       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
8356       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
8357       {
8358         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
8359         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
8360         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
8361         if (aSubPlaneIter + 1 == aNbSubPlanes)
8362         {
8363           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
8364         }
8365         else
8366         {
8367           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
8368         }
8369         aSubPln = aSubPln->ChainNextPlane();
8370       }
8371     }
8372     else if (aChangeArg == "-capping"
8373           || aChangeArg == "capping")
8374     {
8375       if (aNbChangeArgs < 2)
8376       {
8377         Message::SendFail ("Syntax error: need more arguments");
8378         return 1;
8379       }
8380
8381       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8382       {
8383         aClipPlane->SetCapping (toEnable);
8384         anArgIter += 1;
8385       }
8386       else
8387       {
8388         // just skip otherwise (old syntax)
8389       }
8390     }
8391     else if (aChangeArg == "-useobjectmaterial"
8392           || aChangeArg == "-useobjectmat"
8393           || aChangeArg == "-useobjmat"
8394           || aChangeArg == "-useobjmaterial")
8395     {
8396       if (aNbChangeArgs < 2)
8397       {
8398         Message::SendFail ("Syntax error: need more arguments");
8399         return 1;
8400       }
8401
8402       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8403       {
8404         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
8405         anArgIter += 1;
8406       }
8407     }
8408     else if (aChangeArg == "-useobjecttexture"
8409           || aChangeArg == "-useobjecttex"
8410           || aChangeArg == "-useobjtexture"
8411           || aChangeArg == "-useobjtex")
8412     {
8413       if (aNbChangeArgs < 2)
8414       {
8415         Message::SendFail ("Syntax error: need more arguments");
8416         return 1;
8417       }
8418
8419       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8420       {
8421         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
8422         anArgIter += 1;
8423       }
8424     }
8425     else if (aChangeArg == "-useobjectshader"
8426           || aChangeArg == "-useobjshader")
8427     {
8428       if (aNbChangeArgs < 2)
8429       {
8430         Message::SendFail ("Syntax error: need more arguments");
8431         return 1;
8432       }
8433
8434       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
8435       {
8436         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
8437         anArgIter += 1;
8438       }
8439     }
8440     else if (aChangeArg == "-color"
8441           || aChangeArg == "color")
8442     {
8443       Quantity_Color aColor;
8444       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
8445                                                      aChangeArgs + 1,
8446                                                      aColor);
8447       if (aNbParsed == 0)
8448       {
8449         Message::SendFail ("Syntax error: need more arguments");
8450         return 1;
8451       }
8452       aClipPlane->SetCappingColor (aColor);
8453       anArgIter += aNbParsed;
8454     }
8455     else if (aNbChangeArgs >= 1
8456           && (aChangeArg == "-material"
8457            || aChangeArg == "material"))
8458     {
8459       ++anArgIter;
8460       Graphic3d_NameOfMaterial aMatName;
8461       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
8462       {
8463         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
8464         return 1;
8465       }
8466       aClipPlane->SetCappingMaterial (aMatName);
8467     }
8468     else if ((aChangeArg == "-transparency"
8469            || aChangeArg == "-transp")
8470           && aNbChangeArgs >= 2)
8471     {
8472       TCollection_AsciiString aValStr (aChangeArgs[1]);
8473       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
8474       if (aValStr.IsRealValue (Standard_True))
8475       {
8476         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
8477         aMat.SetTransparency ((float )aValStr.RealValue());
8478         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
8479         aClipPlane->SetCappingMaterial (aMat);
8480       }
8481       else
8482       {
8483         aValStr.LowerCase();
8484         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
8485         if (aValStr == "opaque")
8486         {
8487           aMode = Graphic3d_AlphaMode_Opaque;
8488         }
8489         else if (aValStr == "mask")
8490         {
8491           aMode = Graphic3d_AlphaMode_Mask;
8492         }
8493         else if (aValStr == "blend")
8494         {
8495           aMode = Graphic3d_AlphaMode_Blend;
8496         }
8497         else if (aValStr == "maskblend"
8498               || aValStr == "blendmask")
8499         {
8500           aMode = Graphic3d_AlphaMode_MaskBlend;
8501         }
8502         else if (aValStr == "blendauto")
8503         {
8504           aMode = Graphic3d_AlphaMode_BlendAuto;
8505         }
8506         else
8507         {
8508           Message::SendFail() << "Syntax error at '" << aValStr << "'";
8509           return 1;
8510         }
8511         anAspect->SetAlphaMode (aMode);
8512         aClipPlane->SetCappingAspect (anAspect);
8513       }
8514       anArgIter += 1;
8515     }
8516     else if (aChangeArg == "-texname"
8517           || aChangeArg == "texname")
8518     {
8519       if (aNbChangeArgs < 2)
8520       {
8521         Message::SendFail ("Syntax error: need more arguments");
8522         return 1;
8523       }
8524
8525       TCollection_AsciiString aTextureName (aChangeArgs[1]);
8526       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
8527       if (!aTexture->IsDone())
8528       {
8529         aClipPlane->SetCappingTexture (NULL);
8530       }
8531       else
8532       {
8533         aTexture->EnableModulate();
8534         aTexture->EnableRepeat();
8535         aClipPlane->SetCappingTexture (aTexture);
8536       }
8537       anArgIter += 1;
8538     }
8539     else if (aChangeArg == "-texscale"
8540           || aChangeArg == "texscale")
8541     {
8542       if (aClipPlane->CappingTexture().IsNull())
8543       {
8544         Message::SendFail ("Error: no texture is set");
8545         return 1;
8546       }
8547
8548       if (aNbChangeArgs < 3)
8549       {
8550         Message::SendFail ("Syntax error: need more arguments");
8551         return 1;
8552       }
8553
8554       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8555       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8556       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
8557       anArgIter += 2;
8558     }
8559     else if (aChangeArg == "-texorigin"
8560           || aChangeArg == "texorigin") // texture origin
8561     {
8562       if (aClipPlane->CappingTexture().IsNull())
8563       {
8564         Message::SendFail ("Error: no texture is set");
8565         return 1;
8566       }
8567
8568       if (aNbChangeArgs < 3)
8569       {
8570         Message::SendFail ("Syntax error: need more arguments");
8571         return 1;
8572       }
8573
8574       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8575       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
8576
8577       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
8578       anArgIter += 2;
8579     }
8580     else if (aChangeArg == "-texrotate"
8581           || aChangeArg == "texrotate") // texture rotation
8582     {
8583       if (aClipPlane->CappingTexture().IsNull())
8584       {
8585         Message::SendFail ("Error: no texture is set");
8586         return 1;
8587       }
8588
8589       if (aNbChangeArgs < 2)
8590       {
8591         Message::SendFail ("Syntax error: need more arguments");
8592         return 1;
8593       }
8594
8595       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
8596       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
8597       anArgIter += 1;
8598     }
8599     else if (aChangeArg == "-hatch"
8600           || aChangeArg == "hatch")
8601     {
8602       if (aNbChangeArgs < 2)
8603       {
8604         Message::SendFail ("Syntax error: need more arguments");
8605         return 1;
8606       }
8607
8608       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
8609       aHatchStr.LowerCase();
8610       if (aHatchStr == "on")
8611       {
8612         aClipPlane->SetCappingHatchOn();
8613       }
8614       else if (aHatchStr == "off")
8615       {
8616         aClipPlane->SetCappingHatchOff();
8617       }
8618       else
8619       {
8620         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
8621       }
8622       anArgIter += 1;
8623     }
8624     else if (aChangeArg == "-delete"
8625           || aChangeArg == "delete")
8626     {
8627       removePlane (aRegPlanes, aPlaneName);
8628       return 0;
8629     }
8630     else if (aChangeArg == "-set"
8631           || aChangeArg == "-unset"
8632           || aChangeArg == "-setoverrideglobal")
8633     {
8634       // set / unset plane command
8635       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
8636       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
8637       Standard_Integer anIt = 1;
8638       for (; anIt < aNbChangeArgs; ++anIt)
8639       {
8640         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
8641         if (anEntityName.IsEmpty()
8642          || anEntityName.Value (1) == '-')
8643         {
8644           break;
8645         }
8646         else if (!toOverrideGlobal
8647                && ViewerTest_myViews.IsBound1 (anEntityName))
8648         {
8649           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
8650           if (toSet)
8651           {
8652             aView->AddClipPlane (aClipPlane);
8653           }
8654           else
8655           {
8656             aView->RemoveClipPlane (aClipPlane);
8657           }
8658           continue;
8659         }
8660         else if (GetMapOfAIS().IsBound2 (anEntityName))
8661         {
8662           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
8663           if (toSet)
8664           {
8665             aIObj->AddClipPlane (aClipPlane);
8666           }
8667           else
8668           {
8669             aIObj->RemoveClipPlane (aClipPlane);
8670           }
8671           if (!aIObj->ClipPlanes().IsNull())
8672           {
8673             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
8674           }
8675         }
8676         else
8677         {
8678           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
8679           return 1;
8680         }
8681       }
8682
8683       if (anIt == 1)
8684       {
8685         // apply to active view
8686         if (toSet)
8687         {
8688           anActiveView->AddClipPlane (aClipPlane);
8689         }
8690         else
8691         {
8692           anActiveView->RemoveClipPlane (aClipPlane);
8693         }
8694       }
8695       else
8696       {
8697         anArgIter = anArgIter + anIt - 1;
8698       }
8699     }
8700     else
8701     {
8702       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
8703       return 1;
8704     }
8705   }
8706
8707   ViewerTest::RedrawAllViews();
8708   return 0;
8709 }
8710
8711 //===============================================================================================
8712 //function : VZRange
8713 //purpose  :
8714 //===============================================================================================
8715 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8716 {
8717   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8718
8719   if (aCurrentView.IsNull())
8720   {
8721     Message::SendFail ("Error: no active viewer");
8722     return 1;
8723   }
8724
8725   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
8726
8727   if (theArgsNb < 2)
8728   {
8729     theDi << "ZNear: " << aCamera->ZNear() << "\n";
8730     theDi << "ZFar: " << aCamera->ZFar() << "\n";
8731     return 0;
8732   }
8733
8734   if (theArgsNb == 3)
8735   {
8736     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
8737     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
8738
8739     if (aNewZNear >= aNewZFar)
8740     {
8741       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
8742       return 1;
8743     }
8744
8745     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
8746     {
8747       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
8748       return 1;
8749     }
8750
8751     aCamera->SetZRange (aNewZNear, aNewZFar);
8752   }
8753   else
8754   {
8755     Message::SendFail ("Syntax error: wrong command arguments");
8756     return 1;
8757   }
8758
8759   aCurrentView->Redraw();
8760
8761   return 0;
8762 }
8763
8764 //===============================================================================================
8765 //function : VAutoZFit
8766 //purpose  :
8767 //===============================================================================================
8768 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8769 {
8770   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
8771
8772   if (aCurrentView.IsNull())
8773   {
8774     Message::SendFail ("Error: no active viewer");
8775     return 1;
8776   }
8777
8778   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
8779
8780   if (theArgsNb > 3)
8781   {
8782     Message::SendFail ("Syntax error: wrong command arguments");
8783     return 1;
8784   }
8785
8786   if (theArgsNb < 2)
8787   {
8788     theDi << "Auto z-fit mode: \n"
8789           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
8790           << "Scale: " << aScale << "\n";
8791     return 0;
8792   }
8793
8794   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
8795
8796   if (theArgsNb >= 3)
8797   {
8798     aScale = Draw::Atoi (theArgVec[2]);
8799   }
8800
8801   aCurrentView->SetAutoZFitMode (isOn, aScale);
8802   aCurrentView->Redraw();
8803   return 0;
8804 }
8805
8806 //! Auxiliary function to print projection type
8807 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
8808 {
8809   switch (theProjType)
8810   {
8811     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
8812     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
8813     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
8814     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
8815     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
8816   }
8817   return "UNKNOWN";
8818 }
8819
8820 //===============================================================================================
8821 //function : VCamera
8822 //purpose  :
8823 //===============================================================================================
8824 static int VCamera (Draw_Interpretor& theDI,
8825                     Standard_Integer  theArgsNb,
8826                     const char**      theArgVec)
8827 {
8828   Handle(V3d_View) aView = ViewerTest::CurrentView();
8829   if (aView.IsNull())
8830   {
8831     Message::SendFail ("Error: no active viewer");
8832     return 1;
8833   }
8834
8835   Handle(Graphic3d_Camera) aCamera = aView->Camera();
8836   if (theArgsNb < 2)
8837   {
8838     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
8839     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
8840     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
8841     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
8842     theDI << "Distance:   " << aCamera->Distance() << "\n";
8843     theDI << "IOD:        " << aCamera->IOD() << "\n";
8844     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
8845     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
8846     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
8847     theDI << "ZNear:      " << aCamera->ZNear() << "\n";
8848     theDI << "ZFar:       " << aCamera->ZFar() << "\n";
8849     return 0;
8850   }
8851
8852   TCollection_AsciiString aPrsName;
8853   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
8854   {
8855     Standard_CString        anArg = theArgVec[anArgIter];
8856     TCollection_AsciiString anArgCase (anArg);
8857     anArgCase.LowerCase();
8858     if (anArgCase == "-proj"
8859      || anArgCase == "-projection"
8860      || anArgCase == "-projtype"
8861      || anArgCase == "-projectiontype")
8862     {
8863       theDI << projTypeName (aCamera->ProjectionType()) << " ";
8864     }
8865     else if (anArgCase == "-ortho"
8866           || anArgCase == "-orthographic")
8867     {
8868       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
8869     }
8870     else if (anArgCase == "-persp"
8871           || anArgCase == "-perspective"
8872           || anArgCase == "-perspmono"
8873           || anArgCase == "-perspectivemono"
8874           || anArgCase == "-mono")
8875     {
8876       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
8877     }
8878     else if (anArgCase == "-stereo"
8879           || anArgCase == "-stereoscopic"
8880           || anArgCase == "-perspstereo"
8881           || anArgCase == "-perspectivestereo")
8882     {
8883       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
8884     }
8885     else if (anArgCase == "-left"
8886           || anArgCase == "-lefteye"
8887           || anArgCase == "-monoleft"
8888           || anArgCase == "-monolefteye"
8889           || anArgCase == "-perpsleft"
8890           || anArgCase == "-perpslefteye")
8891     {
8892       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
8893     }
8894     else if (anArgCase == "-right"
8895           || anArgCase == "-righteye"
8896           || anArgCase == "-monoright"
8897           || anArgCase == "-monorighteye"
8898           || anArgCase == "-perpsright")
8899     {
8900       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
8901     }
8902     else if (anArgCase == "-dist"
8903           || anArgCase == "-distance")
8904     {
8905       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
8906       if (anArgValue != NULL
8907       && *anArgValue != '-')
8908       {
8909         ++anArgIter;
8910         aCamera->SetDistance (Draw::Atof (anArgValue));
8911         continue;
8912       }
8913       theDI << aCamera->Distance() << " ";
8914     }
8915     else if (anArgCase == "-iod")
8916     {
8917       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
8918       if (anArgValue != NULL
8919       && *anArgValue != '-')
8920       {
8921         ++anArgIter;
8922         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
8923         continue;
8924       }
8925       theDI << aCamera->IOD() << " ";
8926     }
8927     else if (anArgCase == "-iodtype")
8928     {
8929       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
8930       TCollection_AsciiString anValueCase (anArgValue);
8931       anValueCase.LowerCase();
8932       if (anValueCase == "abs"
8933        || anValueCase == "absolute")
8934       {
8935         ++anArgIter;
8936         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
8937         continue;
8938       }
8939       else if (anValueCase == "rel"
8940             || anValueCase == "relative")
8941       {
8942         ++anArgIter;
8943         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
8944         continue;
8945       }
8946       else if (*anArgValue != '-')
8947       {
8948         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
8949         return 1;
8950       }
8951       switch (aCamera->GetIODType())
8952       {
8953         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
8954         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
8955       }
8956     }
8957     else if (anArgCase == "-zfocus")
8958     {
8959       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
8960       if (anArgValue != NULL
8961       && *anArgValue != '-')
8962       {
8963         ++anArgIter;
8964         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
8965         continue;
8966       }
8967       theDI << aCamera->ZFocus() << " ";
8968     }
8969     else if (anArgCase == "-zfocustype")
8970     {
8971       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
8972       TCollection_AsciiString anValueCase (anArgValue);
8973       anValueCase.LowerCase();
8974       if (anValueCase == "abs"
8975        || anValueCase == "absolute")
8976       {
8977         ++anArgIter;
8978         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
8979         continue;
8980       }
8981       else if (anValueCase == "rel"
8982             || anValueCase == "relative")
8983       {
8984         ++anArgIter;
8985         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
8986         continue;
8987       }
8988       else if (*anArgValue != '-')
8989       {
8990         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
8991         return 1;
8992       }
8993       switch (aCamera->ZFocusType())
8994       {
8995         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
8996         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
8997       }
8998     }
8999     else if (anArgCase == "-lockzup"
9000           || anArgCase == "-turntable")
9001     {
9002       bool toLockUp = true;
9003       if (++anArgIter < theArgsNb
9004       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
9005       {
9006         --anArgIter;
9007       }
9008       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
9009     }
9010     else if (anArgCase == "-rotationmode"
9011           || anArgCase == "-rotmode")
9012     {
9013       AIS_RotationMode aRotMode = AIS_RotationMode_BndBoxActive;
9014       TCollection_AsciiString aRotStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9015       aRotStr.LowerCase();
9016       if (aRotStr == "bndboxactive"
9017        || aRotStr == "active")
9018       {
9019         aRotMode = AIS_RotationMode_BndBoxActive;
9020       }
9021       else if (aRotStr == "picklast"
9022             || aRotStr == "pick")
9023       {
9024         aRotMode = AIS_RotationMode_PickLast;
9025       }
9026       else if (aRotStr == "pickcenter")
9027       {
9028         aRotMode = AIS_RotationMode_PickCenter;
9029       }
9030       else if (aRotStr == "cameraat"
9031             || aRotStr == "cameracenter")
9032       {
9033         aRotMode = AIS_RotationMode_CameraAt;
9034       }
9035       else if (aRotStr == "bndboxscene"
9036             || aRotStr == "boxscene")
9037       {
9038         aRotMode = AIS_RotationMode_BndBoxScene;
9039       }
9040       else
9041       {
9042         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9043         return 1;
9044       }
9045
9046       ViewerTest::CurrentEventManager()->SetRotationMode (aRotMode);
9047       ++anArgIter;
9048     }
9049     else if (anArgCase == "-navigationmode"
9050           || anArgCase == "-navmode")
9051     {
9052       AIS_NavigationMode aNavMode = AIS_NavigationMode_Orbit;
9053       TCollection_AsciiString aNavStr ((anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "");
9054       aNavStr.LowerCase();
9055       if (aNavStr == "orbit")
9056       {
9057         aNavMode = AIS_NavigationMode_Orbit;
9058       }
9059       else if (aNavStr == "flight"
9060             || aNavStr == "fly"
9061             || aNavStr == "copter"
9062             || aNavStr == "helicopter")
9063       {
9064         aNavMode = AIS_NavigationMode_FirstPersonFlight;
9065       }
9066       else if (aNavStr == "walk"
9067             || aNavStr == "shooter")
9068       {
9069         aNavMode = AIS_NavigationMode_FirstPersonWalk;
9070       }
9071       else
9072       {
9073         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
9074         return 1;
9075       }
9076
9077       Handle(ViewerTest_EventManager) aViewMgr = ViewerTest::CurrentEventManager();
9078       aViewMgr->SetNavigationMode (aNavMode);
9079       if (aNavMode == AIS_NavigationMode_Orbit)
9080       {
9081         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateOrbit);
9082       }
9083       else
9084       {
9085         aViewMgr->ChangeMouseGestureMap().Bind (Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_RotateView);
9086       }
9087       ++anArgIter;
9088     }
9089     else if (anArgCase == "-fov"
9090           || anArgCase == "-fovy"
9091           || anArgCase == "-fovx"
9092           || anArgCase == "-fov2d")
9093     {
9094       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9095       if (anArgValue != NULL
9096       && *anArgValue != '-')
9097       {
9098         ++anArgIter;
9099         if (anArgCase == "-fov2d")
9100         {
9101           aCamera->SetFOV2d (Draw::Atof (anArgValue));
9102         }
9103         else if (anArgCase == "-fovx")
9104         {
9105           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
9106         }
9107         else
9108         {
9109           aCamera->SetFOVy (Draw::Atof (anArgValue));
9110         }
9111         continue;
9112       }
9113       if (anArgCase == "-fov2d")
9114       {
9115         theDI << aCamera->FOV2d() << " ";
9116       }
9117       else if (anArgCase == "-fovx")
9118       {
9119         theDI << aCamera->FOVx() << " ";
9120       }
9121       else
9122       {
9123         theDI << aCamera->FOVy() << " ";
9124       }
9125     }
9126     else if (anArgIter + 1 < theArgsNb
9127           && anArgCase == "-xrpose")
9128     {
9129       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
9130       anXRArg.LowerCase();
9131       if (anXRArg == "base")
9132       {
9133         aCamera = aView->View()->BaseXRCamera();
9134       }
9135       else if (anXRArg == "head")
9136       {
9137         aCamera = aView->View()->PosedXRCamera();
9138       }
9139       else
9140       {
9141         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
9142         return 1;
9143       }
9144       if (aCamera.IsNull())
9145       {
9146         Message::SendFail() << "Error: undefined XR pose";
9147         return 0;
9148       }
9149       if (aView->AutoZFitMode())
9150       {
9151         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
9152         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
9153         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
9154       }
9155     }
9156     else if (aPrsName.IsEmpty()
9157          && !anArgCase.StartsWith ("-"))
9158     {
9159       aPrsName = anArg;
9160     }
9161     else
9162     {
9163       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
9164       return 1;
9165     }
9166   }
9167
9168   if (aPrsName.IsEmpty()
9169    || theArgsNb > 2)
9170   {
9171     aView->Redraw();
9172   }
9173
9174   if (!aPrsName.IsEmpty())
9175   {
9176     Handle(AIS_CameraFrustum) aCameraFrustum;
9177     if (GetMapOfAIS().IsBound2 (aPrsName))
9178     {
9179       // find existing object
9180       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
9181       if (aCameraFrustum.IsNull())
9182       {
9183         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
9184         return 1;
9185       }
9186     }
9187
9188     if (aCameraFrustum.IsNull())
9189     {
9190       aCameraFrustum = new AIS_CameraFrustum();
9191     }
9192     else
9193     {
9194       // not include displayed object of old camera frustum in the new one.
9195       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
9196       aView->ZFitAll();
9197     }
9198     aCameraFrustum->SetCameraFrustum (aCamera);
9199
9200     ViewerTest::Display (aPrsName, aCameraFrustum);
9201   }
9202
9203   return 0;
9204 }
9205
9206 //! Parse stereo output mode
9207 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
9208                                          Graphic3d_StereoMode& theMode)
9209 {
9210   TCollection_AsciiString aFlag (theArg);
9211   aFlag.LowerCase();
9212   if (aFlag == "quadbuffer")
9213   {
9214     theMode = Graphic3d_StereoMode_QuadBuffer;
9215   }
9216   else if (aFlag == "anaglyph")
9217   {
9218     theMode = Graphic3d_StereoMode_Anaglyph;
9219   }
9220   else if (aFlag == "row"
9221         || aFlag == "rowinterlaced")
9222   {
9223     theMode = Graphic3d_StereoMode_RowInterlaced;
9224   }
9225   else if (aFlag == "col"
9226         || aFlag == "colinterlaced"
9227         || aFlag == "columninterlaced")
9228   {
9229     theMode = Graphic3d_StereoMode_ColumnInterlaced;
9230   }
9231   else if (aFlag == "chess"
9232         || aFlag == "chessboard")
9233   {
9234     theMode = Graphic3d_StereoMode_ChessBoard;
9235   }
9236   else if (aFlag == "sbs"
9237         || aFlag == "sidebyside")
9238   {
9239     theMode = Graphic3d_StereoMode_SideBySide;
9240   }
9241   else if (aFlag == "ou"
9242         || aFlag == "overunder")
9243   {
9244     theMode = Graphic3d_StereoMode_OverUnder;
9245   }
9246   else if (aFlag == "pageflip"
9247         || aFlag == "softpageflip")
9248   {
9249     theMode = Graphic3d_StereoMode_SoftPageFlip;
9250   }
9251   else if (aFlag == "openvr"
9252         || aFlag == "vr")
9253   {
9254     theMode = Graphic3d_StereoMode_OpenVR;
9255   }
9256   else
9257   {
9258     return Standard_False;
9259   }
9260   return Standard_True;
9261 }
9262
9263 //! Parse anaglyph filter
9264 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
9265                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
9266 {
9267   TCollection_AsciiString aFlag (theArg);
9268   aFlag.LowerCase();
9269   if (aFlag == "redcyansimple")
9270   {
9271     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9272   }
9273   else if (aFlag == "redcyan"
9274         || aFlag == "redcyanoptimized")
9275   {
9276     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
9277   }
9278   else if (aFlag == "yellowbluesimple")
9279   {
9280     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
9281   }
9282   else if (aFlag == "yellowblue"
9283         || aFlag == "yellowblueoptimized")
9284   {
9285     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
9286   }
9287   else if (aFlag == "greenmagenta"
9288         || aFlag == "greenmagentasimple")
9289   {
9290     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
9291   }
9292   else
9293   {
9294     return Standard_False;
9295   }
9296   return Standard_True;
9297 }
9298
9299 //==============================================================================
9300 //function : VStereo
9301 //purpose  :
9302 //==============================================================================
9303
9304 static int VStereo (Draw_Interpretor& theDI,
9305                     Standard_Integer  theArgNb,
9306                     const char**      theArgVec)
9307 {
9308   Handle(V3d_View) aView = ViewerTest::CurrentView();
9309   if (aView.IsNull())
9310   {
9311     Message::SendFail ("Error: no active viewer");
9312     return 0;
9313   }
9314
9315   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9316   Graphic3d_RenderingParams* aParams = &aView->ChangeRenderingParams();
9317   if (theArgNb < 2)
9318   {
9319     Standard_Boolean isActive = aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo;
9320     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
9321     if (isActive)
9322     {
9323       TCollection_AsciiString aMode;
9324       switch (aView->RenderingParams().StereoMode)
9325       {
9326         case Graphic3d_StereoMode_QuadBuffer       : aMode = "quadBuffer";       break;
9327         case Graphic3d_StereoMode_RowInterlaced    : aMode = "rowInterlaced";    break;
9328         case Graphic3d_StereoMode_ColumnInterlaced : aMode = "columnInterlaced"; break;
9329         case Graphic3d_StereoMode_ChessBoard       : aMode = "chessBoard";       break;
9330         case Graphic3d_StereoMode_SideBySide       : aMode = "sideBySide";       break;
9331         case Graphic3d_StereoMode_OverUnder        : aMode = "overUnder";        break;
9332         case Graphic3d_StereoMode_SoftPageFlip     : aMode = "softpageflip";     break;
9333         case Graphic3d_StereoMode_OpenVR           : aMode = "openVR";           break;
9334         case Graphic3d_StereoMode_Anaglyph  :
9335           aMode = "anaglyph";
9336           switch (aView->RenderingParams().AnaglyphFilter)
9337           {
9338             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
9339             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
9340             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
9341             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
9342             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
9343             default: break;
9344           }
9345         default: break;
9346       }
9347       theDI << "Mode " << aMode << "\n";
9348     }
9349     return 0;
9350   }
9351
9352   Graphic3d_StereoMode aMode = aParams->StereoMode;
9353   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
9354   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
9355   {
9356     Standard_CString        anArg = theArgVec[anArgIter];
9357     TCollection_AsciiString aFlag (anArg);
9358     aFlag.LowerCase();
9359     if (anUpdateTool.parseRedrawMode (aFlag))
9360     {
9361       continue;
9362     }
9363     else if (aFlag == "0"
9364           || aFlag == "off")
9365     {
9366       if (++anArgIter < theArgNb)
9367       {
9368         Message::SendFail ("Error: wrong number of arguments");
9369         return 1;
9370       }
9371
9372       if (aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
9373       {
9374         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9375       }
9376       return 0;
9377     }
9378     else if (aFlag == "1"
9379           || aFlag == "on")
9380     {
9381       if (++anArgIter < theArgNb)
9382       {
9383         Message::SendFail ("Error: wrong number of arguments");
9384         return 1;
9385       }
9386
9387       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9388       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
9389       {
9390         return 0;
9391       }
9392     }
9393     else if (aFlag == "-reverse"
9394           || aFlag == "-reversed"
9395           || aFlag == "-swap")
9396     {
9397       Standard_Boolean toEnable = Standard_True;
9398       if (++anArgIter < theArgNb
9399       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
9400       {
9401         --anArgIter;
9402       }
9403       aParams->ToReverseStereo = toEnable;
9404     }
9405     else if (aFlag == "-noreverse"
9406           || aFlag == "-noswap")
9407     {
9408       Standard_Boolean toDisable = Standard_True;
9409       if (++anArgIter < theArgNb
9410       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
9411       {
9412         --anArgIter;
9413       }
9414       aParams->ToReverseStereo = !toDisable;
9415     }
9416     else if (aFlag == "-mode"
9417           || aFlag == "-stereomode")
9418     {
9419       if (++anArgIter >= theArgNb
9420       || !parseStereoMode (theArgVec[anArgIter], aMode))
9421       {
9422         Message::SendFail() << "Syntax error at '" << anArg << "'";
9423         return 1;
9424       }
9425
9426       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9427       {
9428         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9429       }
9430     }
9431     else if (aFlag == "-anaglyph"
9432           || aFlag == "-anaglyphfilter")
9433     {
9434       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9435       if (++anArgIter >= theArgNb
9436       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
9437       {
9438         Message::SendFail() << "Syntax error at '" << anArg << "'";
9439         return 1;
9440       }
9441
9442       aMode = Graphic3d_StereoMode_Anaglyph;
9443       aParams->AnaglyphFilter = aFilter;
9444     }
9445     else if (parseStereoMode (anArg, aMode)) // short syntax
9446     {
9447       if (aMode == Graphic3d_StereoMode_QuadBuffer)
9448       {
9449         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
9450       }
9451     }
9452     else if (anArgIter + 1 < theArgNb
9453           && aFlag == "-hmdfov2d")
9454     {
9455       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
9456       if (aParams->HmdFov2d < 10.0f
9457        || aParams->HmdFov2d > 180.0f)
9458       {
9459         Message::SendFail() << "Error: FOV is out of range";
9460         return 1;
9461       }
9462     }
9463     else if (aFlag == "-mirror"
9464           || aFlag == "-mirrorcomposer")
9465     {
9466       Standard_Boolean toEnable = Standard_True;
9467       if (++anArgIter < theArgNb
9468       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
9469       {
9470         --anArgIter;
9471       }
9472       aParams->ToMirrorComposer = toEnable;
9473     }
9474     else if (anArgIter + 1 < theArgNb
9475           && (aFlag == "-unitfactor"
9476            || aFlag == "-unitscale"))
9477     {
9478       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
9479     }
9480     else
9481     {
9482       Message::SendFail() << "Syntax error at '" << anArg << "'";
9483       return 1;
9484     }
9485   }
9486
9487   aParams->StereoMode = aMode;
9488   aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9489   if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
9490   {
9491     // initiate implicit continuous rendering
9492     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
9493   }
9494   return 0;
9495 }
9496
9497 //===============================================================================================
9498 //function : VDefaults
9499 //purpose  :
9500 //===============================================================================================
9501 static int VDefaults (Draw_Interpretor& theDi,
9502                       Standard_Integer  theArgsNb,
9503                       const char**      theArgVec)
9504 {
9505   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9506   if (aCtx.IsNull())
9507   {
9508     Message::SendFail ("Error: no active viewer");
9509     return 1;
9510   }
9511
9512   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
9513   if (theArgsNb < 2)
9514   {
9515     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
9516     {
9517       theDi << "DeflType:           relative\n"
9518             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
9519     }
9520     else
9521     {
9522       theDi << "DeflType:           absolute\n"
9523             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
9524     }
9525     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
9526     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
9527     return 0;
9528   }
9529
9530   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9531   {
9532     TCollection_AsciiString anArg (theArgVec[anArgIter]);
9533     anArg.UpperCase();
9534     if (anArg == "-ABSDEFL"
9535      || anArg == "-ABSOLUTEDEFLECTION"
9536      || anArg == "-DEFL"
9537      || anArg == "-DEFLECTION")
9538     {
9539       if (++anArgIter >= theArgsNb)
9540       {
9541         Message::SendFail() << "Syntax error at " << anArg;
9542         return 1;
9543       }
9544       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
9545       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
9546     }
9547     else if (anArg == "-RELDEFL"
9548           || anArg == "-RELATIVEDEFLECTION"
9549           || anArg == "-DEVCOEFF"
9550           || anArg == "-DEVIATIONCOEFF"
9551           || anArg == "-DEVIATIONCOEFFICIENT")
9552     {
9553       if (++anArgIter >= theArgsNb)
9554       {
9555         Message::SendFail() << "Syntax error at " << anArg;
9556         return 1;
9557       }
9558       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
9559       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
9560     }
9561     else if (anArg == "-ANGDEFL"
9562           || anArg == "-ANGULARDEFL"
9563           || anArg == "-ANGULARDEFLECTION")
9564     {
9565       if (++anArgIter >= theArgsNb)
9566       {
9567         Message::SendFail() << "Syntax error at " << anArg;
9568         return 1;
9569       }
9570       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
9571     }
9572     else if (anArg == "-AUTOTR"
9573           || anArg == "-AUTOTRIANG"
9574           || anArg == "-AUTOTRIANGULATION")
9575     {
9576       ++anArgIter;
9577       bool toTurnOn = true;
9578       if (anArgIter >= theArgsNb
9579       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
9580       {
9581         Message::SendFail() << "Syntax error at '" << anArg << "'";
9582         return 1;
9583       }
9584       aDefParams->SetAutoTriangulation (toTurnOn);
9585     }
9586     else
9587     {
9588       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
9589       return 1;
9590     }
9591   }
9592
9593   return 0;
9594 }
9595
9596 //! Parse light source type from string.
9597 static bool parseLightSourceType (const TCollection_AsciiString& theTypeName,
9598                                   Graphic3d_TypeOfLightSource& theType)
9599 {
9600   TCollection_AsciiString aType (theTypeName);
9601   aType.LowerCase();
9602   if (aType == "amb"
9603    || aType == "ambient"
9604    || aType == "amblight")
9605   {
9606     theType = Graphic3d_TypeOfLightSource_Ambient;
9607   }
9608   else if (aType == "directional"
9609         || aType == "dirlight")
9610   {
9611     theType = Graphic3d_TypeOfLightSource_Directional;
9612   }
9613   else if (aType == "spot"
9614         || aType == "spotlight")
9615   {
9616     theType = Graphic3d_TypeOfLightSource_Spot;
9617   }
9618   else if (aType == "poslight"
9619         || aType == "positional"
9620         || aType == "point"
9621         || aType == "pnt")
9622   {
9623     theType = Graphic3d_TypeOfLightSource_Positional;
9624   }
9625   else
9626   {
9627     return false;
9628   }
9629   return true;
9630 }
9631
9632 //! Find existing light by name or index.
9633 static Handle(V3d_Light) findLightSource (const TCollection_AsciiString& theName)
9634 {
9635   Handle(V3d_Light) aLight;
9636   Standard_Integer aLightIndex = -1;
9637   Draw::ParseInteger (theName.ToCString(), aLightIndex);
9638   Standard_Integer aLightIt = 0;
9639   Handle(V3d_View) aView = ViewerTest::CurrentView();
9640   for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
9641   {
9642     if (aLightIndex != -1)
9643     {
9644       if (aLightIt == aLightIndex)
9645       {
9646         return aLightIter.Value();
9647       }
9648     }
9649     else if (aLightIter.Value()->GetId() == theName
9650           || aLightIter.Value()->Name()  == theName)
9651     {
9652       if (!aLight.IsNull())
9653       {
9654         Message::SendWarning() << "Warning: ambiguous light name '" << theName << "'";
9655         break;
9656       }
9657       aLight = aLightIter.Value();
9658     }
9659   }
9660   return aLight;
9661 }
9662
9663 //===============================================================================================
9664 //function : VLight
9665 //purpose  :
9666 //===============================================================================================
9667 static int VLight (Draw_Interpretor& theDi,
9668                    Standard_Integer  theArgsNb,
9669                    const char**      theArgVec)
9670 {
9671   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
9672   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
9673   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
9674   if (aView.IsNull()
9675    || aViewer.IsNull())
9676   {
9677     Message::SendFail ("Error: no active viewer");
9678     return 1;
9679   }
9680
9681   if (theArgsNb < 2)
9682   {
9683     // print lights info
9684     Standard_Integer aLightId = 0;
9685     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
9686     {
9687       Handle(V3d_Light) aLight = aLightIter.Value();
9688       const Quantity_Color aColor = aLight->Color();
9689       theDi << "Light #" << aLightId
9690             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
9691             << " [" << aLight->GetId() << "] "
9692             << (aLight->IsEnabled() ? "ON" : "OFF") << "\n";
9693       switch (aLight->Type())
9694       {
9695         case V3d_AMBIENT:
9696         {
9697           theDi << "  Type:       Ambient\n"
9698                 << "  Intensity:  " << aLight->Intensity() << "\n";
9699           break;
9700         }
9701         case V3d_DIRECTIONAL:
9702         {
9703           theDi << "  Type:       Directional\n"
9704                 << "  Intensity:  " << aLight->Intensity() << "\n"
9705                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9706                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9707                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9708                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n";
9709           break;
9710         }
9711         case V3d_POSITIONAL:
9712         {
9713           theDi << "  Type:       Positional\n"
9714                 << "  Intensity:  " << aLight->Intensity() << "\n"
9715                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9716                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9717                 << "  Smoothness: " << aLight->Smoothness() << "\n"
9718                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9719                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9720                 << "  Range:      " << aLight->Range() << "\n";
9721           break;
9722         }
9723         case V3d_SPOT:
9724         {
9725           theDi << "  Type:       Spot\n"
9726                 << "  Intensity:  " << aLight->Intensity() << "\n"
9727                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
9728                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
9729                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
9730                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n"
9731                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
9732                 << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n"
9733                 << "  Exponent:   " << aLight->Concentration() << "\n"
9734                 << "  Range:      " << aLight->Range() << "\n";
9735           break;
9736         }
9737         default:
9738         {
9739           theDi << "  Type:       UNKNOWN\n";
9740           break;
9741         }
9742       }
9743       theDi << "  Color:      " << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
9744     }
9745   }
9746
9747   Handle(V3d_Light) aLightOld, aLightNew;
9748   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
9749   bool isGlobal = true;
9750   ViewerTest_AutoUpdater anUpdateTool (aCtx, aView);
9751   Handle(AIS_LightSource) aLightPrs;
9752   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
9753   {
9754     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
9755     TCollection_AsciiString anArgCase (anArg);
9756     anArgCase.LowerCase();
9757     if (anUpdateTool.parseRedrawMode (anArg))
9758     {
9759       continue;
9760     }
9761     else if (anArgCase == "-new"
9762           || anArgCase == "-add"
9763           || anArgCase == "-create"
9764           || anArgCase == "-type"
9765           || (anArgCase == "-reset"
9766           && !aLightNew.IsNull())
9767           || (anArgCase == "-defaults"
9768           && !aLightNew.IsNull())
9769           || anArgCase == "add"
9770           || anArgCase == "new"
9771           || anArgCase == "create")
9772     {
9773       Graphic3d_TypeOfLightSource aType = Graphic3d_TypeOfLightSource_Ambient;
9774       if (anArgCase == "-reset")
9775       {
9776         aType = aLightNew->Type();
9777       }
9778       else if (anArgIt + 1 >= theArgsNb
9779            || !parseLightSourceType (theArgVec[++anArgIt], aType))
9780       {
9781         theDi << "Syntax error at '" << theArgVec[anArgIt] << "'\n";
9782         return 1;
9783       }
9784
9785       TCollection_AsciiString aName;
9786       if (!aLightNew.IsNull())
9787       {
9788         aName = aLightNew->Name();
9789       }
9790       switch (aType)
9791       {
9792         case Graphic3d_TypeOfLightSource_Ambient:
9793         {
9794           aLightNew = new V3d_AmbientLight();
9795           break;
9796         }
9797         case Graphic3d_TypeOfLightSource_Directional:
9798         {
9799           aLightNew = new V3d_DirectionalLight();
9800           break;
9801         }
9802         case Graphic3d_TypeOfLightSource_Spot:
9803         {
9804           aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
9805           break;
9806         }
9807         case Graphic3d_TypeOfLightSource_Positional:
9808         {
9809           aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
9810           break;
9811         }
9812       }
9813
9814       if (anArgCase == "-type"
9815       && !aLightOld.IsNull())
9816       {
9817         aLightNew->CopyFrom (aLightOld);
9818       }
9819       aLightNew->SetName (aName);
9820     }
9821     else if ((anArgCase == "-layer"
9822            || anArgCase == "-zlayer")
9823           && anArgIt + 1 < theArgsNb)
9824     {
9825       if (!ViewerTest::ParseZLayer (theArgVec[++anArgIt], aLayer)
9826       ||  aLayer == Graphic3d_ZLayerId_UNKNOWN)
9827       {
9828         Message::SendFail() << "Error: wrong syntax at '" << theArgVec[anArgIt] << "'";
9829         return 1;
9830       }
9831     }
9832     else if (anArgCase == "-glob"
9833           || anArgCase == "-global"
9834           || anArgCase == "-loc"
9835           || anArgCase == "-local")
9836     {
9837       isGlobal = anArgCase.StartsWith ("-glob");
9838     }
9839     else if (anArgCase == "-def"
9840           || anArgCase == "-defaults"
9841           || anArgCase == "-reset")
9842     {
9843       aViewer->SetDefaultLights();
9844       aLightOld.Nullify();
9845       aLightNew.Nullify();
9846       aLightPrs.Nullify();
9847     }
9848     else if (anArgCase == "-clr"
9849           || anArgCase == "-clear"
9850           || anArgCase == "clear")
9851     {
9852       TColStd_SequenceOfInteger aLayers;
9853       aViewer->GetAllZLayers (aLayers);
9854       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
9855       {
9856         if (aLayeriter.Value() == aLayer
9857          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
9858         {
9859           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
9860           aSettings.SetLights (Handle(Graphic3d_LightSet)());
9861           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
9862           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
9863           {
9864             break;
9865           }
9866         }
9867       }
9868
9869       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
9870       {
9871         ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
9872         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
9873         {
9874           Handle(V3d_Light) aLight = aLightIter.Value();
9875           Handle(AIS_InteractiveObject) aPrsObject;
9876           GetMapOfAIS().Find2 (aLight->Name(), aPrsObject);
9877           if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
9878           {
9879             aCtx->Remove (aLightSourceDel, false);
9880             aMap.UnBind1 (aLightSourceDel);
9881           }
9882           aViewer->DelLight (aLight);
9883           aLightIter = aView->ActiveLightIterator();
9884         }
9885       }
9886
9887       aLightOld.Nullify();
9888       aLightNew.Nullify();
9889       aLightPrs.Nullify();
9890     }
9891     else if (!aLightNew.IsNull()
9892           && (anArgCase == "-display"
9893            || anArgCase == "-disp"
9894            || anArgCase == "-presentation"
9895            || anArgCase == "-prs"))
9896     {
9897       TCollection_AsciiString aLightName = aLightNew->Name();
9898       if (anArgIt + 1 < theArgsNb
9899        && theArgVec[anArgIt + 1][0] != '-')
9900       {
9901         // old syntax
9902         aLightName = theArgVec[++anArgIt];
9903         if (aLightNew->Name() != aLightName)
9904         {
9905           if (Handle(V3d_Light) anOtherLight = findLightSource (aLightName))
9906           {
9907             theDi << "Syntax error: light with name '" << aLightName << "' is already defined";
9908             return 1;
9909           }
9910           aLightNew->SetName (aLightName);
9911         }
9912       }
9913       if (aLightName.IsEmpty())
9914       {
9915         Message::SendFail() << "Error: nameless light source cannot be displayed";
9916         return 1;
9917       }
9918       if (aLightPrs.IsNull())
9919       {
9920         aLightPrs = new AIS_LightSource (aLightNew);
9921       }
9922       theDi << aLightName << " ";
9923     }
9924     else if (!aLightNew.IsNull()
9925           && (anArgCase == "-disable"
9926            || anArgCase == "-disabled"
9927            || anArgCase == "-enable"
9928            || anArgCase == "-enabled"))
9929     {
9930       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
9931       if (anArgCase == "-disable"
9932        || anArgCase == "-disabled")
9933       {
9934         toEnable = !toEnable;
9935       }
9936       aLightNew->SetEnabled (toEnable);
9937     }
9938     else if (!aLightNew.IsNull()
9939           && (anArgCase == "-color"
9940            || anArgCase == "-colour"
9941            || anArgCase == "color"))
9942     {
9943       Quantity_Color aColor;
9944       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
9945                                                      theArgVec + anArgIt + 1,
9946                                                      aColor);
9947       anArgIt += aNbParsed;
9948       if (aNbParsed == 0)
9949       {
9950         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
9951         return 1;
9952       }
9953       aLightNew->SetColor (aColor);
9954     }
9955     else if (!aLightNew.IsNull()
9956           && (anArgCase == "-pos"
9957            || anArgCase == "-position"
9958            || anArgCase == "-prsposition"
9959            || anArgCase == "-prspos"
9960            || anArgCase == "pos"
9961            || anArgCase == "position")
9962           && (anArgIt + 3) < theArgsNb)
9963     {
9964       gp_XYZ aPosXYZ;
9965       if (!parseXYZ (theArgVec + anArgIt + 1, aPosXYZ))
9966       {
9967         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
9968         return 1;
9969       }
9970
9971       anArgIt += 3;
9972       if (anArgCase == "-prsposition"
9973        || anArgCase == "-prspos")
9974       {
9975         aLightNew->SetDisplayPosition (aPosXYZ);
9976       }
9977       else
9978       {
9979         if (aLightNew->Type() != Graphic3d_TypeOfLightSource_Positional
9980          && aLightNew->Type() != Graphic3d_TypeOfLightSource_Spot)
9981         {
9982           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
9983           return 1;
9984         }
9985
9986         aLightNew->SetPosition (aPosXYZ);
9987       }
9988     }
9989     else if (!aLightNew.IsNull()
9990           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional
9991            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
9992           && (anArgCase == "-dir"
9993            || anArgCase == "-direction")
9994           && (anArgIt + 3) < theArgsNb)
9995     {
9996       gp_XYZ aDirXYZ;
9997       if (!parseXYZ (theArgVec + anArgIt + 1, aDirXYZ))
9998       {
9999         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10000         return 1;
10001       }
10002
10003       anArgIt += 3;
10004       aLightNew->SetDirection (gp_Dir (aDirXYZ));
10005     }
10006     else if (!aLightNew.IsNull()
10007           && (anArgCase == "-smoothangle"
10008            || anArgCase == "-smoothradius"
10009            || anArgCase == "-sm"
10010            || anArgCase == "-smoothness")
10011           && anArgIt + 1 < theArgsNb)
10012     {
10013       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10014       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10015       {
10016         aSmoothness = Standard_ShortReal(aSmoothness * M_PI / 180.0);
10017       }
10018       if (Abs (aSmoothness) <= ShortRealEpsilon())
10019       {
10020         aLightNew->SetIntensity (1.f);
10021       }
10022       else if (Abs (aLightNew->Smoothness()) <= ShortRealEpsilon())
10023       {
10024         aLightNew->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
10025       }
10026       else
10027       {
10028         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightNew->Smoothness());
10029         aLightNew->SetIntensity (aLightNew->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
10030       }
10031
10032       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10033       {
10034         aLightNew->SetSmoothRadius (aSmoothness);
10035       }
10036       else if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10037       {
10038         aLightNew->SetSmoothAngle (aSmoothness);
10039       }
10040     }
10041     else if (!aLightNew.IsNull()
10042           && (anArgCase == "-int"
10043            || anArgCase == "-intensity")
10044           && anArgIt + 1 < theArgsNb)
10045     {
10046       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10047       aLightNew->SetIntensity (aIntensity);
10048     }
10049     else if (!aLightNew.IsNull()
10050           &&  aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10051           && (anArgCase == "-spotangle"
10052            || anArgCase == "-ang"
10053            || anArgCase == "-angle")
10054           && anArgIt + 1 < theArgsNb)
10055     {
10056       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10057       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
10058       aLightNew->SetAngle (anAngle);
10059     }
10060     else if (!aLightNew.IsNull()
10061           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10062            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10063           && (anArgCase == "-constatten"
10064            || anArgCase == "-constattenuation")
10065           && anArgIt + 1 < theArgsNb)
10066     {
10067       const Standard_ShortReal aConstAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10068       aLightNew->SetAttenuation (aConstAtten, aLightNew->LinearAttenuation());
10069     }
10070     else if (!aLightNew.IsNull()
10071           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10072            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10073           && (anArgCase == "-linatten"
10074            || anArgCase == "-linearatten"
10075            || anArgCase == "-linearattenuation")
10076           && anArgIt + 1 < theArgsNb)
10077     {
10078       const Standard_ShortReal aLinAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10079       aLightNew->SetAttenuation (aLightNew->ConstAttenuation(), aLinAtten);
10080     }
10081     else if (!aLightNew.IsNull()
10082           && aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10083           && (anArgCase == "-spotexp"
10084            || anArgCase == "-spotexponent"
10085            || anArgCase == "-exp"
10086            || anArgCase == "-exponent")
10087           && anArgIt + 1 < theArgsNb)
10088     {
10089       aLightNew->SetConcentration ((Standard_ShortReal )Atof (theArgVec[++anArgIt]));
10090     }
10091     else if (!aLightNew.IsNull()
10092            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10093            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Directional
10094            && anArgCase == "-range"
10095            && anArgIt + 1 < theArgsNb)
10096     {
10097       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[++anArgIt]));
10098       aLightNew->SetRange (aRange);
10099     }
10100     else if (!aLightNew.IsNull()
10101           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10102           && (anArgCase == "-head"
10103            || anArgCase == "-headlight"))
10104     {
10105       Standard_Boolean isHeadLight = Standard_True;
10106       if (anArgIt + 1 < theArgsNb
10107        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
10108       {
10109         ++anArgIt;
10110       }
10111       aLightNew->SetHeadlight (isHeadLight);
10112     }
10113     else if (!aLightNew.IsNull()
10114            && anArgCase == "-name"
10115            && anArgIt + 1 < theArgsNb)
10116     {
10117       const TCollection_AsciiString aName = theArgVec[++anArgIt];
10118       if (aLightNew->Name() == aName)
10119       {
10120         continue;
10121       }
10122
10123       if (Handle(V3d_Light) anOtherLight = findLightSource (aName))
10124       {
10125         theDi << "Syntax error: light with name '" << aName << "' is already defined";
10126         return 1;
10127       }
10128       aLightNew->SetName (aName);
10129     }
10130     else if (!aLightPrs.IsNull()
10131           && (anArgCase == "-showzoomable"
10132            || anArgCase == "-prszoomable"
10133            || anArgCase == "-zoomable"))
10134     {
10135       const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10136       aLightPrs->SetZoomable (isZoomable);
10137     }
10138     else if (!aLightPrs.IsNull()
10139          && (anArgCase == "-showdraggable"
10140           || anArgCase == "-prsdraggable"
10141           || anArgCase == "-draggable"))
10142     {
10143       const bool isDraggable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10144       aLightPrs->SetDraggable (isDraggable);
10145     }
10146     else if (!aLightPrs.IsNull()
10147           && (anArgCase == "-showname"
10148            || anArgCase == "-prsname"))
10149     {
10150       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10151       aLightPrs->SetDisplayName (toDisplay);
10152     }
10153     else if (!aLightPrs.IsNull()
10154           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10155            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10156           && (anArgCase == "-showrange"
10157            || anArgCase == "-prsrange"))
10158     {
10159       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10160       aLightPrs->SetDisplayRange (toDisplay);
10161     }
10162     else if (!aLightPrs.IsNull()
10163           && (anArgCase == "-showsize"
10164            || anArgCase == "-prssize")
10165           && anArgIt + 1 < theArgsNb)
10166     {
10167       Standard_Real aSize = 0.0;
10168       if (!Draw::ParseReal (theArgVec[++anArgIt], aSize)
10169        || aSize <= 0.0
10170        || aLightPrs.IsNull())
10171       {
10172         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10173         return 1;
10174       }
10175
10176       aLightPrs->SetSize (aSize);
10177     }
10178     else if (!aLightPrs.IsNull()
10179           && (anArgCase == "-dirarcsize"
10180            || anArgCase == "-arcsize"
10181            || anArgCase == "-arc")
10182           && anArgIt + 1 < theArgsNb)
10183     {
10184       Standard_Integer aSize = 0;
10185       if (!Draw::ParseInteger (theArgVec[anArgIt + 1], aSize)
10186        || aSize <= 0
10187        || aLightPrs->Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
10188       {
10189         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10190         return 1;
10191       }
10192       ++anArgIt;
10193       aLightPrs->SetArcSize (aSize);
10194     }
10195     else if (!aLightNew.IsNull()
10196           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10197           && (anArgCase == "-castshadow"
10198            || anArgCase == "-castshadows"
10199            || anArgCase == "-shadows"))
10200     {
10201       bool toCastShadows = true;
10202       if (anArgIt + 1 < theArgsNb
10203        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
10204       {
10205         ++anArgIt;
10206       }
10207       aLightNew->SetCastShadows (toCastShadows);
10208     }
10209     else if (anArgCase == "-del"
10210           || anArgCase == "-delete"
10211           || anArgCase == "-remove"
10212           || anArgCase == "del"
10213           || anArgCase == "delete"
10214           || anArgCase == "remove")
10215     {
10216       if (aLightOld.IsNull())
10217       {
10218         if (!aLightNew.IsNull())
10219         {
10220           aLightNew.Nullify();
10221           continue;
10222         }
10223
10224         if (++anArgIt >= theArgsNb)
10225         {
10226           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10227           return 1;
10228         }
10229
10230         const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10231         aLightOld = findLightSource (anOldName);
10232         if (aLightOld.IsNull())
10233         {
10234           Message::SendWarning() << "Warning: light '" << anOldName << "' not found";
10235           continue;
10236         }
10237       }
10238
10239       aLightNew.Nullify();
10240       aLightPrs.Nullify();
10241     }
10242     else if (anArgCase == "-change"
10243           || anArgCase == "change")
10244     {
10245       // just skip old syntax
10246     }
10247     else if (aLightNew.IsNull()
10248          && !anArgCase.StartsWith ("-"))
10249     {
10250       if (!aLightNew.IsNull())
10251       {
10252         continue;
10253       }
10254
10255       const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10256       aLightOld = findLightSource (anOldName);
10257       if (!aLightOld.IsNull())
10258       {
10259         aLightNew = aLightOld;
10260
10261         Handle(AIS_InteractiveObject) aPrsObject;
10262         GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10263         aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsObject);
10264       }
10265       else
10266       {
10267         Standard_Integer aLightIndex = -1;
10268         Draw::ParseInteger (anOldName.ToCString(), aLightIndex);
10269         if (aLightIndex != -1)
10270         {
10271           Message::SendFail() << "Syntax error: light source with index '" << aLightIndex << "' is not found";
10272           return 1;
10273         }
10274
10275         aLightNew = new V3d_AmbientLight();
10276         aLightNew->SetName (anOldName);
10277       }
10278     }
10279     else
10280     {
10281       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
10282       return 1;
10283     }
10284   }
10285
10286   // delete old light source
10287   if (!aLightOld.IsNull()
10288     && aLightOld != aLightNew)
10289   {
10290     TColStd_SequenceOfInteger aLayers;
10291     aViewer->GetAllZLayers (aLayers);
10292     for (TColStd_SequenceOfInteger::Iterator aLayerIter (aLayers); aLayerIter.More(); aLayerIter.Next())
10293     {
10294       if (aLayerIter.Value() == aLayer
10295        || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10296       {
10297         Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerIter.Value());
10298         if (!aSettings.Lights().IsNull())
10299         {
10300           aSettings.Lights()->Remove (aLightOld);
10301           if (aSettings.Lights()->IsEmpty())
10302           {
10303             aSettings.SetLights (Handle(Graphic3d_LightSet)());
10304           }
10305         }
10306         aViewer->SetZLayerSettings (aLayerIter.Value(), aSettings);
10307         if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10308         {
10309           break;
10310         }
10311       }
10312     }
10313
10314     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10315     {
10316       Handle(AIS_InteractiveObject) aPrsObject;
10317       GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10318       if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10319       {
10320         aCtx->Remove (aLightSourceDel, false);
10321         GetMapOfAIS().UnBind1 (aLightSourceDel);
10322       }
10323       aViewer->DelLight (aLightOld);
10324     }
10325     aLightOld.Nullify();
10326   }
10327
10328   // add new light source
10329   if (!aLightNew.IsNull())
10330   {
10331     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10332     {
10333       aViewer->AddLight (aLightNew);
10334       if (isGlobal)
10335       {
10336         aViewer->SetLightOn (aLightNew);
10337       }
10338       else
10339       {
10340         aView->SetLightOn (aLightNew);
10341       }
10342     }
10343     else
10344     {
10345       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayer);
10346       if (aSettings.Lights().IsNull())
10347       {
10348         aSettings.SetLights (new Graphic3d_LightSet());
10349       }
10350       aSettings.Lights()->Add (aLightNew);
10351       aViewer->SetZLayerSettings (aLayer, aSettings);
10352     }
10353
10354     if (!aLightPrs.IsNull())
10355     {
10356       aLightPrs->SetLight (aLightNew);
10357       ViewerTest::Display (aLightNew->Name(), aLightPrs, false);
10358     }
10359   }
10360
10361   // manage presentations
10362   struct LightPrsSort
10363   {
10364     bool operator() (const Handle(AIS_LightSource)& theLeft,
10365                      const Handle(AIS_LightSource)& theRight)
10366     {
10367       return theLeft->Light()->GetId() < theRight->Light()->GetId();
10368     }
10369   };
10370
10371   AIS_ListOfInteractive aPrsList;
10372   aCtx->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
10373   if (!aPrsList.IsEmpty())
10374   {
10375     // update light source presentations
10376     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
10377     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
10378     {
10379       if (Handle(AIS_LightSource) aLightPrs2 = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
10380       {
10381         aLightPrsVec.push_back (aLightPrs2);
10382       }
10383     }
10384
10385     // sort objects by id as AIS_InteractiveContext stores them in unordered map
10386     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
10387
10388     Standard_Integer aTopStack = 0;
10389     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
10390     {
10391       Handle(AIS_LightSource) aLightPrs2 = *aPrsIter;
10392       if (!aLightPrs2->TransformPersistence().IsNull()
10393         && aLightPrs2->TransformPersistence()->IsTrihedronOr2d())
10394       {
10395         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs2->Size();
10396         aLightPrs2->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
10397         aTopStack += aPrsSize + aPrsSize / 2;
10398       }
10399       aCtx->Redisplay (aLightPrs2, false);
10400       aCtx->SetTransformPersistence (aLightPrs2, aLightPrs2->TransformPersistence());
10401     }
10402   }
10403   return 0;
10404 }
10405
10406 //===============================================================================================
10407 //function : VPBREnvironment
10408 //purpose  :
10409 //===============================================================================================
10410 static int VPBREnvironment (Draw_Interpretor&,
10411                             Standard_Integer theArgsNb,
10412                             const char**     theArgVec)
10413 {
10414   if (theArgsNb > 2)
10415   {
10416     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
10417     return 1;
10418   }
10419
10420   Handle(V3d_View) aView = ViewerTest::CurrentView();
10421   if (aView.IsNull())
10422   {
10423     Message::SendFail ("Error: no active viewer");
10424     return 1;
10425   }
10426
10427   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
10428   anArg.LowerCase();
10429
10430   if (anArg == "-generate"
10431    || anArg == "-gen")
10432   {
10433     aView->GeneratePBREnvironment (Standard_True);
10434   }
10435   else if (anArg == "-clear")
10436   {
10437     aView->ClearPBREnvironment (Standard_True);
10438   }
10439   else
10440   {
10441     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
10442     return 1;
10443   }
10444
10445   return 0;
10446 }
10447
10448 //! Read Graphic3d_RenderingParams::PerfCounters flag.
10449 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
10450                                             Standard_Boolean& theToReset,
10451                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
10452                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
10453 {
10454   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
10455   TCollection_AsciiString aVal = theValue;
10456   Standard_Boolean toReverse = Standard_False;
10457   if (aVal == "none")
10458   {
10459     theToReset = Standard_True;
10460     return Standard_True;
10461   }
10462   else if (aVal.StartsWith ("-"))
10463   {
10464     toReverse = Standard_True;
10465     aVal = aVal.SubString (2, aVal.Length());
10466   }
10467   else if (aVal.StartsWith ("no"))
10468   {
10469     toReverse = Standard_True;
10470     aVal = aVal.SubString (3, aVal.Length());
10471   }
10472   else if (aVal.StartsWith ("+"))
10473   {
10474     aVal = aVal.SubString (2, aVal.Length());
10475   }
10476   else
10477   {
10478     theToReset = Standard_True;
10479   }
10480
10481   if (     aVal == "fps"
10482         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
10483   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
10484   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
10485   else if (aVal == "structs"
10486         || aVal == "structures"
10487         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
10488   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
10489   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
10490   else if (aVal == "tris"
10491         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
10492   else if (aVal == "pnts"
10493         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
10494   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
10495   else if (aVal == "mem"
10496         || aVal == "gpumem"
10497         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
10498   else if (aVal == "skipimmediate"
10499         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
10500   else if (aVal == "frametime"
10501         || aVal == "frametimers"
10502         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
10503   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
10504   else if (aVal == "extended"
10505         || aVal == "verbose"
10506         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
10507   else if (aVal == "full"
10508         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
10509   else
10510   {
10511     return Standard_False;
10512   }
10513
10514   if (toReverse)
10515   {
10516     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
10517   }
10518   else
10519   {
10520     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
10521   }
10522   return Standard_True;
10523 }
10524
10525 //! Read Graphic3d_RenderingParams::PerfCounters flags.
10526 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
10527                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
10528 {
10529   TCollection_AsciiString aValue = theValue;
10530   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
10531   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
10532   Standard_Boolean toReset = Standard_False;
10533   for (;;)
10534   {
10535     Standard_Integer aSplitPos = aValue.Search ("|");
10536     if (aSplitPos <= 0)
10537     {
10538       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
10539       {
10540         return Standard_False;
10541       }
10542       if (toReset)
10543       {
10544         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
10545       }
10546       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
10547       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
10548       return Standard_True;
10549     }
10550
10551     if (aSplitPos > 1)
10552     {
10553       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
10554       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
10555       {
10556         return Standard_False;
10557       }
10558     }
10559     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
10560   }
10561 }
10562
10563 //=======================================================================
10564 //function : VRenderParams
10565 //purpose  : Enables/disables rendering features
10566 //=======================================================================
10567
10568 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
10569                                        Standard_Integer  theArgNb,
10570                                        const char**      theArgVec)
10571 {
10572   Handle(V3d_View) aView = ViewerTest::CurrentView();
10573   if (aView.IsNull())
10574   {
10575     Message::SendFail ("Error: no active viewer");
10576     return 1;
10577   }
10578
10579   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
10580   TCollection_AsciiString aCmdName (theArgVec[0]);
10581   aCmdName.LowerCase();
10582   if (aCmdName == "vraytrace")
10583   {
10584     if (theArgNb == 1)
10585     {
10586       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
10587       return 0;
10588     }
10589     else if (theArgNb == 2)
10590     {
10591       TCollection_AsciiString aValue (theArgVec[1]);
10592       aValue.LowerCase();
10593       if (aValue == "on"
10594        || aValue == "1")
10595       {
10596         aParams.Method = Graphic3d_RM_RAYTRACING;
10597         aView->Redraw();
10598         return 0;
10599       }
10600       else if (aValue == "off"
10601             || aValue == "0")
10602       {
10603         aParams.Method = Graphic3d_RM_RASTERIZATION;
10604         aView->Redraw();
10605         return 0;
10606       }
10607       else
10608       {
10609         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
10610         return 1;
10611       }
10612     }
10613     else
10614     {
10615       Message::SendFail ("Syntax error: wrong number of arguments");
10616       return 1;
10617     }
10618   }
10619
10620   if (theArgNb < 2)
10621   {
10622     theDI << "renderMode:  ";
10623     switch (aParams.Method)
10624     {
10625       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10626       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
10627     }
10628     theDI << "\n";
10629     theDI << "transparency:  ";
10630     switch (aParams.TransparencyMethod)
10631     {
10632       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
10633       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
10634                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
10635       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
10636                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
10637     }
10638     theDI << "\n";
10639     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
10640     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
10641     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
10642     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
10643     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
10644     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
10645     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
10646     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
10647     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
10648     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
10649     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
10650     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
10651     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
10652     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
10653     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
10654     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
10655     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
10656     theDI << "shadingModel: ";
10657     switch (aView->ShadingModel())
10658     {
10659       case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
10660       case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit";     break;
10661       case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat";      break;
10662       case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud";   break;
10663       case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong";     break;
10664       case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
10665       case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
10666     }
10667     theDI << "\n";
10668     {
10669       theDI << "perfCounters:";
10670       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
10671       {
10672         theDI << " fps";
10673       }
10674       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
10675       {
10676         theDI << " cpu";
10677       }
10678       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
10679       {
10680         theDI << " structs";
10681       }
10682       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
10683       {
10684         theDI << " groups";
10685       }
10686       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
10687       {
10688         theDI << " arrays";
10689       }
10690       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
10691       {
10692         theDI << " tris";
10693       }
10694       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
10695       {
10696         theDI << " lines";
10697       }
10698       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
10699       {
10700         theDI << " pnts";
10701       }
10702       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
10703       {
10704         theDI << " gpumem";
10705       }
10706       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
10707       {
10708         theDI << " frameTime";
10709       }
10710       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
10711       {
10712         theDI << " skipimmediate";
10713       }
10714       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
10715       {
10716         theDI << " none";
10717       }
10718       theDI << "\n";
10719     }
10720     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
10721     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
10722     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
10723                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
10724                                                                                                                     "noUpdate") << "\n";
10725     theDI << "\n";
10726     return 0;
10727   }
10728
10729   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
10730   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10731   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10732   {
10733     Standard_CString        anArg (theArgVec[anArgIter]);
10734     TCollection_AsciiString aFlag (anArg);
10735     aFlag.LowerCase();
10736     if (anUpdateTool.parseRedrawMode (aFlag))
10737     {
10738       continue;
10739     }
10740     else if (aFlag == "-echo"
10741           || aFlag == "-print")
10742     {
10743       toPrint = Standard_True;
10744       anUpdateTool.Invalidate();
10745     }
10746     else if (aFlag == "-reset")
10747     {
10748       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
10749     }
10750     else if (aFlag == "-sync"
10751           && (anArgIter + 1 < theArgNb))
10752     {
10753       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
10754       aSyncFlag.LowerCase();
10755       if (aSyncFlag == "default"
10756        || aSyncFlag == "defaults"
10757        || aSyncFlag == "viewer")
10758       {
10759         toSyncDefaults = true;
10760       }
10761       else if (aSyncFlag == "allviews"
10762             || aSyncFlag == "views")
10763       {
10764         toSyncAllViews = true;
10765       }
10766       else
10767       {
10768         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
10769         return 1;
10770       }
10771     }
10772     else if (aFlag == "-mode"
10773           || aFlag == "-rendermode"
10774           || aFlag == "-render_mode")
10775     {
10776       if (toPrint)
10777       {
10778         switch (aParams.Method)
10779         {
10780           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
10781           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
10782         }
10783         continue;
10784       }
10785       else
10786       {
10787         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10788         return 1;
10789       }
10790     }
10791     else if (aFlag == "-ray"
10792           || aFlag == "-raytrace")
10793     {
10794       if (toPrint)
10795       {
10796         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
10797         continue;
10798       }
10799
10800       bool isRayTrace = true;
10801       if (anArgIter + 1 < theArgNb
10802        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
10803       {
10804         ++anArgIter;
10805       }
10806       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
10807     }
10808     else if (aFlag == "-rast"
10809           || aFlag == "-raster"
10810           || aFlag == "-rasterization")
10811     {
10812       if (toPrint)
10813       {
10814         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
10815         continue;
10816       }
10817
10818       bool isRaster = true;
10819       if (anArgIter + 1 < theArgNb
10820        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
10821       {
10822         ++anArgIter;
10823       }
10824       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
10825     }
10826     else if (aFlag == "-msaa")
10827     {
10828       if (toPrint)
10829       {
10830         theDI << aParams.NbMsaaSamples << " ";
10831         continue;
10832       }
10833       else if (++anArgIter >= theArgNb)
10834       {
10835         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10836         return 1;
10837       }
10838
10839       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
10840       if (aNbSamples < 0)
10841       {
10842         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
10843         return 1;
10844       }
10845       else
10846       {
10847         aParams.NbMsaaSamples = aNbSamples;
10848       }
10849     }
10850     else if (aFlag == "-linefeather"
10851           || aFlag == "-edgefeather"
10852           || aFlag == "-feather")
10853     {
10854       if (toPrint)
10855       {
10856         theDI << " " << aParams.LineFeather << " ";
10857         continue;
10858       }
10859       else if (++anArgIter >= theArgNb)
10860       {
10861         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10862         return 1;
10863       }
10864
10865       TCollection_AsciiString aParam = theArgVec[anArgIter];
10866       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
10867       if (aFeather <= 0.0f)
10868       {
10869         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
10870         return 1;
10871       }
10872       aParams.LineFeather = aFeather;
10873     }
10874     else if (aFlag == "-oit")
10875     {
10876       if (toPrint)
10877       {
10878         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
10879         {
10880           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
10881         }
10882         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
10883         {
10884           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
10885         }
10886         else
10887         {
10888           theDI << "off" << " ";
10889         }
10890         continue;
10891       }
10892       else if (++anArgIter >= theArgNb)
10893       {
10894         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10895         return 1;
10896       }
10897
10898       TCollection_AsciiString aParam = theArgVec[anArgIter];
10899       aParam.LowerCase();
10900       if (aParam == "peeling"
10901        || aParam == "peel")
10902       {
10903         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
10904         if (anArgIter + 1 < theArgNb
10905          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
10906         {
10907           ++anArgIter;
10908           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
10909           if (aNbLayers < 2)
10910           {
10911             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
10912             return 1;
10913           }
10914           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
10915         }
10916       }
10917       else if (aParam == "weighted"
10918             || aParam == "weight")
10919       {
10920         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
10921         if (anArgIter + 1 < theArgNb
10922          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
10923         {
10924           ++anArgIter;
10925           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
10926           if (aWeight < 0.f || aWeight > 1.f)
10927           {
10928             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
10929             return 1;
10930           }
10931           aParams.OitDepthFactor = aWeight;
10932         }
10933       }
10934       else if (aParam.IsRealValue())
10935       {
10936         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
10937         if (aWeight < 0.f || aWeight > 1.f)
10938         {
10939           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
10940           return 1;
10941         }
10942
10943         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
10944         aParams.OitDepthFactor     = aWeight;
10945       }
10946       else if (aParam == "off")
10947       {
10948         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
10949       }
10950       else
10951       {
10952         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10953         return 1;
10954       }
10955     }
10956     else if (aFlag == "-fonthinting"
10957           || aFlag == "-fonthint")
10958     {
10959       if (toPrint)
10960       {
10961         if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
10962         {
10963           theDI << "normal" << " ";
10964         }
10965         else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
10966         {
10967           theDI << "light" << " ";
10968         }
10969         else
10970         {
10971           theDI << "off" << " ";
10972         }
10973         continue;
10974       }
10975       else if (anArgIter + 1 >= theArgNb)
10976       {
10977         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
10978         return 1;
10979       }
10980
10981       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
10982       aHintStyle.LowerCase();
10983       if (aHintStyle == "normal"
10984        || aHintStyle == "on"
10985        || aHintStyle == "1")
10986       {
10987         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
10988         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Normal);
10989       }
10990       else if (aHintStyle == "light")
10991       {
10992         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
10993         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Light);
10994       }
10995       else if (aHintStyle == "no"
10996             || aHintStyle == "off"
10997             || aHintStyle == "0")
10998       {
10999         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11000         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11001       }
11002       else
11003       {
11004         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11005         return 1;
11006       }
11007     }
11008     else if (aFlag == "-fontautohinting"
11009           || aFlag == "-fontautohint")
11010     {
11011       if (toPrint)
11012       {
11013         if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
11014         {
11015           theDI << "force" << " ";
11016         }
11017         else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
11018         {
11019           theDI << "disallow" << " ";
11020         }
11021         else
11022         {
11023           theDI << "auto" << " ";
11024         }
11025         continue;
11026       }
11027       else if (anArgIter + 1 >= theArgNb)
11028       {
11029         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11030         return 1;
11031       }
11032
11033       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11034       aHintStyle.LowerCase();
11035       if (aHintStyle == "force")
11036       {
11037         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11038         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_ForceAutohint);
11039       }
11040       else if (aHintStyle == "disallow"
11041             || aHintStyle == "no")
11042       {
11043         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11044         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_NoAutohint);
11045       }
11046       else if (aHintStyle == "auto")
11047       {
11048         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11049         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11050       }
11051       else
11052       {
11053         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11054         return 1;
11055       }
11056     }
11057     else if (aFlag == "-depthprepass")
11058     {
11059       if (toPrint)
11060       {
11061         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11062         continue;
11063       }
11064       aParams.ToEnableDepthPrepass = Standard_True;
11065       if (anArgIter + 1 < theArgNb
11066        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11067       {
11068         ++anArgIter;
11069       }
11070     }
11071     else if (aFlag == "-samplealphatocoverage"
11072           || aFlag == "-alphatocoverage")
11073     {
11074       if (toPrint)
11075       {
11076         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11077         continue;
11078       }
11079       aParams.ToEnableAlphaToCoverage = Standard_True;
11080       if (anArgIter + 1 < theArgNb
11081        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11082       {
11083         ++anArgIter;
11084       }
11085     }
11086     else if (aFlag == "-rendscale"
11087           || aFlag == "-renderscale"
11088           || aFlag == "-renderresolutionscale")
11089     {
11090       if (toPrint)
11091       {
11092         theDI << aParams.RenderResolutionScale << " ";
11093         continue;
11094       }
11095       else if (++anArgIter >= theArgNb)
11096       {
11097         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11098         return 1;
11099       }
11100
11101       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11102       if (aScale < 0.01)
11103       {
11104         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11105         return 1;
11106       }
11107       else
11108       {
11109         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11110       }
11111     }
11112     else if (aFlag == "-raydepth"
11113           || aFlag == "-ray_depth")
11114     {
11115       if (toPrint)
11116       {
11117         theDI << aParams.RaytracingDepth << " ";
11118         continue;
11119       }
11120       else if (++anArgIter >= theArgNb)
11121       {
11122         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11123         return 1;
11124       }
11125
11126       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11127
11128       // We allow RaytracingDepth be more than 10 in case of GI enabled
11129       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11130       {
11131         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11132         return 1;
11133       }
11134       else
11135       {
11136         aParams.RaytracingDepth = aDepth;
11137       }
11138     }
11139     else if (aFlag == "-shad"
11140           || aFlag == "-shadows")
11141     {
11142       if (toPrint)
11143       {
11144         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11145         continue;
11146       }
11147
11148       Standard_Boolean toEnable = Standard_True;
11149       if (++anArgIter < theArgNb
11150       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11151       {
11152         --anArgIter;
11153       }
11154       aParams.IsShadowEnabled = toEnable;
11155     }
11156     else if (aFlag == "-shadowmapresolution"
11157           || aFlag == "-shadowmap")
11158     {
11159       if (toPrint)
11160       {
11161         theDI << aParams.ShadowMapResolution << " ";
11162         continue;
11163       }
11164       else if (++anArgIter >= theArgNb)
11165       {
11166         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11167         return 1;
11168       }
11169
11170       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
11171     }
11172     else if (aFlag == "-shadowmapbias")
11173     {
11174       if (toPrint)
11175       {
11176         theDI << aParams.ShadowMapBias << " ";
11177         continue;
11178       }
11179       else if (++anArgIter >= theArgNb)
11180       {
11181         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11182         return 1;
11183       }
11184
11185       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
11186     }
11187     else if (aFlag == "-refl"
11188           || aFlag == "-reflections")
11189     {
11190       if (toPrint)
11191       {
11192         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11193         continue;
11194       }
11195
11196       Standard_Boolean toEnable = Standard_True;
11197       if (++anArgIter < theArgNb
11198       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11199       {
11200         --anArgIter;
11201       }
11202       aParams.IsReflectionEnabled = toEnable;
11203     }
11204     else if (aFlag == "-fsaa")
11205     {
11206       if (toPrint)
11207       {
11208         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11209         continue;
11210       }
11211
11212       Standard_Boolean toEnable = Standard_True;
11213       if (++anArgIter < theArgNb
11214       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11215       {
11216         --anArgIter;
11217       }
11218       aParams.IsAntialiasingEnabled = toEnable;
11219     }
11220     else if (aFlag == "-gleam")
11221     {
11222       if (toPrint)
11223       {
11224         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11225         continue;
11226       }
11227
11228       Standard_Boolean toEnable = Standard_True;
11229       if (++anArgIter < theArgNb
11230       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11231       {
11232         --anArgIter;
11233       }
11234       aParams.IsTransparentShadowEnabled = toEnable;
11235     }
11236     else if (aFlag == "-gi")
11237     {
11238       if (toPrint)
11239       {
11240         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11241         continue;
11242       }
11243
11244       Standard_Boolean toEnable = Standard_True;
11245       if (++anArgIter < theArgNb
11246       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11247       {
11248         --anArgIter;
11249       }
11250       aParams.IsGlobalIlluminationEnabled = toEnable;
11251       if (!toEnable)
11252       {
11253         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11254       }
11255     }
11256     else if (aFlag == "-blockedrng"
11257           || aFlag == "-brng")
11258     {
11259       if (toPrint)
11260       {
11261         theDI << (aParams.CoherentPathTracingMode ? "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.CoherentPathTracingMode = toEnable;
11272     }
11273     else if (aFlag == "-maxrad")
11274     {
11275       if (toPrint)
11276       {
11277         theDI << aParams.RadianceClampingValue << " ";
11278         continue;
11279       }
11280       else if (++anArgIter >= theArgNb)
11281       {
11282         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11283         return 1;
11284       }
11285
11286       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11287       if (!aMaxRadStr.IsRealValue (Standard_True))
11288       {
11289         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11290         return 1;
11291       }
11292
11293       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11294       if (aMaxRadiance <= 0.0)
11295       {
11296         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
11297         return 1;
11298       }
11299       else
11300       {
11301         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
11302       }
11303     }
11304     else if (aFlag == "-iss")
11305     {
11306       if (toPrint)
11307       {
11308         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
11309         continue;
11310       }
11311
11312       Standard_Boolean toEnable = Standard_True;
11313       if (++anArgIter < theArgNb
11314         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11315       {
11316         --anArgIter;
11317       }
11318       aParams.AdaptiveScreenSampling = toEnable;
11319     }
11320     else if (aFlag == "-issatomic")
11321     {
11322       if (toPrint)
11323       {
11324         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
11325         continue;
11326       }
11327
11328       Standard_Boolean toEnable = Standard_True;
11329       if (++anArgIter < theArgNb
11330       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11331       {
11332         --anArgIter;
11333       }
11334       aParams.AdaptiveScreenSamplingAtomic = toEnable;
11335     }
11336     else if (aFlag == "-issd")
11337     {
11338       if (toPrint)
11339       {
11340         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
11341         continue;
11342       }
11343
11344       Standard_Boolean toEnable = Standard_True;
11345       if (++anArgIter < theArgNb
11346         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11347       {
11348         --anArgIter;
11349       }
11350       aParams.ShowSamplingTiles = toEnable;
11351     }
11352     else if (aFlag == "-tilesize")
11353     {
11354       if (toPrint)
11355       {
11356         theDI << aParams.RayTracingTileSize << " ";
11357         continue;
11358       }
11359       else if (++anArgIter >= theArgNb)
11360       {
11361         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11362         return 1;
11363       }
11364
11365       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
11366       if (aTileSize < 1)
11367       {
11368         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
11369         return 1;
11370       }
11371       aParams.RayTracingTileSize = aTileSize;
11372     }
11373     else if (aFlag == "-nbtiles")
11374     {
11375       if (toPrint)
11376       {
11377         theDI << aParams.NbRayTracingTiles << " ";
11378         continue;
11379       }
11380       else if (++anArgIter >= theArgNb)
11381       {
11382         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11383         return 1;
11384       }
11385
11386       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
11387       if (aNbTiles < -1)
11388       {
11389         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
11390         return 1;
11391       }
11392       else if (aNbTiles > 0
11393             && (aNbTiles < 64
11394              || aNbTiles > 1024))
11395       {
11396         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
11397       }
11398       aParams.NbRayTracingTiles = aNbTiles;
11399     }
11400     else if (aFlag == "-env")
11401     {
11402       if (toPrint)
11403       {
11404         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
11405         continue;
11406       }
11407
11408       Standard_Boolean toEnable = Standard_True;
11409       if (++anArgIter < theArgNb
11410         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11411       {
11412         --anArgIter;
11413       }
11414       aParams.UseEnvironmentMapBackground = toEnable;
11415     }
11416     else if (aFlag == "-ignorenormalmap")
11417     {
11418       if (toPrint)
11419       {
11420         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
11421         continue;
11422       }
11423
11424       Standard_Boolean toEnable = Standard_True;
11425       if (++anArgIter < theArgNb
11426         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11427       {
11428         --anArgIter;
11429       }
11430       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
11431     }
11432     else if (aFlag == "-twoside")
11433     {
11434       if (toPrint)
11435       {
11436         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
11437         continue;
11438       }
11439
11440       Standard_Boolean toEnable = Standard_True;
11441       if (++anArgIter < theArgNb
11442         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11443       {
11444         --anArgIter;
11445       }
11446       aParams.TwoSidedBsdfModels = toEnable;
11447     }
11448     else if (aFlag == "-shademodel"
11449           || aFlag == "-shadingmodel"
11450           || aFlag == "-shading")
11451     {
11452       if (toPrint)
11453       {
11454         switch (aView->ShadingModel())
11455         {
11456           case Graphic3d_TypeOfShadingModel_DEFAULT:    theDI << "default";   break;
11457           case Graphic3d_TypeOfShadingModel_Unlit:      theDI << "unlit ";    break;
11458           case Graphic3d_TypeOfShadingModel_PhongFacet: theDI << "flat ";     break;
11459           case Graphic3d_TypeOfShadingModel_Gouraud:    theDI << "gouraud ";  break;
11460           case Graphic3d_TypeOfShadingModel_Phong:      theDI << "phong ";    break;
11461           case Graphic3d_TypeOfShadingModel_Pbr:        theDI << "pbr";       break;
11462           case Graphic3d_TypeOfShadingModel_PbrFacet:   theDI << "pbr_facet"; break;
11463         }
11464         continue;
11465       }
11466
11467       if (++anArgIter >= theArgNb)
11468       {
11469         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11470       }
11471
11472       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TypeOfShadingModel_DEFAULT;
11473       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
11474        && aModel != Graphic3d_TypeOfShadingModel_DEFAULT)
11475       {
11476         aView->SetShadingModel (aModel);
11477       }
11478       else
11479       {
11480         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
11481         return 1;
11482       }
11483     }
11484     else if (aFlag == "-pbrenvpow2size"
11485           || aFlag == "-pbrenvp2s"
11486           || aFlag == "-pep2s")
11487     {
11488       if (++anArgIter >= theArgNb)
11489       {
11490         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11491         return 1;
11492       }
11493
11494       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
11495       if (aPbrEnvPow2Size < 1)
11496       {
11497         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
11498         return 1;
11499       }
11500       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
11501     }
11502     else if (aFlag == "-pbrenvspecmaplevelsnumber"
11503           || aFlag == "-pbrenvspecmapnblevels"
11504           || aFlag == "-pbrenvspecmaplevels"
11505           || aFlag == "-pbrenvsmln"
11506           || aFlag == "-pesmln")
11507     {
11508       if (++anArgIter >= theArgNb)
11509       {
11510         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11511         return 1;
11512       }
11513
11514       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
11515       if (aPbrEnvSpecMapNbLevels < 2)
11516       {
11517         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
11518         return 1;
11519       }
11520       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
11521     }
11522     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
11523           || aFlag == "-pbrenvbakingdiffsamples"
11524           || aFlag == "-pbrenvbdsn")
11525     {
11526       if (++anArgIter >= theArgNb)
11527       {
11528         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11529         return 1;
11530       }
11531
11532       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11533       if (aPbrEnvBakingDiffNbSamples < 1)
11534       {
11535         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
11536         return 1;
11537       }
11538       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
11539     }
11540     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
11541           || aFlag == "-pbrenvbakingspecsamples"
11542           || aFlag == "-pbrenvbssn")
11543     {
11544     if (++anArgIter >= theArgNb)
11545     {
11546       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11547       return 1;
11548     }
11549
11550     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
11551     if (aPbrEnvBakingSpecNbSamples < 1)
11552     {
11553       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
11554       return 1;
11555     }
11556     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
11557     }
11558     else if (aFlag == "-pbrenvbakingprobability"
11559           || aFlag == "-pbrenvbp")
11560     {
11561       if (++anArgIter >= theArgNb)
11562       {
11563         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11564         return 1;
11565       }
11566       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
11567       if (aPbrEnvBakingProbability < 0.f
11568        || aPbrEnvBakingProbability > 1.f)
11569       {
11570         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
11571         return 1;
11572       }
11573       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
11574     }
11575     else if (aFlag == "-resolution")
11576     {
11577       if (++anArgIter >= theArgNb)
11578       {
11579         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11580         return 1;
11581       }
11582
11583       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
11584       if (aResolution.IsIntegerValue())
11585       {
11586         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
11587       }
11588       else
11589       {
11590         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
11591         return 1;
11592       }
11593     }
11594     else if (aFlag == "-rebuildglsl"
11595           || aFlag == "-rebuild")
11596     {
11597       if (toPrint)
11598       {
11599         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
11600         continue;
11601       }
11602
11603       Standard_Boolean toEnable = Standard_True;
11604       if (++anArgIter < theArgNb
11605           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11606       {
11607         --anArgIter;
11608       }
11609       aParams.RebuildRayTracingShaders = toEnable;
11610     }
11611     else if (aFlag == "-focal")
11612     {
11613       if (++anArgIter >= theArgNb)
11614       {
11615         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11616         return 1;
11617       }
11618
11619       TCollection_AsciiString aParam (theArgVec[anArgIter]);
11620       if (aParam.IsRealValue (Standard_True))
11621       {
11622         float aFocalDist = static_cast<float> (aParam.RealValue());
11623         if (aFocalDist < 0)
11624         {
11625           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11626           return 1;
11627         }
11628         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
11629       }
11630       else
11631       {
11632         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11633         return 1;
11634       }
11635     }
11636     else if (aFlag == "-aperture")
11637     {
11638       if (++anArgIter >= theArgNb)
11639       {
11640         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11641         return 1;
11642       }
11643
11644       TCollection_AsciiString aParam(theArgVec[anArgIter]);
11645       if (aParam.IsRealValue (Standard_True))
11646       {
11647         float aApertureSize = static_cast<float> (aParam.RealValue());
11648         if (aApertureSize < 0)
11649         {
11650           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
11651           return 1;
11652         }
11653         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
11654       }
11655       else
11656       {
11657         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11658         return 1;
11659       }
11660     }
11661     else if (aFlag == "-exposure")
11662     {
11663       if (++anArgIter >= theArgNb)
11664       {
11665         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11666         return 1;
11667       }
11668
11669       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
11670       if (anExposure.IsRealValue (Standard_True))
11671       {
11672         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
11673       }
11674       else
11675       {
11676         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11677         return 1;
11678       }
11679     }
11680     else if (aFlag == "-whitepoint")
11681     {
11682       if (++anArgIter >= theArgNb)
11683       {
11684         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11685         return 1;
11686       }
11687
11688       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
11689       if (aWhitePoint.IsRealValue (Standard_True))
11690       {
11691         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
11692       }
11693       else
11694       {
11695         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11696         return 1;
11697       }
11698     }
11699     else if (aFlag == "-tonemapping")
11700     {
11701       if (++anArgIter >= theArgNb)
11702       {
11703         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11704         return 1;
11705       }
11706
11707       TCollection_AsciiString aMode (theArgVec[anArgIter]);
11708       aMode.LowerCase();
11709
11710       if (aMode == "disabled")
11711       {
11712         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
11713       }
11714       else if (aMode == "filmic")
11715       {
11716         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
11717       }
11718       else
11719       {
11720         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
11721         return 1;
11722       }
11723     }
11724     else if (aFlag == "-performancestats"
11725           || aFlag == "-performancecounters"
11726           || aFlag == "-perfstats"
11727           || aFlag == "-perfcounters"
11728           || aFlag == "-stats")
11729     {
11730       if (++anArgIter >= theArgNb)
11731       {
11732         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11733         return 1;
11734       }
11735
11736       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
11737       aFlagsStr.LowerCase();
11738       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
11739       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
11740       {
11741         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11742         return 1;
11743       }
11744       aView->ChangeRenderingParams().CollectedStats = aFlags;
11745       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
11746     }
11747     else if (aFlag == "-perfupdateinterval"
11748           || aFlag == "-statsupdateinterval")
11749     {
11750       if (++anArgIter >= theArgNb)
11751       {
11752         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11753         return 1;
11754       }
11755       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11756     }
11757     else if (aFlag == "-perfchart"
11758           || aFlag == "-statschart")
11759     {
11760       if (++anArgIter >= theArgNb)
11761       {
11762         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11763         return 1;
11764       }
11765       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
11766     }
11767     else if (aFlag == "-perfchartmax"
11768           || aFlag == "-statschartmax")
11769     {
11770       if (++anArgIter >= theArgNb)
11771       {
11772         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11773         return 1;
11774       }
11775       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
11776     }
11777     else if (aFlag == "-frustumculling"
11778           || aFlag == "-culling")
11779     {
11780       if (toPrint)
11781       {
11782         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
11783                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
11784                                                                                                    "noUpdate") << " ";
11785         continue;
11786       }
11787
11788       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
11789       if (++anArgIter < theArgNb)
11790       {
11791         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
11792         aStateStr.LowerCase();
11793         bool toEnable = true;
11794         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
11795         {
11796           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
11797         }
11798         else if (aStateStr == "noupdate"
11799               || aStateStr == "freeze")
11800         {
11801           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
11802         }
11803         else
11804         {
11805           --anArgIter;
11806         }
11807       }
11808       aParams.FrustumCullingState = aState;
11809     }
11810     else
11811     {
11812       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
11813       return 1;
11814     }
11815   }
11816
11817   // set current view parameters as defaults
11818   if (toSyncDefaults)
11819   {
11820     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
11821   }
11822   if (toSyncAllViews)
11823   {
11824     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
11825     {
11826       aViewIter.Value()->ChangeRenderingParams() = aParams;
11827     }
11828   }
11829   return 0;
11830 }
11831
11832 //=======================================================================
11833 //function : searchInfo
11834 //purpose  :
11835 //=======================================================================
11836 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
11837                                            const TCollection_AsciiString&              theKey)
11838 {
11839   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
11840   {
11841     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
11842     {
11843       return anIter.Value();
11844     }
11845   }
11846   return TCollection_AsciiString();
11847 }
11848
11849 //=======================================================================
11850 //function : VStatProfiler
11851 //purpose  :
11852 //=======================================================================
11853 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
11854                                        Standard_Integer  theArgNb,
11855                                        const char**      theArgVec)
11856 {
11857   Handle(V3d_View) aView = ViewerTest::CurrentView();
11858   if (aView.IsNull())
11859   {
11860     Message::SendFail ("Error: no active viewer");
11861     return 1;
11862   }
11863
11864   Standard_Boolean toRedraw = Standard_True;
11865   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
11866   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
11867   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
11868   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11869   {
11870     Standard_CString        anArg (theArgVec[anArgIter]);
11871     TCollection_AsciiString aFlag (anArg);
11872     aFlag.LowerCase();
11873     if (aFlag == "-noredraw")
11874     {
11875       toRedraw = Standard_False;
11876     }
11877     else
11878     {
11879       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
11880       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11881       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
11882       else if (aFlag == "alllayers"
11883             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
11884       else if (aFlag == "allstructs"
11885             || aFlag == "allstructures"
11886             || aFlag == "structs"
11887             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
11888       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
11889       else if (aFlag == "allarrays"
11890             || aFlag == "fillarrays"
11891             || aFlag == "linearrays"
11892             || aFlag == "pointarrays"
11893             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
11894       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
11895       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
11896       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
11897       else if (aFlag == "geommem"
11898             || aFlag == "texturemem"
11899             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
11900       else if (aFlag == "elapsedframe"
11901             || aFlag == "cpuframeaverage"
11902             || aFlag == "cpupickingaverage"
11903             || aFlag == "cpucullingaverage"
11904             || aFlag == "cpudynaverage"
11905             || aFlag == "cpuframemax"
11906             || aFlag == "cpupickingmax"
11907             || aFlag == "cpucullingmax"
11908             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
11909       else
11910       {
11911         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
11912         continue;
11913       }
11914
11915       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
11916     }
11917   }
11918
11919   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
11920   {
11921     aView->ChangeRenderingParams().CollectedStats =
11922       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
11923
11924     if (toRedraw)
11925     {
11926       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
11927       aView->Redraw();
11928       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
11929     }
11930
11931     TColStd_IndexedDataMapOfStringString aDict;
11932     aView->StatisticInformation (aDict);
11933
11934     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
11935
11936     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11937     {
11938       Standard_CString        anArg(theArgVec[anArgIter]);
11939       TCollection_AsciiString aFlag(anArg);
11940       aFlag.LowerCase();
11941       if (aFlag == "fps")
11942       {
11943         theDI << searchInfo (aDict, "FPS") << " ";
11944       }
11945       else if (aFlag == "cpu")
11946       {
11947         theDI << searchInfo (aDict, "CPU FPS") << " ";
11948       }
11949       else if (aFlag == "alllayers")
11950       {
11951         theDI << searchInfo (aDict, "Layers") << " ";
11952       }
11953       else if (aFlag == "layers")
11954       {
11955         theDI << searchInfo (aDict, "Rendered layers") << " ";
11956       }
11957       else if (aFlag == "allstructs"
11958             || aFlag == "allstructures")
11959       {
11960         theDI << searchInfo (aDict, "Structs") << " ";
11961       }
11962       else if (aFlag == "structs"
11963             || aFlag == "structures")
11964       {
11965         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
11966         if (aRend.IsEmpty()) // all structures rendered
11967         {
11968           aRend = searchInfo (aDict, "Structs");
11969         }
11970         theDI << aRend << " ";
11971       }
11972       else if (aFlag == "groups")
11973       {
11974         theDI << searchInfo (aDict, "Rendered groups") << " ";
11975       }
11976       else if (aFlag == "allarrays")
11977       {
11978         theDI << searchInfo (aDict, "Rendered arrays") << " ";
11979       }
11980       else if (aFlag == "fillarrays")
11981       {
11982         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
11983       }
11984       else if (aFlag == "linearrays")
11985       {
11986         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
11987       }
11988       else if (aFlag == "pointarrays")
11989       {
11990         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
11991       }
11992       else if (aFlag == "textarrays")
11993       {
11994         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
11995       }
11996       else if (aFlag == "triangles")
11997       {
11998         theDI << searchInfo (aDict, "Rendered triangles") << " ";
11999       }
12000       else if (aFlag == "points")
12001       {
12002         theDI << searchInfo (aDict, "Rendered points") << " ";
12003       }
12004       else if (aFlag == "geommem")
12005       {
12006         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12007       }
12008       else if (aFlag == "texturemem")
12009       {
12010         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12011       }
12012       else if (aFlag == "framemem")
12013       {
12014         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12015       }
12016       else if (aFlag == "elapsedframe")
12017       {
12018         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12019       }
12020       else if (aFlag == "cpuframe_average")
12021       {
12022         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12023       }
12024       else if (aFlag == "cpupicking_average")
12025       {
12026         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12027       }
12028       else if (aFlag == "cpuculling_average")
12029       {
12030         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12031       }
12032       else if (aFlag == "cpudyn_average")
12033       {
12034         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12035       }
12036       else if (aFlag == "cpuframe_max")
12037       {
12038         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12039       }
12040       else if (aFlag == "cpupicking_max")
12041       {
12042         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12043       }
12044       else if (aFlag == "cpuculling_max")
12045       {
12046         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12047       }
12048       else if (aFlag == "cpudyn_max")
12049       {
12050         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12051       }
12052     }
12053   }
12054   else
12055   {
12056     if (toRedraw)
12057     {
12058       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12059       aView->Redraw();
12060       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12061     }
12062     theDI << "Statistic info:\n" << aView->StatisticInformation();
12063   }
12064   return 0;
12065 }
12066
12067 //=======================================================================
12068 //function : VXRotate
12069 //purpose  :
12070 //=======================================================================
12071 static Standard_Integer VXRotate (Draw_Interpretor& di,
12072                                    Standard_Integer argc,
12073                                    const char ** argv)
12074 {
12075   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12076   if (aContext.IsNull())
12077   {
12078     di << argv[0] << "ERROR : use 'vinit' command before \n";
12079     return 1;
12080   }
12081
12082   if (argc != 3)
12083   {
12084     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12085     return 1;
12086   }
12087
12088   TCollection_AsciiString aName (argv[1]);
12089   Standard_Real anAngle = Draw::Atof (argv[2]);
12090
12091   // find object
12092   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12093   Handle(AIS_InteractiveObject) anIObj;
12094   if (!aMap.Find2 (aName, anIObj))
12095   {
12096     di << "Use 'vdisplay' before\n";
12097     return 1;
12098   }
12099
12100   gp_Trsf aTransform;
12101   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12102   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12103
12104   aContext->SetLocation (anIObj, aTransform);
12105   aContext->UpdateCurrentViewer();
12106   return 0;
12107 }
12108
12109 namespace
12110 {
12111   //! Structure for setting AIS_Manipulator::SetPart() property.
12112   struct ManipAxisModeOnOff
12113   {
12114     Standard_Integer    Axis;
12115     AIS_ManipulatorMode Mode;
12116     Standard_Boolean    ToEnable;
12117
12118     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
12119   };
12120
12121   enum ManipAjustPosition
12122   {
12123     ManipAjustPosition_Off,
12124     ManipAjustPosition_Center,
12125     ManipAjustPosition_Location,
12126     ManipAjustPosition_ShapeLocation,
12127   };
12128 }
12129
12130 //===============================================================================================
12131 //function : VManipulator
12132 //purpose  :
12133 //===============================================================================================
12134 static int VManipulator (Draw_Interpretor& theDi,
12135                          Standard_Integer  theArgsNb,
12136                          const char**      theArgVec)
12137 {
12138   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12139   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12140   if (aCurrentView.IsNull()
12141    || aViewer.IsNull())
12142   {
12143     Message::SendFail ("Error: no active viewer");
12144     return 1;
12145   }
12146
12147   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12148   Standard_Integer anArgIter = 1;
12149   Handle(AIS_Manipulator) aManipulator;
12150   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12151   TCollection_AsciiString aName;
12152   // parameters
12153   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
12154   Standard_Real aGap = -1.0, aSize = -1.0;
12155   NCollection_Sequence<ManipAxisModeOnOff> aParts;
12156   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
12157   //
12158   bool toDetach = false;
12159   AIS_Manipulator::OptionsForAttach anAttachOptions;
12160   Handle(AIS_InteractiveObject) anAttachObject;
12161   Handle(V3d_View) aViewAffinity;
12162   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
12163   //
12164   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
12165   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
12166   Standard_Integer toStopMouseTransform = -1;
12167   // explicit transformation
12168   gp_Trsf aTrsf;
12169   gp_XYZ aTmpXYZ;
12170   Standard_Real aTmpReal = 0.0;
12171   gp_XYZ aRotPnt, aRotAxis;
12172   for (; anArgIter < theArgsNb; ++anArgIter)
12173   {
12174     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12175     anArg.LowerCase();
12176     if (anUpdateTool.parseRedrawMode (anArg))
12177     {
12178       continue;
12179     }
12180     else if (anArg == "-help")
12181     {
12182       theDi.PrintHelp (theArgVec[0]);
12183       return 0;
12184     }
12185     //
12186     else if (anArg == "-autoactivate"
12187           || anArg == "-noautoactivate")
12188     {
12189       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12190     }
12191     else if (anArg == "-followtranslation"
12192           || anArg == "-nofollowtranslation")
12193     {
12194       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12195     }
12196     else if (anArg == "-followrotation"
12197           || anArg == "-nofollowrotation")
12198     {
12199       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12200     }
12201     else if (anArg == "-followdragging"
12202           || anArg == "-nofollowdragging")
12203     {
12204       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12205     }
12206     else if (anArg == "-gap"
12207           && anArgIter + 1 < theArgsNb
12208           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
12209           && aGap >= 0.0)
12210     {
12211       ++anArgIter;
12212     }
12213     else if (anArg == "-size"
12214           && anArgIter + 1 < theArgsNb
12215           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
12216           && aSize > 0.0)
12217     {
12218       ++anArgIter;
12219     }
12220     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
12221           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
12222     {
12223       ManipAxisModeOnOff aPart;
12224       Standard_Integer aMode = 0;
12225       if (anArg == "-part")
12226       {
12227         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
12228           || aPart.Axis < 0 || aPart.Axis > 3)
12229         {
12230           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
12231           return 1;
12232         }
12233       }
12234       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
12235         || aMode < 1 || aMode > 4)
12236       {
12237         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
12238         return 1;
12239       }
12240       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
12241       {
12242         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
12243         return 1;
12244       }
12245       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
12246       aParts.Append (aPart);
12247     }
12248     else if (anArg == "-pos"
12249           && anArgIter + 3 < theArgsNb
12250           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
12251     {
12252       anArgIter += 3;
12253       if (anArgIter + 3 < theArgsNb
12254        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
12255        && aVDir.Modulus() > Precision::Confusion())
12256       {
12257         anArgIter += 3;
12258       }
12259       if (anArgIter + 3 < theArgsNb
12260        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
12261        && anXDir.Modulus() > Precision::Confusion())
12262       {
12263         anArgIter += 3;
12264       }
12265     }
12266     else if (anArg == "-zoomable"
12267           || anArg == "-notzoomable")
12268     {
12269       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12270     }
12271     //
12272     else if (anArg == "-adjustposition"
12273           || anArg == "-noadjustposition")
12274     {
12275       anAttachPos = ManipAjustPosition_Center;
12276       if (anArgIter + 1 < theArgsNb)
12277       {
12278         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
12279         aPosName.LowerCase();
12280         if (aPosName == "0")
12281         {
12282           anAttachPos = ManipAjustPosition_Off;
12283         }
12284         else if (aPosName == "1"
12285               || aPosName == "center")
12286         {
12287           anAttachPos = ManipAjustPosition_Center;
12288         }
12289         else if (aPosName == "transformation"
12290               || aPosName == "trsf"
12291               || aPosName == "location"
12292               || aPosName == "loc")
12293         {
12294           anAttachPos = ManipAjustPosition_Location;
12295         }
12296         else if (aPosName == "shapelocation"
12297               || aPosName == "shapeloc")
12298         {
12299           anAttachPos = ManipAjustPosition_ShapeLocation;
12300         }
12301         else
12302         {
12303           --anArgIter;
12304         }
12305       }
12306       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
12307     }
12308     else if (anArg == "-adjustsize"
12309           || anArg == "-noadjustsize")
12310     {
12311       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12312     }
12313     else if (anArg == "-enablemodes"
12314           || anArg == "-enablemodes")
12315     {
12316       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12317     }
12318     //
12319     else if (anArg == "-starttransform"
12320           && anArgIter + 2 < theArgsNb
12321           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
12322           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
12323     {
12324       anArgIter += 2;
12325     }
12326     else if (anArg == "-transform"
12327           && anArgIter + 2 < theArgsNb
12328           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
12329           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
12330     {
12331       anArgIter += 2;
12332     }
12333     else if (anArg == "-stoptransform")
12334     {
12335       toStopMouseTransform = 1;
12336       if (anArgIter + 1 < theArgsNb
12337        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
12338       {
12339         ++anArgIter;
12340         toStopMouseTransform = 0;
12341       }
12342     }
12343     //
12344     else if (anArg == "-move"
12345           && anArgIter + 3 < theArgsNb
12346           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
12347     {
12348       anArgIter += 3;
12349       aTrsf.SetTranslationPart (aTmpXYZ);
12350     }
12351     else if (anArg == "-scale"
12352           && anArgIter + 1 < theArgsNb
12353           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
12354     {
12355       ++anArgIter;
12356       aTrsf.SetScale (gp_Pnt(), aTmpReal);
12357     }
12358     else if (anArg == "-rotate"
12359           && anArgIter + 7 < theArgsNb
12360           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
12361           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
12362           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
12363     {
12364       anArgIter += 7;
12365       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
12366     }
12367     //
12368     else if (anArg == "-detach")
12369     {
12370       toDetach = true;
12371     }
12372     else if (anArg == "-attach"
12373           && anArgIter + 1 < theArgsNb)
12374     {
12375       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
12376       if (!aMapAIS.Find2 (anObjName, anAttachObject))
12377       {
12378         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
12379         return 1;
12380       }
12381
12382       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
12383       {
12384         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
12385         if (!aManip.IsNull()
12386           && aManip->IsAttached()
12387           && aManip->Object() == anAttachObject)
12388         {
12389           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
12390           return 1;
12391         }
12392       }
12393     }
12394     else if (anArg == "-view"
12395           && anArgIter + 1 < theArgsNb
12396           && aViewAffinity.IsNull())
12397     {
12398       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
12399       if (aViewString == "active")
12400       {
12401         aViewAffinity = ViewerTest::CurrentView();
12402       }
12403       else // Check view name
12404       {
12405         ViewerTest_Names aViewNames (aViewString);
12406         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
12407         {
12408           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
12409           return 1;
12410         }
12411         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
12412         if (aViewAffinity.IsNull())
12413         {
12414           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
12415           return 1;
12416         }
12417       }
12418     }
12419     else if (aName.IsEmpty())
12420     {
12421       aName = theArgVec[anArgIter];
12422       if (!aMapAIS.IsBound2 (aName))
12423       {
12424         aManipulator = new AIS_Manipulator();
12425         aManipulator->SetModeActivationOnDetection (true);
12426         aMapAIS.Bind (aManipulator, aName);
12427       }
12428       else
12429       {
12430         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12431         if (aManipulator.IsNull())
12432         {
12433           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12434           return 1;
12435         }
12436       }
12437     }
12438     else
12439     {
12440       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
12441     }
12442   }
12443
12444   if (aName.IsEmpty())
12445   {
12446     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
12447     return 1;
12448   }
12449   if (!toDetach
12450     && aManipulator.IsNull())
12451   {
12452     aManipulator = new AIS_Manipulator();
12453     aManipulator->SetModeActivationOnDetection (true);
12454     aMapAIS.Bind (aManipulator, aName);
12455   }
12456
12457   // -----------------------------------------
12458   // change properties of manipulator instance
12459   // -----------------------------------------
12460
12461   if (toAutoActivate != -1)
12462   {
12463     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
12464   }
12465   if (toFollowTranslation != -1)
12466   {
12467     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
12468   }
12469   if (toFollowRotation != -1)
12470   {
12471     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
12472   }
12473   if (toFollowDragging != -1)
12474   {
12475     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
12476   }
12477   if (aGap >= 0.0f)
12478   {
12479     aManipulator->SetGap ((float )aGap);
12480   }
12481
12482   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
12483   {
12484     const ManipAxisModeOnOff& aPart = aPartIter.Value();
12485     if (aPart.Axis == -1)
12486     {
12487       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
12488     }
12489     else
12490     {
12491       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
12492     }
12493   }
12494
12495   if (aSize > 0.0)
12496   {
12497     aManipulator->SetSize ((float )aSize);
12498   }
12499   if (isZoomable != -1)
12500   {
12501     aManipulator->SetZoomPersistence (isZoomable == 0);
12502
12503     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12504     {
12505       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
12506       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
12507     }
12508   }
12509
12510   // ----------------------------------
12511   // detach existing manipulator object
12512   // ----------------------------------
12513
12514   if (toDetach)
12515   {
12516     aManipulator->Detach();
12517     aMapAIS.UnBind2 (aName);
12518     ViewerTest::GetAISContext()->Remove (aManipulator, false);
12519   }
12520
12521   // ---------------------------------------------------
12522   // attach, detach or access manipulator from an object
12523   // ---------------------------------------------------
12524
12525   if (!anAttachObject.IsNull())
12526   {
12527     aManipulator->Attach (anAttachObject, anAttachOptions);
12528   }
12529   if (!aViewAffinity.IsNull())
12530   {
12531     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
12532          anIter.More(); anIter.Next())
12533     {
12534       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
12535     }
12536     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
12537   }
12538
12539   if (anAttachPos != ManipAjustPosition_Off
12540    && aManipulator->IsAttached()
12541    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
12542   {
12543     gp_Ax2 aPosition = gp::XOY();
12544     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
12545     switch (anAttachPos)
12546     {
12547       case ManipAjustPosition_Off:
12548       {
12549         break;
12550       }
12551       case ManipAjustPosition_Location:
12552       {
12553         aPosition = gp::XOY().Transformed (aBaseTrsf);
12554         break;
12555       }
12556       case ManipAjustPosition_ShapeLocation:
12557       {
12558         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
12559         {
12560           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
12561         }
12562         else
12563         {
12564           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
12565           return 1;
12566         }
12567         break;
12568       }
12569       case ManipAjustPosition_Center:
12570       {
12571         Bnd_Box aBox;
12572         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
12573         {
12574           Bnd_Box anObjBox;
12575           anObjIter.Value()->BoundingBox (anObjBox);
12576           aBox.Add (anObjBox);
12577         }
12578         aBox = aBox.FinitePart();
12579         if (!aBox.IsVoid())
12580         {
12581           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
12582           aPosition.SetLocation (aCenter);
12583         }
12584         break;
12585       }
12586     }
12587     aManipulator->SetPosition (aPosition);
12588   }
12589   if (!Precision::IsInfinite (aLocation.X()))
12590   {
12591     if (aVDir.Modulus() <= Precision::Confusion())
12592     {
12593       aVDir = aManipulator->Position().Direction().XYZ();
12594     }
12595     if (anXDir.Modulus() <= Precision::Confusion())
12596     {
12597       anXDir = aManipulator->Position().XDirection().XYZ();
12598     }
12599     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
12600   }
12601
12602   // --------------------------------------
12603   // apply transformation using manipulator
12604   // --------------------------------------
12605
12606   if (aMousePosFrom.x() != IntegerLast())
12607   {
12608     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
12609   }
12610   if (aMousePosTo.x() != IntegerLast())
12611   {
12612     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
12613   }
12614   if (toStopMouseTransform != -1)
12615   {
12616     aManipulator->StopTransform (toStopMouseTransform == 1);
12617   }
12618
12619   if (aTrsf.Form() != gp_Identity)
12620   {
12621     aManipulator->Transform (aTrsf);
12622   }
12623
12624   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12625   {
12626     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
12627   }
12628   return 0;
12629 }
12630
12631 //===============================================================================================
12632 //function : VSelectionProperties
12633 //purpose  :
12634 //===============================================================================================
12635 static int VSelectionProperties (Draw_Interpretor& theDi,
12636                                  Standard_Integer  theArgsNb,
12637                                  const char**      theArgVec)
12638 {
12639   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
12640   if (aCtx.IsNull())
12641   {
12642     Message::SendFail ("Error: no active viewer");
12643     return 1;
12644   }
12645
12646   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
12647   {
12648     // handle obsolete alias
12649     bool toEnable = true;
12650     if (theArgsNb < 2)
12651     {
12652       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
12653       return 0;
12654     }
12655     else if (theArgsNb != 2
12656          || !Draw::ParseOnOff (theArgVec[1], toEnable))
12657     {
12658       Message::SendFail ("Syntax error: wrong number of parameters");
12659       return 1;
12660     }
12661     if (toEnable != aCtx->ToHilightSelected())
12662     {
12663       aCtx->ClearDetected();
12664       aCtx->SetToHilightSelected (toEnable);
12665     }
12666     return 0;
12667   }
12668
12669   Standard_Boolean toPrint  = theArgsNb == 1;
12670   Standard_Boolean toRedraw = Standard_False;
12671   Standard_Integer anArgIter = 1;
12672   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
12673   if (anArgIter < theArgsNb)
12674   {
12675     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
12676     anArgFirst.LowerCase();
12677     ++anArgIter;
12678     if (anArgFirst == "dynhighlight"
12679      || anArgFirst == "dynhilight"
12680      || anArgFirst == "dynamichighlight"
12681      || anArgFirst == "dynamichilight")
12682     {
12683       aType = Prs3d_TypeOfHighlight_Dynamic;
12684     }
12685     else if (anArgFirst == "localdynhighlight"
12686           || anArgFirst == "localdynhilight"
12687           || anArgFirst == "localdynamichighlight"
12688           || anArgFirst == "localdynamichilight")
12689     {
12690       aType = Prs3d_TypeOfHighlight_LocalDynamic;
12691     }
12692     else if (anArgFirst == "selhighlight"
12693           || anArgFirst == "selhilight"
12694           || anArgFirst == "selectedhighlight"
12695           || anArgFirst == "selectedhilight")
12696     {
12697       aType = Prs3d_TypeOfHighlight_Selected;
12698     }
12699     else if (anArgFirst == "localselhighlight"
12700           || anArgFirst == "localselhilight"
12701           || anArgFirst == "localselectedhighlight"
12702           || anArgFirst == "localselectedhilight")
12703     {
12704       aType = Prs3d_TypeOfHighlight_LocalSelected;
12705     }
12706     else
12707     {
12708       --anArgIter;
12709     }
12710   }
12711   for (; anArgIter < theArgsNb; ++anArgIter)
12712   {
12713     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12714     anArg.LowerCase();
12715     if (anArg == "-help")
12716     {
12717       theDi.PrintHelp (theArgVec[0]);
12718       return 0;
12719     }
12720     else if (anArg == "-print")
12721     {
12722       toPrint = Standard_True;
12723     }
12724     else if (anArg == "-autoactivate")
12725     {
12726       Standard_Boolean toEnable = Standard_True;
12727       if (anArgIter + 1 < theArgsNb
12728        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12729       {
12730         ++anArgIter;
12731       }
12732       aCtx->SetAutoActivateSelection (toEnable);
12733     }
12734     else if (anArg == "-automatichighlight"
12735           || anArg == "-automatichilight"
12736           || anArg == "-autohighlight"
12737           || anArg == "-autohilight")
12738     {
12739       Standard_Boolean toEnable = Standard_True;
12740       if (anArgIter + 1 < theArgsNb
12741        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12742       {
12743         ++anArgIter;
12744       }
12745       aCtx->ClearSelected (false);
12746       aCtx->ClearDetected();
12747       aCtx->SetAutomaticHilight (toEnable);
12748       toRedraw = true;
12749     }
12750     else if (anArg == "-highlightselected"
12751           || anArg == "-hilightselected")
12752     {
12753       Standard_Boolean toEnable = Standard_True;
12754       if (anArgIter + 1 < theArgsNb
12755        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
12756       {
12757         ++anArgIter;
12758       }
12759       aCtx->ClearDetected();
12760       aCtx->SetToHilightSelected (toEnable);
12761       toRedraw = true;
12762     }
12763     else if (anArg == "-pickstrategy"
12764           || anArg == "-pickingstrategy")
12765     {
12766       if (++anArgIter >= theArgsNb)
12767       {
12768         Message::SendFail ("Syntax error: type of highlighting is undefined");
12769         return 1;
12770       }
12771
12772       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
12773       TCollection_AsciiString aVal (theArgVec[anArgIter]);
12774       aVal.LowerCase();
12775       if (aVal == "first"
12776        || aVal == "firstaccepted"
12777        || aVal == "firstacceptable")
12778       {
12779         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
12780       }
12781       else if (aVal == "topmost"
12782             || aVal == "onlyTopmost")
12783       {
12784         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
12785       }
12786       else
12787       {
12788         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
12789         return 1;
12790       }
12791
12792       aCtx->SetPickingStrategy (aStrategy);
12793     }
12794     else if (anArg == "-pixtol"
12795           && anArgIter + 1 < theArgsNb)
12796     {
12797       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
12798     }
12799     else if (anArg == "-preferclosest")
12800     {
12801       bool toPreferClosest = true;
12802       if (anArgIter + 1 < theArgsNb
12803        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
12804       {
12805         ++anArgIter;
12806       }
12807       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
12808     }
12809     else if ((anArg == "-depthtol"
12810            || anArg == "-depthtolerance")
12811           && anArgIter + 1 < theArgsNb)
12812     {
12813       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
12814       aTolType.LowerCase();
12815       if (aTolType == "uniform")
12816       {
12817         if (anArgIter + 1 >= theArgsNb)
12818         {
12819           Message::SendFail() << "Syntax error: wrong number of arguments";
12820           return 1;
12821         }
12822         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
12823                                                  Draw::Atof (theArgVec[++anArgIter]));
12824       }
12825       else if (aTolType == "uniformpx")
12826       {
12827         if (anArgIter + 1 >= theArgsNb)
12828         {
12829           Message::SendFail() << "Syntax error: wrong number of arguments";
12830           return 1;
12831         }
12832         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
12833                                                  Draw::Atof (theArgVec[++anArgIter]));
12834       }
12835       else if (aTolType == "sensfactor")
12836       {
12837         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
12838       }
12839       else
12840       {
12841         Message::SendFail() << "Syntax error at '" << aTolType << "'";
12842         return 1;
12843       }
12844     }
12845     else if ((anArg == "-mode"
12846            || anArg == "-dispmode")
12847           && anArgIter + 1 < theArgsNb)
12848     {
12849       if (aType == Prs3d_TypeOfHighlight_None)
12850       {
12851         Message::SendFail ("Syntax error: type of highlighting is undefined");
12852         return 1;
12853       }
12854
12855       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
12856       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12857       aStyle->SetDisplayMode (aDispMode);
12858       toRedraw = Standard_True;
12859     }
12860     else if (anArg == "-layer"
12861           && anArgIter + 1 < theArgsNb)
12862     {
12863       if (aType == Prs3d_TypeOfHighlight_None)
12864       {
12865         Message::SendFail ("Syntax error: type of highlighting is undefined");
12866         return 1;
12867       }
12868
12869       ++anArgIter;
12870       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
12871       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
12872       {
12873         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
12874         return 1;
12875       }
12876
12877       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12878       aStyle->SetZLayer (aNewLayer);
12879       toRedraw = Standard_True;
12880     }
12881     else if (anArg == "-hicolor"
12882           || anArg == "-selcolor"
12883           || anArg == "-color")
12884     {
12885       if (anArg.StartsWith ("-hi"))
12886       {
12887         aType = Prs3d_TypeOfHighlight_Dynamic;
12888       }
12889       else if (anArg.StartsWith ("-sel"))
12890       {
12891         aType = Prs3d_TypeOfHighlight_Selected;
12892       }
12893       else if (aType == Prs3d_TypeOfHighlight_None)
12894       {
12895         Message::SendFail ("Syntax error: type of highlighting is undefined");
12896         return 1;
12897       }
12898
12899       Quantity_Color aColor;
12900       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
12901                                                      theArgVec + anArgIter + 1,
12902                                                      aColor);
12903       if (aNbParsed == 0)
12904       {
12905         Message::SendFail ("Syntax error: need more arguments");
12906         return 1;
12907       }
12908       anArgIter += aNbParsed;
12909
12910       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12911       aStyle->SetColor (aColor);
12912       toRedraw = Standard_True;
12913     }
12914     else if ((anArg == "-transp"
12915            || anArg == "-transparency"
12916            || anArg == "-hitransp"
12917            || anArg == "-seltransp"
12918            || anArg == "-hitransplocal"
12919            || anArg == "-seltransplocal")
12920           && anArgIter + 1 < theArgsNb)
12921     {
12922       if (anArg.StartsWith ("-hi"))
12923       {
12924         aType = Prs3d_TypeOfHighlight_Dynamic;
12925       }
12926       else if (anArg.StartsWith ("-sel"))
12927       {
12928         aType = Prs3d_TypeOfHighlight_Selected;
12929       }
12930       else if (aType == Prs3d_TypeOfHighlight_None)
12931       {
12932         Message::SendFail ("Syntax error: type of highlighting is undefined");
12933         return 1;
12934       }
12935
12936       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
12937       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12938       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
12939       toRedraw = Standard_True;
12940     }
12941     else if ((anArg == "-mat"
12942            || anArg == "-material")
12943           && anArgIter + 1 < theArgsNb)
12944     {
12945       if (aType == Prs3d_TypeOfHighlight_None)
12946       {
12947         Message::SendFail ("Syntax error: type of highlighting is undefined");
12948         return 1;
12949       }
12950
12951       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
12952       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
12953       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
12954       {
12955         ++anArgIter;
12956         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
12957         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
12958         Graphic3d_MaterialAspect aMat (aMatName);
12959         aMat.SetColor (aStyle->Color());
12960         aMat.SetTransparency (aStyle->Transparency());
12961         anAspect->SetFrontMaterial (aMat);
12962         anAspect->SetInteriorColor (aStyle->Color());
12963         aStyle->SetBasicFillAreaAspect (anAspect);
12964       }
12965       else
12966       {
12967         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
12968       }
12969       toRedraw = Standard_True;
12970     }
12971     else
12972     {
12973       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
12974       return 1;
12975     }
12976   }
12977
12978   if (toPrint)
12979   {
12980     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
12981     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
12982     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
12983     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
12984     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
12985     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
12986     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
12987     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
12988     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
12989     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
12990     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
12991     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
12992     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
12993     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
12994   }
12995
12996   if (aCtx->NbSelected() != 0 && toRedraw)
12997   {
12998     aCtx->HilightSelected (Standard_True);
12999   }
13000
13001   return 0;
13002 }
13003
13004 //===============================================================================================
13005 //function : VDumpSelectionImage
13006 //purpose  :
13007 //===============================================================================================
13008 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13009                                 Standard_Integer  theArgsNb,
13010                                 const char**      theArgVec)
13011 {
13012   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13013   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13014   if (aContext.IsNull())
13015   {
13016     Message::SendFail ("Error: no active viewer");
13017     return 1;
13018   }
13019
13020   TCollection_AsciiString aFile;
13021   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13022   Handle(Graphic3d_Camera) aCustomCam;
13023   Image_Format anImgFormat = Image_Format_BGR;
13024   Standard_Integer aPickedIndex = 1;
13025   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13026   {
13027     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13028     aParam.LowerCase();
13029     if (aParam == "-type")
13030     {
13031       if (++anArgIter >= theArgsNb)
13032       {
13033         Message::SendFail ("Syntax error: wrong number parameters of flag '-type'");
13034         return 1;
13035       }
13036
13037       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13038       aValue.LowerCase();
13039       if (aValue == "depth"
13040        || aValue == "normdepth"
13041        || aValue == "normalizeddepth")
13042       {
13043         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13044         anImgFormat = Image_Format_GrayF;
13045       }
13046       else if (aValue == "depthinverted"
13047             || aValue == "normdepthinverted"
13048             || aValue == "normalizeddepthinverted"
13049             || aValue == "inverted")
13050       {
13051         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13052         anImgFormat = Image_Format_GrayF;
13053       }
13054       else if (aValue == "unnormdepth"
13055             || aValue == "unnormalizeddepth")
13056       {
13057         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13058         anImgFormat = Image_Format_GrayF;
13059       }
13060       else if (aValue == "objectcolor"
13061             || aValue == "object"
13062             || aValue == "color")
13063       {
13064         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13065       }
13066       else if (aValue == "entitycolor"
13067             || aValue == "entity")
13068       {
13069         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13070       }
13071       else if (aValue == "entitytypecolor"
13072             || aValue == "entitytype")
13073       {
13074         aType = StdSelect_TypeOfSelectionImage_ColoredEntityType;
13075       }
13076       else if (aValue == "ownercolor"
13077             || aValue == "owner")
13078       {
13079         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13080       }
13081       else if (aValue == "selectionmodecolor"
13082             || aValue == "selectionmode"
13083             || aValue == "selmodecolor"
13084             || aValue == "selmode")
13085       {
13086         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13087       }
13088       else if (aValue == "surfnormal"
13089             || aValue == "surfacenormal"
13090             || aValue == "normal")
13091       {
13092         aType = StdSelect_TypeOfSelectionImage_SurfaceNormal;
13093       }
13094       else
13095       {
13096         Message::SendFail() << "Syntax error: unknown type '" << aValue << "'";
13097         return 1;
13098       }
13099     }
13100     else if (aParam == "-picked"
13101           || aParam == "-pickeddepth"
13102           || aParam == "-pickedindex")
13103     {
13104       if (++anArgIter >= theArgsNb)
13105       {
13106         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13107         return 1;
13108       }
13109
13110       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13111     }
13112     else if (anArgIter + 1 < theArgsNb
13113           && aParam == "-xrpose")
13114     {
13115       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13116       anXRArg.LowerCase();
13117       if (anXRArg == "base")
13118       {
13119         aCustomCam = aView->View()->BaseXRCamera();
13120       }
13121       else if (anXRArg == "head")
13122       {
13123         aCustomCam = aView->View()->PosedXRCamera();
13124       }
13125       else
13126       {
13127         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13128         return 1;
13129       }
13130       if (aCustomCam.IsNull())
13131       {
13132         Message::SendFail() << "Error: undefined XR pose";
13133         return 0;
13134       }
13135     }
13136     else if (aFile.IsEmpty())
13137     {
13138       aFile = theArgVec[anArgIter];
13139     }
13140     else
13141     {
13142       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13143       return 1;
13144     }
13145   }
13146   if (aFile.IsEmpty())
13147   {
13148     Message::SendFail ("Syntax error: image file name is missing");
13149     return 1;
13150   }
13151
13152   Standard_Integer aWidth = 0, aHeight = 0;
13153   aView->Window()->Size (aWidth, aHeight);
13154
13155   Image_AlienPixMap aPixMap;
13156   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13157   {
13158     Message::SendFail ("Error: can't allocate image");
13159     return 1;
13160   }
13161
13162   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13163   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13164   if (!aCustomCam.IsNull())
13165   {
13166     aView->SetCamera (aCustomCam);
13167   }
13168   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13169   {
13170     Message::SendFail ("Error: can't generate selection image");
13171     return 1;
13172   }
13173   if (!aCustomCam.IsNull())
13174   {
13175     aView->SetCamera (aCamBack);
13176   }
13177   aView->SetImmediateUpdate (wasImmUpdate);
13178
13179   if (!aPixMap.Save (aFile))
13180   {
13181     Message::SendFail ("Error: can't save selection image");
13182     return 0;
13183   }
13184   return 0;
13185 }
13186
13187 //===============================================================================================
13188 //function : VViewCube
13189 //purpose  :
13190 //===============================================================================================
13191 static int VViewCube (Draw_Interpretor& ,
13192                       Standard_Integer  theNbArgs,
13193                       const char**      theArgVec)
13194 {
13195   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13196   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13197   if (aContext.IsNull() || aView.IsNull())
13198   {
13199     Message::SendFail ("Error: no active viewer");
13200     return 1;
13201   }
13202   else if (theNbArgs < 2)
13203   {
13204     Message::SendFail ("Syntax error: wrong number arguments");
13205     return 1;
13206   }
13207
13208   Handle(AIS_ViewCube) aViewCube;
13209   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13210   Quantity_Color aColorRgb;
13211   TCollection_AsciiString aName;
13212   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13213   {
13214     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13215     anArg.LowerCase();
13216     if (anUpdateTool.parseRedrawMode (anArg))
13217     {
13218       //
13219     }
13220     else if (aViewCube.IsNull())
13221     {
13222       aName = theArgVec[anArgIter];
13223       if (aName.StartsWith ("-"))
13224       {
13225         Message::SendFail ("Syntax error: object name should be specified");
13226         return 1;
13227       }
13228       Handle(AIS_InteractiveObject) aPrs;
13229       GetMapOfAIS().Find2 (aName, aPrs);
13230       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13231       if (aViewCube.IsNull())
13232       {
13233         aViewCube = new AIS_ViewCube();
13234         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13235         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13236         aViewCube->SetFixedAnimationLoop (false);
13237       }
13238     }
13239     else if (anArg == "-reset")
13240     {
13241       aViewCube->ResetStyles();
13242     }
13243     else if (anArg == "-color"
13244           || anArg == "-boxcolor"
13245           || anArg == "-boxsidecolor"
13246           || anArg == "-sidecolor"
13247           || anArg == "-boxedgecolor"
13248           || anArg == "-edgecolor"
13249           || anArg == "-boxcornercolor"
13250           || anArg == "-cornercolor"
13251           || anArg == "-innercolor"
13252           || anArg == "-textcolor"
13253           || anArg == "-xaxistextcolor"
13254           || anArg == "-yaxistextcolor"
13255           || anArg == "-zaxistextcolor")
13256     {
13257       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
13258                                                      theArgVec + anArgIter + 1,
13259                                                      aColorRgb);
13260       if (aNbParsed == 0)
13261       {
13262         Message::SendFail() << "Syntax error at '" << anArg << "'";
13263         return 1;
13264       }
13265       anArgIter += aNbParsed;
13266       if (anArg == "-boxcolor")
13267       {
13268         aViewCube->SetBoxColor (aColorRgb);
13269       }
13270       else if (anArg == "-boxsidecolor"
13271             || anArg == "-sidecolor")
13272       {
13273         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13274         aViewCube->SynchronizeAspects();
13275       }
13276       else if (anArg == "-boxedgecolor"
13277             || anArg == "-edgecolor")
13278       {
13279         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13280         aViewCube->SynchronizeAspects();
13281       }
13282       else if (anArg == "-boxcornercolor"
13283             || anArg == "-cornercolor")
13284       {
13285         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13286         aViewCube->SynchronizeAspects();
13287       }
13288       else if (anArg == "-innercolor")
13289       {
13290         aViewCube->SetInnerColor (aColorRgb);
13291       }
13292       else if (anArg == "-textcolor")
13293       {
13294         aViewCube->SetTextColor (aColorRgb);
13295       }
13296       else if (anArg == "-xaxistextcolor"
13297             || anArg == "-yaxistextcolor"
13298             || anArg == "-zaxistextcolor")
13299       {
13300         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
13301                                 ? Prs3d_DatumParts_XAxis
13302                                 : (anArg.Value (2) == 'y'
13303                                  ? Prs3d_DatumParts_YAxis
13304                                  : Prs3d_DatumParts_ZAxis);
13305         aViewCube->Attributes()->SetOwnDatumAspects();
13306         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
13307       }
13308       else
13309       {
13310         aViewCube->SetColor (aColorRgb);
13311       }
13312     }
13313     else if (anArgIter + 1 < theNbArgs
13314           && (anArg == "-transparency"
13315            || anArg == "-boxtransparency"))
13316     {
13317       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13318       if (aValue < 0.0 || aValue > 1.0)
13319       {
13320         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13321         return 1;
13322       }
13323
13324       if (anArg == "-boxtransparency")
13325       {
13326         aViewCube->SetBoxTransparency (aValue);
13327       }
13328       else
13329       {
13330         aViewCube->SetTransparency (aValue);
13331       }
13332     }
13333     else if (anArg == "-axes"
13334           || anArg == "-edges"
13335           || anArg == "-vertices"
13336           || anArg == "-vertexes"
13337           || anArg == "-fixedanimation")
13338     {
13339       bool toShow = true;
13340       if (anArgIter + 1 < theNbArgs
13341        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
13342       {
13343         ++anArgIter;
13344       }
13345       if (anArg == "-fixedanimation")
13346       {
13347         aViewCube->SetFixedAnimationLoop (toShow);
13348       }
13349       else if (anArg == "-axes")
13350       {
13351         aViewCube->SetDrawAxes (toShow);
13352       }
13353       else if (anArg == "-edges")
13354       {
13355         aViewCube->SetDrawEdges (toShow);
13356       }
13357       else
13358       {
13359         aViewCube->SetDrawVertices (toShow);
13360       }
13361     }
13362     else if (anArg == "-yup"
13363           || anArg == "-zup")
13364     {
13365       bool isOn = true;
13366       if (anArgIter + 1 < theNbArgs
13367        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
13368       {
13369         ++anArgIter;
13370       }
13371       if (anArg == "-yup")
13372       {
13373         aViewCube->SetYup (isOn);
13374       }
13375       else
13376       {
13377         aViewCube->SetYup (!isOn);
13378       }
13379     }
13380     else if (anArgIter + 1 < theNbArgs
13381           && anArg == "-font")
13382     {
13383       aViewCube->SetFont (theArgVec[++anArgIter]);
13384     }
13385     else if (anArgIter + 1 < theNbArgs
13386           && anArg == "-fontheight")
13387     {
13388       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
13389     }
13390     else if (anArgIter + 1 < theNbArgs
13391           && (anArg == "-size"
13392            || anArg == "-boxsize"))
13393     {
13394       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
13395                           anArg != "-boxsize");
13396     }
13397     else if (anArgIter + 1 < theNbArgs
13398           && (anArg == "-boxfacet"
13399            || anArg == "-boxfacetextension"
13400            || anArg == "-facetextension"
13401            || anArg == "-extension"))
13402     {
13403       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
13404     }
13405     else if (anArgIter + 1 < theNbArgs
13406           && (anArg == "-boxedgegap"
13407            || anArg == "-edgegap"))
13408     {
13409       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
13410     }
13411     else if (anArgIter + 1 < theNbArgs
13412           && (anArg == "-boxedgeminsize"
13413            || anArg == "-edgeminsize"))
13414     {
13415       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
13416     }
13417     else if (anArgIter + 1 < theNbArgs
13418           && (anArg == "-boxcornerminsize"
13419            || anArg == "-cornerminsize"))
13420     {
13421       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
13422     }
13423     else if (anArgIter + 1 < theNbArgs
13424           && anArg == "-axespadding")
13425     {
13426       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
13427     }
13428     else if (anArgIter + 1 < theNbArgs
13429           && anArg == "-roundradius")
13430     {
13431       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
13432     }
13433     else if (anArgIter + 1 < theNbArgs
13434           && anArg == "-duration")
13435     {
13436       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
13437     }
13438     else if (anArgIter + 1 < theNbArgs
13439           && anArg == "-axesradius")
13440     {
13441       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
13442     }
13443     else if (anArgIter + 1 < theNbArgs
13444           && anArg == "-axesconeradius")
13445     {
13446       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
13447     }
13448     else if (anArgIter + 1 < theNbArgs
13449           && anArg == "-axessphereradius")
13450     {
13451       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
13452     }
13453     else
13454     {
13455       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13456       return 1;
13457     }
13458   }
13459   if (aViewCube.IsNull())
13460   {
13461     Message::SendFail ("Syntax error: wrong number of arguments");
13462     return 1;
13463   }
13464
13465   ViewerTest::Display (aName, aViewCube, false);
13466   return 0;
13467 }
13468
13469 //===============================================================================================
13470 //function : VColorConvert
13471 //purpose  :
13472 //===============================================================================================
13473 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13474 {
13475   if (theNbArgs != 6)
13476   {
13477     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13478     return 1;
13479   }
13480
13481   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
13482   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
13483   {
13484     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
13485     return 1;
13486   }
13487
13488   const char* aTypeStr = theArgVec[2];
13489   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
13490   if (! strcasecmp (aTypeStr, "srgb"))
13491   {
13492     aType = Quantity_TOC_sRGB;
13493   }
13494   else if (! strcasecmp (aTypeStr, "hls"))
13495   {
13496     aType = Quantity_TOC_HLS;
13497   }
13498   else if (! strcasecmp (aTypeStr, "lab"))
13499   {
13500     aType = Quantity_TOC_CIELab;
13501   }
13502   else if (! strcasecmp (aTypeStr, "lch"))
13503   {
13504     aType = Quantity_TOC_CIELch;
13505   }
13506   else
13507   {
13508     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
13509     return 1;
13510   }
13511
13512   double aC1 = Draw::Atof (theArgVec[3]);
13513   double aC2 = Draw::Atof (theArgVec[4]);
13514   double aC3 = Draw::Atof (theArgVec[5]);
13515
13516   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
13517   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
13518
13519   // print values with 6 decimal digits
13520   char buffer[1024];
13521   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
13522   theDI << buffer;
13523
13524   return 0;
13525 }
13526  
13527 //===============================================================================================
13528 //function : VColorDiff
13529 //purpose  :
13530 //===============================================================================================
13531 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13532 {
13533   if (theNbArgs != 7)
13534   {
13535     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13536     return 1;
13537   }
13538
13539   double aR1 = Draw::Atof (theArgVec[1]);
13540   double aG1 = Draw::Atof (theArgVec[2]);
13541   double aB1 = Draw::Atof (theArgVec[3]);
13542   double aR2 = Draw::Atof (theArgVec[4]);
13543   double aG2 = Draw::Atof (theArgVec[5]);
13544   double aB2 = Draw::Atof (theArgVec[6]);
13545
13546   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
13547   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
13548
13549   theDI << aColor1.DeltaE2000 (aColor2);
13550
13551   return 0;
13552 }
13553  
13554 //===============================================================================================
13555 //function : VSelBvhBuild
13556 //purpose  :
13557 //===============================================================================================
13558 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
13559 {
13560   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
13561   if (aCtx.IsNull())
13562   {
13563     Message::SendFail ("Error: no active viewer");
13564     return 1;
13565   }
13566
13567   if (theNbArgs < 2)
13568   {
13569     Message::SendFail ("Error: command syntax is incorrect, see help");
13570     return 1;
13571   }
13572
13573   Standard_Integer toEnable = -1;
13574   Standard_Integer aThreadsNb = -1;
13575   Standard_Boolean toWait = Standard_False;
13576
13577   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13578   {
13579     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13580     anArg.LowerCase();
13581
13582     if (anArg == "-nbthreads"
13583         && anArgIter + 1 < theNbArgs)
13584     {
13585       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
13586       if (aThreadsNb < 1)
13587       {
13588         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
13589       }
13590     }
13591     else if (anArg == "-wait")
13592     {
13593       toWait = Standard_True;
13594     }
13595     else if (toEnable == -1)
13596     {
13597       Standard_Boolean toEnableValue = Standard_True;
13598       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
13599       {
13600         toEnable = toEnableValue ? 1 : 0;
13601       }
13602       else
13603       {
13604         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13605         return 1;
13606       }
13607     }
13608     else
13609     {
13610       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13611       return 1;
13612     }
13613   }
13614
13615   if (aThreadsNb == -1)
13616   {
13617     aThreadsNb = 1;
13618   }
13619   if (toEnable != -1)
13620   {
13621     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
13622   }
13623   if (toWait)
13624   {
13625     aCtx->MainSelector()->WaitForBVHBuild();
13626   }
13627
13628   return 0;
13629 }
13630
13631 //=======================================================================
13632 //function : ViewerTest_ExitProc
13633 //purpose  :
13634 //=======================================================================
13635 static void ViewerTest_ExitProc (ClientData )
13636 {
13637   NCollection_List<TCollection_AsciiString> aViewList;
13638   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
13639        anIter.More(); anIter.Next())
13640   {
13641     aViewList.Append (anIter.Key1());
13642   }
13643
13644   for (NCollection_List<TCollection_AsciiString>::Iterator anIter (aViewList);
13645        anIter.More(); anIter.Next())
13646   {
13647     ViewerTest::RemoveView (anIter.Value(), true);
13648   }
13649 }
13650
13651 //=======================================================================
13652 //function : ViewerCommands
13653 //purpose  :
13654 //=======================================================================
13655
13656 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
13657 {
13658   static bool TheIsInitialized = false;
13659   if (TheIsInitialized)
13660   {
13661     return;
13662   }
13663
13664   TheIsInitialized = true;
13665   // define destruction callback to destroy views in a well-defined order
13666   Tcl_CreateExitHandler (ViewerTest_ExitProc, 0);
13667
13668   const char* aGroup = "AIS Viewer";
13669   const char* aFileName = __FILE__;
13670   auto addCmd = [&](const char* theName, Draw_Interpretor::CommandFunction theFunc, const char* theHelp)
13671   {
13672     theCommands.Add (theName, theHelp, aFileName, theFunc, aGroup);
13673   };
13674
13675   addCmd ("vdriver", VDriver, /* [vdriver] */ R"(
13676 vdriver [-list] [-default DriverName] [-load DriverName]
13677 Manages active graphic driver factory.
13678 Prints current active driver when called without arguments.
13679 Makes specified driver active when ActiveName argument is specified.
13680  -list    print registered factories
13681  -default define which factory should be used by default (to be used by next vinit call)
13682  -load    try loading factory plugin and set it as default one
13683 )" /* [vdriver] */);
13684
13685   addCmd ("vinit", VInit, /* [vinit] */ R"(
13686 vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]
13687       [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {on|off}=off] [-2d_mode {on|off}=off]
13688       [-display displayName]
13689 Creates new View window with specified name viewName.
13690 By default the new view is created in the viewer and in graphic driver shared with active view.
13691  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}
13692        if driverName isn't specified the driver will be shared with active view;
13693        if viewerName isn't specified the viewer will be shared with active view.
13694  -display HostName.DisplayNumber[:ScreenNumber]
13695
13696 Display name will be used within creation of graphic driver, when specified.
13697  -left,  -top    pixel position of left top corner of the window.
13698  -width, -height width and height of window respectively.
13699  -cloneActive flag to copy camera and dimensions of active view.
13700  -exitOnClose when specified, closing the view will exit application.
13701  -closeOnEscape when specified, view will be closed on pressing Escape.
13702  -virtual create an offscreen window within interactive session
13703  -2d_mode when on, view will not react on rotate scene events
13704 Additional commands for operations with views: vclose, vactivate, vviewlist.
13705 )" /* [vinit] */);
13706
13707   addCmd ("vclose", VClose, /* [vclose] */ R"(
13708 vclose [view_id [keep_context=0|1]]
13709 or vclose ALL - to remove all created views
13710  - removes view(viewer window) defined by its view_id.
13711  - keep_context: by default 0; if 1 and the last view is deleted the current context is not removed.
13712 )" /* [vclose] */);
13713
13714   addCmd ("vactivate", VActivate, /* [vactivate] */ R"(
13715 vactivate view_id [-noUpdate]
13716 Activates view(viewer window) defined by its view_id.
13717 )" /* [vactivate] */);
13718
13719   addCmd ("vviewlist", VViewList, /* [vviewlist] */ R"(
13720 vviewlist [format={tree, long}]=tree
13721 Prints current list of views per viewer and graphic_driver ID shared between viewers
13722  - format: format of result output, if tree the output is a tree view;
13723            otherwise it's a list of full view names.
13724 )" /* [vviewlist] */);
13725
13726   addCmd ("vhelp", VHelp, /* [vhelp] */ R"(
13727 vhelp : display help on the viewer commands and list of hotkeys.
13728 )" /* [vhelp] */);
13729
13730   addCmd ("vviewproj", VViewProj, /* [vviewproj] */ R"(
13731 vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]
13732           [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]
13733 Setup view direction
13734  -Yup      use Y-up convention instead of Zup (which is default).
13735  +-X+-Y+-Z define direction as combination of DX, DY and DZ;
13736            for example '+Z' will show front of the model,
13737            '-X-Y+Z' will define left axonometric view.
13738  -frame    define camera Up and Right directions (regardless Up convention);
13739            for example '+X+Z' will show front of the model with Z-up.
13740 )" /* [vviewproj] */);
13741
13742   addCmd ("vtop", VViewProj, /* [vtop] */ R"(
13743 vtop or <T> : Display top view (+X+Y) in the 3D viewer window.
13744 )" /* [vtop] */);
13745
13746   addCmd ("vbottom", VViewProj, /* [vbottom] */ R"(
13747 vbottom : Display bottom view (+X-Y) in the 3D viewer window.
13748 )" /* [vbottom] */);
13749
13750   addCmd ("vleft", VViewProj, /* [vleft] */ R"(
13751 vleft : Display left view (-Y+Z) in the 3D viewer window.
13752 )" /* [vleft] */);
13753
13754   addCmd ("vright", VViewProj, /* [vright] */ R"(
13755 vright : Display right view (+Y+Z) in the 3D viewer window.
13756 )" /* [vright] */);
13757
13758   addCmd ("vaxo", VViewProj, /* [vaxo] */ R"(
13759 vaxo or <A> : Display axonometric view (+X-Y+Z) in the 3D viewer window.
13760 )" /* [vaxo] */);
13761
13762   addCmd ("vfront", VViewProj, /* [vfront] */ R"(
13763 vfront : Display front view (+X+Z) in the 3D viewer window.
13764 )" /* [vfront] */);
13765
13766   addCmd ("vback", VViewProj, /* [vfront] */ R"(
13767 vback : Display back view (-X+Z) in the 3D viewer window.
13768 )" /* [vback] */);
13769
13770   addCmd ("vpick", VPick, /* [vpick] */ R"(
13771 vpick X Y Z [shape subshape]
13772 )" /* [vpick] */);
13773
13774   addCmd ("vfit", VFit, /* [vfit] */ R"(
13775 vfit or <F> [-selected] [-noupdate]
13776 Fit all / selected. Objects in the view are visualized to occupy the maximum surface.
13777 )" /* [vfit] */);
13778
13779   addCmd ("vfitarea", VFitArea, /* [vfitarea] */ R"(
13780 vfitarea [x1 y1 x2 y2] [x1 y1 z1 x2 y2 z2]
13781 Fit view to show area located between two points
13782 given in world 2D or 3D coordinates.
13783 )" /* [vfitarea] */);
13784
13785   addCmd ("vzfit", VZFit, /* [vzfit] */ R"(
13786 vzfit [scale]
13787 Automatic depth panning.
13788 Matches Z near, Z far view volume planes to the displayed objects.
13789  - "scale" specifies factor to scale computed z range.
13790 )" /* [vzfit] */);
13791
13792   addCmd ("vrepaint", VRepaint, /* [vrepaint] */ R"(
13793 vrepaint [-immediate] [-continuous FPS]
13794 Force redraw of active View.
13795  -immediate  flag performs redraw of immediate layers only;
13796  -continuous activates/deactivates continuous redraw of active View,
13797              0 means no continuous rendering,
13798             -1 means non-stop redraws,
13799             >0 specifies target framerate.
13800 )" /* [vrepaint] */);
13801
13802   addCmd ("vclear", VClear, /* [vclear] */ R"(
13803 vclear : Remove all the object from the viewer
13804 )" /* [vclear] */);
13805
13806   addCmd ("vbackground", VBackground, /* [vbackground] */ R"(
13807 vbackground [-color Color [-default]]
13808     [-gradient Color1 Color2 [-default]
13809     [-gradientMode {NONE|HORIZONTAL|VERTICAL|DIAG1|DIAG2|CORNER1|CORNER2|CORNER3|ELLIPTICAL}]=VERT]
13810     [-imageFile ImageFile [-imageMode {CENTERED|TILED|STRETCH|NONE}]=CENTERED [-srgb {0|1}]=1]
13811     [-cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]=0]
13812     [-pbrEnv {ibl|noibl|keep}]
13813 Changes background or some background settings.
13814  -color        sets background color
13815  -gradient     sets background gradient starting and ending colors
13816  -gradientMode sets gradient fill method
13817  -default      sets background default gradient or color
13818  -imageFile    sets filename of image used as background
13819  -imageMode    sets image fill type
13820  -cubemap      sets environment cubemap as background
13821  -invertedz    sets inversion of Z axis for background cubemap rendering; FALSE when unspecified
13822  -pbrEnv       sets on/off Image Based Lighting (IBL) from background cubemap for PBR
13823  -srgb         prefer sRGB texture format when applicable; TRUE when unspecified"
13824  -order        defines order of tiles in one image cubemap
13825                TileIndexi defubes an index in range [0, 5] for i tile of one image packed cubemap
13826                (has no effect in case of multi-image cubemaps).
13827 )" /* [vbackground] */);
13828
13829   addCmd ("vsetbg", VBackground, /* [vsetbg] */ R"(
13830 Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.
13831 )" /* [vsetbg] */);
13832
13833   addCmd ("vsetbgmode", VBackground, /* [vsetbgmode] */ R"(
13834 Alias for 'vbackground -imageMode FillType'.
13835 )" /* [vsetbgmode] */);
13836
13837   addCmd ("vsetgradientbg", VBackground, /* [vsetgradientbg] */ R"(
13838 Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.
13839 )" /* [vsetgradientbg] */);
13840
13841   addCmd ("vsetgrbgmode", VBackground, /* [vsetgrbgmode] */ R"(
13842 Alias for 'vbackground -gradientMode FillMethod'.
13843 )" /* [vsetgrbgmode] */);
13844
13845   addCmd ("vsetcolorbg", VBackground, /* [vsetcolorbg] */ R"(
13846 Alias for 'vbackground -color Color'.
13847 )" /* [vsetcolorbg] */);
13848
13849   addCmd ("vsetdefaultbg", VBackground, /* [vsetdefaultbg] */ R"(
13850 Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'
13851   and for 'vbackground -default -color Color'.
13852 )" /* [vsetdefaultbg] */);
13853
13854   addCmd ("vscale", VScale, /* [vscale] */ R"(
13855 vscale X Y Z
13856 )" /* [vscale] */);
13857
13858   addCmd ("vzbufftrihedron", VZBuffTrihedron, /* [vzbufftrihedron] */ R"(
13859 vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]
13860        [-position center|left_lower|left_upper|right_lower|right_upper]
13861        [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]
13862        [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]
13863        [-nbfacets value=12] [-colorLabels color=WHITE]
13864        [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]
13865 Displays a trihedron.
13866 )" /* [vzbufftrihedron] */);
13867
13868   addCmd ("vrotate", VRotate, /* [vrotate] */ R"(
13869 vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]
13870  -mouseStart start rotation according to the mouse position;
13871  -mouseMove  continue rotation with angle computed
13872              from last and new mouse position.
13873 )" /* [vrotate] */);
13874
13875   addCmd ("vzoom", VZoom, /* [vzoom] */ R"(
13876 vzoom coef
13877 )" /* [vzoom] */);
13878
13879   addCmd ("vpan", VPan, /* [vpan] */ R"(
13880 vpan dx dy
13881 )" /* [vpan] */);
13882
13883   addCmd ("vcolorscale", VColorScale, /* [vcolorscale] */ R"(
13884 vcolorscale name [-noupdate|-update] [-demo]
13885       [-range RangeMin=0 RangeMax=1 NbIntervals=10]
13886       [-font HeightFont=20]
13887       [-logarithmic {on|off}=off] [-reversed {on|off}=off]
13888       [-smoothTransition {on|off}=off]
13889       [-hueRange MinAngle=230 MaxAngle=0]
13890       [-colorRange MinColor=BLUE1 MaxColor=RED]
13891       [-textPos {left|right|center|none}=right]
13892       [-labelAtBorder {on|off}=on]
13893       [-colors Color1 Color2 ...] [-color Index Color]
13894       [-labels Label1 Label2 ...] [-label Index Label]
13895       [-freeLabels NbOfLabels Label1 Label2 ...]
13896       [-xy Left=0 Bottom=0]
13897       [-uniform lightness hue_from hue_to]
13898  -demo       display a color scale with demonstration values
13899  -colors     set colors for all intervals
13900  -color      set color for specific interval
13901  -uniform    generate colors with the same lightness
13902  -textpos    horizontal label position relative to color scale bar
13903  -labelAtBorder vertical label position relative to color interval;
13904              at border means the value inbetween neighbor intervals,
13905              at center means the center value within current interval
13906  -labels     set labels for all intervals
13907  -freeLabels same as -labels but does not require
13908              matching the number of intervals
13909  -label      set label for specific interval
13910  -title      set title
13911  -reversed   setup smooth color transition between intervals
13912  -smoothTransition swap colorscale direction
13913  -hueRange   set hue angles corresponding to minimum and maximum values
13914 )" /* [vcolorscale] */);
13915
13916   addCmd ("vgraduatedtrihedron", VGraduatedTrihedron, /* [vgraduatedtrihedron] */ R"(
13917 vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]
13918     [-namefont Name] [-valuesfont Name]
13919     [-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]
13920     [-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]
13921     [-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]
13922     [-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]
13923     [-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]
13924     [-xcolor Color] [-ycolor Color] [-zcolor Color]
13925     [-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]
13926     [-xticks Number] [-yticks Number] [-zticks Number]
13927     [-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]
13928     [-drawgrid on/off] [-drawaxes on/off]
13929 Display or erase graduated trihedron
13930  - xname, yname, zname - names of axes, default: X, Y, Z
13931  - namefont - font of axes names. Default: Arial
13932  - xnameoffset, ynameoffset, znameoffset - offset of name
13933    from values or tickmarks or axis. Default: 30
13934  - xnamecolor, ynamecolor, znamecolor - colors of axes names
13935  - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values
13936    from tickmarks or axis. Default: 10
13937  - valuesfont - font of axes values. Default: Arial
13938  - xcolor, ycolor, zcolor - color of axis and values
13939  - xticks, yticks, xzicks - number of tickmark on axes. Default: 5
13940  - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10
13941 )" /* [vgraduatedtrihedron] */);
13942
13943   addCmd ("vtile", VTile, /* [vtile] */ R"(
13944 vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]
13945 Setup view to draw a tile (a part of virtual bigger viewport).
13946  -totalSize the size of virtual bigger viewport
13947  -tileSize  tile size (the view size will be used if omitted)
13948  -lowerLeft tile offset as lower left corner
13949  -upperLeft tile offset as upper left corner
13950 )" /* [vtile] */);
13951
13952   addCmd ("vzlayer", VZLayer, /* [vzlayer] */ R"(
13953 vzlayer [layerId]
13954         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]
13955         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]
13956         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]
13957         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]
13958 ZLayer list management
13959  -add      add new z layer to viewer and print its id
13960  -insertBefore add new z layer and insert it before existing one
13961  -insertAfter  add new z layer and insert it after  existing one
13962  -delete   delete z layer
13963  -get      print sequence of z layers
13964  -settings print status of z layer settings
13965  -disable  disables given setting
13966  -enable   enables  given setting
13967 )" /* [vzlayer] */);
13968
13969   addCmd ("vlayerline", VLayerLine, /* [vlayerline] */ R"(
13970 vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]
13971 )" /* [vlayerline] */);
13972
13973   addCmd ("vgrid", VGrid, /* [vgrid] */ R"(
13974 vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]
13975       [-step X Y] [-size DX DY]
13976       [-step StepRadius NbDivisions] [-radius Radius]
13977 )" /* [vgrid] */);
13978
13979   addCmd ("vpriviledgedplane", VPriviledgedPlane, /* [vpriviledgedplane] */ R"(
13980 vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]
13981 Sets or prints viewer's priviledged plane geometry:
13982   Ox, Oy, Oz - plane origin;
13983   Nx, Ny, Nz - plane normal direction;
13984   Xx, Xy, Xz - plane x-reference axis direction.
13985 )" /* [vpriviledgedplane] */);
13986
13987   addCmd ("vconvert", VConvert, /* [vconvert] */ R"(
13988 vconvert v [Mode={window|view}]
13989 vconvert x y [Mode={window|view|grid|ray}]
13990 vconvert x y z [Mode={window|grid}]
13991 Convert the given coordinates to window/view/model space:
13992  - window - convert to window coordinates, pixels;
13993  - view   - convert to view projection plane;
13994  - grid   - convert to model coordinates, given on grid;
13995  - ray    - convert projection ray to model coordinates.
13996 )" /* [vconvert] */);
13997
13998   addCmd ("vfps", VFps, /* [vfps] */ R"(
13999 vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view.
14000 )" /* [vfps] */);
14001
14002   addCmd ("vstereo", VStereo, /* [vstereo] */ R"(
14003 vstereo [0|1] [-mode Mode] [-reverse {0|1}]
14004         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]
14005         [-anaglyph Filter]
14006 Control stereo output mode. Available modes for -mode:
14007   quadBuffer       OpenGL QuadBuffer stereo;
14008     requires driver support;
14009     should be called BEFORE vinit!
14010   anaglyph         Anaglyph glasses, filters for -anaglyph:
14011     redCyan, redCyanSimple, yellowBlue, yellowBlueSimple, greenMagentaSimple.
14012   rowInterlaced    row-interlaced display
14013   columnInterlaced column-interlaced display
14014   chessBoard       chess-board output
14015   sideBySide       horizontal pair
14016   overUnder        vertical   pair
14017   openVR           OpenVR (HMD), extra options:
14018     -mirrorComposer flag to mirror VR frame in the window (debug);
14019     -unitFactor     specifies meters scale factor for mapping VR input.
14020 )" /* [vstereo] */);
14021
14022   addCmd ("vmemgpu", VMemGpu, /* [vmemgpu] */ R"(
14023 vmemgpu [f]: print system-dependent GPU memory information if available;
14024 with f option returns free memory in bytes.
14025 )" /* [vmemgpu] */);
14026
14027   addCmd ("vreadpixel", VReadPixel, /* [vreadpixel] */ R"(
14028 vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]
14029 Read pixel value for active view.
14030 )" /* [vreadpixel] */);
14031
14032   addCmd ("diffimage", VDiffImage, /* [diffimage] */ R"(
14033 diffimage imageFile1 imageFile2 [diffImageFile]
14034           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]
14035           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]
14036 Compare two images by content and generate difference image.
14037 When -exitOnClose is specified, closing the view will exit application.
14038 When -closeOnEscape is specified, view will be closed on pressing Escape.
14039 )" /* [diffimage] */);
14040
14041   addCmd ("vselect", VSelect, /* [vselect] */ R"(
14042 vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1]
14043         [-replace|-replaceextra|-xor|-add|-remove]
14044 Emulate different types of selection:
14045  1) Single click selection.
14046  2) Selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2).
14047  3) Selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn).
14048  4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.
14049     If the flag is set to 1, both sensitives that were included completely
14050     and overlapped partially by defined rectangle or polygon will be detected,
14051     otherwise algorithm will chose only fully included sensitives.
14052     Default behavior is to detect only full inclusion
14053     (partial inclusion - overlap - is not allowed by default).
14054  5) Selection scheme replace, replaceextra, xor, add or remove (replace by default).
14055 )" /* [vselect] */);
14056
14057   addCmd ("vmoveto", VMoveTo, /* [vmoveto] */ R"(
14058 vmoveto [x y] [-reset]
14059 Emulate cursor movement to pixel position (x,y).
14060  -reset resets current highlighting.
14061 )" /* [vmoveto] */);
14062
14063   addCmd ("vselaxis", VSelectByAxis, /* [vselaxis] */ R"(
14064 vselaxis x y z dx dy dz [-onlyTop 0|1] [-display Name] [-showNormal 0|1]"
14065 Provides intersection by given axis and print result intersection points.
14066  -onlyTop       switches On/Off mode to find only top point or all;
14067  -display Name  displays intersecting axis and result intersection points for debug goals;
14068  -showNormal    adds displaying of normal in intersection point or not.
14069 )" /* [vselaxis] */);
14070
14071   addCmd ("vviewparams", VViewParams, /* [vviewparams] */ R"(
14072 vviewparams [-args] [-scale [s]]
14073             [-eye [x y z]] [-at [x y z]] [-up [x y z]]
14074             [-proj [x y z]] [-center x y] [-size sx]
14075 Manage current view parameters (camera orientation) or prints all
14076 current values when called without argument.
14077  -scale [s]    prints or sets viewport relative scale
14078  -eye  [x y z] prints or sets eye location
14079  -at   [x y z] prints or sets center of look
14080  -up   [x y z] prints or sets direction of up vector
14081  -proj [x y z] prints or sets direction of look
14082  -center x y   sets location of center of the screen in pixels
14083  -size [sx]    prints viewport projection width and height sizes
14084                or changes the size of its maximum dimension
14085  -args         prints vviewparams arguments for restoring current view
14086 )" /* [vviewparams] */);
14087
14088   addCmd ("v2dmode", V2DMode, /* [v2dmode] */ R"(
14089 v2dmode [-name viewName] [-mode {-on|-off}=-on]
14090   name - name of existing view, if not defined, the active view is changed;
14091   mode - switches On/Off rotation mode.
14092 Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:
14093  - rotation of the view by 3rd mouse button with Ctrl active
14094  - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right
14095 View camera position might be changed only by commands.
14096 )" /* [v2dmode] */);
14097
14098   addCmd ("vanimation", VAnimation, /* [vanimation] */ R"(
14099 Alias for vanim
14100 )" /* [vanimation] */);
14101
14102   addCmd ("vanim", VAnimation, /* [vanim] */ R"(
14103 List existing animations:
14104   vanim
14105
14106 Animation playback:
14107   vanim name {-play|-resume|-pause|-stop} [playFrom [playDuration]]
14108              [-speed Coeff] [-freeLook] [-noPauseOnClick] [-lockLoop]
14109
14110   -speed    playback speed (1.0 is normal speed)
14111   -freeLook skip camera animations
14112   -noPauseOnClick do not pause animation on mouse click
14113   -lockLoop disable any interactions
14114
14115 Animation definition:
14116   vanim Name/sub/name [-clear] [-delete]
14117         [start TimeSec] [duration TimeSec]
14118
14119 Animation name defined in path-style (anim/name or anim.name)
14120 specifies nested animations.
14121 There is no syntax to explicitly add new animation,
14122 and all non-existing animations within the name will be
14123 implicitly created on first use (including parents).
14124
14125 Each animation might define the SINGLE action (see below),
14126 like camera transition, object transformation or custom callback.
14127 Child animations can be used for defining concurrent actions.
14128
14129 Camera animation:
14130   vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]
14131                    [-at1  X Y Z] [-at2  X Y Z]
14132                    [-up1  X Y Z] [-up2  X Y Z]
14133                    [-scale1 Scale] [-scale2 Scale]
14134   -eyeX   camera Eye positions pair (start and end)
14135   -atX    camera Center positions pair
14136   -upX    camera Up directions pair
14137   -scaleX camera Scale factors pair
14138
14139 Object animation:
14140   vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]
14141                      [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]
14142                      [-scale1 Scale] [-scale2 Scale]
14143  -locX   object Location points pair (translation)
14144  -rotX   object Orientations pair (quaternions)
14145  -scaleX object Scale factors pair (quaternions)
14146
14147 Custom callback:
14148   vanim name -invoke "Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN"
14149
14150   %Pts        overall animation presentation timestamp
14151   %LocalPts   local animation timestamp
14152   %Normalized local animation normalized value in range 0..1
14153
14154 Video recording:
14155   vanim name -record FileName [Width Height] [-fps FrameRate=24]
14156         [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]
14157         [-crf Value] [-preset Preset]
14158   -fps     video framerate
14159   -format  file format, container (matroska, etc.)
14160   -vcodec  video codec identifier (ffv1, mjpeg, etc.)
14161   -pix_fmt image pixel format (yuv420p, rgb24, etc.)
14162   -crf     constant rate factor (specific to codec)
14163   -preset  codec parameters preset (specific to codec)
14164 )" /* [vanim] */);
14165
14166   addCmd ("vchangeselected", VChangeSelected, /* [vchangeselected] */ R"(
14167 vchangeselected shape : Add shape to selection or remove one from it.
14168 )" /* [vchangeselected] */);
14169
14170   addCmd ("vnbselected", VNbSelected, /* [vnbselected] */ R"(
14171 vnbselected : Returns number of selected objects in the interactive context.
14172 )" /* [vnbselected] */);
14173
14174   addCmd ("vcamera", VCamera, /* [vcamera] */ R"(
14175 vcamera [PrsName] [-ortho] [-projtype]
14176         [-persp]
14177         [-fovy   [Angle]] [-distance [Distance]]
14178         [-stereo] [-leftEye] [-rightEye]
14179         [-iod [Distance]] [-iodType    [absolute|relative]]
14180         [-zfocus [Value]] [-zfocusType [absolute|relative]]
14181         [-fov2d  [Angle]] [-lockZup {0|1}]
14182         [-rotationMode {active|pick|pickCenter|cameraAt|scene}]
14183         [-navigationMode {orbit|walk|flight}]
14184         [-xrPose base|head=base]
14185 Manages camera parameters.
14186 Displays frustum when presentation name PrsName is specified.
14187 Prints current value when option called without argument.
14188
14189 Orthographic camera:
14190  -ortho      activate orthographic projection.
14191
14192 Perspective camera:
14193  -persp      activate perspective  projection (mono);
14194  -fovy       field of view in y axis, in degrees;
14195  -fov2d      field of view limit for 2d on-screen elements;
14196  -distance   distance of eye from camera center;
14197  -lockZup    lock Z up (turntable mode);
14198  -rotationMode rotation mode (gravity point);
14199  -navigationMode navigation mode.
14200
14201 Stereoscopic camera:
14202  -stereo     perspective  projection (stereo);
14203  -leftEye    perspective  projection (left  eye);
14204  -rightEye   perspective  projection (right eye);
14205  -iod        intraocular distance value;
14206  -iodType    distance type, absolute or relative;
14207  -zfocus     stereographic focus value;
14208  -zfocusType focus type, absolute or relative.
14209 )" /* [vcamera] */);
14210
14211   addCmd ("vautozfit", VAutoZFit, /* [vautozfit] */ R"(
14212 vautozfit [on={1|0}] [scale]
14213 Prints or changes parameters of automatic z-fit mode:
14214  "on" - turns automatic z-fit on or off;
14215  "scale" - specifies factor to scale computed z range.
14216 )" /* [vautozfit] */);
14217
14218   addCmd ("vzrange", VZRange, /* [vzrange] */ R"(
14219 vzrange [znear] [zfar]
14220 Applies provided znear/zfar to view or prints current values.
14221 )" /* [vzrange] */);
14222
14223   addCmd ("vsetviewsize", VSetViewSize, /* [vsetviewsize] */ R"(
14224 vsetviewsize size
14225 )" /* [vsetviewsize] */);
14226
14227   addCmd ("vmoveview", VMoveView, /* [vmoveview] */ R"(
14228 vmoveview Dx Dy Dz [Start = 1|0]
14229 )" /* [vmoveview] */);
14230
14231   addCmd ("vtranslateview", VTranslateView, /* [vtranslateview] */ R"(
14232 vtranslateview Dx Dy Dz [Start = 1|0)]
14233 )" /* [vtranslateview] */);
14234
14235   addCmd ("vturnview", VTurnView, /* [vturnview] */ R"(
14236 vturnview Ax Ay Az [Start = 1|0]
14237 )" /* [vturnview] */);
14238
14239   addCmd ("vtextureenv", VTextureEnv, /* [vtextureenv] */ R"(
14240 vtextureenv {on|off} {image_file}
14241             [{clamp|repeat} {decal|modulate} {nearest|bilinear|trilinear} ss st ts tt rot]
14242 Enables or disables environment mapping in the 3D view, loading the texture from the given standard
14243 or user-defined file and optionally applying texture mapping parameters.
14244  ss, st - scale factors for s and t texture coordinates;
14245  ts, tt - translation for s and t texture coordinates;
14246  rot    - texture rotation angle in degrees.
14247 )" /* [vtextureenv] */);
14248
14249   addCmd ("vhlr", VHLR, /* [vhlr] */ R"(
14250 vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]
14251 Hidden Line Removal algorithm.
14252  -showHidden if set ON, hidden lines are drawn as dotted ones;
14253  -algoType   type of HLR algorithm:
14254             'algo' - exact HLR algorithm is applied;
14255             'polyAlgo' - polygonal HLR algorithm is applied.
14256 )" /* [vhlr] */);
14257
14258   addCmd ("vhlrtype", VHLRType, /* [vhlrtype] */ R"(
14259 vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]
14260 Changes the type of HLR algorithm using for shapes:
14261  'algo' - exact HLR algorithm is applied;
14262  'polyAlgo' - polygonal HLR algorithm is applied.
14263 If shapes are not given - option is applied to all shapes in the view.
14264 )" /* [vhlrtype] */);
14265
14266   addCmd ("vclipplane", VClipPlane, /* [vclipplane] */ R"(
14267 vclipplane planeName [{0|1}]
14268     [-equation1 A B C D]
14269     [-equation2 A B C D]
14270     [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]
14271     [-set|-unset|-setOverrideGlobal [objects|views]]
14272     [-maxPlanes]
14273     [-capping {0|1}]
14274       [-color R G B] [-transparency Value] [-hatch {on|off|ID}]
14275       [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]
14276         [-texRotate Angle]
14277       [-useObjMaterial {0|1}] [-useObjTexture {0|1}]
14278         [-useObjShader {0|1}]
14279
14280 Clipping planes management:
14281  -maxPlanes   print plane limit for view;
14282  -delete      delete plane with given name;
14283  {off|on|0|1} turn clipping on/off;
14284  -set|-unset  set/unset plane for Object or View list;
14285               applied to active View when list is omitted;
14286  -equation A B C D change plane equation;
14287  -clone SourcePlane NewPlane clone the plane definition.
14288
14289 Capping options:
14290  -capping {off|on|0|1} turn capping on/off;
14291  -color R G B          set capping color;
14292  -transparency Value   set capping transparency 0..1;
14293  -texName Texture      set capping texture;
14294  -texScale SX SY       set capping tex scale;
14295  -texOrigin TX TY      set capping tex origin;
14296  -texRotate Angle      set capping tex rotation;
14297  -hatch {on|off|ID}    set capping hatching mask;
14298  -useObjMaterial {off|on|0|1} use material of clipped object;
14299  -useObjTexture  {off|on|0|1} use texture of clipped object;
14300  -useObjShader   {off|on|0|1} use shader program of object.
14301 )" /* [vclipplane] */);
14302
14303   addCmd ("vdefaults", VDefaults, /* [vdefaults] */ R"(
14304 vdefaults [-absDefl value] [-devCoeff value] [-angDefl value]
14305           [-autoTriang {off/on | 0/1}]
14306 )" /* [vdefaults] */);
14307
14308   addCmd ("vlight", VLight, /* [vlight] */ R"(
14309 vlight [lightName] [-noupdate]
14310        [-clear|-defaults] [-layer Id] [-local|-global] [-disable|-enable]
14311        [-type {ambient|directional|spotlight|positional}] [-name value]
14312        [-position X Y Z] [-direction X Y Z] [-color colorName] [-intensity value]
14313        [-headlight 0|1] [-castShadows 0|1]
14314        [-range value] [-constAttenuation value] [-linearAttenuation value]
14315        [-spotExponent value] [-spotAngle angleDeg]
14316        [-smoothAngle value] [-smoothRadius value]
14317        [-display] [-showName 1|0] [-showRange 1|0] [-prsZoomable 1|0] [-prsSize Value]
14318        [-arcSize Value]
14319
14320 Command manages light sources. Without arguments shows list of lights.
14321 Arguments affecting the list of defined/active lights:
14322  -clear       remove all light sources;
14323  -defaults    defines two standard light sources;
14324  -reset       resets light source parameters to default values;
14325  -type        sets type of light source;
14326  -name        sets new name to light source;
14327  -global      assigns light source to all views (default state);
14328  -local       assigns light source to active view;
14329  -zlayer      assigns light source to specified Z-Layer.
14330
14331 Ambient light parameters:
14332  -color       sets (normalized) light color;
14333  -intensity   sets intensity of light source, 1.0 by default;
14334               affects also environment cubemap intensity.
14335
14336 Point light parameters:
14337  -color       sets (normalized) light color;
14338  -intensity   sets PBR intensity;
14339  -range       sets clamping distance;
14340  -constAtten  (obsolete) sets constant attenuation factor;
14341  -linearAtten (obsolete) sets linear   attenuation factor;
14342  -smoothRadius sets PBR smoothing radius.
14343
14344 Directional light parameters:
14345  -color       sets (normalized) light color;
14346  -intensity   sets PBR intensity;
14347  -direction   sets direction;
14348  -headlight   sets headlight flag;
14349  -castShadows enables/disables shadow casting;
14350  -smoothAngle sets PBR smoothing angle (in degrees) within 0..90 range.
14351
14352 Spot light parameters:
14353  -color       sets (normalized) light color;
14354  -intensity   sets PBR intensity;
14355  -range       sets clamping distance;
14356  -position    sets position;
14357  -direction   sets direction;
14358  -spotAngle   sets spotlight angle;
14359  -spotExp     sets spotlight exponenta;
14360  -headlight   sets headlight flag;
14361  -constAtten  (obsolete) sets constant attenuation factor;
14362  -linearAtten (obsolete) sets linear   attenuation factor.
14363
14364 Light presentation parameters:
14365  -display     adds light source presentation;
14366  -showName    shows/hides the name of light source; 1 by default;
14367  -showRange   shows/hides the range of spot/positional light source; 1 by default;
14368  -prsZoomable makes light presentation zoomable/non-zoomable;
14369  -prsDraggable makes light presentation draggable/non-draggable;
14370  -prsSize     sets light presentation size;
14371  -arcSize     sets arc presentation size(in pixels)
14372               for rotation directional light source; 25 by default.
14373
14374 Examples:
14375  vlight redlight -type POSITIONAL -headlight 1 -pos 0 1 1 -color RED
14376  vlight redlight -delete
14377 )" /* [vlight] */);
14378
14379   addCmd ("vpbrenv", VPBREnvironment, /* [vpbrenv] */ R"(
14380 vpbrenv -clear|-generate
14381 Clears or generates PBR environment map of active view.
14382  -clear clears PBR environment (fills by white color);
14383  -generate generates PBR environment from current background cubemap.
14384 )" /* [vpbrenv] */);
14385
14386   addCmd ("vraytrace", VRenderParams, /* [vraytrace] */ R"(
14387 vraytrace [0|1] : Turns on/off ray-tracing renderer.
14388  'vraytrace 0' alias for 'vrenderparams -raster'.
14389  'vraytrace 1' alias for 'vrenderparams -rayTrace'.
14390 )" /* [vraytrace] */);
14391
14392   addCmd ("vrenderparams", VRenderParams, /* [vrenderparams] */ R"(
14393 Manages rendering parameters, affecting visual appearance, quality and performance.
14394 Should be applied taking into account GPU hardware capabilities and performance.
14395
14396 Common parameters:
14397 vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]
14398               [-msaa 0..8=0] [-rendScale scale=1]
14399               [-resolution value=72] [-fontHinting {off|normal|light}=off]
14400               [-fontAutoHinting {auto|force|disallow}=auto]
14401               [-oit {off|weight|peel}] [-oit weighted [depthFactor=0.0]] [-oit peeling [nbLayers=4]]
14402               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]
14403               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]
14404               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]
14405               [-sync {default|views}] [-reset]
14406  -raster          Disables GPU ray-tracing.
14407  -shadingModel    Controls shading model.
14408  -msaa            Specifies number of samples for MSAA.
14409  -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA).
14410  -resolution      Sets new pixels density (PPI) used as text scaling factor.
14411  -fontHinting     Enables/disables font hinting for better readability on low-resolution screens.
14412  -fontAutoHinting Manages font autohinting.
14413  -lineFeather     Sets line feather factor while displaying mesh edges.
14414  -alphaToCoverage Enables/disables alpha to coverage (needs MSAA).
14415  -oit             Enables/disables order-independent transparency (OIT) rendering;
14416       off         unordered transparency (but opaque objects implicitly draw first);
14417       weighted    weight OIT is managed by depth weight factor 0.0..1.0;
14418       peeling     depth peeling OIT is managed by number of peeling layers.
14419   -shadows         Enables/disables shadows rendering.
14420   -shadowMapResolution Shadow texture map resolution.
14421   -shadowMapBias   Shadow map bias.
14422   -depthPrePass    Enables/disables depth pre-pass.
14423   -frustumCulling  Enables/disables objects frustum clipping or
14424                    sets state to check structures culled previously.
14425   -sync            Sets active View parameters as Viewer defaults / to other Views.
14426   -reset           Resets active View parameters to Viewer defaults.
14427
14428 Diagnostic output (on-screen overlay):
14429 vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points
14430                                  |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]
14431               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]
14432  -perfCounters       Show/hide performance counters (flags can be combined).
14433  -perfUpdateInterval Performance counters update interval.
14434  -perfChart          Show frame timers chart limited by specified number of frames.
14435  -perfChartMax       Maximum time in seconds with the chart.
14436
14437 Ray-Tracing options:
14438 vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]
14439               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]
14440               [-gi {on|off}=off] [-brng {on|off}=off]
14441               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]
14442               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]
14443               [-maxRad {value>0}=30.0]
14444               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]
14445               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]
14446  -rayTrace     Enables  GPU ray-tracing.
14447  -rayDepth     Defines maximum ray-tracing depth.
14448  -reflections  Enables/disables specular reflections.
14449  -fsaa         Enables/disables adaptive anti-aliasing.
14450  -gleam        Enables/disables transparency shadow effects.
14451  -gi           Enables/disables global illumination effects (Path-Tracing).
14452  -env          Enables/disables environment map background.
14453  -ignoreNormalMap Enables/disables normal map ignoring during path tracing.
14454  -twoSide      Enables/disables two-sided BSDF models (PT mode).
14455  -iss          Enables/disables adaptive screen sampling (PT mode).
14456  -maxRad       Value used for clamping radiance estimation (PT mode).
14457  -tileSize     Specifies   size of screen tiles in ISS mode (32 by default).
14458  -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default).
14459  -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF).
14460  -focal        Focal distance of perspective camera for depth-of-field effect.
14461  -exposure     Exposure value for tone mapping (0.0 value disables the effect).
14462  -whitePoint   White point value for filmic tone mapping.
14463  -toneMapping  Tone mapping mode (disabled, filmic).
14464
14465 PBR environment baking parameters (advanced/debug):
14466 vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]
14467               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]
14468  -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size).
14469  -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map.
14470  -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during
14471                  diffuse IBL map's sherical harmonics calculation.
14472  -pbrEnvBSSN     Controls maximum number of samples per mipmap level
14473                  in Monte-Carlo integration during specular IBL maps generation.
14474  -pbrEnvBP       Controls strength of samples number reducing
14475                  during specular IBL maps generation (1 disables reducing).
14476
14477 Debug options:
14478 vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]
14479  -issd         Shows screen sampling distribution in ISS mode.
14480  -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging).
14481  -brng         Enables/disables blocked RNG (fast coherent PT).
14482 )" /* [vrenderparams] */);
14483
14484   addCmd ("vstatprofiler", VStatProfiler, /* [vstatprofiler] */ R"(
14485 vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups
14486                 |allArrays|fillArrays|lineArrays|pointArrays|textArrays
14487                 |triangles|points|geomMem|textureMem|frameMem
14488                 |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage
14489                 |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]
14490               [-noredraw]
14491 Prints rendering statistics for specified counters or for all when unspecified.
14492 Set '-noredraw' flag to avoid additional redraw call and use already collected values.
14493 )" /* [vstatprofiler] */);
14494
14495   addCmd ("vplace", VPlace, /* [vplace] */ R"(
14496 vplace dx dy : Places the point (in pixels) at the center of the window
14497 )" /* [vplace] */);
14498
14499   addCmd ("vxrotate", VXRotate, /* [vxrotate] */ R"(
14500 vxrotate
14501 )" /* [vxrotate] */);
14502
14503   addCmd ("vmanipulator", VManipulator, /* [vmanipulator] */ R"(
14504 vmanipulator Name [-attach AISObject | -detach | ...]
14505 Tool to create and manage AIS manipulators.
14506 Options:
14507  '-attach AISObject'                 attach manipulator to AISObject
14508  '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching
14509  '-adjustSize     {0|1}'             adjust size when attaching
14510  '-enableModes    {0|1}'             enable modes when attaching
14511  '-view  {active | [name of view]}'  display manipulator only in defined view,
14512                                      by default it is displayed in all views of the current viewer
14513  '-detach'                           detach manipulator
14514  '-startTransform mouse_x mouse_y' - invoke start of transformation
14515  '-transform      mouse_x mouse_y' - invoke transformation
14516  '-stopTransform  [abort]'         - invoke stop of transformation
14517  '-move x y z'                     - move attached object
14518  '-rotate x y z dx dy dz angle'    - rotate attached object
14519  '-scale factor'                   - scale attached object
14520  '-autoActivate      {0|1}'        - set activation on detection
14521  '-followTranslation {0|1}'        - set following translation transform
14522  '-followRotation    {0|1}'        - set following rotation transform
14523  '-followDragging    {0|1}'        - set following dragging transform
14524  '-gap value'                      - set gap between sub-parts
14525  '-part axis mode    {0|1}'        - set visual part
14526  '-parts axis mode   {0|1}'        - set visual part
14527  '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator
14528  '-size value'                     - set size of manipulator
14529  '-zoomable {0|1}'                 - set zoom persistence
14530 )" /* [vmanipulator] */);
14531
14532   addCmd ("vselprops", VSelectionProperties, /* [vselprops] */ R"(
14533 vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]
14534 Customizes selection and dynamic highlight parameters for the whole interactive context:
14535  -autoActivate {0|1}     disables|enables default computation
14536                          and activation of global selection mode
14537  -autoHighlight {0|1}    disables|enables automatic highlighting in 3D Viewer
14538  -highlightSelected {0|1} disables|enables highlighting of detected object in selected state
14539  -pickStrategy {first|topmost} : defines picking strategy
14540                'first'   to pick first acceptable (default)
14541                'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)
14542  -pixTol    value        sets up pixel tolerance
14543  -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth
14544  -depthTol {sensfactor}  use sensitive factor for sorting results by depth
14545  -preferClosest {0|1}    sets if depth should take precedence over priority while sorting results
14546  -dispMode  dispMode     sets display mode for highlighting
14547  -layer     ZLayer       sets ZLayer for highlighting
14548  -color     {name|r g b} sets highlight color
14549  -transp    value        sets transparency coefficient for highlight
14550  -material  material     sets highlight material
14551  -print                  prints current state of all mentioned parameters
14552 )" /* [vselprops] */);
14553
14554   addCmd ("vhighlightselected", VSelectionProperties, /* [vhighlightselected] */ R"(
14555 vhighlightselected [0|1] : alias for vselprops -highlightSelected.
14556 )" /* [vhighlightselected] */);
14557
14558   addCmd ("vseldump", VDumpSelectionImage, /* [vseldump] */ R"(
14559 vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|entityType|surfNormal}=depth
14560          -pickedIndex Index=1
14561          [-xrPose base|head=base]
14562 Generate an image based on detection results:
14563   depth       normalized depth values
14564   unnormDepth unnormalized depth values
14565   object      color of detected object
14566   owner       color of detected owner
14567   selMode     color of selection mode
14568   entity      color of detected entity
14569   entityType  color of detected entity type
14570   surfNormal  normal direction values
14571 )" /* [vseldump] */);
14572
14573   addCmd ("vviewcube", VViewCube, /* [vviewcube] */ R"(
14574 vviewcube name
14575 Displays interactive view manipulation object. Options:
14576  -reset                   reset geometric and visual attributes
14577  -size Size               adapted size of View Cube
14578  -boxSize Size            box size
14579  -axes  {0|1}             show/hide axes (trihedron)
14580  -edges {0|1}             show/hide edges of View Cube
14581  -vertices {0|1}          show/hide vertices of View Cube
14582  -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation
14583  -color Color             color of View Cube
14584  -boxColor Color          box color
14585  -boxSideColor Color      box sides color
14586  -boxEdgeColor Color      box edges color
14587  -boxCornerColor Color    box corner color
14588  -textColor Color         color of side text of view cube
14589  -innerColor Color        inner box color
14590  -transparency Value      transparency of object within [0, 1] range
14591  -boxTransparency Value   transparency of box    within [0, 1] range
14592  -xAxisTextColor Color    color of X axis label
14593  -yAxisTextColor Color    color of Y axis label
14594  -zAxisTextColor Color    color of Z axis label
14595  -font Name               font name
14596  -fontHeight Value        font height
14597  -boxFacetExtension Value box facet extension
14598  -boxEdgeGap Value        gap between box edges and box sides
14599  -boxEdgeMinSize Value    minimal box edge size
14600  -boxCornerMinSize Value  minimal box corner size
14601  -axesPadding Value       padding between box and arrows
14602  -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range
14603  -axesRadius Value        radius of axes of the trihedron
14604  -axesConeRadius Value    radius of the cone (arrow) of the trihedron
14605  -axesSphereRadius Value  radius of the sphere (central point) of trihedron
14606  -fixedAnimation {0|1}    uninterruptible animation loop
14607  -duration Seconds        animation duration in seconds
14608 )" /* [vviewcube] */);
14609
14610   addCmd ("vcolorconvert", VColorConvert, /* [vcolorconvert] */ R"(
14611 vcolorconvert {from|to} type C1 C2 C2
14612 vcolorconvert from type C1 C2 C2 : Converts color from specified color space to linear RGB
14613 vcolorconvert to   type R  G  B  : Converts linear RGB color to specified color space
14614 Type can be sRGB, HLS, Lab, or Lch.
14615 )" /* [vcolorconvert] */);
14616
14617   addCmd ("vcolordiff", VColorDiff, /* [vcolordiff] */ R"(
14618 vcolordiff R1 G1 B1 R2 G2 B2 : returns CIEDE2000 color difference between two RGB colors.
14619 )" /* [vcolordiff] */);
14620
14621   addCmd ("vselbvhbuild", VSelBvhBuild, /* [vselbvhbuild] */ R"(
14622 vselbvhbuild [{0|1}] [-nbThreads value] [-wait]
14623 Turns on/off prebuilding of BVH within background thread(s).
14624  -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1);
14625  -wait        waits for building all of BVH.
14626 )" /* [vselbvhbuild] */);
14627 }