0032464: Draw Harness, ViewerTest - rely on AIS_ViewController within vanimation...
[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 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
195
196 //==============================================================================
197 //  EVENT GLOBAL VARIABLES
198 //==============================================================================
199
200 namespace
201 {
202
203   //! Checks if some set is a subset of other set
204   //! @tparam TheSuperSet the type of the superset
205   //! @tparam TheSubSet the type of the subset
206   //! @param theSuperSet the superset
207   //! @param theSubSet the subset to be checked
208   //! @return true if the superset includes subset, or false otherwise
209   template <typename TheSuperSet, typename TheSubSet>
210   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
211   {
212     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
213   }
214
215   //! A variable set of keys for command-line options.
216   //! It includes a set of mandatory keys and a set of all possible keys.
217   class CommandOptionKeyVariableSet
218   {
219   public:
220     //! Default constructor
221     CommandOptionKeyVariableSet()
222     {
223     }
224
225     //! Constructor
226     //! @param theMandatoryKeySet the set of the mandatory option keys
227     //! @param theAdditionalKeySet the set of additional options that could be omitted
228     CommandOptionKeyVariableSet (
229       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
230       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
231     : myMandatoryKeySet (theMandatoryKeySet)
232     {
233       std::set_union (theMandatoryKeySet.begin(),
234                       theMandatoryKeySet.end(),
235                       theAdditionalKeySet.begin(),
236                       theAdditionalKeySet.end(),
237                       std::inserter (myFullKeySet, myFullKeySet.begin()));
238     }
239
240     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
241     //! and be contained in the full key set)
242     //! @param theCheckedKeySet the set of option keys to be checked
243     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
244     {
245       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
246     }
247
248   private:
249     //! A set of mandatory command-line option keys
250     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
251
252     //! A full set of command-line option keys (includes mandatory and additional option keys)
253     ViewerTest_CommandOptionKeySet myFullKeySet;
254   };
255
256   //! Gets some code by its name
257   //! @tparam TheCode the type of a code to be found
258   //! @param theCodeNameMap the map from code names to codes
259   //! @param theCodeName the name of a code to be found
260   //! @param theCode the code to be found
261   //! @return true if a code is found, or false otherwise
262   template <typename TheCode>
263   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
264                                  TCollection_AsciiString                           theCodeName,
265                                  TheCode&                                          theCode)
266   {
267     theCodeName.LowerCase();
268     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
269       theCodeName);
270     if (aCodeIterator == theCodeNameMap.end())
271     {
272       return false;
273     }
274     theCode = aCodeIterator->second;
275     return true;
276   }
277
278   // Defines possible commands related to background changing
279   enum BackgroundCommand
280   {
281     BackgroundCommand_Main,              //!< The main command that manages other commands through options
282     BackgroundCommand_Image,             //!< Sets an image as a background
283     BackgroundCommand_ImageMode,         //!< Changes a background image mode
284     BackgroundCommand_Gradient,          //!< Sets a gradient as a background
285     BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
286     BackgroundCommand_Color,             //!< Fills background with a specified color
287     BackgroundCommand_Default            //!< Sets the background default color or gradient
288   };
289
290   //! Map from background command names to its codes
291   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
292
293   //! Creates a map from background command names to its codes
294   //! @return a map from background command names to its codes
295   static BackgroundCommandNameMap createBackgroundCommandNameMap()
296   {
297     BackgroundCommandNameMap aBackgroundCommandNameMap;
298     aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
299     aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
300     aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
301     aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
302     aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
303     aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
304     aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
305     return aBackgroundCommandNameMap;
306   }
307
308   //! Gets a background command by its name
309   //! @param theBackgroundCommandName the name of the background command
310   //! @param theBackgroundCommand the background command to be found
311   //! @return true if a background command is found, or false otherwise
312   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
313                                           BackgroundCommand&             theBackgroundCommand)
314   {
315     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
316     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
317   }
318
319   //! Map from background image fill method names to its codes
320   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
321
322   //! Creates a map from background image fill method names to its codes
323   //! @return a map from background image fill method names to its codes
324   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
325   {
326     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
327     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
328     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
329     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
330     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
331     return aBackgroundImageFillMethodNameMap;
332   }
333
334   //! Gets a background image fill method by its name
335   //! @param theBackgroundImageFillMethodName the name of the background image fill method
336   //! @param theBackgroundImageFillMethod the background image fill method to be found
337   //! @return true if a background image fill method is found, or false otherwise
338   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
339                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
340   {
341     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
342       createBackgroundImageFillMethodNameMap();
343     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
344                               theBackgroundImageFillMethodName,
345                               theBackgroundImageFillMethod);
346   }
347
348   //! Map from background gradient fill method names to its codes
349   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
350
351   //! Creates a map from background gradient fill method names to its codes
352   //! @return a map from background gradient fill method names to its codes
353   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
354   {
355     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
356     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
357     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
358     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
359     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
360     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
361     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
362     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
363     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
364     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
365     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
366     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
367     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
368     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
369     return aBackgroundGradientFillMethodNameMap;
370   }
371
372   //! Gets a gradient fill method by its name
373   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
374   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
375   //! @return true if a gradient fill method is found, or false otherwise
376   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
377                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
378   {
379     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
380       createBackgroundGradientFillMethodNameMap();
381     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
382                               theBackgroundGradientFillMethodName,
383                               theBackgroundGradientFillMethod);
384   }
385
386   //! Changes the background in accordance with passed command line options
387   class BackgroundChanger
388   {
389   public:
390     //! Constructor. Prepares the command parser
391     BackgroundChanger()
392     {
393       prepareCommandParser();
394     }
395
396     //! Processes the command line and changes the background
397     //! @param theDrawInterpretor the interpreter of the Draw Harness application
398     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
399     //! @param theCommandLineArguments the array of command line arguments
400     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
401                              const Standard_Integer   theNumberOfCommandLineArguments,
402                              const char* const* const theCommandLineArguments)
403     {
404       const char* const aBackgroundCommandName = theCommandLineArguments[0];
405       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
406       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
407       {
408         return false;
409       }
410       addCommandDescription (aBackgroundCommand);
411       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
412       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
413     }
414
415   private:
416     //! The type of functions that are able to set gradient background filling
417     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
418                                       const Quantity_Color& /* theColor2 */,
419                                       const Aspect_GradientFillMethod /* theGradientMode */);
420
421     //! The type of functions that are able to fill a background with a specific color
422     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
423
424     //! the command parser used to parse command line options and its arguments
425     ViewerTest_CmdParser myCommandParser;
426
427     //! the option key for the command that sets an image as a background
428     ViewerTest_CommandOptionKey myImageOptionKey;
429
430     //! the option key for the command that sets a background image fill type
431     ViewerTest_CommandOptionKey myImageModeOptionKey;
432
433     //! the option key for the command that sets a gradient filling for the background
434     ViewerTest_CommandOptionKey myGradientOptionKey;
435
436     //! the option key for the command that sets a background gradient filling method
437     ViewerTest_CommandOptionKey myGradientModeOptionKey;
438
439     //! the option key for the command that fills background with a specific color
440     ViewerTest_CommandOptionKey myColorOptionKey;
441
442     //! the option key for the command that sets default background gradient or color
443     ViewerTest_CommandOptionKey myDefaultOptionKey;
444
445     //! the option key for the command that sets an environment cubemap as a background
446     ViewerTest_CommandOptionKey myCubeMapOptionKey;
447
448     //! the option key for the command that defines order of tiles in one image packed cubemap
449     ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
450
451     //! the option key for the command that sets inversion of Z axis for background cubemap
452     ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
453
454     //! the option key for the command that allows skip IBL map generation
455     ViewerTest_CommandOptionKey myCubeMapDoNotGenPBREnvOptionKey;
456
457     //! the variable set of options that are allowed for the old scenario (without any option passed)
458     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
459
460     //! the variable set of options that are allowed for setting an environment cubemap as background
461     CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
462
463     //! the variable set of options that are allowed for setting an image as a background
464     CommandOptionKeyVariableSet myImageOptionVariableSet;
465
466     //! the variable set of options that are allowed for setting a background image fill type
467     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
468
469     //! the variable set of options that are allowed for setting a gradient filling for the background
470     CommandOptionKeyVariableSet myGradientOptionVariableSet;
471
472     //! the variable set of options that are allowed for setting a background gradient filling method
473     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
474
475     //! the variable set of options that are allowed for filling a background with a specific color
476     CommandOptionKeyVariableSet myColorOptionVariableSet;
477
478     //! the variable set of options that are allowed for setting a default background gradient
479     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
480
481     //! the variable set of options that are allowed for setting a default background color
482     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
483
484     //! the variable set of options that are allowed for printing help
485     CommandOptionKeyVariableSet myHelpOptionVariableSet;
486
487     //! Adds options to command parser
488     void addOptionsToCommandParser()
489     {
490       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
491                                                     "filename of image used as background");
492       myImageModeOptionKey = myCommandParser.AddOption (
493         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
494       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
495                                                        "sets background gradient starting and ending colors");
496       myGradientModeOptionKey =
497         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
498                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
499                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
500       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
501       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
502
503       myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
504       myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
505       myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
506         "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
507       myCubeMapDoNotGenPBREnvOptionKey = myCommandParser.AddOption ("nopbrenv", "whether IBL map generation should be skipped");
508     }
509
510     //! Creates option sets used to determine if a passed option set is valid or not
511     void createOptionSets()
512     {
513       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
514       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
515       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
516
517       ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
518       aCubeMapOptionSet.insert (myCubeMapOptionKey);
519       ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
520       aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
521       aCubeMapAdditionalOptionKeySet.insert (myCubeMapDoNotGenPBREnvOptionKey);
522       aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
523       myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
524
525       ViewerTest_CommandOptionKeySet anImageOptionSet;
526       anImageOptionSet.insert (myImageOptionKey);
527       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
528       anImageModeOptionSet.insert (myImageModeOptionKey);
529       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
530       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
531
532       ViewerTest_CommandOptionKeySet aGradientOptionSet;
533       aGradientOptionSet.insert (myGradientOptionKey);
534       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
535       aGradientModeOptionSet.insert (myGradientModeOptionKey);
536       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
537       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
538
539       ViewerTest_CommandOptionKeySet aColorOptionSet;
540       aColorOptionSet.insert (myColorOptionKey);
541       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
542
543       aGradientOptionSet.insert (myDefaultOptionKey);
544       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
545       aColorOptionSet.insert (myDefaultOptionKey);
546       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
547
548       ViewerTest_CommandOptionKeySet aHelpOptionSet;
549       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
550       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
551     }
552
553     //! Prepares the command parser. Adds options and creates option sets used to determine
554     //! if a passed option set is valid or not
555     void prepareCommandParser()
556     {
557       addOptionsToCommandParser();
558       createOptionSets();
559     }
560
561     //! Adds a command description to the command parser
562     //! @param theBackgroundCommand the key of the command which description is added to the command parser
563     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
564     {
565       std::string aDescription;
566       bool        isMainCommand = false;
567       switch (theBackgroundCommand)
568       {
569         case BackgroundCommand_Main:
570           aDescription  = "Command: vbackground (changes background or some background settings)";
571           isMainCommand = true;
572           break;
573         case BackgroundCommand_Image:
574           aDescription = "Command: vsetbg (loads image as a background)";
575           break;
576         case BackgroundCommand_ImageMode:
577           aDescription = "Command: vsetbgmode (changes background fill type)";
578           break;
579         case BackgroundCommand_Gradient:
580           aDescription = "Command: vsetgradientbg (mounts gradient background)";
581           break;
582         case BackgroundCommand_GradientMode:
583           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
584           break;
585         case BackgroundCommand_Color:
586           aDescription = "Command: vsetcolorbg (sets color background)";
587           break;
588         case BackgroundCommand_Default:
589           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
590           break;
591         default:
592           return;
593       }
594       if (!isMainCommand)
595       {
596         aDescription += "\nThis command is obsolete. Use vbackground instead.";
597       }
598       myCommandParser.SetDescription (aDescription);
599     }
600
601     //! Check if a viewer is needed to be initialized
602     //! @param theBackgroundCommand the key of the command that changes the background
603     //! @return true if processing was successful, or false otherwise
604     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
605     {
606       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
607       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
608       const bool                           aViewerIsNotNeeded =
609         (theBackgroundCommand == BackgroundCommand_Default)
610         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
611         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
612         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
613       return !aViewerIsNotNeeded;
614     }
615
616     //! Check if a viewer is initialized
617     //! @param theBackgroundCommandName the name of the command that changes the background
618     //! @param theDrawInterpretor the interpreter of the Draw Harness application
619     //! @return true if a viewer is initialized, or false otherwise
620     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
621                                           Draw_Interpretor& theDrawInterpretor)
622     {
623       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
624       if (anAISContext.IsNull())
625       {
626         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
627         return false;
628       }
629       return true;
630     }
631
632     //! Processes command options
633     //! @param theBackgroundCommandName the name of the command that changes the background
634     //! @param theBackgroundCommand the key of the command that changes the background
635     //! @param theDrawInterpretor the interpreter of the Draw Harness application
636     //! @return true if processing was successful, or false otherwise
637     bool processCommandOptions (const char* const       theBackgroundCommandName,
638                                 const BackgroundCommand theBackgroundCommand,
639                                 Draw_Interpretor&       theDrawInterpretor) const
640     {
641       if (myCommandParser.HasNoOption())
642       {
643         return printHelp (theBackgroundCommandName, theDrawInterpretor);
644       }
645       if (checkViewerIsNeeded (theBackgroundCommand)
646           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
647       {
648         return false;
649       }
650       if (myCommandParser.HasOnlyUnnamedOption())
651       {
652         return processUnnamedOption (theBackgroundCommand);
653       }
654       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
655     }
656
657     //! Processes the unnamed option
658     //! @param theBackgroundCommand the key of the command that changes the background
659     //! @return true if processing was successful, or false otherwise
660     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
661     {
662       switch (theBackgroundCommand)
663       {
664         case BackgroundCommand_Main:
665           return false;
666         case BackgroundCommand_Image:
667           return processImageUnnamedOption();
668         case BackgroundCommand_ImageMode:
669           return processImageModeUnnamedOption();
670         case BackgroundCommand_Gradient:
671           return processGradientUnnamedOption();
672         case BackgroundCommand_GradientMode:
673           return processGradientModeUnnamedOption();
674         case BackgroundCommand_Color:
675           return processColorUnnamedOption();
676         case BackgroundCommand_Default:
677           return processDefaultUnnamedOption();
678         default:
679           return false;
680       }
681     }
682
683     //! Processes the image unnamed option
684     //! @return true if processing was successful, or false otherwise
685     bool processImageUnnamedOption() const
686     {
687       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
688         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
689       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
690       {
691         return false;
692       }
693       std::string anImageFileName;
694       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
695       {
696         return false;
697       }
698       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
699       if (aNumberOfImageUnnamedOptionArguments == 2)
700       {
701         std::string anImageModeString;
702         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
703         {
704           return false;
705         }
706         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
707         {
708           return false;
709         }
710       }
711       setImage (anImageFileName.c_str(), anImageMode);
712       return true;
713     }
714
715     //! Processes the image mode unnamed option
716     //! @return true if processing was successful, or false otherwise
717     bool processImageModeUnnamedOption() const
718     {
719       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
720     }
721
722     //! Processes the gradient unnamed option
723     //! @param theSetGradient the function used to set a background gradient filling
724     //! @return true if processing was successful, or false otherwise
725     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
726     {
727       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
728         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
729       if (aNumberOfGradientUnnamedOptionArguments < 2)
730       {
731         return false;
732       }
733
734       Standard_Integer anArgumentIndex = 0;
735       Quantity_Color   aColor1;
736       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
737       {
738         return false;
739       }
740       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
741       {
742         return false;
743       }
744
745       Quantity_Color aColor2;
746       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
747       {
748         return false;
749       }
750       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
751       {
752         return false;
753       }
754
755       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
756       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
757       {
758         std::string anGradientModeString;
759
760         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
761                                   anArgumentIndex,
762                                   anGradientModeString))
763         {
764           return false;
765         }
766         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
767         {
768           return false;
769         }
770         ++anArgumentIndex;
771       }
772       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
773       {
774         return false;
775       }
776       theSetGradient (aColor1, aColor2, aGradientMode);
777       return true;
778     }
779
780     //! Processes the gradient mode unnamed option
781     //! @return true if processing was successful, or false otherwise
782     bool processGradientModeUnnamedOption() const
783     {
784       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
785     }
786
787     //! Processes the color unnamed option
788     //! @param theSetColor the function used to set a background color
789     //! @return true if processing was successful, or false otherwise
790     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
791     {
792       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
793     }
794
795     //! Processes the default back unnamed option
796     //! @return true if processing was successful, or false otherwise
797     bool processDefaultUnnamedOption() const
798     {
799       if (processGradientUnnamedOption (setDefaultGradient))
800       {
801         return true;
802       }
803       return processColorUnnamedOption (setDefaultColor);
804     }
805
806     //! Processes named options
807     //! @param theBackgroundCommandName the name of the command that changes the background
808     //! @param theBackgroundCommand the key of the command that changes the background
809     //! @param theDrawInterpretor the interpreter of the Draw Harness application
810     //! @return true if processing was successful, or false otherwise
811     bool processNamedOptions (const char* const       theBackgroundCommandName,
812                               const BackgroundCommand theBackgroundCommand,
813                               Draw_Interpretor&       theDrawInterpretor) const
814     {
815       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
816       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
817       if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
818       {
819         return processCubeMapOptionSet();
820       }
821       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
822           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
823       {
824         return processImageOptionSet();
825       }
826       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
827           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
828       {
829         return processImageModeOptionSet();
830       }
831       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
832           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
833       {
834         return processGradientOptionSet();
835       }
836       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
837           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
838       {
839         return processGradientModeOptionSet();
840       }
841       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
842           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
843       {
844         return processColorOptionSet();
845       }
846       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
847           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
848               && (theBackgroundCommand == BackgroundCommand_Default)))
849       {
850         return processDefaultGradientOptionSet();
851       }
852       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
853           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
854       {
855         return processDefaultColorOptionSet();
856       }
857       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
858       {
859         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
860       }
861       return false;
862     }
863
864     //! Process the cubemap option set in named and unnamed case.
865     //! @return true if processing was successful, or false otherwise
866     bool processCubeMapOptionSet() const
867     {
868       NCollection_Array1<TCollection_AsciiString> aFilePaths;
869
870       if (!processCubeMapOptions (aFilePaths))
871       {
872         return false;
873       }
874
875       Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
876
877       if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
878       {
879         if (!processCubeMapOrderOptions (anOrder))
880         {
881           return false;
882         }
883       }
884
885       bool aZIsInverted = false;
886       if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
887       {
888         if (!processCubeMapInvertedZOptionSet())
889         {
890           return false;
891         }
892         aZIsInverted = true;
893       }
894
895       bool aToGenPBREnv = true;
896       if (myCommandParser.HasOption (myCubeMapDoNotGenPBREnvOptionKey))
897       {
898         if (!processCubeMapDoNotGenPBREnvOptionSet())
899         {
900           return false;
901         }
902         aToGenPBREnv = false;
903       }
904
905       setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted, aToGenPBREnv);
906       return true;
907     }
908
909     //! Processes the image option set
910     //! @return true if processing was successful, or false otherwise
911     bool processImageOptionSet() const
912     {
913       std::string anImageFileName;
914       if (!processImageOption (anImageFileName))
915       {
916         return false;
917       }
918       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
919       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
920       {
921         return false;
922       }
923       setImage (anImageFileName.c_str(), anImageMode);
924       return true;
925     }
926
927     //! Processes the image mode option set
928     //! @return true if processing was successful, or false otherwise
929     bool processImageModeOptionSet() const
930     {
931       return processImageModeOptionSet (myImageModeOptionKey);
932     }
933
934     //! Processes the image mode option set
935     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
936     //! @return true if processing was successful, or false otherwise
937     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
938     {
939       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
940       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
941       {
942         return false;
943       }
944       setImageMode (anImageMode);
945       return true;
946     }
947
948     //! Processes the gradient option set
949     //! @param theSetGradient the function used to set a background gradient filling
950     //! @return true if processing was successful, or false otherwise
951     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
952     {
953       Quantity_Color aColor1;
954       Quantity_Color aColor2;
955       if (!processGradientOption (aColor1, aColor2))
956       {
957         return false;
958       }
959       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
960       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
961       {
962         return false;
963       }
964       theSetGradient (aColor1, aColor2, aGradientMode);
965       return true;
966     }
967
968     //! Processes the gradient mode option set
969     //! @return true if processing was successful, or false otherwise
970     bool processGradientModeOptionSet() const
971     {
972       return processGradientModeOptionSet (myGradientModeOptionKey);
973     }
974
975     //! Processes the gradient mode option set
976     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
977     //! @return true if processing was successful, or false otherwise
978     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
979     {
980       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
981       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
982       {
983         return false;
984       }
985       setGradientMode (aGradientMode);
986       return true;
987     }
988
989     //! Processes the color option set
990     //! @param theSetColor the function used to set a background color
991     //! @return true if processing was successful, or false otherwise
992     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
993     {
994       return processColorOptionSet (myColorOptionKey, theSetColor);
995     }
996
997     //! Processes the default color option set
998     //! @return true if processing was successful, or false otherwise
999     bool processDefaultGradientOptionSet() const
1000     {
1001       return processGradientOptionSet (setDefaultGradient);
1002     }
1003
1004     //! Processes the default gradient option set
1005     //! @return true if processing was successful, or false otherwise
1006     bool processDefaultColorOptionSet() const
1007     {
1008       return processColorOptionSet (setDefaultColor);
1009     }
1010
1011     //! Processes the color option set
1012     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1013     //! @param theSetColor the function used to set a background color
1014     //! @return true if processing was successful, or false otherwise
1015     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
1016                                 SetColorFunction* const           theSetColor = setColor) const
1017     {
1018       Quantity_Color aColor;
1019       if (!processColorOption (theColorOptionKey, aColor))
1020       {
1021         return false;
1022       }
1023       theSetColor (aColor);
1024       return true;
1025     }
1026
1027     //! Processes the help option set
1028     //! @param theBackgroundCommandName the name of the command that changes the background
1029     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1030     //! @return true if processing was successful, or false otherwise
1031     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
1032     {
1033       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1034         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
1035       if (aNumberOfHelpOptionArguments != 0)
1036       {
1037         return false;
1038       }
1039       return printHelp (theBackgroundCommandName, theDrawInterpretor);
1040     }
1041
1042     //! Processes the cubemap option
1043     //! @param theFilePaths the array of filenames of cubemap sides
1044     //! @return true if processing was successful, or false otherwise
1045     bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
1046     {
1047       const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
1048
1049       if (aNumberOfCubeMapOptionArguments != 1
1050        && aNumberOfCubeMapOptionArguments != 6)
1051       {
1052         return false;
1053       }
1054
1055       theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
1056
1057       for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
1058       {
1059         std::string aCubeMapFileName;
1060         if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
1061         {
1062           return false;
1063         }
1064         theFilePaths[i] = aCubeMapFileName.c_str();
1065       }
1066
1067       return true;
1068     }
1069
1070     //! Processes the inverted z cubemap option
1071     //! @return true if processing was successful, or false otherwise
1072     bool processCubeMapInvertedZOptionSet () const
1073     {
1074       const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
1075         myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
1076
1077       if (aNumberOfCubeMapZInversionOptionArguments != 0)
1078       {
1079         return false;
1080       }
1081
1082       return true;
1083     }
1084
1085     //! Processes the option allowing to skip IBM maps generation
1086     //! @return true if processing was successful, or false otherwise
1087     bool processCubeMapDoNotGenPBREnvOptionSet() const
1088     {
1089       const Standard_Integer aNumberOfCubeMapDoNotGenPBREnvOptionArguments =
1090         myCommandParser.GetNumberOfOptionArguments(myCubeMapDoNotGenPBREnvOptionKey);
1091
1092       if (aNumberOfCubeMapDoNotGenPBREnvOptionArguments != 0)
1093       {
1094         return false;
1095       }
1096
1097       return true;
1098     }
1099
1100     //! Processes the tiles order option
1101     //! @param theOrder the array of indexes if cubemap sides in tile grid
1102     //! @return true if processing was successful, or false otherwise
1103     bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
1104     {
1105       const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
1106         myCubeMapOrderOptionKey);
1107
1108       if (aNumberOfCubeMapOrderOptionArguments != 6)
1109       {
1110         return false;
1111       }
1112
1113
1114       for (unsigned int i = 0; i < 6; ++i)
1115       {
1116         std::string anOrderItem;
1117         if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
1118         {
1119           return false;
1120         }
1121
1122         theOrder.Set (Graphic3d_CubeMapSide (i),
1123                       static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
1124       }
1125
1126       return theOrder.IsValid();
1127     }
1128
1129     //! Processes the image option
1130     //! @param theImageFileName the filename of the image to be used as a background
1131     //! @return true if processing was successful, or false otherwise
1132     bool processImageOption (std::string& theImageFileName) const
1133     {
1134       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1135         myImageOptionKey);
1136       if (aNumberOfImageOptionArguments != 1)
1137       {
1138         return false;
1139       }
1140       std::string anImageFileName;
1141       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
1142       {
1143         return false;
1144       }
1145       theImageFileName = anImageFileName;
1146       return true;
1147     }
1148
1149     //! Processes the image mode option
1150     //! @param theImageMode the fill type used for a background image
1151     //! @return true if processing was successful, or false otherwise
1152     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
1153     {
1154       return processImageModeOption (myImageModeOptionKey, theImageMode);
1155     }
1156
1157     //! Processes the image mode option
1158     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
1159     //! @param theImageMode the fill type used for a background image
1160     //! @return true if processing was successful, or false otherwise
1161     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
1162                                  Aspect_FillMethod&                theImageMode) const
1163     {
1164       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
1165     }
1166
1167     //! Processes the gradient option
1168     //! @param theColor1 the gradient starting color
1169     //! @param theColor2 the gradient ending color
1170     //! @return true if processing was successful, or false otherwise
1171     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
1172     {
1173       Standard_Integer anArgumentIndex = 0;
1174       Quantity_Color   aColor1;
1175       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
1176       {
1177         return false;
1178       }
1179       Quantity_Color aColor2;
1180       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
1181       {
1182         return false;
1183       }
1184       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1185         myGradientOptionKey);
1186       if (anArgumentIndex != aNumberOfGradientOptionArguments)
1187       {
1188         return false;
1189       }
1190       theColor1 = aColor1;
1191       theColor2 = aColor2;
1192       return true;
1193     }
1194
1195     //! Processes the gradient mode option
1196     //! @param theGradientMode the fill method used for a background gradient filling
1197     //! @return true if processing was successful, or false otherwise
1198     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
1199     {
1200       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
1201     }
1202
1203     //! Processes the gradient mode option
1204     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1205     //! @param theGradientMode the fill method used for a background gradient filling
1206     //! @return true if processing was successful, or false otherwise
1207     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1208                                     Aspect_GradientFillMethod&        theGradientMode) const
1209     {
1210       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1211     }
1212
1213     //! Processes some mode option
1214     //! @tparam TheMode the type of a mode to be processed
1215     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1216     //! @param theMode a mode to be processed
1217     //! @return true if processing was successful, or false otherwise
1218     template <typename TheMode>
1219     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1220                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1221                                                             TheMode& /* theMode */),
1222                             TheMode& theMode) const
1223     {
1224       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1225         theModeOptionKey);
1226       if (aNumberOfModeOptionArguments != 1)
1227       {
1228         return false;
1229       }
1230       std::string aModeString;
1231       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1232       {
1233         return false;
1234       }
1235       TheMode aMode = TheMode();
1236       if (!theGetModeByName (aModeString.c_str(), aMode))
1237       {
1238         return false;
1239       }
1240       theMode = aMode;
1241       return true;
1242     }
1243
1244     //! Processes the color option
1245     //! @param theColor a color used for filling a background
1246     //! @return true if processing was successful, or false otherwise
1247     bool processColorOption (Quantity_Color& theColor) const
1248     {
1249       return processColorOption (myColorOptionKey, theColor);
1250     }
1251
1252     //! Processes the color option
1253     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1254     //! @param theColor a color used for filling a background
1255     //! @return true if processing was successful, or false otherwise
1256     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1257     {
1258       Standard_Integer anArgumentIndex = 0;
1259       Quantity_Color   aColor;
1260       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1261       {
1262         return false;
1263       }
1264       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1265         theColorOptionKey);
1266       if (anArgumentIndex != aNumberOfColorOptionArguments)
1267       {
1268         return false;
1269       }
1270       theColor = aColor;
1271       return true;
1272     }
1273
1274     //! Prints helping message
1275     //! @param theBackgroundCommandName the name of the command that changes the background
1276     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1277     //! @return true if printing was successful, or false otherwise
1278     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1279     {
1280       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1281     }
1282
1283     //! Sets the cubemap as a background
1284     //! @param theFileNames the array of filenames of packed or multifile cubemap
1285     //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
1286     static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
1287                             const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
1288                             bool                                               theZIsInverted = false,
1289                             bool                                               theToGenPBREnv = true)
1290     {
1291       const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
1292       Handle(Graphic3d_CubeMap) aCubeMap;
1293
1294       if (theFileNames.Size() == 1)
1295         aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
1296       else
1297         aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
1298
1299       aCubeMap->SetZInversion (theZIsInverted);
1300
1301       aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
1302       aCubeMap->GetParams()->SetRepeat(Standard_False);
1303       aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
1304
1305       aCurrentView->SetBackgroundCubeMap (aCubeMap, theToGenPBREnv, Standard_True);
1306     }
1307
1308     //! Sets the image as a background
1309     //! @param theImageFileName the filename of the image to be used as a background
1310     //! @param theImageMode the fill type used for a background image
1311     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1312     {
1313       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1314       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1315     }
1316
1317     //! Sets the fill type used for a background image
1318     //! @param theImageMode the fill type used for a background image
1319     static void setImageMode (const Aspect_FillMethod theImageMode)
1320     {
1321       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1322       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1323     }
1324
1325     //! Sets the gradient filling for a background
1326     //! @param theColor1 the gradient starting color
1327     //! @param theColor2 the gradient ending color
1328     //! @param theGradientMode the fill method used for a background gradient filling
1329     static void setGradient (const Quantity_Color&           theColor1,
1330                              const Quantity_Color&           theColor2,
1331                              const Aspect_GradientFillMethod theGradientMode)
1332     {
1333       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1334       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1335     }
1336
1337     //! Sets the fill method used for a background gradient filling
1338     //! @param theGradientMode the fill method used for a background gradient filling
1339     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1340     {
1341       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1342       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1343     }
1344
1345     //! Sets the color used for filling a background
1346     //! @param theColor the color used for filling a background
1347     static void setColor (const Quantity_Color& theColor)
1348     {
1349       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1350       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1351       aCurrentView->SetBackgroundColor (theColor);
1352       aCurrentView->Update();
1353     }
1354
1355     //! Sets the gradient filling for a background in a default viewer
1356     //! @param theColor1 the gradient starting color
1357     //! @param theColor2 the gradient ending color
1358     //! @param theGradientMode the fill method used for a background gradient filling
1359     static void setDefaultGradient (const Quantity_Color&           theColor1,
1360                                     const Quantity_Color&           theColor2,
1361                                     const Aspect_GradientFillMethod theGradientMode)
1362     {
1363       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1364       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1365       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1366       setDefaultGradient();
1367     }
1368
1369     //! Sets the color used for filling a background in a default viewer
1370     //! @param theColor the color used for filling a background
1371     static void setDefaultColor (const Quantity_Color& theColor)
1372     {
1373       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1374       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1375       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1376       ViewerTest_DefaultBackground.FlatColor      = theColor;
1377       setDefaultGradient();
1378       setDefaultColor();
1379     }
1380
1381     //! Sets the gradient filling for a background in a default viewer.
1382     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1383     static void setDefaultGradient()
1384     {
1385       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1386              anInteractiveContextIterator (ViewerTest_myContexts);
1387            anInteractiveContextIterator.More();
1388            anInteractiveContextIterator.Next())
1389       {
1390         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1391         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1392                                              ViewerTest_DefaultBackground.GradientColor2,
1393                                              ViewerTest_DefaultBackground.FillMethod);
1394       }
1395     }
1396
1397     //! Sets the color used for filling a background in a default viewer.
1398     //! The color value is taken from ViewerTest_DefaultBackground structure
1399     static void setDefaultColor()
1400     {
1401       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1402              anInteractiveContextIterator (ViewerTest_myContexts);
1403            anInteractiveContextIterator.More();
1404            anInteractiveContextIterator.Next())
1405       {
1406         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1407         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1408       }
1409     }
1410   };
1411
1412 } // namespace
1413
1414 //==============================================================================
1415
1416 #ifdef _WIN32
1417 static LRESULT WINAPI AdvViewerWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
1418 #endif
1419
1420 //==============================================================================
1421 //function : WClass
1422 //purpose  :
1423 //==============================================================================
1424
1425 const Handle(WNT_WClass)& ViewerTest::WClass()
1426 {
1427   static Handle(WNT_WClass) theWClass;
1428 #if defined(_WIN32)
1429   if (theWClass.IsNull())
1430   {
1431     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1432                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1433                                 ::LoadCursor (NULL, IDC_ARROW));
1434   }
1435 #endif
1436   return theWClass;
1437 }
1438
1439 //==============================================================================
1440 //function : CreateName
1441 //purpose  : Create numerical name for new object in theMap
1442 //==============================================================================
1443 template <typename ObjectType>
1444 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1445                                     const TCollection_AsciiString& theDefaultString)
1446 {
1447   if (theObjectMap.IsEmpty())
1448     return theDefaultString + TCollection_AsciiString(1);
1449
1450   Standard_Integer aNextKey = 1;
1451   Standard_Boolean isFound = Standard_False;
1452   while (!isFound)
1453   {
1454     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1455     // Look for objects with default names
1456     if (theObjectMap.IsBound1(aStringKey))
1457     {
1458       aNextKey++;
1459     }
1460     else
1461       isFound = Standard_True;
1462   }
1463
1464   return theDefaultString + TCollection_AsciiString(aNextKey);
1465 }
1466
1467 //==============================================================================
1468 //structure : ViewerTest_Names
1469 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1470 //==============================================================================
1471 struct ViewerTest_Names
1472 {
1473 private:
1474   TCollection_AsciiString myDriverName;
1475   TCollection_AsciiString myViewerName;
1476   TCollection_AsciiString myViewName;
1477
1478 public:
1479
1480   const TCollection_AsciiString& GetDriverName () const
1481   {
1482     return myDriverName;
1483   }
1484   void SetDriverName (const TCollection_AsciiString& theDriverName)
1485   {
1486     myDriverName = theDriverName;
1487   }
1488   const TCollection_AsciiString& GetViewerName () const
1489   {
1490     return myViewerName;
1491   }
1492   void SetViewerName (const TCollection_AsciiString& theViewerName)
1493   {
1494     myViewerName = theViewerName;
1495   }
1496   const TCollection_AsciiString& GetViewName () const
1497   {
1498     return myViewName;
1499   }
1500   void SetViewName (const TCollection_AsciiString& theViewName)
1501   {
1502     myViewName = theViewName;
1503   }
1504
1505   //===========================================================================
1506   //function : Constructor for ViewerTest_Names
1507   //purpose  : Get view, viewer, driver names from custom string
1508   //===========================================================================
1509
1510   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1511   {
1512     TCollection_AsciiString aName(theInputString);
1513     if (theInputString.IsEmpty())
1514     {
1515       // Get current configuration
1516       if (ViewerTest_myDrivers.IsEmpty())
1517         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1518           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1519       else
1520         myDriverName = ViewerTest_myDrivers.Find2
1521         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1522
1523       if(ViewerTest_myContexts.IsEmpty())
1524       {
1525         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1526           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1527       }
1528       else
1529       {
1530         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1531       }
1532
1533       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1534     }
1535     else
1536     {
1537       // There is at least view name
1538       Standard_Integer aParserNumber = 0;
1539       for (Standard_Integer i = 0; i < 3; ++i)
1540       {
1541         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1542         if(aParserPos != -1)
1543         {
1544           aParserNumber++;
1545           aName.Split(aParserPos-1);
1546         }
1547         else
1548           break;
1549       }
1550       if (aParserNumber == 0)
1551       {
1552         // Only view name
1553         if (!ViewerTest::GetAISContext().IsNull())
1554         {
1555           myDriverName = ViewerTest_myDrivers.Find2
1556           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1557           myViewerName = ViewerTest_myContexts.Find2
1558           (ViewerTest::GetAISContext());
1559         }
1560         else
1561         {
1562           // There is no opened contexts here, need to create names for viewer and driver
1563           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1564             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1565
1566           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1567             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1568         }
1569         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1570       }
1571       else if (aParserNumber == 1)
1572       {
1573         // Here is viewerName/viewName
1574         if (!ViewerTest::GetAISContext().IsNull())
1575           myDriverName = ViewerTest_myDrivers.Find2
1576           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1577         else
1578         {
1579           // There is no opened contexts here, need to create name for driver
1580           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1581             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1582         }
1583         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1584
1585         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1586       }
1587       else
1588       {
1589         //Here is driverName/viewerName/viewName
1590         myDriverName = TCollection_AsciiString(aName);
1591
1592         TCollection_AsciiString aViewerName(theInputString);
1593         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1594         myViewerName = TCollection_AsciiString(aViewerName);
1595
1596         myViewName = TCollection_AsciiString(theInputString);
1597       }
1598     }
1599   }
1600 };
1601
1602 //==============================================================================
1603 //function : FindContextByView
1604 //purpose  : Find AIS_InteractiveContext by View
1605 //==============================================================================
1606
1607 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1608 {
1609   Handle(AIS_InteractiveContext) anAISContext;
1610
1611   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1612        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1613   {
1614     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1615        return anIter.Key2();
1616   }
1617   return anAISContext;
1618 }
1619
1620 //==============================================================================
1621 //function : IsWindowOverlapped
1622 //purpose  : Check if theWindow overlapp another view
1623 //==============================================================================
1624
1625 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1626                                      const Standard_Integer thePxTop,
1627                                      const Standard_Integer thePxRight,
1628                                      const Standard_Integer thePxBottom,
1629                                      TCollection_AsciiString& theViewId)
1630 {
1631   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1632       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1633   {
1634     Standard_Integer aTop = 0,
1635       aLeft = 0,
1636       aRight = 0,
1637       aBottom = 0;
1638     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1639     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1640         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1641         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1642         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1643     {
1644       theViewId = anIter.Key1();
1645       return Standard_True;
1646     }
1647   }
1648   return Standard_False;
1649 }
1650
1651 // Workaround: to create and delete non-orthographic views outside ViewerTest
1652 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1653 {
1654   ViewerTest_myViews.UnBind1 (theName);
1655 }
1656
1657 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1658                                const Handle(V3d_View)& theView)
1659 {
1660   ViewerTest_myViews.Bind (theName, theView);
1661 }
1662
1663 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1664 {
1665   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1666 }
1667
1668 //==============================================================================
1669 //function : ViewerInit
1670 //purpose  : Create the window viewer and initialize all the global variable
1671 //==============================================================================
1672
1673 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1674                                                 const Standard_Integer thePxTop,
1675                                                 const Standard_Integer thePxWidth,
1676                                                 const Standard_Integer thePxHeight,
1677                                                 const TCollection_AsciiString& theViewName,
1678                                                 const TCollection_AsciiString& theDisplayName,
1679                                                 const Handle(V3d_View)& theViewToClone,
1680                                                 const Standard_Boolean theIsVirtual)
1681 {
1682   // Default position and dimension of the viewer window.
1683   // Note that left top corner is set to be sufficiently small to have
1684   // window fit in the small screens (actual for remote desktops, see #23003).
1685   // The position corresponds to the window's client area, thus some
1686   // gap is added for window frame to be visible.
1687   Standard_Integer aPxLeft  = 20,  aPxTop    = 40;
1688   Standard_Integer aPxWidth = 409, aPxHeight = 409;
1689   Standard_Boolean isDefViewSize = Standard_True;
1690   Standard_Boolean toCreateViewer = Standard_False;
1691   const Standard_Boolean isVirtual = Draw_VirtualWindows || theIsVirtual;
1692   if (!theViewToClone.IsNull())
1693   {
1694     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1695     isDefViewSize = Standard_False;
1696   #if !defined(__EMSCRIPTEN__)
1697     (void )isDefViewSize;
1698   #endif
1699   }
1700
1701   Handle(Graphic3d_GraphicDriverFactory) aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
1702   if (aFactory.IsNull())
1703   {
1704     Draw::GetInterpretor().Eval ("pload OPENGL");
1705     aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
1706     if (aFactory.IsNull())
1707     {
1708       Draw::GetInterpretor().Eval ("pload GLES");
1709       aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
1710       if (aFactory.IsNull())
1711       {
1712         throw Standard_ProgramError("Error: no graphic driver factory found");
1713       }
1714     }
1715   }
1716
1717   Handle(Graphic3d_GraphicDriver) aGraphicDriver;
1718   ViewerTest_Names aViewNames(theViewName);
1719   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1720   {
1721     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1722   }
1723
1724   if (thePxLeft != 0)
1725   {
1726     aPxLeft = thePxLeft;
1727   }
1728   if (thePxTop != 0)
1729   {
1730     aPxTop = thePxTop;
1731   }
1732   if (thePxWidth != 0)
1733   {
1734     isDefViewSize = Standard_False;
1735     aPxWidth = thePxWidth;
1736   }
1737   if (thePxHeight != 0)
1738   {
1739     isDefViewSize = Standard_False;
1740     aPxHeight = thePxHeight;
1741   }
1742
1743   // Get graphic driver (create it or get from another view)
1744   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1745   if (isNewDriver)
1746   {
1747     // Get connection string
1748   #if defined(HAVE_XLIB)
1749     if (!theDisplayName.IsEmpty())
1750     {
1751       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1752     }
1753     else
1754     {
1755       Aspect_XDisplay* aDispX = NULL;
1756       // create dedicated display connection instead of reusing Tk connection
1757       // so that to proceed events independently through VProcessEvents()/ViewerMainLoop() callbacks
1758       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1759       Tcl_Interp* aTclInterp = aCommands.Interp();
1760       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1761       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1762       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1763     }
1764   #else
1765     (void)theDisplayName; // avoid warning on unused argument
1766     SetDisplayConnection (new Aspect_DisplayConnection ());
1767   #endif
1768
1769     aGraphicDriver = aFactory->CreateDriver (GetDisplayConnection());
1770     if (isVirtual)
1771     {
1772       // don't waste the time waiting for VSync when window is not displayed on the screen
1773       aGraphicDriver->SetVerticalSync (false);
1774     }
1775
1776     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1777     toCreateViewer = Standard_True;
1778   }
1779   else
1780   {
1781     aGraphicDriver = ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName());
1782   }
1783
1784   //Dispose the window if input parameters are default
1785   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1786   {
1787     Standard_Integer aTop = 0,
1788                      aLeft = 0,
1789                      aRight = 0,
1790                      aBottom = 0,
1791                      aScreenWidth = 0,
1792                      aScreenHeight = 0;
1793
1794     // Get screen resolution
1795 #if defined(_WIN32)
1796     RECT aWindowSize;
1797     GetClientRect(GetDesktopWindow(), &aWindowSize);
1798     aScreenHeight = aWindowSize.bottom;
1799     aScreenWidth = aWindowSize.right;
1800 #elif defined(HAVE_XLIB)
1801     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
1802     Screen* aScreen = DefaultScreenOfDisplay(aDispX);
1803     aScreenWidth  = WidthOfScreen(aScreen);
1804     aScreenHeight = HeightOfScreen(aScreen);
1805 #elif defined(__APPLE__)
1806     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1807 #else
1808     // not implemented
1809 #endif
1810
1811     TCollection_AsciiString anOverlappedViewId("");
1812
1813     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1814     {
1815       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1816
1817       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1818         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1819       {
1820         if (aBottom + aPxHeight + 40 > aScreenHeight)
1821         {
1822           aPxLeft = 20;
1823           aPxTop = 40;
1824           break;
1825         }
1826         aPxLeft = 20;
1827         aPxTop = aBottom + 40;
1828       }
1829       else
1830         aPxLeft = aRight + 20;
1831     }
1832   }
1833
1834   // Get viewer name
1835   TCollection_AsciiString aTitle("3D View - ");
1836   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1837
1838   // Change name of current active window
1839   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1840   {
1841     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1842   }
1843
1844   // Create viewer
1845   Handle(V3d_Viewer) a3DViewer;
1846   // If it's the single view, we first look for empty context
1847   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1848   {
1849     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1850       anIter(ViewerTest_myContexts);
1851     if (anIter.More())
1852       ViewerTest::SetAISContext (anIter.Value());
1853     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1854   }
1855   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1856   {
1857     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1858     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1859   }
1860   else if (a3DViewer.IsNull())
1861   {
1862     toCreateViewer = Standard_True;
1863     a3DViewer = new V3d_Viewer(aGraphicDriver);
1864     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1865     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1866                                            ViewerTest_DefaultBackground.GradientColor2,
1867                                            ViewerTest_DefaultBackground.FillMethod);
1868   }
1869
1870   // AIS context setup
1871   if (ViewerTest::GetAISContext().IsNull() ||
1872       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1873   {
1874     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1875     ViewerTest::SetAISContext (aContext);
1876     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1877   }
1878   else
1879   {
1880     ViewerTest::ResetEventManager();
1881   }
1882
1883   // Create window
1884 #if defined(_WIN32)
1885   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
1886                                    isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1887                                     aPxLeft, aPxTop,
1888                                     aPxWidth, aPxHeight,
1889                                     Quantity_NOC_BLACK);
1890   VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
1891 #elif defined(HAVE_XLIB)
1892   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1893                                   aTitle.ToCString(),
1894                                   aPxLeft, aPxTop,
1895                                   aPxWidth, aPxHeight);
1896 #elif defined(__APPLE__)
1897   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1898                                      aPxLeft, aPxTop,
1899                                      aPxWidth, aPxHeight);
1900   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1901 #elif defined(__EMSCRIPTEN__)
1902   // current EGL implementation in Emscripten supports only one global WebGL canvas returned by Module.canvas property;
1903   // the code should be revised for handling multiple canvas elements (which is technically also possible)
1904   TCollection_AsciiString aCanvasId = getModuleCanvasId();
1905   if (!aCanvasId.IsEmpty())
1906   {
1907     aCanvasId = TCollection_AsciiString("#") + aCanvasId;
1908   }
1909
1910   VT_GetWindow() = new Wasm_Window (aCanvasId);
1911   Graphic3d_Vec2i aRealSize;
1912   VT_GetWindow()->Size (aRealSize.x(), aRealSize.y());
1913   if (!isDefViewSize || (aRealSize.x() <= 0 && aRealSize.y() <= 0))
1914   {
1915     // Wasm_Window wraps an existing HTML element without creating a new one.
1916     // Keep size defined on a web page instead of defaulting to 409x409 (as in case of other platform),
1917     // but resize canvas if vinit has been called with explicitly specified dimensions.
1918     VT_GetWindow()->SetSizeLogical (Graphic3d_Vec2d (aPxWidth, aPxHeight));
1919   }
1920 #else
1921   // not implemented
1922   VT_GetWindow() = new Aspect_NeutralWindow();
1923   VT_GetWindow()->SetSize (aPxWidth, aPxHeight);
1924 #endif
1925   VT_GetWindow()->SetVirtual (isVirtual);
1926
1927   // View setup
1928   Handle(V3d_View) aView;
1929   if (!theViewToClone.IsNull())
1930   {
1931     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1932   }
1933   else
1934   {
1935     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1936   }
1937
1938   aView->SetWindow (VT_GetWindow());
1939   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1940
1941   ViewerTest::CurrentView(aView);
1942   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1943
1944   // Setup for X11 or NT
1945   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
1946   ViewerTest_EventManager::SetupWindowCallbacks (VT_GetWindow());
1947
1948   // Set parameters for V3d_View and V3d_Viewer
1949   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1950   aV3dView->SetComputedMode(Standard_False);
1951
1952   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1953   if (toCreateViewer)
1954   {
1955     a3DViewer->SetDefaultLights();
1956     a3DViewer->SetLightOn();
1957   }
1958
1959 #if defined(HAVE_XLIB)
1960   if (isNewDriver)
1961   {
1962     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
1963     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1964   }
1965 #endif
1966
1967   VT_GetWindow()->Map();
1968
1969   // Set the handle of created view in the event manager
1970   ViewerTest::ResetEventManager();
1971
1972   ViewerTest::CurrentView()->Redraw();
1973
1974   aView.Nullify();
1975   a3DViewer.Nullify();
1976
1977   return aViewNames.GetViewName();
1978 }
1979
1980 //==============================================================================
1981 //function : RedrawAllViews
1982 //purpose  : Redraw all created views
1983 //==============================================================================
1984 void ViewerTest::RedrawAllViews()
1985 {
1986   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1987   for (; aViewIt.More(); aViewIt.Next())
1988   {
1989     const Handle(V3d_View)& aView = aViewIt.Key2();
1990     aView->Redraw();
1991   }
1992 }
1993
1994 //==============================================================================
1995 //function : VDriver
1996 //purpose  :
1997 //==============================================================================
1998 static int VDriver (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1999 {
2000   if (theArgsNb == 1)
2001   {
2002     theDi << "Registered: ";
2003     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
2004          aFactoryIter.More(); aFactoryIter.Next())
2005     {
2006       const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
2007       theDi << aFactory->Name() << " ";
2008     }
2009
2010     theDi << "\n";
2011     theDi << "Default: ";
2012     if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
2013     {
2014       theDi << aFactory->Name();
2015     }
2016     else
2017     {
2018       theDi << "NONE";
2019     }
2020     return 0;
2021   }
2022
2023   TCollection_AsciiString aNewActive;
2024   bool toLoad = false;
2025   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2026   {
2027     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2028     anArgCase.LowerCase();
2029     if (anArgCase == "-list")
2030     {
2031       for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
2032            aFactoryIter.More(); aFactoryIter.Next())
2033       {
2034         const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
2035         theDi << aFactory->Name() << " ";
2036       }
2037     }
2038     else if ((anArgCase == "-default"
2039            || anArgCase == "-load")
2040           && aNewActive.IsEmpty())
2041     {
2042       toLoad = (anArgCase == "-load");
2043       if (anArgIter + 1 < theArgsNb)
2044       {
2045         aNewActive = theArgVec[++anArgIter];
2046       }
2047       else if (toLoad)
2048       {
2049         theDi << "Syntax error at '" << theArgVec[anArgIter] << "'";
2050         return 1;
2051       }
2052       else
2053       {
2054         if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
2055         {
2056           theDi << aFactory->Name();
2057         }
2058         else
2059         {
2060           theDi << "NONE";
2061         }
2062       }
2063     }
2064     else if (aNewActive.IsEmpty())
2065     {
2066       aNewActive = theArgVec[anArgIter];
2067     }
2068     else
2069     {
2070       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
2071       return 1;
2072     }
2073   }
2074
2075   if (!aNewActive.IsEmpty())
2076   {
2077     const TCollection_AsciiString aNameCopy = aNewActive;
2078     if (TCollection_AsciiString::IsSameString (aNewActive, "gl", false)
2079      || TCollection_AsciiString::IsSameString (aNewActive, "opengl", false)
2080      || TCollection_AsciiString::IsSameString (aNewActive, "tkopengl", false))
2081     {
2082       aNewActive = "tkopengl";
2083     }
2084     else if (TCollection_AsciiString::IsSameString (aNewActive, "gles", false)
2085           || TCollection_AsciiString::IsSameString (aNewActive, "opengles", false)
2086           || TCollection_AsciiString::IsSameString (aNewActive, "tkopengles", false))
2087     {
2088       aNewActive = "tkopengles";
2089     }
2090     else if (TCollection_AsciiString::IsSameString (aNewActive, "d3d", false)
2091           || TCollection_AsciiString::IsSameString (aNewActive, "d3dhost", false)
2092           || TCollection_AsciiString::IsSameString (aNewActive, "tkd3dhost", false))
2093     {
2094       aNewActive = "tkd3dhost";
2095     }
2096
2097     if (toLoad)
2098     {
2099       if (aNewActive == "tkopengl")
2100       {
2101         Draw::GetInterpretor().Eval ("pload OPENGL");
2102       }
2103       else if (aNewActive == "tkopengles")
2104       {
2105         Draw::GetInterpretor().Eval ("pload GLES");
2106       }
2107       else if (aNewActive == "tkd3dhost")
2108       {
2109         Draw::GetInterpretor().Eval ("pload D3DHOST");
2110       }
2111       else
2112       {
2113         theDi << "Syntax error: unable to load plugin for unknown driver factory '" << aNameCopy << "'";
2114         return 1;
2115       }
2116     }
2117
2118     bool isFound = false;
2119     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
2120          aFactoryIter.More(); aFactoryIter.Next())
2121     {
2122       Handle(Graphic3d_GraphicDriverFactory) aFactory = aFactoryIter.Value();
2123       if (TCollection_AsciiString::IsSameString (aFactory->Name(), aNewActive, false))
2124       {
2125         Graphic3d_GraphicDriverFactory::RegisterFactory (aFactory, true);
2126         isFound = true;
2127         break;
2128       }
2129     }
2130
2131     if (!isFound)
2132     {
2133       theDi << "Syntax error: driver factory '" << aNameCopy << "' not found";
2134       return 1;
2135     }
2136   }
2137
2138   return 0;
2139 }
2140
2141 //==============================================================================
2142 //function : Vinit
2143 //purpose  : Create the window viewer and initialize all the global variable
2144 //    Use Tcl_CreateFileHandler on UNIX to catch the X11 Viewer event
2145 //==============================================================================
2146 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2147 {
2148   TCollection_AsciiString aViewName, aDisplayName;
2149   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
2150   Standard_Boolean isVirtual = false;
2151   Handle(V3d_View) aCopyFrom;
2152   TCollection_AsciiString aName, aValue;
2153   int is2dMode = -1;
2154   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
2155   {
2156     const TCollection_AsciiString anArg = theArgVec[anArgIt];
2157     TCollection_AsciiString anArgCase = anArg;
2158     anArgCase.LowerCase();
2159     if (anArgIt + 1 < theArgsNb
2160      && anArgCase == "-name")
2161     {
2162       aViewName = theArgVec[++anArgIt];
2163     }
2164     else if (anArgIt + 1 < theArgsNb
2165           && (anArgCase == "-left"
2166            || anArgCase == "-l"))
2167     {
2168       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
2169     }
2170     else if (anArgIt + 1 < theArgsNb
2171           && (anArgCase == "-top"
2172            || anArgCase == "-t"))
2173     {
2174       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
2175     }
2176     else if (anArgIt + 1 < theArgsNb
2177           && (anArgCase == "-width"
2178            || anArgCase == "-w"))
2179     {
2180       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
2181     }
2182     else if (anArgIt + 1 < theArgsNb
2183           && (anArgCase == "-height"
2184            || anArgCase == "-h"))
2185     {
2186       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
2187     }
2188     else if (anArgCase == "-virtual"
2189           || anArgCase == "-offscreen")
2190     {
2191       isVirtual = true;
2192       if (anArgIt + 1 < theArgsNb
2193        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isVirtual))
2194       {
2195         ++anArgIt;
2196       }
2197     }
2198     else if (anArgCase == "-exitonclose")
2199     {
2200       ViewerTest_EventManager::ToExitOnCloseView() = true;
2201       if (anArgIt + 1 < theArgsNb
2202        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
2203       {
2204         ++anArgIt;
2205       }
2206     }
2207     else if (anArgCase == "-closeonescape"
2208           || anArgCase == "-closeonesc")
2209     {
2210       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
2211       if (anArgIt + 1 < theArgsNb
2212        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
2213       {
2214         ++anArgIt;
2215       }
2216     }
2217     else if (anArgCase == "-2d_mode"
2218           || anArgCase == "-2dmode"
2219           || anArgCase == "-2d")
2220     {
2221       bool toEnable = true;
2222       if (anArgIt + 1 < theArgsNb
2223        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
2224       {
2225         ++anArgIt;
2226       }
2227       is2dMode = toEnable ? 1 : 0;
2228     }
2229     else if (anArgIt + 1 < theArgsNb
2230           && (anArgCase == "-disp"
2231            || anArgCase == "-display"))
2232     {
2233       aDisplayName = theArgVec[++anArgIt];
2234     }
2235     else if (!ViewerTest::CurrentView().IsNull()
2236           &&  aCopyFrom.IsNull()
2237           && (anArgCase == "-copy"
2238            || anArgCase == "-clone"
2239            || anArgCase == "-cloneactive"
2240            || anArgCase == "-cloneactiveview"))
2241     {
2242       aCopyFrom = ViewerTest::CurrentView();
2243     }
2244     // old syntax
2245     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2246     {
2247       aName.LowerCase();
2248       if (aName == "name")
2249       {
2250         aViewName = aValue;
2251       }
2252       else if (aName == "l"
2253             || aName == "left")
2254       {
2255         aPxLeft = aValue.IntegerValue();
2256       }
2257       else if (aName == "t"
2258             || aName == "top")
2259       {
2260         aPxTop = aValue.IntegerValue();
2261       }
2262       else if (aName == "disp"
2263             || aName == "display")
2264       {
2265         aDisplayName = aValue;
2266       }
2267       else if (aName == "w"
2268             || aName == "width")
2269       {
2270         aPxWidth = aValue.IntegerValue();
2271       }
2272       else if (aName == "h"
2273             || aName == "height")
2274       {
2275         aPxHeight = aValue.IntegerValue();
2276       }
2277       else
2278       {
2279         Message::SendFail() << "Syntax error: unknown argument " << anArg;
2280         return 1;
2281       }
2282     }
2283     else if (aViewName.IsEmpty())
2284     {
2285       aViewName = anArg;
2286     }
2287     else
2288     {
2289       Message::SendFail() << "Syntax error: unknown argument " << anArg;
2290       return 1;
2291     }
2292   }
2293
2294 #if !defined(HAVE_XLIB)
2295   if (!aDisplayName.IsEmpty())
2296   {
2297     aDisplayName.Clear();
2298     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
2299   }
2300 #endif
2301
2302   ViewerTest_Names aViewNames (aViewName);
2303   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2304   {
2305     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2306     theDi.Eval (aCommand.ToCString());
2307     if (is2dMode != -1)
2308     {
2309       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2310     }
2311     return 0;
2312   }
2313
2314   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2315                                                             aViewName, aDisplayName, aCopyFrom, isVirtual);
2316   if (is2dMode != -1)
2317   {
2318     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2319   }
2320   theDi << aViewId;
2321   return 0;
2322 }
2323
2324 //! Parse HLR algo type.
2325 static Standard_Boolean parseHlrAlgoType (const char* theName,
2326                                           Prs3d_TypeOfHLR& theType)
2327 {
2328   TCollection_AsciiString aName (theName);
2329   aName.LowerCase();
2330   if (aName == "polyalgo")
2331   {
2332     theType = Prs3d_TOH_PolyAlgo;
2333   }
2334   else if (aName == "algo")
2335   {
2336     theType = Prs3d_TOH_Algo;
2337   }
2338   else
2339   {
2340     return Standard_False;
2341   }
2342   return Standard_True;
2343 }
2344
2345 //==============================================================================
2346 //function : VHLR
2347 //purpose  : hidden lines removal algorithm
2348 //==============================================================================
2349
2350 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2351 {
2352   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2353   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2354   if (aView.IsNull())
2355   {
2356     Message::SendFail ("Error: no active viewer");
2357     return 1;
2358   }
2359
2360   Standard_Boolean hasHlrOnArg = Standard_False;
2361   Standard_Boolean hasShowHiddenArg = Standard_False;
2362   Standard_Boolean isHLROn = Standard_False;
2363   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2364   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2365   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2366   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2367   {
2368     TCollection_AsciiString anArg (argv[anArgIter]);
2369     anArg.LowerCase();
2370     if (anUpdateTool.parseRedrawMode (anArg))
2371     {
2372       continue;
2373     }
2374     else if (anArg == "-showhidden"
2375           && anArgIter + 1 < argc
2376           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2377     {
2378       ++anArgIter;
2379       hasShowHiddenArg = Standard_True;
2380       continue;
2381     }
2382     else if ((anArg == "-type"
2383            || anArg == "-algo"
2384            || anArg == "-algotype")
2385           && anArgIter + 1 < argc
2386           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2387     {
2388       ++anArgIter;
2389       continue;
2390     }
2391     else if (!hasHlrOnArg
2392           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
2393     {
2394       hasHlrOnArg = Standard_True;
2395       continue;
2396     }
2397     // old syntax
2398     else if (!hasShowHiddenArg
2399           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
2400     {
2401       hasShowHiddenArg = Standard_True;
2402       continue;
2403     }
2404     else
2405     {
2406       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
2407       return 1;
2408     }
2409   }
2410   if (!hasHlrOnArg)
2411   {
2412     di << "HLR:        " << aView->ComputedMode() << "\n";
2413     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2414     di << "HlrAlgo:    ";
2415     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2416     {
2417       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2418       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2419       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2420     }
2421     anUpdateTool.Invalidate();
2422     return 0;
2423   }
2424
2425   Standard_Boolean toRecompute = Standard_False;
2426   if (aTypeOfHLR != Prs3d_TOH_NotSet
2427    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2428   {
2429     toRecompute = Standard_True;
2430     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2431   }
2432   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2433   {
2434     toRecompute = Standard_True;
2435     if (toShowHidden)
2436     {
2437       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2438     }
2439     else
2440     {
2441       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2442     }
2443   }
2444
2445   // redisplay shapes
2446   if (aView->ComputedMode() && isHLROn && toRecompute)
2447   {
2448     AIS_ListOfInteractive aListOfShapes;
2449     aCtx->DisplayedObjects (aListOfShapes);
2450     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2451     {
2452       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2453       {
2454         aCtx->Redisplay (aShape, Standard_False);
2455       }
2456     }
2457   }
2458
2459   aView->SetComputedMode (isHLROn);
2460   return 0;
2461 }
2462
2463 //==============================================================================
2464 //function : VHLRType
2465 //purpose  : change type of using HLR algorithm
2466 //==============================================================================
2467
2468 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2469 {
2470   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2471   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2472   if (aView.IsNull())
2473   {
2474     Message::SendFail ("Error: no active viewer");
2475     return 1;
2476   }
2477
2478   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2479   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2480   AIS_ListOfInteractive aListOfShapes;
2481   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2482   {
2483     TCollection_AsciiString anArg (argv[anArgIter]);
2484     anArg.LowerCase();
2485     if (anUpdateTool.parseRedrawMode (anArg))
2486     {
2487       continue;
2488     }
2489     else if ((anArg == "-type"
2490            || anArg == "-algo"
2491            || anArg == "-algotype")
2492           && anArgIter + 1 < argc
2493           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2494     {
2495       ++anArgIter;
2496       continue;
2497     }
2498     // old syntax
2499     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2500           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2501     {
2502       continue;
2503     }
2504     else
2505     {
2506       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2507       TCollection_AsciiString aName (argv[anArgIter]);
2508       if (!aMap.IsBound2 (aName))
2509       {
2510         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
2511         return 1;
2512       }
2513
2514       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2515       if (aShape.IsNull())
2516       {
2517         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
2518         return 1;
2519       }
2520       aListOfShapes.Append (aShape);
2521       continue;
2522     }
2523   }
2524   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2525   {
2526     Message::SendFail ("Syntax error: wrong number of arguments");
2527     return 1;
2528   }
2529
2530   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2531   if (isGlobal)
2532   {
2533     aCtx->DisplayedObjects (aListOfShapes);
2534     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2535   }
2536
2537   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2538   {
2539     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2540     if (aShape.IsNull())
2541     {
2542       continue;
2543     }
2544
2545     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2546                             && aView->ComputedMode();
2547     if (!isGlobal
2548      || aShape->TypeOfHLR() != aTypeOfHLR)
2549     {
2550       aShape->SetTypeOfHLR (aTypeOfHLR);
2551     }
2552     if (toUpdateShape)
2553     {
2554       aCtx->Redisplay (aShape, Standard_False);
2555     }
2556   }
2557   return 0;
2558 }
2559
2560 //==============================================================================
2561 //function : FindViewIdByWindowHandle
2562 //purpose  : Find theView Id in the map of views by window handle
2563 //==============================================================================
2564 #if defined(_WIN32) || defined(HAVE_XLIB)
2565 static TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2566 {
2567   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2568        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2569   {
2570     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2571     if (aWindowHandle == theWindowHandle)
2572       return anIter.Key1();
2573   }
2574   return TCollection_AsciiString("");
2575 }
2576 #endif
2577
2578 //! Make the view active
2579 void ActivateView (const TCollection_AsciiString& theViewName,
2580                    Standard_Boolean theToUpdate = Standard_True)
2581 {
2582   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2583   if (aView.IsNull())
2584   {
2585     return;
2586   }
2587
2588   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2589   if (!anAISContext.IsNull())
2590   {
2591     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2592     {
2593       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2594     }
2595
2596     ViewerTest::CurrentView (aView);
2597     ViewerTest::SetAISContext (anAISContext);
2598     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2599     VT_GetWindow() = Handle(ViewerTest_Window)::DownCast(ViewerTest::CurrentView()->Window());
2600     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2601     if (theToUpdate)
2602     {
2603       ViewerTest::CurrentView()->Redraw();
2604     }
2605   }
2606 }
2607
2608 //==============================================================================
2609 //function : RemoveView
2610 //purpose  :
2611 //==============================================================================
2612 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2613                              const Standard_Boolean  theToRemoveContext)
2614 {
2615   if (!ViewerTest_myViews.IsBound2 (theView))
2616   {
2617     return;
2618   }
2619
2620   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2621   RemoveView (aViewName, theToRemoveContext);
2622 }
2623
2624 //==============================================================================
2625 //function : RemoveView
2626 //purpose  : Close and remove view from display, clear maps if necessary
2627 //==============================================================================
2628 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2629 {
2630   if (!ViewerTest_myViews.IsBound1(theViewName))
2631   {
2632     Message::SendFail() << "Wrong view name";
2633     return;
2634   }
2635
2636   // Activate another view if it's active now
2637   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2638   {
2639     if (ViewerTest_myViews.Extent() > 1)
2640     {
2641       TCollection_AsciiString aNewViewName;
2642       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2643            anIter.More(); anIter.Next())
2644       {
2645         if (anIter.Key1() != theViewName)
2646         {
2647           aNewViewName = anIter.Key1();
2648           break;
2649         }
2650       }
2651       ActivateView (aNewViewName);
2652     }
2653     else
2654     {
2655       VT_GetWindow().Nullify();
2656       ViewerTest::CurrentView (Handle(V3d_View)());
2657       if (isContextRemoved)
2658       {
2659         Handle(AIS_InteractiveContext) anEmptyContext;
2660         ViewerTest::SetAISContext(anEmptyContext);
2661       }
2662     }
2663   }
2664
2665   // Delete view
2666   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2667   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2668   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2669   aRedrawer.Stop (aView);
2670
2671   // Remove view resources
2672   ViewerTest_myViews.UnBind1(theViewName);
2673   aView->Window()->Unmap();
2674   aView->Remove();
2675
2676 #if defined(HAVE_XLIB)
2677   XFlush ((::Display* )GetDisplayConnection()->GetDisplayAspect());
2678 #endif
2679
2680   // Keep context opened only if the closed view is last to avoid
2681   // unused empty contexts
2682   if (!aCurrentContext.IsNull())
2683   {
2684     // Check if there are more defined views in the viewer
2685     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
2686      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
2687     {
2688       // Remove driver if there is no viewers that use it
2689       Standard_Boolean isRemoveDriver = Standard_True;
2690       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2691           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2692       {
2693         if (aCurrentContext != anIter.Key2() &&
2694           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2695         {
2696           isRemoveDriver = Standard_False;
2697           break;
2698         }
2699       }
2700
2701       aCurrentContext->RemoveAll (Standard_False);
2702       if(isRemoveDriver)
2703       {
2704         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2705       #if defined(HAVE_XLIB)
2706         Tcl_DeleteFileHandler (XConnectionNumber ((::Display* )aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplayAspect()));
2707       #endif
2708       }
2709
2710       ViewerTest_myContexts.UnBind2(aCurrentContext);
2711     }
2712   }
2713   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
2714   if (ViewerTest_EventManager::ToExitOnCloseView())
2715   {
2716     Draw_Interprete ("exit");
2717   }
2718 }
2719
2720 //==============================================================================
2721 //function : VClose
2722 //purpose  : Remove the view defined by its name
2723 //==============================================================================
2724
2725 static int VClose (Draw_Interpretor& /*theDi*/,
2726                    Standard_Integer  theArgsNb,
2727                    const char**      theArgVec)
2728 {
2729   NCollection_List<TCollection_AsciiString> aViewList;
2730   if (theArgsNb > 1)
2731   {
2732     TCollection_AsciiString anArg (theArgVec[1]);
2733     anArg.UpperCase();
2734     if (anArg.IsEqual ("ALL")
2735      || anArg.IsEqual ("*"))
2736     {
2737       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2738            anIter.More(); anIter.Next())
2739       {
2740         aViewList.Append (anIter.Key1());
2741       }
2742       if (aViewList.IsEmpty())
2743       {
2744         std::cout << "No view to close\n";
2745         return 0;
2746       }
2747     }
2748     else
2749     {
2750       ViewerTest_Names aViewName (theArgVec[1]);
2751       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2752       {
2753         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
2754         return 1;
2755       }
2756       aViewList.Append (aViewName.GetViewName());
2757     }
2758   }
2759   else
2760   {
2761     // close active view
2762     if (ViewerTest::CurrentView().IsNull())
2763     {
2764       Message::SendFail ("Error: no active view");
2765       return 1;
2766     }
2767     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2768   }
2769
2770   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2771   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2772        anIter.More(); anIter.Next())
2773   {
2774     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2775   }
2776
2777   return 0;
2778 }
2779
2780 //==============================================================================
2781 //function : VActivate
2782 //purpose  : Activate the view defined by its ID
2783 //==============================================================================
2784
2785 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2786 {
2787   if (theArgsNb == 1)
2788   {
2789     theDi.Eval("vviewlist");
2790     return 0;
2791   }
2792
2793   TCollection_AsciiString aNameString;
2794   Standard_Boolean toUpdate = Standard_True;
2795   Standard_Boolean toActivate = Standard_True;
2796   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2797   {
2798     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2799     anArg.LowerCase();
2800     if (toUpdate
2801      && anArg == "-noupdate")
2802     {
2803       toUpdate = Standard_False;
2804     }
2805     else if (toActivate
2806           && aNameString.IsEmpty()
2807           && anArg == "none")
2808     {
2809       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2810       VT_GetWindow().Nullify();
2811       ViewerTest::CurrentView (Handle(V3d_View)());
2812       ViewerTest::ResetEventManager();
2813       theDi << theArgVec[0] << ": all views are inactive\n";
2814       toActivate = Standard_False;
2815     }
2816     else if (toActivate
2817           && aNameString.IsEmpty())
2818     {
2819       aNameString = theArgVec[anArgIter];
2820     }
2821     else
2822     {
2823       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2824       return 1;
2825     }
2826   }
2827
2828   if (!toActivate)
2829   {
2830     return 0;
2831   }
2832   else if (aNameString.IsEmpty())
2833   {
2834     Message::SendFail ("Syntax error: wrong number of arguments");
2835     return 1;
2836   }
2837
2838   // Check if this view exists in the viewer with the driver
2839   ViewerTest_Names aViewNames (aNameString);
2840   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2841   {
2842     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2843     return 1;
2844   }
2845
2846   // Check if it is active already
2847   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2848   {
2849     theDi << theArgVec[0] << ": the view is active already\n";
2850     return 0;
2851   }
2852
2853   ActivateView (aViewNames.GetViewName(), toUpdate);
2854   return 0;
2855 }
2856
2857 //==============================================================================
2858 //function : VViewList
2859 //purpose  : Print current list of views per viewer and graphic driver ID
2860 //           shared between viewers
2861 //==============================================================================
2862
2863 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2864 {
2865   if (theArgsNb > 2)
2866   {
2867     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2868           << "Usage: " << theArgVec[0] << " name";
2869     return 1;
2870   }
2871   if (ViewerTest_myContexts.Size() < 1)
2872     return 0;
2873
2874   Standard_Boolean isTreeView =
2875     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2876
2877   if (isTreeView)
2878   {
2879     theDi << theArgVec[0] <<":\n";
2880   }
2881
2882   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2883        aDriverIter.More(); aDriverIter.Next())
2884   {
2885     if (isTreeView)
2886       theDi << aDriverIter.Key1() << ":\n";
2887
2888     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2889       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2890     {
2891       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2892       {
2893         if (isTreeView)
2894         {
2895           TCollection_AsciiString aContextName(aContextIter.Key1());
2896           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2897         }
2898
2899         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2900              aViewIter.More(); aViewIter.Next())
2901         {
2902           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2903           {
2904             TCollection_AsciiString aViewName(aViewIter.Key1());
2905             if (isTreeView)
2906             {
2907               if (aViewIter.Value() == ViewerTest::CurrentView())
2908                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2909               else
2910                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2911             }
2912             else
2913             {
2914               theDi << aViewName << " ";
2915             }
2916           }
2917         }
2918       }
2919     }
2920   }
2921   return 0;
2922 }
2923
2924 //==============================================================================
2925 //function : GetMousePosition
2926 //purpose  :
2927 //==============================================================================
2928 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2929                                    Standard_Integer& theY)
2930 {
2931   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2932   {
2933     theX = aViewCtrl->LastMousePosition().x();
2934     theY = aViewCtrl->LastMousePosition().y();
2935   }
2936 }
2937
2938 //==============================================================================
2939 //function : VViewProj
2940 //purpose  : Switch view projection
2941 //==============================================================================
2942 static int VViewProj (Draw_Interpretor& ,
2943                       Standard_Integer theNbArgs,
2944                       const char** theArgVec)
2945 {
2946   static Standard_Boolean isYup = Standard_False;
2947   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2948   if (aView.IsNull())
2949   {
2950     Message::SendFail ("Error: no active viewer");
2951     return 1;
2952   }
2953
2954   TCollection_AsciiString aCmdName (theArgVec[0]);
2955   Standard_Boolean isGeneralCmd = Standard_False;
2956   if (aCmdName == "vfront")
2957   {
2958     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2959   }
2960   else if (aCmdName == "vback")
2961   {
2962     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2963   }
2964   else if (aCmdName == "vtop")
2965   {
2966     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2967   }
2968   else if (aCmdName == "vbottom")
2969   {
2970     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2971   }
2972   else if (aCmdName == "vleft")
2973   {
2974     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2975   }
2976   else if (aCmdName == "vright")
2977   {
2978     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2979   }
2980   else if (aCmdName == "vaxo")
2981   {
2982     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2983   }
2984   else
2985   {
2986     isGeneralCmd = Standard_True;
2987     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2988     {
2989       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2990       anArgCase.LowerCase();
2991       if (anArgCase == "-zup")
2992       {
2993         isYup = Standard_False;
2994       }
2995       else if (anArgCase == "-yup")
2996       {
2997         isYup = Standard_True;
2998       }
2999       else if (anArgCase == "-front"
3000             || anArgCase == "front"
3001             || anArgCase == "-f"
3002             || anArgCase == "f")
3003       {
3004         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
3005       }
3006       else if (anArgCase == "-back"
3007             || anArgCase == "back"
3008             || anArgCase == "-b"
3009             || anArgCase == "b")
3010       {
3011         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
3012       }
3013       else if (anArgCase == "-top"
3014             || anArgCase == "top"
3015             || anArgCase == "-t"
3016             || anArgCase == "t")
3017       {
3018         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
3019       }
3020       else if (anArgCase == "-bottom"
3021             || anArgCase == "bottom"
3022             || anArgCase == "-bot"
3023             || anArgCase == "bot"
3024             || anArgCase == "-b"
3025             || anArgCase == "b")
3026       {
3027         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
3028       }
3029       else if (anArgCase == "-left"
3030             || anArgCase == "left"
3031             || anArgCase == "-l"
3032             || anArgCase == "l")
3033       {
3034         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
3035       }
3036       else if (anArgCase == "-right"
3037             || anArgCase == "right"
3038             || anArgCase == "-r"
3039             || anArgCase == "r")
3040       {
3041         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
3042       }
3043       else if (anArgCase == "-axoleft"
3044             || anArgCase == "-leftaxo"
3045             || anArgCase == "axoleft"
3046             || anArgCase == "leftaxo")
3047       {
3048         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
3049       }
3050       else if (anArgCase == "-axo"
3051             || anArgCase == "axo"
3052             || anArgCase == "-a"
3053             || anArgCase == "a"
3054             || anArgCase == "-axoright"
3055             || anArgCase == "-rightaxo"
3056             || anArgCase == "axoright"
3057             || anArgCase == "rightaxo")
3058       {
3059         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
3060       }
3061       else if (anArgCase == "+x")
3062       {
3063         aView->SetProj (V3d_Xpos, isYup);
3064       }
3065       else if (anArgCase == "-x")
3066       {
3067         aView->SetProj (V3d_Xneg, isYup);
3068       }
3069       else if (anArgCase == "+y")
3070       {
3071         aView->SetProj (V3d_Ypos, isYup);
3072       }
3073       else if (anArgCase == "-y")
3074       {
3075         aView->SetProj (V3d_Yneg, isYup);
3076       }
3077       else if (anArgCase == "+z")
3078       {
3079         aView->SetProj (V3d_Zpos, isYup);
3080       }
3081       else if (anArgCase == "-z")
3082       {
3083         aView->SetProj (V3d_Zneg, isYup);
3084       }
3085       else if (anArgCase == "+x+y+z")
3086       {
3087         aView->SetProj (V3d_XposYposZpos, isYup);
3088       }
3089       else if (anArgCase == "+x+y-z")
3090       {
3091         aView->SetProj (V3d_XposYposZneg, isYup);
3092       }
3093       else if (anArgCase == "+x-y+z")
3094       {
3095         aView->SetProj (V3d_XposYnegZpos, isYup);
3096       }
3097       else if (anArgCase == "+x-y-z")
3098       {
3099         aView->SetProj (V3d_XposYnegZneg, isYup);
3100       }
3101       else if (anArgCase == "-x+y+z")
3102       {
3103         aView->SetProj (V3d_XnegYposZpos, isYup);
3104       }
3105       else if (anArgCase == "-x+y-z")
3106       {
3107         aView->SetProj (V3d_XnegYposZneg, isYup);
3108       }
3109       else if (anArgCase == "-x-y+z")
3110       {
3111         aView->SetProj (V3d_XnegYnegZpos, isYup);
3112       }
3113       else if (anArgCase == "-x-y-z")
3114       {
3115         aView->SetProj (V3d_XnegYnegZneg, isYup);
3116       }
3117       else if (anArgCase == "+x+y")
3118       {
3119         aView->SetProj (V3d_XposYpos, isYup);
3120       }
3121       else if (anArgCase == "+x-y")
3122       {
3123         aView->SetProj (V3d_XposYneg, isYup);
3124       }
3125       else if (anArgCase == "-x+y")
3126       {
3127         aView->SetProj (V3d_XnegYpos, isYup);
3128       }
3129       else if (anArgCase == "-x-y")
3130       {
3131         aView->SetProj (V3d_XnegYneg, isYup);
3132       }
3133       else if (anArgCase == "+x+z")
3134       {
3135         aView->SetProj (V3d_XposZpos, isYup);
3136       }
3137       else if (anArgCase == "+x-z")
3138       {
3139         aView->SetProj (V3d_XposZneg, isYup);
3140       }
3141       else if (anArgCase == "-x+z")
3142       {
3143         aView->SetProj (V3d_XnegZpos, isYup);
3144       }
3145       else if (anArgCase == "-x-z")
3146       {
3147         aView->SetProj (V3d_XnegZneg, isYup);
3148       }
3149       else if (anArgCase == "+y+z")
3150       {
3151         aView->SetProj (V3d_YposZpos, isYup);
3152       }
3153       else if (anArgCase == "+y-z")
3154       {
3155         aView->SetProj (V3d_YposZneg, isYup);
3156       }
3157       else if (anArgCase == "-y+z")
3158       {
3159         aView->SetProj (V3d_YnegZpos, isYup);
3160       }
3161       else if (anArgCase == "-y-z")
3162       {
3163         aView->SetProj (V3d_YnegZneg, isYup);
3164       }
3165       else if (anArgIter + 1 < theNbArgs
3166             && anArgCase == "-frame"
3167             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
3168       {
3169         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
3170         aFrameDef.LowerCase();
3171         gp_Dir aRight, anUp;
3172         if (aFrameDef.Value (2) == aFrameDef.Value (4))
3173         {
3174           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3175           return 1;
3176         }
3177
3178         if (aFrameDef.Value (2) == 'x')
3179         {
3180           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
3181         }
3182         else if (aFrameDef.Value (2) == 'y')
3183         {
3184           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
3185         }
3186         else if (aFrameDef.Value (2) == 'z')
3187         {
3188           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
3189         }
3190         else
3191         {
3192           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3193           return 1;
3194         }
3195
3196         if (aFrameDef.Value (4) == 'x')
3197         {
3198           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
3199         }
3200         else if (aFrameDef.Value (4) == 'y')
3201         {
3202           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
3203         }
3204         else if (aFrameDef.Value (4) == 'z')
3205         {
3206           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
3207         }
3208         else
3209         {
3210           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3211           return 1;
3212         }
3213
3214         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
3215         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
3216         const gp_Dir aDir = anUp.Crossed (aRight);
3217         aCamera->SetCenter (gp_Pnt (0, 0, 0));
3218         aCamera->SetDirection (aDir);
3219         aCamera->SetUp (anUp);
3220         aCamera->OrthogonalizeUp();
3221
3222         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
3223         aView->Update();
3224       }
3225       else
3226       {
3227         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3228         return 1;
3229       }
3230     }
3231   }
3232
3233   if (!isGeneralCmd
3234     && theNbArgs != 1)
3235   {
3236     Message::SendFail ("Syntax error: wrong number of arguments");
3237     return 1;
3238   }
3239   return 0;
3240 }
3241
3242 //==============================================================================
3243 //function : VHelp
3244 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3245 //Draw arg : No args
3246 //==============================================================================
3247
3248 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3249 {
3250   di << "=========================\n";
3251   di << "F : FitAll\n";
3252   di << "T : TopView\n";
3253   di << "B : BottomView\n";
3254   di << "R : RightView\n";
3255   di << "L : LeftView\n";
3256   di << "Backspace : AxonometricView\n";
3257
3258   di << "=========================\n";
3259   di << "W, S : Fly   forward/backward\n";
3260   di << "A, D : Slide left/right\n";
3261   di << "Q, E : Bank  left/right\n";
3262   di << "-, + : Change flying speed\n";
3263   di << "Arrows : look left/right/up/down\n";
3264   di << "Arrows+Shift : slide left/right/up/down\n";
3265
3266   di << "=========================\n";
3267   di << "S + Ctrl : Shading\n";
3268   di << "W + Ctrl : Wireframe\n";
3269   di << "H : HiddenLineRemoval\n";
3270   di << "U : Unset display mode\n";
3271   di << "Delete : Remove selection from viewer\n";
3272
3273   di << "=========================\n";
3274   di << "Selection mode \n";
3275   di << "0 : Shape\n";
3276   di << "1 : Vertex\n";
3277   di << "2 : Edge\n";
3278   di << "3 : Wire\n";
3279   di << "4 : Face\n";
3280   di << "5 : Shell\n";
3281   di << "6 : Solid\n";
3282   di << "7 : Compound\n";
3283
3284   di << "=========================\n";
3285   di << "< : Hilight next detected\n";
3286   di << "> : Hilight previous detected\n";
3287
3288   return 0;
3289 }
3290
3291 #ifdef _WIN32
3292
3293 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3294                                            UINT theMsg,
3295                                            WPARAM wParam,
3296                                            LPARAM lParam )
3297 {
3298   if (ViewerTest_myViews.IsEmpty())
3299   {
3300     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3301   }
3302
3303   switch (theMsg)
3304   {
3305     case WM_CLOSE:
3306     {
3307       // Delete view from map of views
3308       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3309       return 0;
3310     }
3311     case WM_ACTIVATE:
3312     {
3313       if (LOWORD(wParam) == WA_CLICKACTIVE
3314        || LOWORD(wParam) == WA_ACTIVE
3315        || ViewerTest::CurrentView().IsNull())
3316       {
3317         // Activate inactive window
3318         if (VT_GetWindow().IsNull()
3319          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3320         {
3321           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3322         }
3323       }
3324       return 0;
3325     }
3326     default:
3327     {
3328       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3329       if (!aView.IsNull()
3330        && !VT_GetWindow().IsNull())
3331       {
3332         MSG aMsg = {};
3333         aMsg.hwnd = theWinHandle;
3334         aMsg.message = theMsg;
3335         aMsg.wParam = wParam;
3336         aMsg.lParam = lParam;
3337         if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg))
3338         {
3339           return 0;
3340         }
3341       }
3342     }
3343   }
3344   return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3345 }
3346
3347 //==============================================================================
3348 //function : ViewerMainLoop
3349 //purpose  : Get a Event on the view and dispatch it
3350 //==============================================================================
3351
3352 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3353 {
3354   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3355   if (aViewCtrl.IsNull()
3356    || theNbArgs < 4)
3357   {
3358     return 0;
3359   }
3360
3361   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3362
3363   std::cout << "Start picking\n";
3364
3365   MSG aMsg;
3366   aMsg.wParam = 1;
3367   while (aViewCtrl->ToPickPoint())
3368   {
3369     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3370     if (GetMessageW (&aMsg, NULL, 0, 0))
3371     {
3372       TranslateMessage (&aMsg);
3373       DispatchMessageW (&aMsg);
3374     }
3375   }
3376
3377   std::cout << "Picking done\n";
3378   return 0;
3379 }
3380
3381 #elif defined(HAVE_XLIB)
3382
3383 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3384 {
3385   static XEvent aReport;
3386   const Standard_Boolean toPick = theNbArgs > 0;
3387   if (theNbArgs > 0)
3388   {
3389     if (ViewerTest::CurrentEventManager().IsNull())
3390     {
3391       return 0;
3392     }
3393     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3394   }
3395
3396   Display* aDisplay = (Display* )GetDisplayConnection()->GetDisplayAspect();
3397   XNextEvent (aDisplay, &aReport);
3398
3399   // Handle event for the chosen display connection
3400   switch (aReport.type)
3401   {
3402     case ClientMessage:
3403     {
3404       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3405       {
3406         // Close the window
3407         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3408         return toPick ? 0 : 1;
3409       }
3410       break;
3411     }
3412     case FocusIn:
3413     {
3414       // Activate inactive view
3415       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3416       if (aWindow != aReport.xfocus.window)
3417       {
3418         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3419       }
3420       break;
3421     }
3422     default:
3423     {
3424       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3425       if (!aView.IsNull()
3426        && !VT_GetWindow().IsNull())
3427       {
3428         VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aReport);
3429       }
3430       break;
3431     }
3432   }
3433   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
3434 }
3435
3436 //==============================================================================
3437 //function : VProcessEvents
3438 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
3439 //==============================================================================
3440 static void VProcessEvents (ClientData theDispX, int)
3441 {
3442   Display* aDispX = (Display* )theDispX;
3443   Handle(Aspect_DisplayConnection) aDispConn;
3444   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
3445        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
3446   {
3447     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
3448     if ((Display* )aDispConnTmp->GetDisplayAspect() == aDispX)
3449     {
3450       aDispConn = aDispConnTmp;
3451       break;
3452     }
3453   }
3454   if (aDispConn.IsNull())
3455   {
3456     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
3457     return;
3458   }
3459
3460   // process new events in queue
3461   SetDisplayConnection (aDispConn);
3462   int aNbRemain = 0;
3463   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
3464   {
3465     const int anEventResult = ViewerMainLoop (0, NULL);
3466     if (anEventResult == 0)
3467     {
3468       return;
3469     }
3470
3471     aNbRemain = XPending (aDispX);
3472     if (++anEventIter >= aNbEventsMax
3473      || aNbRemain <= 0)
3474     {
3475       break;
3476     }
3477   }
3478
3479   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
3480   // it is possible that new events will arrive to queue before the end of this callback
3481   // so that either this callback should go into an infinite loop (blocking processing of other events)
3482   // or to keep unprocessed events till the next queue update (which can arrive not soon).
3483   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
3484   if (aNbRemain != 0)
3485   {
3486     XEvent aDummyEvent;
3487     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
3488     aDummyEvent.type = ClientMessage;
3489     aDummyEvent.xclient.format = 32;
3490     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
3491     XFlush (aDispX);
3492   }
3493
3494   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
3495   {
3496     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
3497   }
3498 }
3499 #elif !defined(__APPLE__)
3500 // =======================================================================
3501 // function : ViewerMainLoop
3502 // purpose  :
3503 // =======================================================================
3504 int ViewerMainLoop (Standard_Integer , const char** )
3505 {
3506   // unused
3507   return 0;
3508 }
3509 #endif
3510
3511 //==============================================================================
3512 //function : VFit
3513 //purpose  :
3514 //==============================================================================
3515
3516 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3517 {
3518   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3519   if (aView.IsNull())
3520   {
3521     Message::SendFail ("Error: no active viewer");
3522     return 1;
3523   }
3524
3525   Standard_Boolean toFit = Standard_True;
3526   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3527   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3528   {
3529     TCollection_AsciiString anArg (theArgv[anArgIter]);
3530     anArg.LowerCase();
3531     if (anUpdateTool.parseRedrawMode (anArg))
3532     {
3533       continue;
3534     }
3535     else if (anArg == "-selected")
3536     {
3537       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3538       toFit = Standard_False;
3539     }
3540     else
3541     {
3542       Message::SendFail() << "Syntax error at '" << anArg << "'";
3543     }
3544   }
3545
3546   if (toFit)
3547   {
3548     aView->FitAll (0.01, Standard_False);
3549   }
3550   return 0;
3551 }
3552
3553 //=======================================================================
3554 //function : VFitArea
3555 //purpose  : Fit view to show area located between two points
3556 //         : given in world 2D or 3D coordinates.
3557 //=======================================================================
3558 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3559 {
3560   Handle(V3d_View) aView = ViewerTest::CurrentView();
3561   if (aView.IsNull())
3562   {
3563     Message::SendFail ("Error: No active viewer");
3564     return 1;
3565   }
3566
3567   // Parse arguments.
3568   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3569   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3570
3571   if (theArgNb == 5)
3572   {
3573     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3574     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3575     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3576     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3577   }
3578   else if (theArgNb == 7)
3579   {
3580     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3581     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3582     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3583     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3584     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3585     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3586   }
3587   else
3588   {
3589     Message::SendFail ("Syntax error: Invalid number of arguments");
3590     theDI.PrintHelp(theArgVec[0]);
3591     return 1;
3592   }
3593
3594   // Convert model coordinates to view space
3595   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3596   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3597   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3598
3599   // Determine fit area
3600   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3601   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3602
3603   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3604
3605   if (aDiagonal < Precision::Confusion())
3606   {
3607     Message::SendFail ("Error: view area is too small");
3608     return 1;
3609   }
3610
3611   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3612   return 0;
3613 }
3614
3615 //==============================================================================
3616 //function : VZFit
3617 //purpose  : ZFitall, no DRAW arguments
3618 //Draw arg : No args
3619 //==============================================================================
3620 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3621 {
3622   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3623
3624   if (aCurrentView.IsNull())
3625   {
3626     Message::SendFail ("Error: no active viewer");
3627     return 1;
3628   }
3629
3630   if (theArgsNb == 1)
3631   {
3632     aCurrentView->ZFitAll();
3633     aCurrentView->Redraw();
3634     return 0;
3635   }
3636
3637   Standard_Real aScale = 1.0;
3638
3639   if (theArgsNb >= 2)
3640   {
3641     aScale = Draw::Atoi (theArgVec[1]);
3642   }
3643
3644   aCurrentView->ZFitAll (aScale);
3645   aCurrentView->Redraw();
3646
3647   return 0;
3648 }
3649
3650 //==============================================================================
3651 //function : VRepaint
3652 //purpose  :
3653 //==============================================================================
3654 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3655 {
3656   Handle(V3d_View) aView = ViewerTest::CurrentView();
3657   if (aView.IsNull())
3658   {
3659     Message::SendFail ("Error: no active viewer");
3660     return 1;
3661   }
3662
3663   Standard_Boolean isImmediateUpdate = Standard_False;
3664   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3665   {
3666     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3667     anArg.LowerCase();
3668     if (anArg == "-immediate"
3669      || anArg == "-imm")
3670     {
3671       isImmediateUpdate = Standard_True;
3672       if (anArgIter + 1 < theArgNb
3673        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3674       {
3675         ++anArgIter;
3676       }
3677     }
3678     else if (anArg == "-continuous"
3679           || anArg == "-cont"
3680           || anArg == "-fps"
3681           || anArg == "-framerate")
3682     {
3683       Standard_Real aFps = -1.0;
3684       if (anArgIter + 1 < theArgNb
3685        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
3686       {
3687         aFps = Draw::Atof (theArgVec[++anArgIter]);
3688       }
3689
3690       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3691       ViewerTest::CurrentEventManager()->SetContinuousRedraw (false);
3692       if (aFps >= 1.0)
3693       {
3694         aRedrawer.Start (aView, aFps);
3695       }
3696       else if (aFps < 0.0)
3697       {
3698         if (ViewerTest::GetViewerFromContext()->ActiveViews().Extent() == 1)
3699         {
3700           aRedrawer.Stop();
3701           ViewerTest::CurrentEventManager()->SetContinuousRedraw (true);
3702           ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3703           continue;
3704         }
3705         aRedrawer.Start (aView, aFps);
3706       }
3707       else
3708       {
3709         aRedrawer.Stop();
3710       }
3711     }
3712     else
3713     {
3714       Message::SendFail() << "Syntax error at '" << anArg << "'";
3715       return 1;
3716     }
3717   }
3718
3719   if (isImmediateUpdate)
3720   {
3721     aView->RedrawImmediate();
3722   }
3723   else
3724   {
3725     aView->Redraw();
3726   }
3727   return 0;
3728 }
3729
3730 //==============================================================================
3731 //function : VClear
3732 //purpose  : Remove all the object from the viewer
3733 //Draw arg : No args
3734 //==============================================================================
3735
3736 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3737 {
3738   Handle(V3d_View) V = ViewerTest::CurrentView();
3739   if(!V.IsNull())
3740     ViewerTest::Clear();
3741   return 0;
3742 }
3743
3744 //==============================================================================
3745 //function : VPick
3746 //purpose  :
3747 //==============================================================================
3748
3749 static int VPick (Draw_Interpretor& ,
3750                   Standard_Integer theNbArgs,
3751                   const char** theArgVec)
3752 {
3753   if (ViewerTest::CurrentView().IsNull())
3754   {
3755     return 1;
3756   }
3757
3758   if (theNbArgs < 4)
3759   {
3760     Message::SendFail ("Syntax error: wrong number of arguments");
3761     return 1;
3762   }
3763
3764   while (ViewerMainLoop (theNbArgs, theArgVec))
3765   {
3766     //
3767   }
3768
3769   return 0;
3770 }
3771
3772 namespace
3773 {
3774
3775   //! Changes the background
3776   //! @param theDrawInterpretor the interpreter of the Draw Harness application
3777   //! @param theNumberOfCommandLineArguments the number of passed command line arguments
3778   //! @param theCommandLineArguments the array of command line arguments
3779   //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
3780   static int vbackground (Draw_Interpretor&      theDrawInterpretor,
3781                           const Standard_Integer theNumberOfCommandLineArguments,
3782                           const char** const     theCommandLineArguments)
3783   {
3784     if (theNumberOfCommandLineArguments < 1)
3785     {
3786       return TCL_ERROR;
3787     }
3788     BackgroundChanger aBackgroundChanger;
3789     if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
3790                                                 theNumberOfCommandLineArguments,
3791                                                 theCommandLineArguments))
3792     {
3793       theDrawInterpretor << "Wrong command arguments.\n"
3794                             "Type 'help "
3795                          << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
3796       return TCL_ERROR;
3797     }
3798     return TCL_OK;
3799   }
3800
3801 } // namespace
3802
3803 //==============================================================================
3804 //function : VScale
3805 //purpose  : View Scaling
3806 //==============================================================================
3807
3808 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3809 {
3810   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3811   if ( V3dView.IsNull() ) return 1;
3812
3813   if ( argc != 4 ) {
3814     di << argv[0] << "Invalid number of arguments\n";
3815     return 1;
3816   }
3817   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3818   return 0;
3819 }
3820 //==============================================================================
3821 //function : VZBuffTrihedron
3822 //purpose  :
3823 //==============================================================================
3824
3825 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3826                             Standard_Integer  theArgNb,
3827                             const char**      theArgVec)
3828 {
3829   Handle(V3d_View) aView = ViewerTest::CurrentView();
3830   if (aView.IsNull())
3831   {
3832     Message::SendFail ("Error: no active viewer");
3833     return 1;
3834   }
3835
3836   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3837
3838   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3839   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3840   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
3841   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
3842   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
3843   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3844   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3845   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3846   Standard_Real                 aScale        = 0.1;
3847   Standard_Real                 aSizeRatio    = 0.8;
3848   Standard_Real                 anArrowDiam   = 0.05;
3849   Standard_Integer              aNbFacets     = 12;
3850   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3851   {
3852     Standard_CString        anArg = theArgVec[anArgIter];
3853     TCollection_AsciiString aFlag (anArg);
3854     aFlag.LowerCase();
3855     if (anUpdateTool.parseRedrawMode (aFlag))
3856     {
3857       continue;
3858     }
3859     else if (aFlag == "-on")
3860     {
3861       continue;
3862     }
3863     else if (aFlag == "-off")
3864     {
3865       aView->TriedronErase();
3866       return 0;
3867     }
3868     else if (aFlag == "-pos"
3869           || aFlag == "-position"
3870           || aFlag == "-corner")
3871     {
3872       if (++anArgIter >= theArgNb)
3873       {
3874         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3875         return 1;
3876       }
3877
3878       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
3879       aPosName.LowerCase();
3880       if (aPosName == "center")
3881       {
3882         aPosition = Aspect_TOTP_CENTER;
3883       }
3884       else if (aPosName == "left_lower"
3885             || aPosName == "lower_left"
3886             || aPosName == "leftlower"
3887             || aPosName == "lowerleft")
3888       {
3889         aPosition = Aspect_TOTP_LEFT_LOWER;
3890       }
3891       else if (aPosName == "left_upper"
3892             || aPosName == "upper_left"
3893             || aPosName == "leftupper"
3894             || aPosName == "upperleft")
3895       {
3896         aPosition = Aspect_TOTP_LEFT_UPPER;
3897       }
3898       else if (aPosName == "right_lower"
3899             || aPosName == "lower_right"
3900             || aPosName == "rightlower"
3901             || aPosName == "lowerright")
3902       {
3903         aPosition = Aspect_TOTP_RIGHT_LOWER;
3904       }
3905       else if (aPosName == "right_upper"
3906             || aPosName == "upper_right"
3907             || aPosName == "rightupper"
3908             || aPosName == "upperright")
3909       {
3910         aPosition = Aspect_TOTP_RIGHT_UPPER;
3911       }
3912       else
3913       {
3914         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
3915         return 1;
3916       }
3917     }
3918     else if (aFlag == "-type")
3919     {
3920       if (++anArgIter >= theArgNb)
3921       {
3922         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3923         return 1;
3924       }
3925
3926       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
3927       aTypeName.LowerCase();
3928       if (aTypeName == "wireframe"
3929        || aTypeName == "wire")
3930       {
3931         aVisType = V3d_WIREFRAME;
3932       }
3933       else if (aTypeName == "zbuffer"
3934             || aTypeName == "shaded")
3935       {
3936         aVisType = V3d_ZBUFFER;
3937       }
3938       else
3939       {
3940         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
3941       }
3942     }
3943     else if (aFlag == "-scale")
3944     {
3945       if (++anArgIter >= theArgNb)
3946       {
3947         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3948         return 1;
3949       }
3950
3951       aScale = Draw::Atof (theArgVec[anArgIter]);
3952     }
3953     else if (aFlag == "-size"
3954           || aFlag == "-sizeratio")
3955     {
3956       if (++anArgIter >= theArgNb)
3957       {
3958         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3959         return 1;
3960       }
3961
3962       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
3963     }
3964     else if (aFlag == "-arrowdiam"
3965           || aFlag == "-arrowdiameter")
3966     {
3967       if (++anArgIter >= theArgNb)
3968       {
3969         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3970         return 1;
3971       }
3972
3973       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
3974     }
3975     else if (aFlag == "-nbfacets")
3976     {
3977       if (++anArgIter >= theArgNb)
3978       {
3979         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3980         return 1;
3981       }
3982
3983       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
3984     }
3985     else if (aFlag == "-colorlabel"
3986           || aFlag == "-colorlabels"
3987           || aFlag == "-colorlabelx"
3988           || aFlag == "-colorlabely"
3989           || aFlag == "-colorlabelz"
3990           || aFlag == "-colorarrowx"
3991           || aFlag == "-colorarrowy"
3992           || aFlag == "-colorarrowz")
3993     {
3994       Quantity_Color aColor;
3995       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
3996                                                      theArgVec + anArgIter + 1,
3997                                                      aColor);
3998       if (aNbParsed == 0)
3999       {
4000         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4001         return 1;
4002       }
4003
4004       if (aFlag == "-colorarrowx")
4005       {
4006         anArrowColorX = aColor;
4007       }
4008       else if (aFlag == "-colorarrowy")
4009       {
4010         anArrowColorY = aColor;
4011       }
4012       else if (aFlag == "-colorarrowz")
4013       {
4014         anArrowColorZ = aColor;
4015       }
4016       else if (aFlag == "-colorlabelx")
4017       {
4018         aLabelsColorX = aColor;
4019       }
4020       else if (aFlag == "-colorlabely")
4021       {
4022         aLabelsColorY = aColor;
4023       }
4024       else if (aFlag == "-colorlabelz")
4025       {
4026         aLabelsColorZ = aColor;
4027       }
4028       else
4029       {
4030         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
4031       }
4032       anArgIter += aNbParsed;
4033     }
4034     else
4035     {
4036       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4037       return 1;
4038     }
4039   }
4040
4041   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
4042   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
4043   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
4044   aTrihedron->SetSizeRatio    (aSizeRatio);
4045   aTrihedron->SetNbFacets     (aNbFacets);
4046   aTrihedron->SetArrowDiameter(anArrowDiam);
4047   aTrihedron->SetScale        (aScale);
4048   aTrihedron->SetPosition     (aPosition);
4049   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
4050   aTrihedron->Display (aView);
4051
4052   aView->ZFitAll();
4053   return 0;
4054 }
4055
4056 //==============================================================================
4057 //function : VRotate
4058 //purpose  : Camera Rotating
4059 //==============================================================================
4060
4061 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
4062 {
4063   Handle(V3d_View) aView = ViewerTest::CurrentView();
4064   if (aView.IsNull())
4065   {
4066     Message::SendFail ("Error: no active viewer");
4067     return 1;
4068   }
4069
4070   Standard_Boolean hasFlags = Standard_False;
4071   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4072   {
4073     Standard_CString        anArg (theArgVec[anArgIter]);
4074     TCollection_AsciiString aFlag (anArg);
4075     aFlag.LowerCase();
4076     if (aFlag == "-mousestart"
4077      || aFlag == "-mousefrom")
4078     {
4079       hasFlags = Standard_True;
4080       if (anArgIter + 2 >= theArgNb)
4081       {
4082         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4083         return 1;
4084       }
4085
4086       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4087       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4088       aView->StartRotation (anX, anY);
4089     }
4090     else if (aFlag == "-mousemove")
4091     {
4092       hasFlags = Standard_True;
4093       if (anArgIter + 2 >= theArgNb)
4094       {
4095         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4096         return 1;
4097       }
4098
4099       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4100       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4101       aView->Rotation (anX, anY);
4102     }
4103     else if (theArgNb != 4
4104           && theArgNb != 7)
4105     {
4106       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4107       return 1;
4108     }
4109   }
4110
4111   if (hasFlags)
4112   {
4113     return 0;
4114   }
4115   else if (theArgNb == 4)
4116   {
4117     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4118     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4119     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4120     aView->Rotate (anAX, anAY, anAZ);
4121     return 0;
4122   }
4123   else if (theArgNb == 7)
4124   {
4125     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4126     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4127     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4128
4129     Standard_Real anX = Draw::Atof (theArgVec[4]);
4130     Standard_Real anY = Draw::Atof (theArgVec[5]);
4131     Standard_Real anZ = Draw::Atof (theArgVec[6]);
4132
4133     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
4134     return 0;
4135   }
4136
4137   Message::SendFail ("Error: Invalid number of arguments");
4138   return 1;
4139 }
4140
4141 //==============================================================================
4142 //function : VZoom
4143 //purpose  : View zoom in / out (relative to current zoom)
4144 //==============================================================================
4145
4146 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4147   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4148   if ( V3dView.IsNull() ) {
4149     return 1;
4150   }
4151
4152   if ( argc == 2 ) {
4153     Standard_Real coef = Draw::Atof(argv[1]);
4154     if ( coef <= 0.0 ) {
4155       di << argv[1] << "Invalid value\n";
4156       return 1;
4157     }
4158     V3dView->SetZoom( Draw::Atof(argv[1]) );
4159     return 0;
4160   } else {
4161     di << argv[0] << " Invalid number of arguments\n";
4162     return 1;
4163   }
4164 }
4165
4166 //==============================================================================
4167 //function : VPan
4168 //purpose  : View panning (in pixels)
4169 //==============================================================================
4170
4171 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4172   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4173   if ( V3dView.IsNull() ) return 1;
4174
4175   if ( argc == 3 ) {
4176     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
4177     return 0;
4178   } else {
4179     di << argv[0] << " Invalid number of arguments\n";
4180     return 1;
4181   }
4182 }
4183
4184 //==============================================================================
4185 //function : VPlace
4186 //purpose  : Place the point (in pixels) at the center of the window
4187 //==============================================================================
4188 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
4189 {
4190   Handle(V3d_View) aView = ViewerTest::CurrentView();
4191   if (aView.IsNull())
4192   {
4193     Message::SendFail ("Error: no active viewer");
4194     return 1;
4195   }
4196
4197   if (theArgNb != 3)
4198   {
4199     Message::SendFail ("Syntax error: wrong number of arguments");
4200     return 1;
4201   }
4202
4203   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
4204
4205   return 0;
4206 }
4207
4208 static int VColorScale (Draw_Interpretor& theDI,
4209                         Standard_Integer  theArgNb,
4210                         const char**      theArgVec)
4211 {
4212   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4213   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
4214   if (aContext.IsNull())
4215   {
4216     Message::SendFail ("Error: no active viewer");
4217     return 1;
4218   }
4219   if (theArgNb <= 1)
4220   {
4221     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
4222     return 1;
4223   }
4224
4225   Handle(AIS_ColorScale) aColorScale;
4226   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
4227   {
4228     // find existing object
4229     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
4230     if (aColorScale.IsNull())
4231     {
4232       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
4233       return 1;
4234     }
4235   }
4236
4237   if (theArgNb <= 2)
4238   {
4239     if (aColorScale.IsNull())
4240     {
4241       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
4242       return 1;
4243     }
4244
4245     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
4246           << "Min range: "            << aColorScale->GetMin() << "\n"
4247           << "Max range: "            << aColorScale->GetMax() << "\n"
4248           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
4249           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
4250           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
4251           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
4252           << "Label position: ";
4253     switch (aColorScale->GetLabelPosition())
4254     {
4255       case Aspect_TOCSP_NONE:
4256         theDI << "None\n";
4257         break;
4258       case Aspect_TOCSP_LEFT:
4259         theDI << "Left\n";
4260         break;
4261       case Aspect_TOCSP_RIGHT:
4262         theDI << "Right\n";
4263         break;
4264       case Aspect_TOCSP_CENTER:
4265         theDI << "Center\n";
4266         break;
4267     }
4268     return 0;
4269   }
4270
4271   if (aColorScale.IsNull())
4272   {
4273     aColorScale = new AIS_ColorScale();
4274     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4275     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4276   }
4277
4278   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
4279   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
4280   {
4281     Standard_CString        anArg = theArgVec[anArgIter];
4282     TCollection_AsciiString aFlag (anArg);
4283     aFlag.LowerCase();
4284     if (anUpdateTool.parseRedrawMode (aFlag))
4285     {
4286       continue;
4287     }
4288     else if (aFlag == "-range")
4289     {
4290       if (anArgIter + 3 >= theArgNb)
4291       {
4292         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
4293         return 1;
4294       }
4295
4296       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
4297       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
4298       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
4299       if (!aRangeMin.IsRealValue (Standard_True)
4300        || !aRangeMax.IsRealValue (Standard_True))
4301       {
4302         Message::SendFail ("Syntax error: the range values should be real");
4303         return 1;
4304       }
4305       else if (!aNbIntervals.IsIntegerValue())
4306       {
4307         Message::SendFail ("Syntax error: the number of intervals should be integer");
4308         return 1;
4309       }
4310
4311       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
4312       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
4313     }
4314     else if (aFlag == "-font")
4315     {
4316       if (anArgIter + 1 >= theArgNb)
4317       {
4318         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4319         return 1;
4320       }
4321       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
4322       if (!aFontArg.IsIntegerValue())
4323       {
4324         Message::SendFail ("Syntax error: HeightFont value should be integer");
4325         return 1;
4326       }
4327
4328       aColorScale->SetTextHeight (aFontArg.IntegerValue());
4329       anArgIter += 1;
4330     }
4331     else if (aFlag == "-textpos")
4332     {
4333       if (anArgIter + 1 >= theArgNb)
4334       {
4335         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4336         return 1;
4337       }
4338
4339       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
4340       aTextPosArg.LowerCase();
4341       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
4342       if (aTextPosArg == "none")
4343       {
4344         aLabPosition = Aspect_TOCSP_NONE;
4345       }
4346       else if (aTextPosArg == "left")
4347       {
4348         aLabPosition = Aspect_TOCSP_LEFT;
4349       }
4350       else if (aTextPosArg == "right")
4351       {
4352         aLabPosition = Aspect_TOCSP_RIGHT;
4353       }
4354       else if (aTextPosArg == "center")
4355       {
4356         aLabPosition = Aspect_TOCSP_CENTER;
4357       }
4358       else
4359       {
4360         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
4361         return 1;
4362       }
4363       aColorScale->SetLabelPosition (aLabPosition);
4364     }
4365     else if (aFlag == "-logarithmic"
4366           || aFlag == "-log")
4367     {
4368       if (anArgIter + 1 >= theArgNb)
4369       {
4370         Message::SendFail() << "Synta error at argument '" << anArg << "'";
4371         return 1;
4372       }
4373
4374       Standard_Boolean IsLog;
4375       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
4376       {
4377         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4378         return 1;
4379       }
4380       aColorScale->SetLogarithmic (IsLog);
4381     }
4382     else if (aFlag == "-huerange"
4383           || aFlag == "-hue")
4384     {
4385       if (anArgIter + 2 >= theArgNb)
4386       {
4387         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4388         return 1;
4389       }
4390
4391       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
4392       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
4393       aColorScale->SetHueRange (aHueMin, aHueMax);
4394     }
4395     else if (aFlag == "-colorrange")
4396     {
4397       Quantity_Color aColorMin, aColorMax;
4398       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4399                                                       theArgVec + (anArgIter + 1),
4400                                                       aColorMin);
4401       anArgIter += aNbParsed1;
4402       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4403                                                       theArgVec + (anArgIter + 1),
4404                                                       aColorMax);
4405       anArgIter += aNbParsed2;
4406       if (aNbParsed1 == 0
4407        || aNbParsed2 == 0)
4408       {
4409         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4410         return 1;
4411       }
4412
4413       aColorScale->SetColorRange (aColorMin, aColorMax);
4414     }
4415     else if (aFlag == "-reversed"
4416           || aFlag == "-inverted"
4417           || aFlag == "-topdown"
4418           || aFlag == "-bottomup")
4419     {
4420       Standard_Boolean toEnable = Standard_True;
4421       if (anArgIter + 1 < theArgNb
4422        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
4423       {
4424         ++anArgIter;
4425       }
4426       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
4427     }
4428     else if (aFlag == "-smooth"
4429           || aFlag == "-smoothtransition")
4430     {
4431       Standard_Boolean toEnable = Standard_True;
4432       if (anArgIter + 1 < theArgNb
4433        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4434       {
4435         ++anArgIter;
4436       }
4437       aColorScale->SetSmoothTransition (toEnable);
4438     }
4439     else if (aFlag == "-xy")
4440     {
4441       if (anArgIter + 2 >= theArgNb)
4442       {
4443         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4444         return 1;
4445       }
4446
4447       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
4448       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
4449       if (!anX.IsIntegerValue()
4450        || !anY.IsIntegerValue())
4451       {
4452         Message::SendFail ("Syntax error: coordinates should be integer values");
4453         return 1;
4454       }
4455
4456       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
4457     }
4458     else if (aFlag == "-width"
4459           || aFlag == "-w"
4460           || aFlag == "-breadth")
4461     {
4462       if (anArgIter + 1 >= theArgNb)
4463       {
4464         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4465         return 1;
4466       }
4467
4468       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
4469       if (!aBreadth.IsIntegerValue())
4470       {
4471         Message::SendFail ("Syntax error: a width should be an integer value");
4472         return 1;
4473       }
4474       aColorScale->SetBreadth (aBreadth.IntegerValue());
4475     }
4476     else if (aFlag == "-height"
4477           || aFlag == "-h")
4478     {
4479       if (anArgIter + 1 >= theArgNb)
4480       {
4481         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4482         return 1;
4483       }
4484
4485       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
4486       if (!aHeight.IsIntegerValue())
4487       {
4488         Message::SendFail ("Syntax error: a width should be an integer value");
4489         return 1;
4490       }
4491       aColorScale->SetHeight (aHeight.IntegerValue());
4492     }
4493     else if (aFlag == "-color")
4494     {
4495       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4496       {
4497         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
4498         return 1;
4499       }
4500       else if (anArgIter + 2 >= theArgNb)
4501       {
4502         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4503         return 1;
4504       }
4505
4506       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
4507       if (!anInd.IsIntegerValue())
4508       {
4509         Message::SendFail ("Syntax error: Index value should be integer");
4510         return 1;
4511       }
4512       const Standard_Integer anIndex = anInd.IntegerValue();
4513       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
4514       {
4515         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
4516         return 1;
4517       }
4518
4519       Quantity_Color aColor;
4520       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4521                                                      theArgVec + (anArgIter + 1),
4522                                                      aColor);
4523       if (aNbParsed == 0)
4524       {
4525         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4526         return 1;
4527       }
4528       aColorScale->SetIntervalColor (aColor, anIndex);
4529       aColorScale->SetColorType (Aspect_TOCSD_USER);
4530       anArgIter += aNbParsed;
4531     }
4532     else if (aFlag == "-label")
4533     {
4534       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4535       {
4536         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
4537         return 1;
4538       }
4539       else if (anArgIter + 2 >= theArgNb)
4540       {
4541         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4542         return 1;
4543       }
4544
4545       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
4546       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
4547       {
4548         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
4549         return 1;
4550       }
4551
4552       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
4553       aColorScale->SetLabel     (aText, anIndex);
4554       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4555       anArgIter += 2;
4556     }
4557     else if (aFlag == "-labelat"
4558           || aFlag == "-labat"
4559           || aFlag == "-labelatborder"
4560           || aFlag == "-labatborder"
4561           || aFlag == "-labelatcenter"
4562           || aFlag == "-labatcenter")
4563     {
4564       Standard_Boolean toEnable = Standard_True;
4565       if (aFlag == "-labelat"
4566        || aFlag == "-labat")
4567       {
4568         Standard_Integer aLabAtBorder = -1;
4569         if (++anArgIter >= theArgNb)
4570         {
4571           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
4572           anAtBorder.LowerCase();
4573           if (anAtBorder == "border")
4574           {
4575             aLabAtBorder = 1;
4576           }
4577           else if (anAtBorder == "center")
4578           {
4579             aLabAtBorder = 0;
4580           }
4581         }
4582         if (aLabAtBorder == -1)
4583         {
4584           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4585           return 1;
4586         }
4587         toEnable = (aLabAtBorder == 1);
4588       }
4589       else if (anArgIter + 1 < theArgNb
4590             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4591       {
4592         ++anArgIter;
4593       }
4594       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
4595                                   || aFlag == "-labatcenter"
4596                                    ? !toEnable
4597                                    :  toEnable);
4598     }
4599     else if (aFlag == "-colors")
4600     {
4601       Aspect_SequenceOfColor aSeq;
4602       for (;;)
4603       {
4604         Quantity_Color aColor;
4605         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4606                                                        theArgVec + (anArgIter + 1),
4607                                                        aColor);
4608         if (aNbParsed == 0)
4609         {
4610           break;
4611         }
4612         anArgIter += aNbParsed;
4613         aSeq.Append (aColor);
4614       }
4615       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4616       {
4617         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4618                             << aColorScale->GetNumberOfIntervals() << " intervals";
4619         return 1;
4620       }
4621
4622       aColorScale->SetColors    (aSeq);
4623       aColorScale->SetColorType (Aspect_TOCSD_USER);
4624     }
4625     else if (aFlag == "-uniform")
4626     {
4627       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4628       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4629       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4630       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4631       aColorScale->SetColorType (Aspect_TOCSD_USER);
4632     }
4633     else if (aFlag == "-labels"
4634           || aFlag == "-freelabels")
4635     {
4636       if (anArgIter + 1 >= theArgNb)
4637       {
4638         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4639         return 1;
4640       }
4641
4642       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4643                                  ? aColorScale->GetNumberOfIntervals() + 1
4644                                  : aColorScale->GetNumberOfIntervals();
4645       if (aFlag == "-freelabels")
4646       {
4647         ++anArgIter;
4648         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4649       }
4650       if (anArgIter + aNbLabels >= theArgNb)
4651       {
4652         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4653         return 1;
4654       }
4655
4656       TColStd_SequenceOfExtendedString aSeq;
4657       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4658       {
4659         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
4660       }
4661       aColorScale->SetLabels (aSeq);
4662       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4663     }
4664     else if (aFlag == "-title")
4665     {
4666       if (anArgIter + 1 >= theArgNb)
4667       {
4668         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4669         return 1;
4670       }
4671
4672       Standard_Boolean isTwoArgs = Standard_False;
4673       if (anArgIter + 2 < theArgNb)
4674       {
4675         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4676         aSecondArg.LowerCase();
4677       Standard_DISABLE_DEPRECATION_WARNINGS
4678         if (aSecondArg == "none")
4679         {
4680           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4681           isTwoArgs = Standard_True;
4682         }
4683         else if (aSecondArg == "left")
4684         {
4685           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4686           isTwoArgs = Standard_True;
4687         }
4688         else if (aSecondArg == "right")
4689         {
4690           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4691           isTwoArgs = Standard_True;
4692         }
4693         else if (aSecondArg == "center")
4694         {
4695           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4696           isTwoArgs = Standard_True;
4697         }
4698       Standard_ENABLE_DEPRECATION_WARNINGS
4699       }
4700
4701       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
4702       aColorScale->SetTitle (aTitle);
4703       if (isTwoArgs)
4704       {
4705         anArgIter += 1;
4706       }
4707       anArgIter += 1;
4708     }
4709     else if (aFlag == "-demoversion"
4710           || aFlag == "-demo")
4711     {
4712       aColorScale->SetPosition (0, 0);
4713       aColorScale->SetTextHeight (16);
4714       aColorScale->SetRange (0.0, 100.0);
4715       aColorScale->SetNumberOfIntervals (10);
4716       aColorScale->SetBreadth (0);
4717       aColorScale->SetHeight  (0);
4718       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4719       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4720       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4721     }
4722     else if (aFlag == "-findcolor")
4723     {
4724       if (anArgIter + 1 >= theArgNb)
4725       {
4726         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4727         return 1;
4728       }
4729
4730       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4731
4732       if (!anArg1.IsRealValue (Standard_True))
4733       {
4734         Message::SendFail ("Syntax error: the value should be real");
4735         return 1;
4736       }
4737
4738       Quantity_Color aColor;
4739       aColorScale->FindColor (anArg1.RealValue(), aColor);
4740       theDI << Quantity_Color::StringName (aColor.Name());
4741       return 0;
4742     }
4743     else
4744     {
4745       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4746       return 1;
4747     }
4748   }
4749
4750   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4751   aView->Window()->Size (aWinWidth, aWinHeight);
4752   if (aColorScale->GetBreadth() == 0)
4753   {
4754     aColorScale->SetBreadth (aWinWidth);
4755   }
4756   if (aColorScale->GetHeight() == 0)
4757   {
4758     aColorScale->SetHeight (aWinHeight);
4759   }
4760   aColorScale->SetToUpdate();
4761   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4762   return 0;
4763 }
4764
4765 //==============================================================================
4766 //function : VGraduatedTrihedron
4767 //purpose  : Displays or hides a graduated trihedron
4768 //==============================================================================
4769 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4770                                   Quantity_Color& theColor)
4771 {
4772   Quantity_NameOfColor aColorName;
4773   TCollection_AsciiString aVal = theValue;
4774   aVal.UpperCase();
4775   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4776   {
4777     return Standard_False;
4778   }
4779   theColor = Quantity_Color (aColorName);
4780   return Standard_True;
4781 }
4782
4783 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4784 {
4785   if (theArgNum < 2)
4786   {
4787     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4788                         << theArgs[0] <<"' for more information";
4789     return 1;
4790   }
4791
4792   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4793   TCollection_AsciiString aParseKey;
4794   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4795   {
4796     TCollection_AsciiString anArg (theArgs [anArgIt]);
4797
4798     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4799     {
4800       aParseKey = anArg;
4801       aParseKey.Remove (1);
4802       aParseKey.LowerCase();
4803       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4804       continue;
4805     }
4806
4807     if (aParseKey.IsEmpty())
4808     {
4809       continue;
4810     }
4811
4812     aMapOfArgs(aParseKey)->Append (anArg);
4813   }
4814
4815   // Check parameters
4816   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4817        aMapIt.More(); aMapIt.Next())
4818   {
4819     const TCollection_AsciiString& aKey = aMapIt.Key();
4820     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4821
4822     // Bool key, without arguments
4823     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4824         && anArgs->IsEmpty())
4825     {
4826       continue;
4827     }
4828
4829     // One argument
4830     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4831           && anArgs->Length() == 1)
4832     {
4833       continue;
4834     }
4835
4836     // On/off arguments
4837     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4838         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4839         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4840         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4841         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4842     {
4843       continue;
4844     }
4845
4846     // One string argument
4847     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4848           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4849           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4850     {
4851       continue;
4852     }
4853
4854     // One integer argument
4855     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4856           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4857           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4858           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4859          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4860     {
4861       continue;
4862     }
4863
4864     // One real argument
4865     if ( aKey.IsEqual ("arrowlength")
4866          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
4867     {
4868       continue;
4869     }
4870
4871     // Two string arguments
4872     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
4873          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
4874     {
4875       continue;
4876     }
4877
4878     TCollection_AsciiString aLowerKey;
4879     aLowerKey  = "-";
4880     aLowerKey += aKey;
4881     aLowerKey.LowerCase();
4882     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
4883                         << "Type help for more information";
4884     return 1;
4885   }
4886
4887   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
4888   if (anAISContext.IsNull())
4889   {
4890     Message::SendFail ("Error: no active viewer");
4891     return 1;
4892   }
4893
4894   Standard_Boolean toDisplay = Standard_True;
4895   Quantity_Color aColor;
4896   Graphic3d_GraduatedTrihedron aTrihedronData;
4897   // Process parameters
4898   Handle(TColStd_HSequenceOfAsciiString) aValues;
4899   if (aMapOfArgs.Find ("off", aValues))
4900   {
4901     toDisplay = Standard_False;
4902   }
4903
4904   // AXES NAMES
4905   if (aMapOfArgs.Find ("xname", aValues))
4906   {
4907     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
4908   }
4909   if (aMapOfArgs.Find ("yname", aValues))
4910   {
4911     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
4912   }
4913   if (aMapOfArgs.Find ("zname", aValues))
4914   {
4915     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
4916   }
4917   if (aMapOfArgs.Find ("xdrawname", aValues))
4918   {
4919     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4920   }
4921   if (aMapOfArgs.Find ("ydrawname", aValues))
4922   {
4923     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4924   }
4925   if (aMapOfArgs.Find ("zdrawname", aValues))
4926   {
4927     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
4928   }
4929   if (aMapOfArgs.Find ("xnameoffset", aValues))
4930   {
4931     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4932   }
4933   if (aMapOfArgs.Find ("ynameoffset", aValues))
4934   {
4935     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4936   }
4937   if (aMapOfArgs.Find ("znameoffset", aValues))
4938   {
4939     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
4940   }
4941
4942   // COLORS
4943   if (aMapOfArgs.Find ("xnamecolor", aValues))
4944   {
4945     if (!GetColor (aValues->Value(1), aColor))
4946     {
4947       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
4948       return 1;
4949     }
4950     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
4951   }
4952   if (aMapOfArgs.Find ("ynamecolor", aValues))
4953   {
4954     if (!GetColor (aValues->Value(1), aColor))
4955     {
4956       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
4957       return 1;
4958     }
4959     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
4960   }
4961   if (aMapOfArgs.Find ("znamecolor", aValues))
4962   {
4963     if (!GetColor (aValues->Value(1), aColor))
4964     {
4965       Message::SendFail ("Syntax error: -znamecolor wrong color name");
4966       return 1;
4967     }
4968     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
4969   }
4970   if (aMapOfArgs.Find ("xcolor", aValues))
4971   {
4972     if (!GetColor (aValues->Value(1), aColor))
4973     {
4974       Message::SendFail ("Syntax error: -xcolor wrong color name");
4975       return 1;
4976     }
4977     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
4978   }
4979   if (aMapOfArgs.Find ("ycolor", aValues))
4980   {
4981     if (!GetColor (aValues->Value(1), aColor))
4982     {
4983       Message::SendFail ("Syntax error: -ycolor wrong color name");
4984       return 1;
4985     }
4986     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
4987   }
4988   if (aMapOfArgs.Find ("zcolor", aValues))
4989   {
4990     if (!GetColor (aValues->Value(1), aColor))
4991     {
4992       Message::SendFail ("Syntax error: -zcolor wrong color name");
4993       return 1;
4994     }
4995     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
4996   }
4997
4998   // TICKMARKS
4999   if (aMapOfArgs.Find ("xticks", aValues))
5000   {
5001     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5002   }
5003   if (aMapOfArgs.Find ("yticks", aValues))
5004   {
5005     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5006   }
5007   if (aMapOfArgs.Find ("zticks", aValues))
5008   {
5009     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5010   }
5011   if (aMapOfArgs.Find ("xticklength", aValues))
5012   {
5013     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5014   }
5015   if (aMapOfArgs.Find ("yticklength", aValues))
5016   {
5017     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5018   }
5019   if (aMapOfArgs.Find ("zticklength", aValues))
5020   {
5021     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5022   }
5023   if (aMapOfArgs.Find ("xdrawticks", aValues))
5024   {
5025     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5026   }
5027   if (aMapOfArgs.Find ("ydrawticks", aValues))
5028   {
5029     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5030   }
5031   if (aMapOfArgs.Find ("zdrawticks", aValues))
5032   {
5033     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5034   }
5035
5036   // VALUES
5037   if (aMapOfArgs.Find ("xdrawvalues", aValues))
5038   {
5039     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5040   }
5041   if (aMapOfArgs.Find ("ydrawvalues", aValues))
5042   {
5043     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5044   }
5045   if (aMapOfArgs.Find ("zdrawvalues", aValues))
5046   {
5047     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5048   }
5049   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
5050   {
5051     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5052   }
5053   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
5054   {
5055     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5056   }
5057   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
5058   {
5059     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5060   }
5061
5062   // ARROWS
5063   if (aMapOfArgs.Find ("arrowlength", aValues))
5064   {
5065     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
5066   }
5067
5068   // FONTS
5069   if (aMapOfArgs.Find ("namefont", aValues))
5070   {
5071     aTrihedronData.SetNamesFont (aValues->Value(1));
5072   }
5073   if (aMapOfArgs.Find ("valuesfont", aValues))
5074   {
5075     aTrihedronData.SetValuesFont (aValues->Value(1));
5076   }
5077
5078   if (aMapOfArgs.Find ("drawgrid", aValues))
5079   {
5080     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
5081   }
5082   if (aMapOfArgs.Find ("drawaxes", aValues))
5083   {
5084     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
5085   }
5086
5087   // The final step: display of erase trihedron
5088   if (toDisplay)
5089   {
5090     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
5091   }
5092   else
5093   {
5094     ViewerTest::CurrentView()->GraduatedTrihedronErase();
5095   }
5096
5097   ViewerTest::GetAISContext()->UpdateCurrentViewer();
5098   ViewerTest::CurrentView()->Redraw();
5099
5100   return 0;
5101 }
5102
5103 //==============================================================================
5104 //function : VTile
5105 //purpose  :
5106 //==============================================================================
5107 static int VTile (Draw_Interpretor& theDI,
5108                   Standard_Integer  theArgNb,
5109                   const char**      theArgVec)
5110 {
5111   Handle(V3d_View) aView = ViewerTest::CurrentView();
5112   if (aView.IsNull())
5113   {
5114     Message::SendFail ("Error: no active viewer");
5115     return 1;
5116   }
5117
5118   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
5119   if (theArgNb < 2)
5120   {
5121     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
5122           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
5123           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
5124     return 0;
5125   }
5126
5127   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
5128   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5129   {
5130     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5131     anArg.LowerCase();
5132     if (anArg == "-lowerleft"
5133      || anArg == "-upperleft")
5134     {
5135       if (anArgIter + 3 < theArgNb)
5136       {
5137         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5138         return 1;
5139       }
5140       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
5141       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5142       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5143     }
5144     else if (anArg == "-total"
5145           || anArg == "-totalsize"
5146           || anArg == "-viewsize")
5147     {
5148       if (anArgIter + 3 < theArgNb)
5149       {
5150         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5151         return 1;
5152       }
5153       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5154       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5155       if (aTile.TotalSize.x() < 1
5156        || aTile.TotalSize.y() < 1)
5157       {
5158         Message::SendFail ("Error: total size is incorrect");
5159         return 1;
5160       }
5161     }
5162     else if (anArg == "-tilesize")
5163     {
5164       if (anArgIter + 3 < theArgNb)
5165       {
5166         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5167         return 1;
5168       }
5169
5170       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5171       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5172       if (aTile.TileSize.x() < 1
5173        || aTile.TileSize.y() < 1)
5174       {
5175         Message::SendFail ("Error: tile size is incorrect");
5176         return 1;
5177       }
5178     }
5179     else if (anArg == "-unset")
5180     {
5181       aView->Camera()->SetTile (Graphic3d_CameraTile());
5182       aView->Redraw();
5183       return 0;
5184     }
5185   }
5186
5187   if (aTile.TileSize.x() < 1
5188    || aTile.TileSize.y() < 1)
5189   {
5190     Message::SendFail ("Error: tile size is undefined");
5191     return 1;
5192   }
5193   else if (aTile.TotalSize.x() < 1
5194         || aTile.TotalSize.y() < 1)
5195   {
5196     Message::SendFail ("Error: total size is undefined");
5197     return 1;
5198   }
5199
5200   aView->Camera()->SetTile (aTile);
5201   aView->Redraw();
5202   return 0;
5203 }
5204
5205 //! Format ZLayer ID.
5206 inline const char* formZLayerId (const Standard_Integer theLayerId)
5207 {
5208   switch (theLayerId)
5209   {
5210     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
5211     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
5212     case Graphic3d_ZLayerId_Top:     return "[TOP]";
5213     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
5214     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
5215     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
5216   }
5217   return "";
5218 }
5219
5220 //! Print the ZLayer information.
5221 inline void printZLayerInfo (Draw_Interpretor& theDI,
5222                              const Graphic3d_ZLayerSettings& theLayer)
5223 {
5224   if (!theLayer.Name().IsEmpty())
5225   {
5226     theDI << "  Name: " << theLayer.Name() << "\n";
5227   }
5228   if (theLayer.IsImmediate())
5229   {
5230     theDI << "  Immediate: TRUE\n";
5231   }
5232   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
5233   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
5234   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
5235   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
5236   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
5237   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
5238   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
5239   {
5240     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
5241   }
5242 }
5243
5244 //==============================================================================
5245 //function : VZLayer
5246 //purpose  : Test z layer operations for v3d viewer
5247 //==============================================================================
5248 static int VZLayer (Draw_Interpretor& theDI,
5249                     Standard_Integer  theArgNb,
5250                     const char**      theArgVec)
5251 {
5252   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5253   if (aContextAIS.IsNull())
5254   {
5255     Message::SendFail ("Error: no active viewer");
5256     return 1;
5257   }
5258
5259   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
5260   if (theArgNb < 2)
5261   {
5262     TColStd_SequenceOfInteger aLayers;
5263     aViewer->GetAllZLayers (aLayers);
5264     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5265     {
5266       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
5267       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
5268       printZLayerInfo (theDI, aSettings);
5269     }
5270     return 0;
5271   }
5272
5273   Standard_Integer anArgIter = 1;
5274   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5275   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
5276   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5277   {
5278     ++anArgIter;
5279   }
5280
5281   {
5282     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
5283     if (aFirstArg.IsIntegerValue())
5284     {
5285       ++anArgIter;
5286       aLayerId = aFirstArg.IntegerValue();
5287     }
5288     else
5289     {
5290       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
5291       {
5292         ++anArgIter;
5293       }
5294     }
5295   }
5296
5297   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
5298   for (; anArgIter < theArgNb; ++anArgIter)
5299   {
5300     // perform operation
5301     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5302     anArg.LowerCase();
5303     if (anUpdateTool.parseRedrawMode (anArg))
5304     {
5305       //
5306     }
5307     else if (anArg == "-add"
5308           || anArg == "add")
5309     {
5310       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5311       if (!aViewer->AddZLayer (aLayerId))
5312       {
5313         Message::SendFail ("Error: can not add a new z layer");
5314         return 0;
5315       }
5316
5317       theDI << aLayerId;
5318     }
5319     else if (anArg == "-insertbefore"
5320           && anArgIter + 1 < theArgNb
5321           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5322     {
5323       ++anArgIter;
5324       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5325       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5326       {
5327         Message::SendFail ("Error: can not add a new z layer");
5328         return 0;
5329       }
5330
5331       theDI << aLayerId;
5332     }
5333     else if (anArg == "-insertafter"
5334           && anArgIter + 1 < theArgNb
5335           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5336     {
5337       ++anArgIter;
5338       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5339       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5340       {
5341         Message::SendFail ("Error: can not add a new z layer");
5342         return 0;
5343       }
5344
5345       theDI << aLayerId;
5346     }
5347     else if (anArg == "-del"
5348           || anArg == "-delete"
5349           || anArg == "del")
5350     {
5351       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5352       {
5353         if (++anArgIter >= theArgNb)
5354         {
5355           Message::SendFail ("Syntax error: id of z layer to remove is missing");
5356           return 1;
5357         }
5358
5359         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5360       }
5361
5362       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
5363        || aLayerId == Graphic3d_ZLayerId_Default
5364        || aLayerId == Graphic3d_ZLayerId_Top
5365        || aLayerId == Graphic3d_ZLayerId_Topmost
5366        || aLayerId == Graphic3d_ZLayerId_TopOSD
5367        || aLayerId == Graphic3d_ZLayerId_BotOSD)
5368       {
5369         Message::SendFail ("Syntax error: standard Z layer can not be removed");
5370         return 1;
5371       }
5372
5373       // move all object displayed in removing layer to default layer
5374       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
5375            anObjIter.More(); anObjIter.Next())
5376       {
5377         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
5378         if (aPrs.IsNull()
5379          || aPrs->ZLayer() != aLayerId)
5380         {
5381           continue;
5382         }
5383         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
5384       }
5385
5386       if (!aViewer->RemoveZLayer (aLayerId))
5387       {
5388         Message::SendFail ("Z layer can not be removed");
5389       }
5390       else
5391       {
5392         theDI << aLayerId << " ";
5393       }
5394     }
5395     else if (anArg == "-get"
5396           || anArg == "get")
5397     {
5398       TColStd_SequenceOfInteger aLayers;
5399       aViewer->GetAllZLayers (aLayers);
5400       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5401       {
5402         theDI << aLayeriter.Value() << " ";
5403       }
5404
5405       theDI << "\n";
5406     }
5407     else if (anArg == "-name")
5408     {
5409       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5410       {
5411         Message::SendFail ("Syntax error: id of Z layer is missing");
5412         return 1;
5413       }
5414
5415       if (++anArgIter >= theArgNb)
5416       {
5417         Message::SendFail ("Syntax error: name is missing");
5418         return 1;
5419       }
5420
5421       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5422       aSettings.SetName (theArgVec[anArgIter]);
5423       aViewer->SetZLayerSettings (aLayerId, aSettings);
5424     }
5425     else if (anArg == "-origin")
5426     {
5427       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5428       {
5429         Message::SendFail ("Syntax error: id of Z layer is missing");
5430         return 1;
5431       }
5432
5433       if (anArgIter + 2 >= theArgNb)
5434       {
5435         Message::SendFail ("Syntax error: origin coordinates are missing");
5436         return 1;
5437       }
5438
5439       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5440       gp_XYZ anOrigin;
5441       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
5442       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
5443       anOrigin.SetZ (0.0);
5444       if (anArgIter + 3 < theArgNb)
5445       {
5446         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
5447         anArgIter += 3;
5448       }
5449       else
5450       {
5451         anArgIter += 2;
5452       }
5453       aSettings.SetOrigin (anOrigin);
5454       aViewer->SetZLayerSettings (aLayerId, aSettings);
5455     }
5456     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5457           && anArgIter + 1 < theArgNb
5458           && (anArg == "-cullingdistance"
5459            || anArg == "-cullingdist"
5460            || anArg == "-culldistance"
5461            || anArg == "-culldist"
5462            || anArg == "-distcull"
5463            || anArg == "-distculling"
5464            || anArg == "-distanceculling"))
5465     {
5466       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5467       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
5468       aSettings.SetCullingDistance (aDist);
5469       aViewer->SetZLayerSettings (aLayerId, aSettings);
5470     }
5471     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5472           && anArgIter + 1 < theArgNb
5473           && (anArg == "-cullingsize"
5474            || anArg == "-cullsize"
5475            || anArg == "-sizecull"
5476            || anArg == "-sizeculling"))
5477     {
5478       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5479       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
5480       aSettings.SetCullingSize (aSize);
5481       aViewer->SetZLayerSettings (aLayerId, aSettings);
5482     }
5483     else if (anArg == "-settings"
5484           || anArg == "settings")
5485     {
5486       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5487       {
5488         if (++anArgIter >= theArgNb)
5489         {
5490           Message::SendFail ("Syntax error: id of Z layer is missing");
5491           return 1;
5492         }
5493
5494         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5495       }
5496
5497       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5498       printZLayerInfo (theDI, aSettings);
5499     }
5500     else if (anArg == "-enable"
5501           || anArg == "enable"
5502           || anArg == "-disable"
5503           || anArg == "disable")
5504     {
5505       const Standard_Boolean toEnable = anArg == "-enable"
5506                                      || anArg == "enable";
5507       if (++anArgIter >= theArgNb)
5508       {
5509         Message::SendFail ("Syntax error: option name is missing");
5510         return 1;
5511       }
5512
5513       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
5514       aSubOp.LowerCase();
5515       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5516       {
5517         if (++anArgIter >= theArgNb)
5518         {
5519           Message::SendFail ("Syntax error: id of Z layer is missing");
5520           return 1;
5521         }
5522
5523         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5524       }
5525
5526       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5527       if (aSubOp == "depthtest"
5528        || aSubOp == "test")
5529       {
5530         aSettings.SetEnableDepthTest (toEnable);
5531       }
5532       else if (aSubOp == "depthwrite"
5533             || aSubOp == "write")
5534       {
5535         aSettings.SetEnableDepthWrite (toEnable);
5536       }
5537       else if (aSubOp == "depthclear"
5538             || aSubOp == "clear")
5539       {
5540         aSettings.SetClearDepth (toEnable);
5541       }
5542       else if (aSubOp == "depthoffset"
5543             || aSubOp == "offset")
5544       {
5545         Graphic3d_PolygonOffset aParams;
5546         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
5547         if (toEnable)
5548         {
5549           if (anArgIter + 2 >= theArgNb)
5550           {
5551             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
5552             return 1;
5553           }
5554
5555           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5556           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5557         }
5558         aSettings.SetPolygonOffset (aParams);
5559       }
5560       else if (aSubOp == "positiveoffset"
5561             || aSubOp == "poffset")
5562       {
5563         if (toEnable)
5564         {
5565           aSettings.SetDepthOffsetPositive();
5566         }
5567         else
5568         {
5569           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
5570         }
5571       }
5572       else if (aSubOp == "negativeoffset"
5573             || aSubOp == "noffset")
5574       {
5575         if (toEnable)
5576         {
5577           aSettings.SetDepthOffsetNegative();
5578         }
5579         else
5580         {
5581           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
5582         }
5583       }
5584       else if (aSubOp == "textureenv")
5585       {
5586         aSettings.SetEnvironmentTexture (toEnable);
5587       }
5588       else if (aSubOp == "raytracing")
5589       {
5590         aSettings.SetRaytracable (toEnable);
5591       }
5592
5593       aViewer->SetZLayerSettings (aLayerId, aSettings);
5594     }
5595     else
5596     {
5597       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
5598       return 1;
5599     }
5600   }
5601
5602   return 0;
5603 }
5604
5605 // The interactive presentation of 2d layer item
5606 // for "vlayerline" command it provides a presentation of
5607 // line with user-defined linewidth, linetype and transparency.
5608 class V3d_LineItem : public AIS_InteractiveObject
5609 {
5610 public:
5611   // CASCADE RTTI
5612   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
5613
5614   // constructor
5615   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5616                                Standard_Real X2, Standard_Real Y2,
5617                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5618                                Standard_Real theWidth    = 0.5,
5619                                Standard_Real theTransp   = 1.0);
5620
5621 private:
5622
5623   virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
5624                         const Handle(Prs3d_Presentation)& thePrs,
5625                         const Standard_Integer theMode) Standard_OVERRIDE;
5626
5627   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& ,
5628                                  const Standard_Integer ) Standard_OVERRIDE
5629   {}
5630
5631 private:
5632
5633   Standard_Real       myX1, myY1, myX2, myY2;
5634   Aspect_TypeOfLine   myType;
5635   Standard_Real       myWidth;
5636 };
5637
5638 // default constructor for line item
5639 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5640                            Standard_Real X2, Standard_Real Y2,
5641                            Aspect_TypeOfLine theType,
5642                            Standard_Real theWidth,
5643                            Standard_Real theTransp) :
5644   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5645   myType(theType), myWidth(theWidth)
5646 {
5647   SetTransparency (1-theTransp);
5648 }
5649
5650 // render line
5651 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager)& ,
5652                             const Handle(Prs3d_Presentation)& thePresentation,
5653                             const Standard_Integer )
5654 {
5655   thePresentation->Clear();
5656   Quantity_Color aColor (Quantity_NOC_RED);
5657   Standard_Integer aWidth, aHeight;
5658   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5659   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
5660   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5661   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5662   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5663   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5664   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5665   aGroup->AddPrimitiveArray (aPrim);
5666 }
5667
5668 //=============================================================================
5669 //function : VLayerLine
5670 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5671 //         : linewidth, transparency coefficient
5672 //============================================================================
5673 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5674 {
5675   // get the active view
5676   Handle(V3d_View) aView = ViewerTest::CurrentView();
5677   if (aView.IsNull())
5678   {
5679     di << "Call vinit before!\n";
5680     return 1;
5681   }
5682   else if (argc < 5)
5683   {
5684     di << "Use: " << argv[0];
5685     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5686     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5687     di << "              0 - solid  \n";
5688     di << "              1 - dashed \n";
5689     di << "              2 - dot    \n";
5690     di << "              3 - dashdot\n";
5691     di << " transparency : { 0.0 - 1.0 } \n";
5692     di << "                  0.0 - transparent\n";
5693     di << "                  1.0 - visible    \n";
5694     return 1;
5695   }
5696
5697   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5698   // get the input params
5699   Standard_Real X1 = Draw::Atof(argv[1]);
5700   Standard_Real Y1 = Draw::Atof(argv[2]);
5701   Standard_Real X2 = Draw::Atof(argv[3]);
5702   Standard_Real Y2 = Draw::Atof(argv[4]);
5703
5704   Standard_Real aWidth = 0.5;
5705   Standard_Real aTransparency = 1.0;
5706
5707   // has width
5708   if (argc > 5)
5709     aWidth = Draw::Atof(argv[5]);
5710
5711   // select appropriate line type
5712   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5713   if (argc > 6
5714   && !ViewerTest::ParseLineType (argv[6], aLineType))
5715   {
5716     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5717     return 1;
5718   }
5719
5720   // has transparency
5721   if (argc > 7)
5722   {
5723     aTransparency = Draw::Atof(argv[7]);
5724     if (aTransparency < 0 || aTransparency > 1.0)
5725       aTransparency = 1.0;
5726   }
5727
5728   static Handle (V3d_LineItem) aLine;
5729   if (!aLine.IsNull())
5730   {
5731     aContext->Erase (aLine, Standard_False);
5732   }
5733   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5734                             aLineType, aWidth,
5735                             aTransparency);
5736
5737   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5738   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5739   aLine->SetToUpdate();
5740   aContext->Display (aLine, Standard_True);
5741
5742   return 0;
5743 }
5744
5745
5746 //==============================================================================
5747 //function : VGrid
5748 //purpose  :
5749 //==============================================================================
5750
5751 static int VGrid (Draw_Interpretor& /*theDI*/,
5752                   Standard_Integer  theArgNb,
5753                   const char**      theArgVec)
5754 {
5755   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5756   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5757   if (aView.IsNull() || aViewer.IsNull())
5758   {
5759     Message::SendFail ("Error: no active viewer");
5760     return 1;
5761   }
5762
5763   Aspect_GridType     aType = aViewer->GridType();
5764   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5765   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5766   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5767   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5768   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5769   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5770   {
5771     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5772     anArg.LowerCase();
5773     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5774     {
5775       continue;
5776     }
5777     else if (anArgIter + 1 < theArgNb
5778           && anArg == "-type")
5779     {
5780       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5781       anArgNext.LowerCase();
5782       if (anArgNext == "r"
5783        || anArgNext == "rect"
5784        || anArgNext == "rectangular")
5785       {
5786         aType = Aspect_GT_Rectangular;
5787       }
5788       else if (anArgNext == "c"
5789             || anArgNext == "circ"
5790             || anArgNext == "circular")
5791       {
5792         aType = Aspect_GT_Circular;
5793       }
5794       else
5795       {
5796         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5797         return 1;
5798       }
5799     }
5800     else if (anArgIter + 1 < theArgNb
5801           && anArg == "-mode")
5802     {
5803       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5804       anArgNext.LowerCase();
5805       if (anArgNext == "l"
5806        || anArgNext == "line"
5807        || anArgNext == "lines")
5808       {
5809         aMode = Aspect_GDM_Lines;
5810       }
5811       else if (anArgNext == "p"
5812             || anArgNext == "point"
5813             || anArgNext == "points")
5814       {
5815         aMode = Aspect_GDM_Points;
5816       }
5817       else
5818       {
5819         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5820         return 1;
5821       }
5822     }
5823     else if (anArgIter + 2 < theArgNb
5824           && (anArg == "-origin"
5825            || anArg == "-orig"))
5826     {
5827       hasOrigin = true;
5828       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5829                               Draw::Atof (theArgVec[anArgIter + 2]));
5830       anArgIter += 2;
5831     }
5832     else if (anArgIter + 2 < theArgNb
5833           && anArg == "-step")
5834     {
5835       hasStep = true;
5836       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5837                             Draw::Atof (theArgVec[anArgIter + 2]));
5838       if (aNewStepXY.x() <= 0.0
5839        || aNewStepXY.y() <= 0.0)
5840       {
5841         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5842         return 1;
5843       }
5844       anArgIter += 2;
5845     }
5846     else if (anArgIter + 1 < theArgNb
5847           && (anArg == "-angle"
5848            || anArg == "-rotangle"
5849            || anArg == "-rotationangle"))
5850     {
5851       hasRotAngle = true;
5852       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5853     }
5854     else if (anArgIter + 1 < theArgNb
5855           && (anArg == "-zoffset"
5856            || anArg == "-dz"))
5857     {
5858       hasZOffset = true;
5859       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5860     }
5861     else if (anArgIter + 1 < theArgNb
5862           && anArg == "-radius")
5863     {
5864       hasSize = true;
5865       ++anArgIter;
5866       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
5867       if (aNewStepXY.x() <= 0.0)
5868       {
5869         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
5870         return 1;
5871       }
5872     }
5873     else if (anArgIter + 2 < theArgNb
5874           && anArg == "-size")
5875     {
5876       hasSize = true;
5877       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5878                             Draw::Atof (theArgVec[anArgIter + 2]));
5879       if (aNewStepXY.x() <= 0.0
5880        || aNewStepXY.y() <= 0.0)
5881       {
5882         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5883         return 1;
5884       }
5885       anArgIter += 2;
5886     }
5887     else if (anArg == "r"
5888           || anArg == "rect"
5889           || anArg == "rectangular")
5890     {
5891       aType = Aspect_GT_Rectangular;
5892     }
5893     else if (anArg == "c"
5894           || anArg == "circ"
5895           || anArg == "circular")
5896     {
5897       aType = Aspect_GT_Circular;
5898     }
5899     else if (anArg == "l"
5900           || anArg == "line"
5901           || anArg == "lines")
5902     {
5903       aMode = Aspect_GDM_Lines;
5904     }
5905     else if (anArg == "p"
5906           || anArg == "point"
5907           || anArg == "points")
5908     {
5909       aMode = Aspect_GDM_Points;
5910     }
5911     else if (anArgIter + 1 >= theArgNb
5912           && anArg == "off")
5913     {
5914       aViewer->DeactivateGrid();
5915       return 0;
5916     }
5917     else
5918     {
5919       Message::SendFail() << "Syntax error at '" << anArg << "'";
5920       return 1;
5921     }
5922   }
5923
5924   if (aType == Aspect_GT_Rectangular)
5925   {
5926     Graphic3d_Vec2d anOrigXY, aStepXY;
5927     Standard_Real aRotAngle = 0.0;
5928     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5929     if (hasOrigin)
5930     {
5931       anOrigXY = aNewOriginXY;
5932     }
5933     if (hasStep)
5934     {
5935       aStepXY = aNewStepXY;
5936     }
5937     if (hasRotAngle)
5938     {
5939       aRotAngle = aNewRotAngle;
5940     }
5941     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
5942     if (hasSize || hasZOffset)
5943     {
5944       Graphic3d_Vec3d aSize;
5945       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5946       if (hasSize)
5947       {
5948         aSize.x() = aNewSizeXY.x();
5949         aSize.y() = aNewSizeXY.y();
5950       }
5951       if (hasZOffset)
5952       {
5953         aSize.z() = aNewZOffset;
5954       }
5955       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
5956     }
5957   }
5958   else if (aType == Aspect_GT_Circular)
5959   {
5960     Graphic3d_Vec2d anOrigXY;
5961     Standard_Real aRadiusStep;
5962     Standard_Integer aDivisionNumber;
5963     Standard_Real aRotAngle = 0.0;
5964     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5965     if (hasOrigin)
5966     {
5967       anOrigXY = aNewOriginXY;
5968     }
5969     if (hasStep)
5970     {
5971       aRadiusStep     = aNewStepXY[0];
5972       aDivisionNumber = (int )aNewStepXY[1];
5973       if (aDivisionNumber < 1)
5974       {
5975         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
5976         return 1;
5977       }
5978     }
5979     if (hasRotAngle)
5980     {
5981       aRotAngle = aNewRotAngle;
5982     }
5983
5984     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
5985     if (hasSize || hasZOffset)
5986     {
5987       Standard_Real aRadius = 0.0, aZOffset = 0.0;
5988       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
5989       if (hasSize)
5990       {
5991         aRadius = aNewSizeXY.x();
5992         if (aNewSizeXY.y() != 0.0)
5993         {
5994           Message::SendFail ("Syntax error: circular size should be specified as radius");
5995           return 1;
5996         }
5997       }
5998       if (hasZOffset)
5999       {
6000         aZOffset = aNewZOffset;
6001       }
6002       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
6003     }
6004   }
6005   aViewer->ActivateGrid (aType, aMode);
6006   return 0;
6007 }
6008
6009 //==============================================================================
6010 //function : VPriviledgedPlane
6011 //purpose  :
6012 //==============================================================================
6013
6014 static int VPriviledgedPlane (Draw_Interpretor& theDI,
6015                               Standard_Integer  theArgNb,
6016                               const char**      theArgVec)
6017 {
6018   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
6019   {
6020     Message::SendFail ("Error: wrong number of arguments! See usage:");
6021     theDI.PrintHelp (theArgVec[0]);
6022     return 1;
6023   }
6024
6025   // get the active viewer
6026   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
6027   if (aViewer.IsNull())
6028   {
6029     Message::SendFail ("Error: no active viewer");
6030     return 1;
6031   }
6032
6033   if (theArgNb == 1)
6034   {
6035     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
6036     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
6037     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
6038     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
6039     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
6040           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
6041           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
6042     return 0;
6043   }
6044
6045   Standard_Integer anArgIdx = 1;
6046   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
6047   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
6048   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
6049   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
6050   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
6051   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
6052
6053   gp_Ax3 aPriviledgedPlane;
6054   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
6055   gp_Dir aNorm (aNormX, aNormY, aNormZ);
6056   if (theArgNb > 7)
6057   {
6058     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
6059     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
6060     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
6061     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
6062     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
6063   }
6064   else
6065   {
6066     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
6067   }
6068
6069   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
6070
6071   return 0;
6072 }
6073
6074 //==============================================================================
6075 //function : VConvert
6076 //purpose  :
6077 //==============================================================================
6078
6079 static int VConvert (Draw_Interpretor& theDI,
6080                      Standard_Integer  theArgNb,
6081                      const char**      theArgVec)
6082 {
6083   // get the active view
6084   Handle(V3d_View) aView = ViewerTest::CurrentView();
6085   if (aView.IsNull())
6086   {
6087     Message::SendFail ("Error: no active viewer");
6088     return 1;
6089   }
6090
6091   enum { Model, Ray, View, Window, Grid } aMode = Model;
6092
6093   // access coordinate arguments
6094   TColStd_SequenceOfReal aCoord;
6095   Standard_Integer anArgIdx = 1;
6096   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
6097   {
6098     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6099     if (!anArg.IsRealValue (Standard_True))
6100     {
6101       break;
6102     }
6103     aCoord.Append (anArg.RealValue());
6104   }
6105
6106   // non-numeric argument too early
6107   if (aCoord.IsEmpty())
6108   {
6109     Message::SendFail ("Error: wrong number of arguments! See usage:");
6110     theDI.PrintHelp (theArgVec[0]);
6111     return 1;
6112   }
6113
6114   // collect all other arguments and options
6115   for (; anArgIdx < theArgNb; ++anArgIdx)
6116   {
6117     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6118     anArg.LowerCase();
6119     if      (anArg == "window") aMode = Window;
6120     else if (anArg == "view")   aMode = View;
6121     else if (anArg == "grid")   aMode = Grid;
6122     else if (anArg == "ray")    aMode = Ray;
6123     else
6124     {
6125       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
6126       theDI.PrintHelp (theArgVec[0]);
6127       return 1;
6128     }
6129   }
6130
6131   // complete input checks
6132   if ((aCoord.Length() == 1 && theArgNb > 3) ||
6133       (aCoord.Length() == 2 && theArgNb > 4) ||
6134       (aCoord.Length() == 3 && theArgNb > 5))
6135   {
6136     Message::SendFail ("Error: wrong number of arguments! See usage:");
6137     theDI.PrintHelp (theArgVec[0]);
6138     return 1;
6139   }
6140
6141   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
6142   Standard_Integer aXYp[2] = {0, 0};
6143
6144   // convert one-dimensional coordinate
6145   if (aCoord.Length() == 1)
6146   {
6147     switch (aMode)
6148     {
6149       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
6150       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
6151       default:
6152         Message::SendFail ("Error: wrong arguments! See usage:");
6153         theDI.PrintHelp (theArgVec[0]);
6154         return 1;
6155     }
6156   }
6157
6158   // convert 2D coordinates from projection or view reference space
6159   if (aCoord.Length() == 2)
6160   {
6161     switch (aMode)
6162     {
6163       case Model :
6164         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6165         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6166         return 0;
6167
6168       case View :
6169         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
6170         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
6171         return 0;
6172
6173       case Window :
6174         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
6175         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6176         return 0;
6177
6178       case Grid :
6179         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6180         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
6181         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6182         return 0;
6183
6184       case Ray :
6185         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
6186                                 (Standard_Integer) aCoord (2),
6187                                 aXYZ[0], aXYZ[1], aXYZ[2],
6188                                 aXYZ[3], aXYZ[4], aXYZ[5]);
6189         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6190         return 0;
6191
6192       default:
6193         Message::SendFail ("Error: wrong arguments! See usage:");
6194         theDI.PrintHelp (theArgVec[0]);
6195         return 1;
6196     }
6197   }
6198
6199   // convert 3D coordinates from view reference space
6200   else if (aCoord.Length() == 3)
6201   {
6202     switch (aMode)
6203     {
6204       case Window :
6205         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
6206         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6207         return 0;
6208
6209       case Grid :
6210         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
6211         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6212         return 0;
6213
6214       default:
6215         Message::SendFail ("Error: wrong arguments! See usage:");
6216         theDI.PrintHelp (theArgVec[0]);
6217         return 1;
6218     }
6219   }
6220
6221   return 0;
6222 }
6223
6224 //==============================================================================
6225 //function : VFps
6226 //purpose  :
6227 //==============================================================================
6228
6229 static int VFps (Draw_Interpretor& theDI,
6230                  Standard_Integer  theArgNb,
6231                  const char**      theArgVec)
6232 {
6233   // get the active view
6234   Handle(V3d_View) aView = ViewerTest::CurrentView();
6235   if (aView.IsNull())
6236   {
6237     Message::SendFail ("Error: no active viewer");
6238     return 1;
6239   }
6240
6241   Standard_Integer aFramesNb = -1;
6242   Standard_Real aDuration = -1.0;
6243   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6244   {
6245     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6246     anArg.LowerCase();
6247     if (aDuration < 0.0
6248      && anArgIter + 1 < theArgNb
6249      && (anArg == "-duration"
6250       || anArg == "-dur"
6251       || anArg == "-time"))
6252     {
6253       aDuration = Draw::Atof (theArgVec[++anArgIter]);
6254     }
6255     else if (aFramesNb < 0
6256           && anArg.IsIntegerValue())
6257     {
6258       aFramesNb = anArg.IntegerValue();
6259       if (aFramesNb <= 0)
6260       {
6261         Message::SendFail() << "Syntax error at '" << anArg << "'";
6262         return 1;
6263       }
6264     }
6265     else
6266     {
6267       Message::SendFail() << "Syntax error at '" << anArg << "'";
6268       return 1;
6269     }
6270   }
6271   if (aFramesNb < 0 && aDuration < 0.0)
6272   {
6273     aFramesNb = 100;
6274   }
6275
6276   // the time is meaningless for first call
6277   // due to async OpenGl rendering
6278   aView->Redraw();
6279
6280   // redraw view in loop to estimate average values
6281   OSD_Timer aTimer;
6282   aTimer.Start();
6283   Standard_Integer aFrameIter = 1;
6284   for (;; ++aFrameIter)
6285   {
6286     aView->Redraw();
6287     if ((aFramesNb > 0
6288       && aFrameIter >= aFramesNb)
6289      || (aDuration > 0.0
6290       && aTimer.ElapsedTime() >= aDuration))
6291     {
6292       break;
6293     }
6294   }
6295   aTimer.Stop();
6296   Standard_Real aCpu;
6297   const Standard_Real aTime = aTimer.ElapsedTime();
6298   aTimer.OSD_Chronometer::Show (aCpu);
6299
6300   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
6301   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
6302
6303   // return statistics
6304   theDI << "FPS: " << aFpsAver << "\n"
6305         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
6306
6307   // compute additional statistics in ray-tracing mode
6308   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
6309   if (aParams.Method == Graphic3d_RM_RAYTRACING)
6310   {
6311     Graphic3d_Vec2i aWinSize (0, 0);
6312     aView->Window()->Size (aWinSize.x(), aWinSize.y());
6313
6314     // 1 shadow ray and 1 secondary ray pew each bounce
6315     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
6316     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
6317   }
6318
6319   return 0;
6320 }
6321
6322
6323 //==============================================================================
6324 //function : VMemGpu
6325 //purpose  :
6326 //==============================================================================
6327
6328 static int VMemGpu (Draw_Interpretor& theDI,
6329                     Standard_Integer  theArgNb,
6330                     const char**      theArgVec)
6331 {
6332   // get the context
6333   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6334   if (aContextAIS.IsNull())
6335   {
6336     Message::SendFail ("Error: no active viewer");
6337     return 1;
6338   }
6339
6340   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
6341   if (aDriver.IsNull())
6342   {
6343     Message::SendFail ("Error: graphic driver not available");
6344     return 1;
6345   }
6346
6347   Standard_Size aFreeBytes = 0;
6348   TCollection_AsciiString anInfo;
6349   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
6350   {
6351     Message::SendFail ("Error: information not available");
6352     return 1;
6353   }
6354
6355   if (theArgNb > 1 && *theArgVec[1] == 'f')
6356   {
6357     theDI << Standard_Real (aFreeBytes);
6358   }
6359   else
6360   {
6361     theDI << anInfo;
6362   }
6363
6364   return 0;
6365 }
6366
6367 // ==============================================================================
6368 // function : VReadPixel
6369 // purpose  :
6370 // ==============================================================================
6371 static int VReadPixel (Draw_Interpretor& theDI,
6372                        Standard_Integer  theArgNb,
6373                        const char**      theArgVec)
6374 {
6375   // get the active view
6376   Handle(V3d_View) aView = ViewerTest::CurrentView();
6377   if (aView.IsNull())
6378   {
6379     Message::SendFail ("Error: no active viewer");
6380     return 1;
6381   }
6382   else if (theArgNb < 3)
6383   {
6384     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
6385                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
6386     return 1;
6387   }
6388
6389   Image_Format         aFormat     = Image_Format_RGBA;
6390   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
6391
6392   Standard_Integer aWidth, aHeight;
6393   aView->Window()->Size (aWidth, aHeight);
6394   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
6395   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
6396   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
6397   {
6398     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
6399     return 1;
6400   }
6401
6402   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
6403   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
6404   {
6405     TCollection_AsciiString aParam (theArgVec[anIter]);
6406     aParam.LowerCase();
6407     if (aParam == "-rgb"
6408      || aParam == "rgb"
6409      || aParam == "-srgb"
6410      || aParam == "srgb")
6411     {
6412       aFormat     = Image_Format_RGB;
6413       aBufferType = Graphic3d_BT_RGB;
6414       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
6415     }
6416     else if (aParam == "-hls"
6417           || aParam == "hls")
6418     {
6419       aFormat     = Image_Format_RGB;
6420       aBufferType = Graphic3d_BT_RGB;
6421       toShowHls   = Standard_True;
6422     }
6423     else if (aParam == "-rgbf"
6424           || aParam == "rgbf")
6425     {
6426       aFormat     = Image_Format_RGBF;
6427       aBufferType = Graphic3d_BT_RGB;
6428     }
6429     else if (aParam == "-rgba"
6430           || aParam == "rgba"
6431           || aParam == "-srgba"
6432           || aParam == "srgba")
6433     {
6434       aFormat     = Image_Format_RGBA;
6435       aBufferType = Graphic3d_BT_RGBA;
6436       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
6437     }
6438     else if (aParam == "-rgbaf"
6439           || aParam == "rgbaf")
6440     {
6441       aFormat     = Image_Format_RGBAF;
6442       aBufferType = Graphic3d_BT_RGBA;
6443     }
6444     else if (aParam == "-depth"
6445           || aParam == "depth")
6446     {
6447       aFormat     = Image_Format_GrayF;
6448       aBufferType = Graphic3d_BT_Depth;
6449     }
6450     else if (aParam == "-name"
6451           || aParam == "name")
6452     {
6453       toShowName = Standard_True;
6454     }
6455     else if (aParam == "-hex"
6456           || aParam == "hex")
6457     {
6458       toShowHex = Standard_True;
6459     }
6460     else
6461     {
6462       Message::SendFail() << "Syntax error at '" << aParam << "'";
6463       return 1;
6464     }
6465   }
6466
6467   Image_PixMap anImage;
6468   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
6469   {
6470     Message::SendFail ("Error: image allocation failed");
6471     return 1;
6472   }
6473   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
6474   {
6475     Message::SendFail ("Error: image dump failed");
6476     return 1;
6477   }
6478
6479   // redirect possible warning messages that could have been added by ToPixMap
6480   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
6481   // contaminate result of the command
6482   Standard_CString aWarnLog = theDI.Result();
6483   if (aWarnLog != NULL && aWarnLog[0] != '\0')
6484   {
6485     std::cout << aWarnLog << std::endl;
6486   }
6487   theDI.Reset();
6488
6489   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
6490   if (toShowName)
6491   {
6492     if (aBufferType == Graphic3d_BT_RGBA)
6493     {
6494       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
6495     }
6496     else
6497     {
6498       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
6499     }
6500   }
6501   else if (toShowHex)
6502   {
6503     if (aBufferType == Graphic3d_BT_RGBA)
6504     {
6505       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
6506     }
6507     else
6508     {
6509       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
6510     }
6511   }
6512   else
6513   {
6514     switch (aBufferType)
6515     {
6516       default:
6517       case Graphic3d_BT_RGB:
6518       {
6519         if (toShowHls)
6520         {
6521           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
6522         }
6523         else if (toShow_sRGB)
6524         {
6525           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
6526           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
6527         }
6528         else
6529         {
6530           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
6531         }
6532         break;
6533       }
6534       case Graphic3d_BT_RGBA:
6535       {
6536         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
6537         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
6538         break;
6539       }
6540       case Graphic3d_BT_Depth:
6541       {
6542         theDI << aColor.GetRGB().Red();
6543         break;
6544       }
6545     }
6546   }
6547
6548   return 0;
6549 }
6550
6551 //! Auxiliary presentation for an image plane.
6552 class ViewerTest_ImagePrs : public AIS_InteractiveObject
6553 {
6554 public:
6555   //! Main constructor.
6556   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
6557                        const Standard_Real theWidth,
6558                        const Standard_Real theHeight,
6559                        const TCollection_AsciiString& theLabel)
6560   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
6561   {
6562     SetDisplayMode (0);
6563     SetHilightMode (1);
6564     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
6565     {
6566       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
6567       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
6568       Graphic3d_MaterialAspect aMat;
6569       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
6570       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
6571       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
6572       aMat.SetSpecularColor (Quantity_NOC_BLACK);
6573       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
6574       aFillAspect->SetFrontMaterial (aMat);
6575       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
6576       aFillAspect->SetTextureMapOn();
6577     }
6578     {
6579       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
6580       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
6581       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
6582       myDrawer->SetTextAspect (aTextAspect);
6583     }
6584     {
6585       const gp_Dir aNorm (0.0, 0.0, 1.0);
6586       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
6587       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
6588       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
6589       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
6590       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
6591       myTris->AddEdge (1);
6592       myTris->AddEdge (2);
6593       myTris->AddEdge (3);
6594       myTris->AddEdge (3);
6595       myTris->AddEdge (2);
6596       myTris->AddEdge (4);
6597
6598       myRect = new Graphic3d_ArrayOfPolylines (4);
6599       myRect->AddVertex (myTris->Vertice (1));
6600       myRect->AddVertex (myTris->Vertice (3));
6601       myRect->AddVertex (myTris->Vertice (4));
6602       myRect->AddVertex (myTris->Vertice (2));
6603     }
6604   }
6605
6606   //! Returns TRUE for accepted display modes.
6607   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
6608
6609   //! Compute presentation.
6610   virtual void Compute (const Handle(PrsMgr_PresentationManager)& ,
6611                         const Handle(Prs3d_Presentation)& thePrs,
6612                         const Standard_Integer theMode) Standard_OVERRIDE
6613   {
6614     switch (theMode)
6615     {
6616       case 0:
6617       {
6618         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
6619         aGroup->AddPrimitiveArray (myTris);
6620         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
6621         aGroup->AddPrimitiveArray (myRect);
6622         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
6623         return;
6624       }
6625       case 1:
6626       {
6627         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
6628         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
6629         aGroup->AddPrimitiveArray (myRect);
6630         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
6631         return;
6632       }
6633     }
6634   }
6635
6636   //! Compute selection.
6637   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
6638   {
6639     if (theMode == 0)
6640     {
6641       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
6642       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
6643       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
6644       theSel->Add (aSensitive);
6645     }
6646   }
6647
6648 private:
6649   Handle(Graphic3d_ArrayOfTriangles) myTris;
6650   Handle(Graphic3d_ArrayOfPolylines) myRect;
6651   TCollection_AsciiString myLabel;
6652   Standard_Real myWidth;
6653   Standard_Real myHeight;
6654 };
6655
6656 //==============================================================================
6657 //function : VDiffImage
6658 //purpose  : The draw-command compares two images.
6659 //==============================================================================
6660
6661 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
6662 {
6663   if (theArgNb < 3)
6664   {
6665     Message::SendFail ("Syntax error: not enough arguments");
6666     return 1;
6667   }
6668
6669   Standard_Integer anArgIter = 1;
6670   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
6671   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
6672   TCollection_AsciiString aDiffImagePath;
6673   Standard_Real    aTolColor        = -1.0;
6674   Standard_Integer toBlackWhite     = -1;
6675   Standard_Integer isBorderFilterOn = -1;
6676   Standard_Boolean isOldSyntax = Standard_False;
6677   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
6678   for (; anArgIter < theArgNb; ++anArgIter)
6679   {
6680     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6681     anArg.LowerCase();
6682     if (anArgIter + 1 < theArgNb
6683      && (anArg == "-toleranceofcolor"
6684       || anArg == "-tolerancecolor"
6685       || anArg == "-tolerance"
6686       || anArg == "-toler"))
6687     {
6688       aTolColor = Atof (theArgVec[++anArgIter]);
6689       if (aTolColor < 0.0 || aTolColor > 1.0)
6690       {
6691         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6692         return 1;
6693       }
6694     }
6695     else if (anArg == "-blackwhite")
6696     {
6697       Standard_Boolean toEnable = Standard_True;
6698       if (anArgIter + 1 < theArgNb
6699        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6700       {
6701         ++anArgIter;
6702       }
6703       toBlackWhite = toEnable ? 1 : 0;
6704     }
6705     else if (anArg == "-borderfilter")
6706     {
6707       Standard_Boolean toEnable = Standard_True;
6708       if (anArgIter + 1 < theArgNb
6709        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
6710       {
6711         ++anArgIter;
6712       }
6713       isBorderFilterOn = toEnable ? 1 : 0;
6714     }
6715     else if (anArg == "-exitonclose")
6716     {
6717       ViewerTest_EventManager::ToExitOnCloseView() = true;
6718       if (anArgIter + 1 < theArgNb
6719        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
6720       {
6721         ++anArgIter;
6722       }
6723     }
6724     else if (anArg == "-closeonescape"
6725           || anArg == "-closeonesc")
6726     {
6727       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
6728       if (anArgIter + 1 < theArgNb
6729        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
6730       {
6731         ++anArgIter;
6732       }
6733     }
6734     else if (anArgIter + 3 < theArgNb
6735           && anArg == "-display")
6736     {
6737       aViewName   = theArgVec[++anArgIter];
6738       aPrsNameRef = theArgVec[++anArgIter];
6739       aPrsNameNew = theArgVec[++anArgIter];
6740       if (anArgIter + 1 < theArgNb
6741       && *theArgVec[anArgIter + 1] != '-')
6742       {
6743         aPrsNameDiff = theArgVec[++anArgIter];
6744       }
6745     }
6746     else if (aTolColor < 0.0
6747           && anArg.IsRealValue (Standard_True))
6748     {
6749       isOldSyntax = Standard_True;
6750       aTolColor = anArg.RealValue();
6751       if (aTolColor < 0.0 || aTolColor > 1.0)
6752       {
6753         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
6754         return 1;
6755       }
6756     }
6757     else if (isOldSyntax
6758           && toBlackWhite == -1
6759           && (anArg == "0" || anArg == "1"))
6760     {
6761       toBlackWhite = anArg == "1" ? 1 : 0;
6762     }
6763     else if (isOldSyntax
6764           && isBorderFilterOn == -1
6765           && (anArg == "0" || anArg == "1"))
6766     {
6767       isBorderFilterOn = anArg == "1" ? 1 : 0;
6768     }
6769     else if (aDiffImagePath.IsEmpty())
6770     {
6771       aDiffImagePath = theArgVec[anArgIter];
6772     }
6773     else
6774     {
6775       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
6776       return 1;
6777     }
6778   }
6779
6780   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
6781   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
6782   if (!anImgRef->Load (anImgPathRef))
6783   {
6784     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
6785     return 1;
6786   }
6787   if (!anImgNew->Load (anImgPathNew))
6788   {
6789     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
6790     return 1;
6791   }
6792
6793   // compare the images
6794   Image_Diff aComparer;
6795   Standard_Integer aDiffColorsNb = -1;
6796   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
6797   {
6798     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
6799     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
6800     aDiffColorsNb = aComparer.Compare();
6801     theDI << aDiffColorsNb << "\n";
6802   }
6803
6804   // save image of difference
6805   Handle(Image_AlienPixMap) aDiff;
6806   if (aDiffColorsNb > 0
6807   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
6808   {
6809     aDiff = new Image_AlienPixMap();
6810     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
6811     {
6812       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
6813       return 1;
6814     }
6815     aComparer.SaveDiffImage (*aDiff);
6816     if (!aDiffImagePath.IsEmpty()
6817      && !aDiff->Save (aDiffImagePath))
6818     {
6819       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
6820       return 1;
6821     }
6822   }
6823
6824   if (aViewName.IsEmpty())
6825   {
6826     return 0;
6827   }
6828
6829   ViewerTest_Names aViewNames (aViewName);
6830   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
6831   {
6832     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
6833     theDI.Eval (aCommand.ToCString());
6834   }
6835
6836   Standard_Integer aPxLeft = 0;
6837   Standard_Integer aPxTop  = 0;
6838   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
6839   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
6840                               ? int(anImgRef->SizeY() * 2)
6841                               : int(anImgRef->SizeY());
6842   TCollection_AsciiString aDisplayName;
6843   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
6844                                                             aViewName, aDisplayName);
6845
6846   Standard_Real aRatio = anImgRef->Ratio();
6847   Standard_Real aSizeX = 1.0;
6848   Standard_Real aSizeY = aSizeX / aRatio;
6849   {
6850     OSD_Path aPath (anImgPathRef);
6851     TCollection_AsciiString aLabelRef;
6852     if (!aPath.Name().IsEmpty())
6853     {
6854       aLabelRef = aPath.Name() + aPath.Extension();
6855     }
6856     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
6857
6858     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
6859     gp_Trsf aTrsfRef;
6860     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
6861     anImgRefPrs->SetLocalTransformation (aTrsfRef);
6862     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
6863   }
6864   {
6865     OSD_Path aPath (anImgPathNew);
6866     TCollection_AsciiString aLabelNew;
6867     if (!aPath.Name().IsEmpty())
6868     {
6869       aLabelNew = aPath.Name() + aPath.Extension();
6870     }
6871     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
6872
6873     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
6874     gp_Trsf aTrsfRef;
6875     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
6876     anImgNewPrs->SetLocalTransformation (aTrsfRef);
6877     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
6878   }
6879   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
6880   if (!aDiff.IsNull())
6881   {
6882     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
6883     gp_Trsf aTrsfDiff;
6884     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
6885     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
6886   }
6887   if (!aPrsNameDiff.IsEmpty())
6888   {
6889     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
6890   }
6891   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
6892   ViewerTest::CurrentView()->FitAll();
6893   return 0;
6894 }
6895
6896 //=======================================================================
6897 //function : VSelect
6898 //purpose  : Emulates different types of selection by mouse:
6899 //           1) single click selection
6900 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
6901 //           3) selection with polygon having corners at
6902 //           pixel positions (x1,y1),...,(xn,yn)
6903 //           4) any of these selections with shift button pressed
6904 //=======================================================================
6905 static Standard_Integer VSelect (Draw_Interpretor& ,
6906                                  Standard_Integer theNbArgs,
6907                                  const char** theArgVec)
6908 {
6909   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
6910   if (aCtx.IsNull())
6911   {
6912     Message::SendFail ("Error: no active viewer");
6913     return 1;
6914   }
6915
6916   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
6917   bool toAllowOverlap = false;
6918   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
6919   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
6920   {
6921     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6922     anArg.LowerCase();
6923     if (anArg == "-allowoverlap")
6924     {
6925       toAllowOverlap = true;
6926       if (anArgIter + 1 < theNbArgs
6927        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
6928       {
6929         ++anArgIter;
6930       }
6931     }
6932     else if (anArg == "-replace")
6933     {
6934       aSelScheme = AIS_SelectionScheme_Replace;
6935     }
6936     else if (anArg == "-replaceextra")
6937     {
6938       aSelScheme = AIS_SelectionScheme_ReplaceExtra;
6939     }
6940     else if (anArg == "-xor"
6941           || anArg == "-shift")
6942     {
6943       aSelScheme = AIS_SelectionScheme_XOR;
6944     }
6945     else if (anArg == "-add")
6946     {
6947       aSelScheme = AIS_SelectionScheme_Add;
6948     }
6949     else if (anArg == "-remove")
6950     {
6951       aSelScheme = AIS_SelectionScheme_Remove;
6952     }
6953     else if (anArgIter + 1 < theNbArgs
6954           && anArg.IsIntegerValue()
6955           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
6956     {
6957       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
6958       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
6959     }
6960     else if (anArgIter + 1 == theNbArgs
6961           && anArg.IsIntegerValue())
6962     {
6963       if (anArg.IntegerValue() == 1)
6964       {
6965         aSelScheme = AIS_SelectionScheme_XOR;
6966       }
6967     }
6968     else
6969     {
6970       Message::SendFail() << "Syntax error at '" << anArg << "'";
6971       return 1;
6972     }
6973   }
6974
6975   if (toAllowOverlap)
6976   {
6977     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
6978   }
6979
6980   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
6981   if (aPnts.IsEmpty())
6982   {
6983     aCtx->SelectDetected (aSelScheme);
6984     aCtx->CurrentViewer()->Invalidate();
6985   }
6986   else if (aPnts.Length() == 2)
6987   {
6988     if (toAllowOverlap
6989      && aPnts.First().y() < aPnts.Last().y())
6990     {
6991       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6992     }
6993     else if (!toAllowOverlap
6994            && aPnts.First().y() > aPnts.Last().y())
6995     {
6996       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
6997     }
6998
6999     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
7000   }
7001   else
7002   {
7003     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme);
7004   }
7005   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
7006   return 0;
7007 }
7008
7009 //=======================================================================
7010 //function : VMoveTo
7011 //purpose  : Emulates cursor movement to defined pixel position
7012 //=======================================================================
7013 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
7014                                 Standard_Integer theNbArgs,
7015                                 const char**     theArgVec)
7016 {
7017   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
7018   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
7019   if (aContext.IsNull())
7020   {
7021     Message::SendFail ("Error: no active viewer");
7022     return 1;
7023   }
7024
7025   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
7026   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7027   {
7028     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
7029     anArgStr.LowerCase();
7030     if (anArgStr == "-reset"
7031      || anArgStr == "-clear")
7032     {
7033       if (anArgIter + 1 < theNbArgs)
7034       {
7035         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
7036         return 1;
7037       }
7038
7039       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
7040                                        && aContext->CurrentViewer()->GridEcho();
7041       if (toEchoGrid)
7042       {
7043         aContext->CurrentViewer()->HideGridEcho (aView);
7044       }
7045       if (aContext->ClearDetected() || toEchoGrid)
7046       {
7047         aContext->CurrentViewer()->RedrawImmediate();
7048       }
7049       return 0;
7050     }
7051     else if (aMousePos.x() == IntegerLast()
7052           && anArgStr.IsIntegerValue())
7053     {
7054       aMousePos.x() = anArgStr.IntegerValue();
7055     }
7056     else if (aMousePos.y() == IntegerLast()
7057           && anArgStr.IsIntegerValue())
7058     {
7059       aMousePos.y() = anArgStr.IntegerValue();
7060     }
7061     else
7062     {
7063       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7064       return 1;
7065     }
7066   }
7067
7068   if (aMousePos.x() == IntegerLast()
7069    || aMousePos.y() == IntegerLast())
7070   {
7071     Message::SendFail ("Syntax error: wrong number of arguments");
7072     return 1;
7073   }
7074
7075   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
7076   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
7077   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
7078
7079   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
7080   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
7081   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
7082   {
7083     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
7084     {
7085       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
7086       break;
7087     }
7088   }
7089   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
7090   return 0;
7091 }
7092
7093 //=======================================================================
7094 //function : VSelectByAxis
7095 //purpose  :
7096 //=======================================================================
7097 static Standard_Integer VSelectByAxis (Draw_Interpretor& theDI,
7098                                        Standard_Integer theNbArgs,
7099                                        const char**     theArgVec)
7100 {
7101   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
7102   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
7103   if (aContext.IsNull())
7104   {
7105     Message::SendFail ("Error: no active viewer");
7106     return 1;
7107   }
7108
7109   TCollection_AsciiString aName;
7110   gp_XYZ anAxisLocation(RealLast(), RealLast(), RealLast());
7111   gp_XYZ anAxisDirection(RealLast(), RealLast(), RealLast());
7112   Standard_Boolean isOnlyTop = true;
7113   Standard_Boolean toShowNormal = false;
7114   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7115   {
7116     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
7117     anArgStr.LowerCase();
7118     if (anArgStr == "-display")
7119     {
7120       if (anArgIter + 1 >= theNbArgs)
7121       {
7122         Message::SendFail() << "Syntax error at argument '" << anArgStr << "'";
7123         return 1;
7124       }
7125       aName = theArgVec[++anArgIter];
7126     }
7127     else if (anArgStr == "-onlytop")
7128     {
7129       isOnlyTop = true;
7130       if (anArgIter + 1 < theNbArgs
7131         && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOnlyTop))
7132       {
7133         ++anArgIter;
7134       }
7135     }
7136     else if (anArgStr == "-shownormal")
7137     {
7138       toShowNormal = true;
7139       if (anArgIter + 1 < theNbArgs
7140         && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShowNormal))
7141       {
7142         ++anArgIter;
7143       }
7144     }
7145     else if (Precision::IsInfinite(anAxisLocation.X())
7146           && anArgStr.IsRealValue())
7147     {
7148       anAxisLocation.SetX (anArgStr.RealValue());
7149     }
7150     else if (Precision::IsInfinite(anAxisLocation.Y())
7151           && anArgStr.IsRealValue())
7152     {
7153       anAxisLocation.SetY (anArgStr.RealValue());
7154     }
7155     else if (Precision::IsInfinite(anAxisLocation.Z())
7156           && anArgStr.IsRealValue())
7157     {
7158       anAxisLocation.SetZ (anArgStr.RealValue());
7159     }
7160     else if (Precision::IsInfinite(anAxisDirection.X())
7161           && anArgStr.IsRealValue())
7162     {
7163       anAxisDirection.SetX (anArgStr.RealValue());
7164     }
7165     else if (Precision::IsInfinite(anAxisDirection.Y())
7166           && anArgStr.IsRealValue())
7167     {
7168       anAxisDirection.SetY (anArgStr.RealValue());
7169     }
7170     else if (Precision::IsInfinite(anAxisDirection.Z())
7171           && anArgStr.IsRealValue())
7172     {
7173       anAxisDirection.SetZ (anArgStr.RealValue());
7174     }
7175     else
7176     {
7177       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7178       return 1;
7179     }
7180   }
7181
7182   if (Precision::IsInfinite (anAxisLocation.X()) ||
7183       Precision::IsInfinite (anAxisLocation.Y()) ||
7184       Precision::IsInfinite (anAxisLocation.Z()) ||
7185       Precision::IsInfinite (anAxisDirection.X()) ||
7186       Precision::IsInfinite (anAxisDirection.Y()) ||
7187       Precision::IsInfinite (anAxisDirection.Z()))
7188   {
7189     Message::SendFail() << "Invalid axis location and direction";
7190     return 1;
7191   }
7192
7193   gp_Ax1 anAxis(anAxisLocation, anAxisDirection);
7194   gp_Pnt aTopPnt;
7195   if (!ViewerTest::CurrentEventManager()->PickAxis (aTopPnt, aContext, aView, anAxis))
7196   {
7197     theDI << "There are no any intersections with this axis.";
7198     return 0;
7199   }
7200   NCollection_Sequence<gp_Pnt> aPoints;
7201   NCollection_Sequence<Graphic3d_Vec3> aNormals;
7202   NCollection_Sequence<Standard_Real> aNormalLengths;
7203   for (Standard_Integer aPickIter = 1; aPickIter <= aContext->MainSelector()->NbPicked(); ++aPickIter)
7204   {
7205     const SelectMgr_SortCriterion& aPickedData = aContext->MainSelector()->PickedData (aPickIter);
7206     aPoints.Append (aPickedData.Point);
7207     aNormals.Append (aPickedData.Normal);
7208     Standard_Real aNormalLength = 1.0;
7209     if (!aPickedData.Entity.IsNull())
7210     {
7211       aNormalLength = 0.2 * aPickedData.Entity->BoundingBox().Size().maxComp();
7212     }
7213     aNormalLengths.Append (aNormalLength);
7214   }
7215   if (!aName.IsEmpty())
7216   {
7217     Standard_Boolean wasAuto = aContext->GetAutoActivateSelection();
7218     aContext->SetAutoActivateSelection (false);
7219
7220     // Display axis
7221     Quantity_Color anAxisColor = Quantity_NOC_GREEN;
7222     Handle(Geom_Axis2Placement) anAx2Axis =
7223       new Geom_Axis2Placement (gp_Ax2(anAxisLocation, anAxisDirection));
7224     Handle(AIS_Axis) anAISAxis = new AIS_Axis (gp_Ax1 (anAxisLocation, anAxisDirection));
7225     anAISAxis->SetColor (anAxisColor);
7226     ViewerTest::Display (TCollection_AsciiString (aName) + "_axis", anAISAxis, false);
7227
7228     // Display axis start point
7229     Handle(AIS_Point) anAISStartPnt = new AIS_Point (new Geom_CartesianPoint (anAxisLocation));
7230     anAISStartPnt->SetMarker (Aspect_TOM_O);
7231     anAISStartPnt->SetColor (anAxisColor);
7232     ViewerTest::Display (TCollection_AsciiString(aName) + "_start", anAISStartPnt, false);
7233
7234     Standard_Integer anIndex = 0;
7235     for (NCollection_Sequence<gp_Pnt>::Iterator aPntIter(aPoints); aPntIter.More(); aPntIter.Next(), anIndex++)
7236     {
7237       const gp_Pnt& aPoint = aPntIter.Value();
7238
7239       // Display normals in intersection points
7240       if (toShowNormal)
7241       {
7242         const Graphic3d_Vec3& aNormal = aNormals.Value (anIndex + 1);
7243         Standard_Real aNormalLength = aNormalLengths.Value (anIndex + 1);
7244         if (aNormal.SquareModulus() > ShortRealEpsilon())
7245         {
7246           gp_Dir aNormalDir ((Standard_Real)aNormal.x(), (Standard_Real)aNormal.y(), (Standard_Real)aNormal.z());
7247           Handle(AIS_Axis) anAISNormal = new AIS_Axis (gp_Ax1 (aPoint, aNormalDir), aNormalLength);
7248           anAISNormal->SetColor (Quantity_NOC_BLUE);
7249           anAISNormal->SetInfiniteState (false);
7250           ViewerTest::Display (TCollection_AsciiString(aName) + "_normal_" + anIndex, anAISNormal, false);
7251         }
7252       }
7253
7254       // Display intersection points
7255       Handle(Geom_CartesianPoint) anIntersectPnt = new Geom_CartesianPoint (aPoint);
7256       Handle(AIS_Point) anAISIntersectPoint = new AIS_Point (anIntersectPnt);
7257       anAISIntersectPoint->SetMarker (Aspect_TOM_PLUS);
7258       anAISIntersectPoint->SetColor (Quantity_NOC_RED);
7259       ViewerTest::Display (TCollection_AsciiString(aName) + "_intersect_" + anIndex, anAISIntersectPoint, true);
7260     }
7261
7262     aContext->SetAutoActivateSelection (wasAuto);
7263   }
7264
7265   Standard_Integer anIndex = 0;
7266   for (NCollection_Sequence<gp_Pnt>::Iterator anIter(aPoints); anIter.More(); anIter.Next(), anIndex++)
7267   {
7268     const gp_Pnt& aPnt = anIter.Value();
7269     theDI << aPnt.X() << " " << aPnt.Y() << " " << aPnt.Z() << "\n";
7270   }
7271   return 0;
7272 }
7273
7274 namespace
7275 {
7276   //! Global map storing all animations registered in ViewerTest.
7277   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
7278
7279   //! The animation calling the Draw Harness command.
7280   class ViewerTest_AnimationProc : public AIS_Animation
7281   {
7282     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationProc, AIS_Animation)
7283   public:
7284
7285     //! Main constructor.
7286     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
7287                               Draw_Interpretor* theDI,
7288                               const TCollection_AsciiString& theCommand)
7289     : AIS_Animation (theAnimationName),
7290       myDrawInter(theDI),
7291       myCommand  (theCommand)
7292     {
7293       //
7294     }
7295
7296   protected:
7297
7298     //! Evaluate the command.
7299     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
7300     {
7301       TCollection_AsciiString aCmd = myCommand;
7302       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
7303       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
7304       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
7305       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
7306       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
7307       myDrawInter->Eval (aCmd.ToCString());
7308     }
7309
7310     //! Find the keyword in the command and replace it with value.
7311     //! @return the position of the keyword to pass value
7312     void replace (TCollection_AsciiString&       theCmd,
7313                   const TCollection_AsciiString& theKey,
7314                   const TCollection_AsciiString& theVal)
7315     {
7316       TCollection_AsciiString aCmd (theCmd);
7317       aCmd.LowerCase();
7318       const Standard_Integer aPos = aCmd.Search (theKey);
7319       if (aPos == -1)
7320       {
7321         return;
7322       }
7323
7324       TCollection_AsciiString aPart1, aPart2;
7325       Standard_Integer aPart1To = aPos - 1;
7326       if (aPart1To >= 1
7327        && aPart1To <= theCmd.Length())
7328       {
7329         aPart1 = theCmd.SubString (1, aPart1To);
7330       }
7331
7332       Standard_Integer aPart2From = aPos + theKey.Length();
7333       if (aPart2From >= 1
7334        && aPart2From <= theCmd.Length())
7335       {
7336         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
7337       }
7338
7339       theCmd = aPart1 + theVal + aPart2;
7340     }
7341
7342   protected:
7343
7344     Draw_Interpretor*       myDrawInter;
7345     TCollection_AsciiString myCommand;
7346
7347   };
7348
7349   //! Auxiliary animation holder.
7350   class ViewerTest_AnimationHolder : public AIS_AnimationCamera
7351   {
7352     DEFINE_STANDARD_RTTI_INLINE(ViewerTest_AnimationHolder, AIS_AnimationCamera)
7353   public:
7354     ViewerTest_AnimationHolder (const Handle(AIS_Animation)& theAnim,
7355                                 const Handle(V3d_View)& theView,
7356                                 const Standard_Boolean theIsFreeView)
7357     : AIS_AnimationCamera ("ViewerTest_AnimationHolder", Handle(V3d_View)())
7358     {
7359       if (theAnim->Timer().IsNull())
7360       {
7361         theAnim->SetTimer (new Media_Timer());
7362       }
7363       myTimer = theAnim->Timer();
7364       myView = theView;
7365       if (theIsFreeView)
7366       {
7367         myCamStart = new Graphic3d_Camera (theView->Camera());
7368       }
7369       Add (theAnim);
7370     }
7371
7372     //! Start playback.
7373     virtual void StartTimer (const Standard_Real    theStartPts,
7374                              const Standard_Real    thePlaySpeed,
7375                              const Standard_Boolean theToUpdate,
7376                              const Standard_Boolean theToStopTimer) Standard_OVERRIDE
7377     {
7378       base_type::StartTimer (theStartPts, thePlaySpeed, theToUpdate, theToStopTimer);
7379       if (theToStopTimer)
7380       {
7381         abortPlayback();
7382       }
7383     }
7384
7385     //! Pause animation.
7386     virtual void Pause() Standard_OVERRIDE
7387     {
7388       myState = AnimationState_Paused;
7389       // default implementation would stop all children,
7390       // but we want to keep wrapped animation paused
7391       myAnimations.First()->Pause();
7392       abortPlayback();
7393     }
7394
7395     //! Stop animation.
7396     virtual void Stop() Standard_OVERRIDE
7397     {
7398       base_type::Stop();
7399       abortPlayback();
7400     }
7401
7402     //! Process one step of the animation according to the input time progress, including all children.
7403     virtual void updateWithChildren (const AIS_AnimationProgress& thePosition) Standard_OVERRIDE
7404     {
7405       Handle(V3d_View) aView = myView;
7406       if (!aView.IsNull()
7407        && !myCamStart.IsNull())
7408       {
7409         myCamStart->Copy (aView->Camera());
7410       }
7411       base_type::updateWithChildren (thePosition);
7412       if (!aView.IsNull()
7413        && !myCamStart.IsNull())
7414       {
7415         aView->Camera()->Copy (myCamStart);
7416       }
7417     }
7418   private:
7419     void abortPlayback()
7420     {
7421       if (!myView.IsNull())
7422       {
7423         myView.Nullify();
7424       }
7425     }
7426   };
7427
7428   //! Replace the animation with the new one.
7429   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
7430                                 Handle(AIS_Animation)&       theAnimation,
7431                                 const Handle(AIS_Animation)& theAnimationNew)
7432   {
7433     theAnimationNew->CopyFrom (theAnimation);
7434     if (!theParentAnimation.IsNull())
7435     {
7436       theParentAnimation->Replace (theAnimation, theAnimationNew);
7437     }
7438     else
7439     {
7440       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
7441       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
7442     }
7443     theAnimation = theAnimationNew;
7444   }
7445
7446   //! Parse the point.
7447   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
7448   {
7449     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
7450     if (!anXYZ[0].IsRealValue (Standard_True)
7451      || !anXYZ[1].IsRealValue (Standard_True)
7452      || !anXYZ[2].IsRealValue (Standard_True))
7453     {
7454       return Standard_False;
7455     }
7456
7457     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
7458     return Standard_True;
7459   }
7460
7461   //! Parse the quaternion.
7462   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
7463   {
7464     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
7465     if (!anXYZW[0].IsRealValue (Standard_True)
7466      || !anXYZW[1].IsRealValue (Standard_True)
7467      || !anXYZW[2].IsRealValue (Standard_True)
7468      || !anXYZW[3].IsRealValue (Standard_True))
7469     {
7470       return Standard_False;
7471     }
7472
7473     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
7474     return Standard_True;
7475   }
7476
7477   //! Auxiliary class for flipping image upside-down.
7478   class ImageFlipper
7479   {
7480   public:
7481
7482     //! Empty constructor.
7483     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
7484
7485     //! Perform flipping.
7486     Standard_Boolean FlipY (Image_PixMap& theImage)
7487     {
7488       if (theImage.IsEmpty()
7489        || theImage.SizeX() == 0
7490        || theImage.SizeY() == 0)
7491       {
7492         return Standard_False;
7493       }
7494
7495       const Standard_Size aRowSize = theImage.SizeRowBytes();
7496       if (myTmp.Size() < aRowSize
7497       && !myTmp.Allocate (aRowSize))
7498       {
7499         return Standard_False;
7500       }
7501
7502       // for odd height middle row should be left as is
7503       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
7504       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
7505       {
7506         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
7507         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
7508         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
7509         memcpy (aTop,               aBot,         aRowSize);
7510         memcpy (aBot,               myTmp.Data(), aRowSize);
7511       }
7512       return Standard_True;
7513     }
7514
7515   private:
7516     NCollection_Buffer myTmp;
7517   };
7518
7519 }
7520
7521 //=================================================================================================
7522 //function : VViewParams
7523 //purpose  : Gets or sets AIS View characteristics
7524 //=================================================================================================
7525 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
7526 {
7527   Handle(V3d_View) aView = ViewerTest::CurrentView();
7528   if (aView.IsNull())
7529   {
7530     Message::SendFail ("Error: no active viewer");
7531     return 1;
7532   }
7533
7534   Standard_Boolean toSetProj     = Standard_False;
7535   Standard_Boolean toSetUp       = Standard_False;
7536   Standard_Boolean toSetAt       = Standard_False;
7537   Standard_Boolean toSetEye      = Standard_False;
7538   Standard_Boolean toSetScale    = Standard_False;
7539   Standard_Boolean toSetSize     = Standard_False;
7540   Standard_Boolean toSetCenter2d = Standard_False;
7541   Standard_Real    aViewScale = aView->Scale();
7542   Standard_Real    aViewAspect = aView->Camera()->Aspect();
7543   Standard_Real    aViewSize  = 1.0;
7544   Graphic3d_Vec2i  aCenter2d;
7545   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
7546   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
7547   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
7548   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
7549   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
7550   const Graphic3d_Mat4d& anOrientMat = aView->Camera()->OrientationMatrix();
7551   const Graphic3d_Mat4d& aProjMat = aView->Camera()->ProjectionMatrix();
7552   if (theArgsNb == 1)
7553   {
7554     // print all of the available view parameters
7555     char aText[4096];
7556     Sprintf (aText,
7557              "Scale:  %g\n"
7558              "Aspect: %g\n"
7559              "Proj:   %12g %12g %12g\n"
7560              "Up:     %12g %12g %12g\n"
7561              "At:     %12g %12g %12g\n"
7562              "Eye:    %12g %12g %12g\n"
7563              "OrientMat:    %12g %12g %12g %12g\n"
7564              "              %12g %12g %12g %12g\n"
7565              "              %12g %12g %12g %12g\n"
7566              "              %12g %12g %12g %12g\n"
7567              "ProjMat:      %12g %12g %12g %12g\n"
7568              "              %12g %12g %12g %12g\n"
7569              "              %12g %12g %12g %12g\n"
7570              "              %12g %12g %12g %12g\n",
7571               aViewScale, aViewAspect,
7572               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7573               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7574               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
7575               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z(),
7576               anOrientMat.GetValue (0, 0), anOrientMat.GetValue (0, 1), anOrientMat.GetValue (0, 2), anOrientMat.GetValue (0, 3),
7577               anOrientMat.GetValue (1, 0), anOrientMat.GetValue (1, 1), anOrientMat.GetValue (1, 2), anOrientMat.GetValue (1, 3),
7578               anOrientMat.GetValue (2, 0), anOrientMat.GetValue (2, 1), anOrientMat.GetValue (2, 2), anOrientMat.GetValue (2, 3),
7579               anOrientMat.GetValue (3, 0), anOrientMat.GetValue (3, 1), anOrientMat.GetValue (3, 2), anOrientMat.GetValue (3, 3),
7580               aProjMat.GetValue (0, 0), aProjMat.GetValue (0, 1), aProjMat.GetValue (0, 2), aProjMat.GetValue (0, 3),
7581               aProjMat.GetValue (1, 0), aProjMat.GetValue (1, 1), aProjMat.GetValue (1, 2), aProjMat.GetValue (1, 3),
7582               aProjMat.GetValue (2, 0), aProjMat.GetValue (2, 1), aProjMat.GetValue (2, 2), aProjMat.GetValue (2, 3),
7583               aProjMat.GetValue (3, 0), aProjMat.GetValue (3, 1), aProjMat.GetValue (3, 2), aProjMat.GetValue (3, 3));
7584     theDi << aText;
7585     return 0;
7586   }
7587
7588   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
7589   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
7590   {
7591     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7592     anArg.LowerCase();
7593     if (anUpdateTool.parseRedrawMode (anArg))
7594     {
7595       continue;
7596     }
7597     else if (anArg == "-cmd"
7598           || anArg == "-command"
7599           || anArg == "-args")
7600     {
7601       char aText[4096];
7602       Sprintf (aText,
7603                "-scale %g "
7604                "-proj %g %g %g "
7605                "-up %g %g %g "
7606                "-at %g %g %g\n",
7607                 aViewScale,
7608                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7609                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7610                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
7611       theDi << aText;
7612     }
7613     else if (anArg == "-scale"
7614           || anArg == "-size")
7615     {
7616       if (anArgIter + 1 < theArgsNb
7617        && *theArgVec[anArgIter + 1] != '-')
7618       {
7619         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7620         if (aValueArg.IsRealValue (Standard_True))
7621         {
7622           ++anArgIter;
7623           if (anArg == "-scale")
7624           {
7625             toSetScale = Standard_True;
7626             aViewScale = aValueArg.RealValue();
7627           }
7628           else if (anArg == "-size")
7629           {
7630             toSetSize = Standard_True;
7631             aViewSize = aValueArg.RealValue();
7632           }
7633           continue;
7634         }
7635       }
7636       if (anArg == "-scale")
7637       {
7638         theDi << "Scale: " << aView->Scale() << "\n";
7639       }
7640       else if (anArg == "-size")
7641       {
7642         Graphic3d_Vec2d aSizeXY;
7643         aView->Size (aSizeXY.x(), aSizeXY.y());
7644         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
7645       }
7646     }
7647     else if (anArg == "-eye"
7648           || anArg == "-at"
7649           || anArg == "-up"
7650           || anArg == "-proj")
7651     {
7652       if (anArgIter + 3 < theArgsNb)
7653       {
7654         gp_XYZ anXYZ;
7655         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
7656         {
7657           anArgIter += 3;
7658           if (anArg == "-eye")
7659           {
7660             toSetEye = Standard_True;
7661             aViewEye = anXYZ;
7662           }
7663           else if (anArg == "-at")
7664           {
7665             toSetAt = Standard_True;
7666             aViewAt = anXYZ;
7667           }
7668           else if (anArg == "-up")
7669           {
7670             toSetUp = Standard_True;
7671             aViewUp = anXYZ;
7672           }
7673           else if (anArg == "-proj")
7674           {
7675             toSetProj = Standard_True;
7676             aViewProj = anXYZ;
7677           }
7678           continue;
7679         }
7680       }
7681
7682       if (anArg == "-eye")
7683       {
7684         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
7685       }
7686       else if (anArg == "-at")
7687       {
7688         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
7689       }
7690       else if (anArg == "-up")
7691       {
7692         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
7693       }
7694       else if (anArg == "-proj")
7695       {
7696         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
7697       }
7698     }
7699     else if (anArg == "-center")
7700     {
7701       if (anArgIter + 2 < theArgsNb)
7702       {
7703         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
7704         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
7705         if (anX.IsIntegerValue()
7706          && anY.IsIntegerValue())
7707         {
7708           toSetCenter2d = Standard_True;
7709           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
7710         }
7711       }
7712     }
7713     else
7714     {
7715       Message::SendFail() << "Syntax error at '" << anArg << "'";
7716       return 1;
7717     }
7718   }
7719
7720   // change view parameters in proper order
7721   if (toSetScale)
7722   {
7723     aView->SetScale (aViewScale);
7724   }
7725   if (toSetSize)
7726   {
7727     aView->SetSize (aViewSize);
7728   }
7729   if (toSetEye)
7730   {
7731     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
7732   }
7733   if (toSetAt)
7734   {
7735     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
7736   }
7737   if (toSetProj)
7738   {
7739     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
7740   }
7741   if (toSetUp)
7742   {
7743     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
7744   }
7745   if (toSetCenter2d)
7746   {
7747     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
7748   }
7749
7750   return 0;
7751 }
7752
7753 //==============================================================================
7754 //function : V2DMode
7755 //purpose  :
7756 //==============================================================================
7757 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
7758 {
7759   bool is2dMode = true;
7760   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
7761   if (aV3dView.IsNull())
7762   {
7763     Message::SendFail ("Error: no active viewer");
7764     return 1;
7765   }
7766   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
7767   {
7768     const TCollection_AsciiString anArg = theArgVec[anArgIt];
7769     TCollection_AsciiString anArgCase = anArg;
7770     anArgCase.LowerCase();
7771     if (anArgIt + 1 < theArgsNb
7772      && anArgCase == "-name")
7773     {
7774       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
7775       TCollection_AsciiString aViewName = aViewNames.GetViewName();
7776       if (!ViewerTest_myViews.IsBound1 (aViewName))
7777       {
7778         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
7779         return 1;
7780       }
7781       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
7782     }
7783     else if (anArgCase == "-mode")
7784     {
7785       if (anArgIt + 1 < theArgsNb
7786        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
7787       {
7788         ++anArgIt;
7789       }
7790     }
7791     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
7792     {
7793       //
7794     }
7795     else
7796     {
7797       Message::SendFail() << "Syntax error: unknown argument " << anArg;
7798       return 1;
7799     }
7800   }
7801
7802   aV3dView->SetView2DMode (is2dMode);
7803   return 0;
7804 }
7805
7806 //==============================================================================
7807 //function : VAnimation
7808 //purpose  :
7809 //==============================================================================
7810 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
7811                                     Standard_Integer  theArgNb,
7812                                     const char**      theArgVec)
7813 {
7814   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
7815   if (theArgNb < 2)
7816   {
7817     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
7818          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
7819     {
7820       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
7821     }
7822     return 0;
7823   }
7824   if (aCtx.IsNull())
7825   {
7826     Message::SendFail ("Error: no active viewer");
7827     return 1;
7828   }
7829
7830   Standard_Integer anArgIter = 1;
7831   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
7832   if (aNameArg.IsEmpty())
7833   {
7834     Message::SendFail ("Syntax error: animation name is not defined");
7835     return 1;
7836   }
7837
7838   TCollection_AsciiString aNameArgLower = aNameArg;
7839   aNameArgLower.LowerCase();
7840   if (aNameArgLower == "-reset"
7841    || aNameArgLower == "-clear")
7842   {
7843     ViewerTest_AnimationTimelineMap.Clear();
7844     return 0;
7845   }
7846   else if (aNameArg.Value (1) == '-')
7847   {
7848     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
7849     return 1;
7850   }
7851
7852   const char* aNameSplitter = "/";
7853   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
7854   if (aSplitPos == -1)
7855   {
7856     aNameSplitter = ".";
7857     aSplitPos = aNameArg.Search (aNameSplitter);
7858   }
7859
7860   // find existing or create a new animation by specified name within syntax "parent.child".
7861   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
7862   for (; !aNameArg.IsEmpty();)
7863   {
7864     TCollection_AsciiString aNameParent;
7865     if (aSplitPos != -1)
7866     {
7867       if (aSplitPos == aNameArg.Length())
7868       {
7869         Message::SendFail ("Syntax error: animation name is not defined");
7870         return 1;
7871       }
7872
7873       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
7874       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
7875
7876       aSplitPos = aNameArg.Search (aNameSplitter);
7877     }
7878     else
7879     {
7880       aNameParent = aNameArg;
7881       aNameArg.Clear();
7882     }
7883
7884     if (anAnimation.IsNull())
7885     {
7886       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
7887       {
7888         anAnimation = new AIS_Animation (aNameParent);
7889         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
7890       }
7891       aRootAnimation = anAnimation;
7892     }
7893     else
7894     {
7895       aParentAnimation = anAnimation;
7896       anAnimation = aParentAnimation->Find (aNameParent);
7897       if (anAnimation.IsNull())
7898       {
7899         anAnimation = new AIS_Animation (aNameParent);
7900         aParentAnimation->Add (anAnimation);
7901       }
7902     }
7903   }
7904
7905   if (anArgIter >= theArgNb)
7906   {
7907     // just print the list of children
7908     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
7909     {
7910       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
7911     }
7912     return 0;
7913   }
7914
7915   // animation parameters
7916   Standard_Boolean toPlay = Standard_False;
7917   Standard_Real aPlaySpeed     = 1.0;
7918   Standard_Real aPlayStartTime = anAnimation->StartPts();
7919   Standard_Real aPlayDuration  = anAnimation->Duration();
7920   Standard_Boolean isFreeCamera = Standard_False;
7921   Standard_Boolean toPauseOnClick = Standard_True;
7922   Standard_Boolean isLockLoop   = Standard_False;
7923
7924   // video recording parameters
7925   TCollection_AsciiString aRecFile;
7926   Image_VideoParams aRecParams;
7927
7928   Handle(V3d_View) aView = ViewerTest::CurrentView();
7929   for (; anArgIter < theArgNb; ++anArgIter)
7930   {
7931     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7932     anArg.LowerCase();
7933     // general options
7934     if (anArg == "-reset"
7935      || anArg == "-clear")
7936     {
7937       anAnimation->Clear();
7938     }
7939     else if (anArg == "-remove"
7940           || anArg == "-del"
7941           || anArg == "-delete")
7942     {
7943       if (!aParentAnimation.IsNull())
7944       {
7945         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
7946       }
7947       else
7948       {
7949         aParentAnimation->Remove (anAnimation);
7950       }
7951     }
7952     // playback options
7953     else if (anArg == "-play")
7954     {
7955       toPlay = Standard_True;
7956       if (++anArgIter < theArgNb)
7957       {
7958         if (*theArgVec[anArgIter] == '-')
7959         {
7960           --anArgIter;
7961           continue;
7962         }
7963         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
7964
7965         if (++anArgIter < theArgNb)
7966         {
7967           if (*theArgVec[anArgIter] == '-')
7968           {
7969             --anArgIter;
7970             continue;
7971           }
7972           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7973         }
7974       }
7975     }
7976     else if (anArg == "-resume")
7977     {
7978       toPlay = Standard_True;
7979       aPlayStartTime = anAnimation->ElapsedTime();
7980       if (++anArgIter < theArgNb)
7981       {
7982         if (*theArgVec[anArgIter] == '-')
7983         {
7984           --anArgIter;
7985           continue;
7986         }
7987
7988         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
7989       }
7990     }
7991     else if (anArg == "-pause")
7992     {
7993       anAnimation->Pause();
7994     }
7995     else if (anArg == "-stop")
7996     {
7997       anAnimation->Stop();
7998     }
7999     else if (anArg == "-playspeed"
8000           || anArg == "-speed")
8001     {
8002       if (++anArgIter >= theArgNb)
8003       {
8004         Message::SendFail() << "Syntax error at " << anArg << "";
8005         return 1;
8006       }
8007       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
8008     }
8009     else if (anArg == "-lock"
8010           || anArg == "-lockloop"
8011           || anArg == "-playlockloop")
8012     {
8013       isLockLoop = Draw::ParseOnOffIterator (theArgNb, theArgVec, anArgIter);
8014     }
8015     else if (anArg == "-freecamera"
8016           || anArg == "-nofreecamera"
8017           || anArg == "-playfreecamera"
8018           || anArg == "-noplayfreecamera"
8019           || anArg == "-freelook"
8020           || anArg == "-nofreelook")
8021     {
8022       isFreeCamera = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
8023     }
8024     else if (anArg == "-pauseonclick"
8025           || anArg == "-nopauseonclick"
8026           || anArg == "-nopause")
8027     {
8028       toPauseOnClick = Draw::ParseOnOffNoIterator (theArgNb, theArgVec, anArgIter);
8029     }
8030     // video recodring options
8031     else if (anArg == "-rec"
8032           || anArg == "-record")
8033     {
8034       if (++anArgIter >= theArgNb)
8035       {
8036         Message::SendFail() << "Syntax error at " << anArg;
8037         return 1;
8038       }
8039
8040       aRecFile = theArgVec[anArgIter];
8041       if (aRecParams.FpsNum <= 0)
8042       {
8043         aRecParams.FpsNum = 24;
8044       }
8045
8046       if (anArgIter + 2 < theArgNb
8047       && *theArgVec[anArgIter + 1] != '-'
8048       && *theArgVec[anArgIter + 2] != '-')
8049       {
8050         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
8051         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
8052         if (aWidthArg .IsIntegerValue()
8053          && aHeightArg.IsIntegerValue())
8054         {
8055           aRecParams.Width  = aWidthArg .IntegerValue();
8056           aRecParams.Height = aHeightArg.IntegerValue();
8057           anArgIter += 2;
8058         }
8059       }
8060     }
8061     else if (anArg == "-fps")
8062     {
8063       if (++anArgIter >= theArgNb)
8064       {
8065         Message::SendFail() << "Syntax error at " << anArg;
8066         return 1;
8067       }
8068
8069       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
8070       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
8071       if (aSplitIndex == 0)
8072       {
8073         aRecParams.FpsNum = aFpsArg.IntegerValue();
8074       }
8075       else
8076       {
8077         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
8078         aFpsArg.Split (aFpsArg.Length() - 1);
8079         const TCollection_AsciiString aNumStr = aFpsArg;
8080         aRecParams.FpsNum = aNumStr.IntegerValue();
8081         aRecParams.FpsDen = aDenStr.IntegerValue();
8082         if (aRecParams.FpsDen < 1)
8083         {
8084           Message::SendFail() << "Syntax error at " << anArg;
8085           return 1;
8086         }
8087       }
8088     }
8089     else if (anArg == "-format")
8090     {
8091       if (++anArgIter >= theArgNb)
8092       {
8093         Message::SendFail() << "Syntax error at " << anArg;
8094         return 1;
8095       }
8096       aRecParams.Format = theArgVec[anArgIter];
8097     }
8098     else if (anArg == "-pix_fmt"
8099           || anArg == "-pixfmt"
8100           || anArg == "-pixelformat")
8101     {
8102       if (++anArgIter >= theArgNb)
8103       {
8104         Message::SendFail() << "Syntax error at " << anArg;
8105         return 1;
8106       }
8107       aRecParams.PixelFormat = theArgVec[anArgIter];
8108     }
8109     else if (anArg == "-codec"
8110           || anArg == "-vcodec"
8111           || anArg == "-videocodec")
8112     {
8113       if (++anArgIter >= theArgNb)
8114       {
8115         Message::SendFail() << "Syntax error at " << anArg;
8116         return 1;
8117       }
8118       aRecParams.VideoCodec = theArgVec[anArgIter];
8119     }
8120     else if (anArg == "-crf"
8121           || anArg == "-preset"
8122           || anArg == "-qp")
8123     {
8124       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
8125       if (++anArgIter >= theArgNb)
8126       {
8127         Message::SendFail() << "Syntax error at " << anArg;
8128         return 1;
8129       }
8130
8131       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
8132     }
8133     // animation definition options
8134     else if (anArg == "-start"
8135           || anArg == "-starttime"
8136           || anArg == "-startpts")
8137     {
8138       if (++anArgIter >= theArgNb)
8139       {
8140         Message::SendFail() << "Syntax error at " << anArg;
8141         return 1;
8142       }
8143
8144       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
8145       aRootAnimation->UpdateTotalDuration();
8146     }
8147     else if (anArg == "-end"
8148           || anArg == "-endtime"
8149           || anArg == "-endpts")
8150     {
8151       if (++anArgIter >= theArgNb)
8152       {
8153         Message::SendFail() << "Syntax error at " << anArg;
8154         return 1;
8155       }
8156
8157       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
8158       aRootAnimation->UpdateTotalDuration();
8159     }
8160     else if (anArg == "-dur"
8161           || anArg == "-duration")
8162     {
8163       if (++anArgIter >= theArgNb)
8164       {
8165         Message::SendFail() << "Syntax error at " << anArg;
8166         return 1;
8167       }
8168
8169       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
8170       aRootAnimation->UpdateTotalDuration();
8171     }
8172     else if (anArg == "-command"
8173           || anArg == "-cmd"
8174           || anArg == "-invoke"
8175           || anArg == "-eval"
8176           || anArg == "-proc")
8177     {
8178       if (++anArgIter >= theArgNb)
8179       {
8180         Message::SendFail() << "Syntax error at " << anArg;
8181         return 1;
8182       }
8183
8184       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
8185       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
8186     }
8187     else if (anArg == "-objecttrsf"
8188           || anArg == "-objectransformation"
8189           || anArg == "-objtransformation"
8190           || anArg == "-objtrsf"
8191           || anArg == "-object"
8192           || anArg == "-obj")
8193     {
8194       if (++anArgIter >= theArgNb)
8195       {
8196         Message::SendFail() << "Syntax error at " << anArg;
8197         return 1;
8198       }
8199
8200       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
8201       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
8202       Handle(AIS_InteractiveObject) anObject;
8203       if (!aMapOfAIS.Find2 (anObjName, anObject))
8204       {
8205         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
8206         return 1;
8207       }
8208
8209       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
8210       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
8211       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
8212       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
8213       Standard_Boolean isTrsfSet = Standard_False;
8214       Standard_Integer aTrsfArgIter = anArgIter + 1;
8215       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
8216       {
8217         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
8218         aTrsfArg.LowerCase();
8219         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
8220         if (aTrsfArg.StartsWith ("-rotation")
8221          || aTrsfArg.StartsWith ("-rot"))
8222         {
8223           isTrsfSet = Standard_True;
8224           if (aTrsfArgIter + 4 >= theArgNb
8225           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
8226           {
8227             Message::SendFail() << "Syntax error at " << aTrsfArg;
8228             return 1;
8229           }
8230           aTrsfArgIter += 4;
8231         }
8232         else if (aTrsfArg.StartsWith ("-location")
8233               || aTrsfArg.StartsWith ("-loc"))
8234         {
8235           isTrsfSet = Standard_True;
8236           if (aTrsfArgIter + 3 >= theArgNb
8237           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
8238           {
8239             Message::SendFail() << "Syntax error at " << aTrsfArg;
8240             return 1;
8241           }
8242           aTrsfArgIter += 3;
8243         }
8244         else if (aTrsfArg.StartsWith ("-scale"))
8245         {
8246           isTrsfSet = Standard_True;
8247           if (++aTrsfArgIter >= theArgNb)
8248           {
8249             Message::SendFail() << "Syntax error at " << aTrsfArg;
8250             return 1;
8251           }
8252
8253           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
8254           if (!aScaleStr.IsRealValue (Standard_True))
8255           {
8256             Message::SendFail() << "Syntax error at " << aTrsfArg;
8257             return 1;
8258           }
8259           aScales[anIndex] = aScaleStr.RealValue();
8260         }
8261         else
8262         {
8263           anArgIter = aTrsfArgIter - 1;
8264           break;
8265         }
8266       }
8267       if (!isTrsfSet)
8268       {
8269         Message::SendFail() << "Syntax error at " << anArg;
8270         return 1;
8271       }
8272       else if (aTrsfArgIter >= theArgNb)
8273       {
8274         anArgIter = theArgNb;
8275       }
8276
8277       aTrsfs[0].SetRotation        (aRotQuats[0]);
8278       aTrsfs[1].SetRotation        (aRotQuats[1]);
8279       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
8280       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
8281       aTrsfs[0].SetScaleFactor     (aScales[0]);
8282       aTrsfs[1].SetScaleFactor     (aScales[1]);
8283
8284       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
8285       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
8286     }
8287     else if (anArg == "-viewtrsf"
8288           || anArg == "-view")
8289     {
8290       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
8291       if (aCamAnimation.IsNull())
8292       {
8293         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
8294         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
8295       }
8296
8297       Handle(Graphic3d_Camera) aCams[2] =
8298       {
8299         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
8300         new Graphic3d_Camera (aCamAnimation->View()->Camera())
8301       };
8302
8303       Standard_Boolean isTrsfSet = Standard_False;
8304       Standard_Integer aViewArgIter = anArgIter + 1;
8305       for (; aViewArgIter < theArgNb; ++aViewArgIter)
8306       {
8307         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
8308         aViewArg.LowerCase();
8309         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
8310         if (aViewArg.StartsWith ("-scale"))
8311         {
8312           isTrsfSet = Standard_True;
8313           if (++aViewArgIter >= theArgNb)
8314           {
8315             Message::SendFail() << "Syntax error at " << anArg;
8316             return 1;
8317           }
8318
8319           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
8320           if (!aScaleStr.IsRealValue (Standard_True))
8321           {
8322             Message::SendFail() << "Syntax error at " << aViewArg;
8323             return 1;
8324           }
8325           Standard_Real aScale = aScaleStr.RealValue();
8326           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
8327           aCams[anIndex]->SetScale (aScale);
8328         }
8329         else if (aViewArg.StartsWith ("-eye")
8330               || aViewArg.StartsWith ("-center")
8331               || aViewArg.StartsWith ("-at")
8332               || aViewArg.StartsWith ("-up"))
8333         {
8334           isTrsfSet = Standard_True;
8335           gp_XYZ anXYZ;
8336           if (aViewArgIter + 3 >= theArgNb
8337           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
8338           {
8339             Message::SendFail() << "Syntax error at " << aViewArg;
8340             return 1;
8341           }
8342           aViewArgIter += 3;
8343
8344           if (aViewArg.StartsWith ("-eye"))
8345           {
8346             aCams[anIndex]->SetEye (anXYZ);
8347           }
8348           else if (aViewArg.StartsWith ("-center")
8349                 || aViewArg.StartsWith ("-at"))
8350           {
8351             aCams[anIndex]->SetCenter (anXYZ);
8352           }
8353           else if (aViewArg.StartsWith ("-up"))
8354           {
8355             aCams[anIndex]->SetUp (anXYZ);
8356           }
8357         }
8358         else
8359         {
8360           anArgIter = aViewArgIter - 1;
8361           break;
8362         }
8363       }
8364       if (!isTrsfSet)
8365       {
8366         Message::SendFail() << "Syntax error at " << anArg;
8367         return 1;
8368       }
8369       else if (aViewArgIter >= theArgNb)
8370       {
8371         anArgIter = theArgNb;
8372       }
8373
8374       aCamAnimation->SetCameraStart(aCams[0]);
8375       aCamAnimation->SetCameraEnd  (aCams[1]);
8376     }
8377     else
8378     {
8379       Message::SendFail() << "Syntax error at " << anArg;
8380       return 1;
8381     }
8382   }
8383
8384   ViewerTest::CurrentEventManager()->AbortViewAnimation();
8385   ViewerTest::CurrentEventManager()->SetObjectsAnimation (Handle(AIS_Animation)());
8386   if (!toPlay && aRecFile.IsEmpty())
8387   {
8388     return 0;
8389   }
8390
8391   // Start animation timeline and process frame updating.
8392   if (aRecParams.FpsNum <= 0
8393   && !isLockLoop)
8394   {
8395     Handle(ViewerTest_AnimationHolder) aHolder = new ViewerTest_AnimationHolder (anAnimation, aView, isFreeCamera);
8396     aHolder->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
8397     ViewerTest::CurrentEventManager()->SetPauseObjectsAnimation (toPauseOnClick);
8398     ViewerTest::CurrentEventManager()->SetObjectsAnimation (aHolder);
8399     ViewerTest::CurrentEventManager()->ProcessExpose();
8400     return 0;
8401   }
8402
8403   // Perform video recording
8404   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
8405   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
8406   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
8407
8408   OSD_Timer aPerfTimer;
8409   aPerfTimer.Start();
8410
8411   Handle(Image_VideoRecorder) aRecorder;
8412   ImageFlipper aFlipper;
8413   Handle(Draw_ProgressIndicator) aProgress;
8414   if (!aRecFile.IsEmpty())
8415   {
8416     if (aRecParams.Width  <= 0
8417      || aRecParams.Height <= 0)
8418     {
8419       aView->Window()->Size (aRecParams.Width, aRecParams.Height);
8420     }
8421
8422     aRecorder = new Image_VideoRecorder();
8423     if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
8424     {
8425       Message::SendFail ("Error: failed to open video file for recording");
8426       return 0;
8427     }
8428
8429     aProgress = new Draw_ProgressIndicator (theDI, 1);
8430   }
8431
8432   // Manage frame-rated animation here
8433   Standard_Real aPts = aPlayStartTime;
8434   int64_t aNbFrames = 0;
8435   Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
8436                             "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
8437   Standard_Integer aSecondsProgress = 0;
8438   for (; aPts <= anUpperPts && aPS.More();)
8439   {
8440     Standard_Real aRecPts = 0.0;
8441     if (aRecParams.FpsNum > 0)
8442     {
8443       aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
8444     }
8445     else
8446     {
8447       aRecPts = aPlaySpeed * aPerfTimer.ElapsedTime();
8448     }
8449
8450     aPts = aPlayStartTime + aRecPts;
8451     ++aNbFrames;
8452     if (!anAnimation->Update (aPts))
8453     {
8454       break;
8455     }
8456
8457     if (!aRecorder.IsNull())
8458     {
8459       V3d_ImageDumpOptions aDumpParams;
8460       aDumpParams.Width          = aRecParams.Width;
8461       aDumpParams.Height         = aRecParams.Height;
8462       aDumpParams.BufferType     = Graphic3d_BT_RGBA;
8463       aDumpParams.StereoOptions  = V3d_SDO_MONO;
8464       aDumpParams.ToAdjustAspect = Standard_True;
8465       if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
8466       {
8467         Message::SendFail ("Error: view dump is failed");
8468         return 0;
8469       }
8470       aFlipper.FlipY (aRecorder->ChangeFrame());
8471       if (!aRecorder->PushFrame())
8472       {
8473         return 0;
8474       }
8475     }
8476     else
8477     {
8478       aView->Redraw();
8479     }
8480
8481     while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
8482     {
8483       aPS.Next();
8484       ++aSecondsProgress;
8485     }
8486   }
8487
8488   aPerfTimer.Stop();
8489   anAnimation->Stop();
8490   const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
8491   theDI << "Average FPS: " << aRecFps << "\n"
8492         << "Nb. Frames: "  << Standard_Real(aNbFrames);
8493
8494   aView->Redraw();
8495   aView->SetImmediateUpdate (wasImmediateUpdate);
8496   return 0;
8497 }
8498
8499
8500 //=======================================================================
8501 //function : VChangeSelected
8502 //purpose  : Adds the shape to selection or remove one from it
8503 //=======================================================================
8504 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
8505                                 Standard_Integer argc,
8506                                 const char ** argv)
8507 {
8508   if(argc != 2)
8509   {
8510     di<<"Usage : " << argv[0] << " shape \n";
8511     return 1;
8512   }
8513   //get AIS_Shape:
8514   TCollection_AsciiString aName(argv[1]);
8515   Handle(AIS_InteractiveObject) anAISObject;
8516   if (!GetMapOfAIS().Find2 (aName, anAISObject)
8517     || anAISObject.IsNull())
8518   {
8519     di<<"Use 'vdisplay' before";
8520     return 1;
8521   }
8522
8523   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
8524   return 0;
8525 }
8526
8527 //=======================================================================
8528 //function : VNbSelected
8529 //purpose  : Returns number of selected objects
8530 //=======================================================================
8531 static Standard_Integer VNbSelected (Draw_Interpretor& di,
8532                                 Standard_Integer argc,
8533                                 const char ** argv)
8534 {
8535   if(argc != 1)
8536   {
8537     di << "Usage : " << argv[0] << "\n";
8538     return 1;
8539   }
8540   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8541   if(aContext.IsNull())
8542   {
8543     di << "use 'vinit' command before " << argv[0] << "\n";
8544     return 1;
8545   }
8546   di << aContext->NbSelected() << "\n";
8547   return 0;
8548 }
8549
8550 //=======================================================================
8551 //function : VSetViewSize
8552 //purpose  :
8553 //=======================================================================
8554 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
8555                                 Standard_Integer argc,
8556                                 const char ** argv)
8557 {
8558   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8559   if(aContext.IsNull())
8560   {
8561     di << "use 'vinit' command before " << argv[0] << "\n";
8562     return 1;
8563   }
8564   if(argc != 2)
8565   {
8566     di<<"Usage : " << argv[0] << " Size\n";
8567     return 1;
8568   }
8569   Standard_Real aSize = Draw::Atof (argv[1]);
8570   if (aSize <= 0.)
8571   {
8572     di<<"Bad Size value  : " << aSize << "\n";
8573     return 1;
8574   }
8575
8576   Handle(V3d_View) aView = ViewerTest::CurrentView();
8577   aView->SetSize(aSize);
8578   return 0;
8579 }
8580
8581 //=======================================================================
8582 //function : VMoveView
8583 //purpose  :
8584 //=======================================================================
8585 static Standard_Integer VMoveView (Draw_Interpretor& di,
8586                                 Standard_Integer argc,
8587                                 const char ** argv)
8588 {
8589   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8590   if(aContext.IsNull())
8591   {
8592     di << "use 'vinit' command before " << argv[0] << "\n";
8593     return 1;
8594   }
8595   if(argc < 4 || argc > 5)
8596   {
8597     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8598     return 1;
8599   }
8600   Standard_Real Dx = Draw::Atof (argv[1]);
8601   Standard_Real Dy = Draw::Atof (argv[2]);
8602   Standard_Real Dz = Draw::Atof (argv[3]);
8603   Standard_Boolean aStart = Standard_True;
8604   if (argc == 5)
8605   {
8606       aStart = (Draw::Atoi (argv[4]) > 0);
8607   }
8608
8609   Handle(V3d_View) aView = ViewerTest::CurrentView();
8610   aView->Move(Dx,Dy,Dz,aStart);
8611   return 0;
8612 }
8613
8614 //=======================================================================
8615 //function : VTranslateView
8616 //purpose  :
8617 //=======================================================================
8618 static Standard_Integer VTranslateView (Draw_Interpretor& di,
8619                                 Standard_Integer argc,
8620                                 const char ** argv)
8621 {
8622   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8623   if(aContext.IsNull())
8624   {
8625     di << "use 'vinit' command before " << argv[0] << "\n";
8626     return 1;
8627   }
8628   if(argc < 4 || argc > 5)
8629   {
8630     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8631     return 1;
8632   }
8633   Standard_Real Dx = Draw::Atof (argv[1]);
8634   Standard_Real Dy = Draw::Atof (argv[2]);
8635   Standard_Real Dz = Draw::Atof (argv[3]);
8636   Standard_Boolean aStart = Standard_True;
8637   if (argc == 5)
8638   {
8639       aStart = (Draw::Atoi (argv[4]) > 0);
8640   }
8641
8642   Handle(V3d_View) aView = ViewerTest::CurrentView();
8643   aView->Translate(Dx,Dy,Dz,aStart);
8644   return 0;
8645 }
8646
8647 //=======================================================================
8648 //function : VTurnView
8649 //purpose  :
8650 //=======================================================================
8651 static Standard_Integer VTurnView (Draw_Interpretor& di,
8652                                 Standard_Integer argc,
8653                                 const char ** argv)
8654 {
8655   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8656   if(aContext.IsNull()) {
8657     di << "use 'vinit' command before " << argv[0] << "\n";
8658     return 1;
8659   }
8660   if(argc < 4 || argc > 5){
8661     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
8662     return 1;
8663   }
8664   Standard_Real Ax = Draw::Atof (argv[1]);
8665   Standard_Real Ay = Draw::Atof (argv[2]);
8666   Standard_Real Az = Draw::Atof (argv[3]);
8667   Standard_Boolean aStart = Standard_True;
8668   if (argc == 5)
8669   {
8670       aStart = (Draw::Atoi (argv[4]) > 0);
8671   }
8672
8673   Handle(V3d_View) aView = ViewerTest::CurrentView();
8674   aView->Turn(Ax,Ay,Az,aStart);
8675   return 0;
8676 }
8677
8678 //==============================================================================
8679 //function : VTextureEnv
8680 //purpose  : ENables or disables environment mapping
8681 //==============================================================================
8682 class OCC_TextureEnv : public Graphic3d_TextureEnv
8683 {
8684 public:
8685   OCC_TextureEnv(const Standard_CString FileName);
8686   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
8687   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
8688                             const Standard_Boolean theModulateFlag,
8689                             const Graphic3d_TypeOfTextureFilter theFilter,
8690                             const Standard_ShortReal theXScale,
8691                             const Standard_ShortReal theYScale,
8692                             const Standard_ShortReal theXShift,
8693                             const Standard_ShortReal theYShift,
8694                             const Standard_ShortReal theAngle);
8695   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
8696 };
8697 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
8698
8699 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
8700   : Graphic3d_TextureEnv(theFileName)
8701 {
8702 }
8703
8704 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
8705   : Graphic3d_TextureEnv(theTexId)
8706 {
8707 }
8708
8709 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
8710                                           const Standard_Boolean theModulateFlag,
8711                                           const Graphic3d_TypeOfTextureFilter theFilter,
8712                                           const Standard_ShortReal theXScale,
8713                                           const Standard_ShortReal theYScale,
8714                                           const Standard_ShortReal theXShift,
8715                                           const Standard_ShortReal theYShift,
8716                                           const Standard_ShortReal theAngle)
8717 {
8718   myParams->SetRepeat     (theRepeatFlag);
8719   myParams->SetModulate   (theModulateFlag);
8720   myParams->SetFilter     (theFilter);
8721   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
8722   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
8723   myParams->SetRotation   (theAngle);
8724 }
8725
8726 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
8727 {
8728   // get the active view
8729   Handle(V3d_View) aView = ViewerTest::CurrentView();
8730   if (aView.IsNull())
8731   {
8732     Message::SendFail ("Error: no active viewer");
8733     return 1;
8734   }
8735
8736   // Checking the input arguments
8737   Standard_Boolean anEnableFlag = Standard_False;
8738   Standard_Boolean isOk         = theArgNb >= 2;
8739   if (isOk)
8740   {
8741     TCollection_AsciiString anEnableOpt(theArgVec[1]);
8742     anEnableFlag = anEnableOpt.IsEqual("on");
8743     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
8744   }
8745   if (anEnableFlag)
8746   {
8747     isOk = (theArgNb == 3 || theArgNb == 11);
8748     if (isOk)
8749     {
8750       TCollection_AsciiString aTextureOpt(theArgVec[2]);
8751       isOk = (!aTextureOpt.IsIntegerValue() ||
8752              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
8753
8754       if (isOk && theArgNb == 11)
8755       {
8756         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
8757                                 aModulateOpt(theArgVec[4]),
8758                                 aFilterOpt  (theArgVec[5]),
8759                                 aSScaleOpt  (theArgVec[6]),
8760                                 aTScaleOpt  (theArgVec[7]),
8761                                 aSTransOpt  (theArgVec[8]),
8762                                 aTTransOpt  (theArgVec[9]),
8763                                 anAngleOpt  (theArgVec[10]);
8764         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
8765                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
8766                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
8767                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
8768                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
8769                 anAngleOpt.IsRealValue (Standard_True));
8770       }
8771     }
8772   }
8773
8774   if (!isOk)
8775   {
8776     Message::SendFail() << "Usage:\n"
8777                         << theArgVec[0] << " off\n"
8778                         << 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]";
8779     return 1;
8780   }
8781
8782   if (anEnableFlag)
8783   {
8784     TCollection_AsciiString aTextureOpt(theArgVec[2]);
8785     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
8786                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
8787                                      new OCC_TextureEnv(theArgVec[2]);
8788
8789     if (theArgNb == 11)
8790     {
8791       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
8792       aTexEnv->SetTextureParameters(
8793         aRepeatOpt.  IsEqual("repeat"),
8794         aModulateOpt.IsEqual("modulate"),
8795         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
8796                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
8797                                                                            Graphic3d_TOTF_TRILINEAR,
8798         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
8799         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
8800         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
8801         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
8802         (Standard_ShortReal)Draw::Atof(theArgVec[10])
8803         );
8804     }
8805     aView->SetTextureEnv(aTexEnv);
8806   }
8807   else // Disabling environment mapping
8808   {
8809     Handle(Graphic3d_TextureEnv) aTexture;
8810     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
8811   }
8812
8813   aView->Redraw();
8814   return 0;
8815 }
8816
8817 namespace
8818 {
8819   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
8820
8821   //! Remove registered clipping plane from all views and objects.
8822   static void removePlane (MapOfPlanes& theRegPlanes,
8823                            const TCollection_AsciiString& theName)
8824   {
8825     Handle(Graphic3d_ClipPlane) aClipPlane;
8826     if (!theRegPlanes.Find (theName, aClipPlane))
8827     {
8828       Message::SendWarning ("Warning: no such plane");
8829       return;
8830     }
8831
8832     theRegPlanes.UnBind (theName);
8833     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
8834          anIObjIt.More(); anIObjIt.Next())
8835     {
8836       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
8837       aPrs->RemoveClipPlane (aClipPlane);
8838     }
8839
8840     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
8841          aViewIt.More(); aViewIt.Next())
8842     {
8843       const Handle(V3d_View)& aView = aViewIt.Key2();
8844       aView->RemoveClipPlane(aClipPlane);
8845     }
8846
8847     ViewerTest::RedrawAllViews();
8848   }
8849 }
8850
8851 //===============================================================================================
8852 //function : VClipPlane
8853 //purpose  :
8854 //===============================================================================================
8855 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
8856 {
8857   // use short-cut for created clip planes map of created (or "registered by name") clip planes
8858   static MapOfPlanes aRegPlanes;
8859
8860   if (theArgsNb < 2)
8861   {
8862     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
8863     {
8864       theDi << aPlaneIter.Key() << " ";
8865     }
8866     return 0;
8867   }
8868
8869   TCollection_AsciiString aCommand (theArgVec[1]);
8870   aCommand.LowerCase();
8871   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
8872   if (anActiveView.IsNull())
8873   {
8874     Message::SendFail ("Error: no active viewer");
8875     return 1;
8876   }
8877
8878   // print maximum number of planes for current viewer
8879   if (aCommand == "-maxplanes"
8880    || aCommand == "maxplanes")
8881   {
8882     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
8883           << " plane slots provided by driver.\n";
8884     return 0;
8885   }
8886
8887   // create / delete plane instance
8888   if (aCommand == "-create"
8889    || aCommand == "create"
8890    || aCommand == "-delete"
8891    || aCommand == "delete"
8892    || aCommand == "-clone"
8893    || aCommand == "clone")
8894   {
8895     if (theArgsNb < 3)
8896     {
8897       Message::SendFail ("Syntax error: plane name is required");
8898       return 1;
8899     }
8900
8901     Standard_Boolean toCreate = aCommand == "-create"
8902                              || aCommand == "create";
8903     Standard_Boolean toClone  = aCommand == "-clone"
8904                              || aCommand == "clone";
8905     Standard_Boolean toDelete = aCommand == "-delete"
8906                              || aCommand == "delete";
8907     TCollection_AsciiString aPlane (theArgVec[2]);
8908
8909     if (toCreate)
8910     {
8911       if (aRegPlanes.IsBound (aPlane))
8912       {
8913         std::cout << "Warning: existing plane has been overridden.\n";
8914         toDelete = true;
8915       }
8916       else
8917       {
8918         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8919         return 0;
8920       }
8921     }
8922     else if (toClone) // toClone
8923     {
8924       if (!aRegPlanes.IsBound (aPlane))
8925       {
8926         Message::SendFail ("Error: no such plane");
8927         return 1;
8928       }
8929       else if (theArgsNb < 4)
8930       {
8931         Message::SendFail ("Syntax error: enter name for new plane");
8932         return 1;
8933       }
8934
8935       TCollection_AsciiString aClone (theArgVec[3]);
8936       if (aRegPlanes.IsBound (aClone))
8937       {
8938         Message::SendFail ("Error: plane name is in use");
8939         return 1;
8940       }
8941
8942       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
8943
8944       aRegPlanes.Bind (aClone, aClipPlane->Clone());
8945       return 0;
8946     }
8947
8948     if (toDelete)
8949     {
8950       if (aPlane == "ALL"
8951        || aPlane == "all"
8952        || aPlane == "*")
8953       {
8954         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
8955         {
8956           aPlane = aPlaneIter.Key();
8957           removePlane (aRegPlanes, aPlane);
8958           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
8959         }
8960       }
8961       else
8962       {
8963         removePlane (aRegPlanes, aPlane);
8964       }
8965     }
8966
8967     if (toCreate)
8968     {
8969       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
8970     }
8971     return 0;
8972   }
8973
8974   // set / unset plane command
8975   if (aCommand == "set"
8976    || aCommand == "unset")
8977   {
8978     if (theArgsNb < 5)
8979     {
8980       Message::SendFail ("Syntax error: need more arguments");
8981       return 1;
8982     }
8983
8984     // redirect to new syntax
8985     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
8986     anArgVec.SetValue (1, theArgVec[0]);
8987     anArgVec.SetValue (2, theArgVec[2]);
8988     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
8989     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
8990     {
8991       anArgVec.SetValue (anIt, theArgVec[anIt]);
8992     }
8993
8994     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
8995   }
8996
8997   // change plane command
8998   TCollection_AsciiString aPlaneName;
8999   Handle(Graphic3d_ClipPlane) aClipPlane;
9000   Standard_Integer anArgIter = 0;
9001   if (aCommand == "-change"
9002    || aCommand == "change")
9003   {
9004     // old syntax support
9005     if (theArgsNb < 3)
9006     {
9007       Message::SendFail ("Syntax error: need more arguments");
9008       return 1;
9009     }
9010
9011     anArgIter  = 3;
9012     aPlaneName = theArgVec[2];
9013     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
9014     {
9015       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
9016       return 1;
9017     }
9018   }
9019   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
9020   {
9021     anArgIter  = 2;
9022     aPlaneName = theArgVec[1];
9023   }
9024   else
9025   {
9026     anArgIter  = 2;
9027     aPlaneName = theArgVec[1];
9028     aClipPlane = new Graphic3d_ClipPlane();
9029     aRegPlanes.Bind (aPlaneName, aClipPlane);
9030     theDi << "Created new plane " << aPlaneName << ".\n";
9031   }
9032
9033   if (theArgsNb - anArgIter < 1)
9034   {
9035     Message::SendFail ("Syntax error: need more arguments");
9036     return 1;
9037   }
9038
9039   for (; anArgIter < theArgsNb; ++anArgIter)
9040   {
9041     const char**     aChangeArgs   = theArgVec + anArgIter;
9042     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
9043     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
9044     aChangeArg.LowerCase();
9045
9046     Standard_Boolean toEnable = Standard_True;
9047     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
9048     {
9049       aClipPlane->SetOn (toEnable);
9050     }
9051     else if (aChangeArg.StartsWith ("-equation")
9052           || aChangeArg.StartsWith ("equation"))
9053     {
9054       if (aNbChangeArgs < 5)
9055       {
9056         Message::SendFail ("Syntax error: need more arguments");
9057         return 1;
9058       }
9059
9060       Standard_Integer aSubIndex = 1;
9061       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
9062       if (aPrefixLen < aChangeArg.Length())
9063       {
9064         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
9065         if (!aSubStr.IsIntegerValue()
9066           || aSubStr.IntegerValue() <= 0)
9067         {
9068           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9069           return 1;
9070         }
9071         aSubIndex = aSubStr.IntegerValue();
9072       }
9073
9074       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
9075       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
9076       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
9077       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
9078       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9079       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
9080       {
9081         if (aSubPln->ChainNextPlane().IsNull())
9082         {
9083           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9084         }
9085         aSubPln = aSubPln->ChainNextPlane();
9086       }
9087       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9088       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
9089       anArgIter += 4;
9090     }
9091     else if ((aChangeArg == "-boxinterior"
9092            || aChangeArg == "-boxint"
9093            || aChangeArg == "-box")
9094             && aNbChangeArgs >= 7)
9095     {
9096       Graphic3d_BndBox3d aBndBox;
9097       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
9098       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
9099       anArgIter += 6;
9100
9101       Standard_Integer aNbSubPlanes = 6;
9102       const Graphic3d_Vec3d aDirArray[6] =
9103       {
9104         Graphic3d_Vec3d (-1, 0, 0),
9105         Graphic3d_Vec3d ( 1, 0, 0),
9106         Graphic3d_Vec3d ( 0,-1, 0),
9107         Graphic3d_Vec3d ( 0, 1, 0),
9108         Graphic3d_Vec3d ( 0, 0,-1),
9109         Graphic3d_Vec3d ( 0, 0, 1),
9110       };
9111       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9112       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
9113       {
9114         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
9115         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
9116         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
9117         if (aSubPlaneIter + 1 == aNbSubPlanes)
9118         {
9119           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9120         }
9121         else
9122         {
9123           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9124         }
9125         aSubPln = aSubPln->ChainNextPlane();
9126       }
9127     }
9128     else if (aChangeArg == "-capping"
9129           || aChangeArg == "capping")
9130     {
9131       if (aNbChangeArgs < 2)
9132       {
9133         Message::SendFail ("Syntax error: need more arguments");
9134         return 1;
9135       }
9136
9137       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9138       {
9139         aClipPlane->SetCapping (toEnable);
9140         anArgIter += 1;
9141       }
9142       else
9143       {
9144         // just skip otherwise (old syntax)
9145       }
9146     }
9147     else if (aChangeArg == "-useobjectmaterial"
9148           || aChangeArg == "-useobjectmat"
9149           || aChangeArg == "-useobjmat"
9150           || aChangeArg == "-useobjmaterial")
9151     {
9152       if (aNbChangeArgs < 2)
9153       {
9154         Message::SendFail ("Syntax error: need more arguments");
9155         return 1;
9156       }
9157
9158       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9159       {
9160         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
9161         anArgIter += 1;
9162       }
9163     }
9164     else if (aChangeArg == "-useobjecttexture"
9165           || aChangeArg == "-useobjecttex"
9166           || aChangeArg == "-useobjtexture"
9167           || aChangeArg == "-useobjtex")
9168     {
9169       if (aNbChangeArgs < 2)
9170       {
9171         Message::SendFail ("Syntax error: need more arguments");
9172         return 1;
9173       }
9174
9175       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9176       {
9177         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
9178         anArgIter += 1;
9179       }
9180     }
9181     else if (aChangeArg == "-useobjectshader"
9182           || aChangeArg == "-useobjshader")
9183     {
9184       if (aNbChangeArgs < 2)
9185       {
9186         Message::SendFail ("Syntax error: need more arguments");
9187         return 1;
9188       }
9189
9190       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9191       {
9192         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
9193         anArgIter += 1;
9194       }
9195     }
9196     else if (aChangeArg == "-color"
9197           || aChangeArg == "color")
9198     {
9199       Quantity_Color aColor;
9200       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
9201                                                      aChangeArgs + 1,
9202                                                      aColor);
9203       if (aNbParsed == 0)
9204       {
9205         Message::SendFail ("Syntax error: need more arguments");
9206         return 1;
9207       }
9208       aClipPlane->SetCappingColor (aColor);
9209       anArgIter += aNbParsed;
9210     }
9211     else if (aNbChangeArgs >= 1
9212           && (aChangeArg == "-material"
9213            || aChangeArg == "material"))
9214     {
9215       ++anArgIter;
9216       Graphic3d_NameOfMaterial aMatName;
9217       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
9218       {
9219         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
9220         return 1;
9221       }
9222       aClipPlane->SetCappingMaterial (aMatName);
9223     }
9224     else if ((aChangeArg == "-transparency"
9225            || aChangeArg == "-transp")
9226           && aNbChangeArgs >= 2)
9227     {
9228       TCollection_AsciiString aValStr (aChangeArgs[1]);
9229       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
9230       if (aValStr.IsRealValue (Standard_True))
9231       {
9232         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
9233         aMat.SetTransparency ((float )aValStr.RealValue());
9234         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
9235         aClipPlane->SetCappingMaterial (aMat);
9236       }
9237       else
9238       {
9239         aValStr.LowerCase();
9240         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
9241         if (aValStr == "opaque")
9242         {
9243           aMode = Graphic3d_AlphaMode_Opaque;
9244         }
9245         else if (aValStr == "mask")
9246         {
9247           aMode = Graphic3d_AlphaMode_Mask;
9248         }
9249         else if (aValStr == "blend")
9250         {
9251           aMode = Graphic3d_AlphaMode_Blend;
9252         }
9253         else if (aValStr == "maskblend"
9254               || aValStr == "blendmask")
9255         {
9256           aMode = Graphic3d_AlphaMode_MaskBlend;
9257         }
9258         else if (aValStr == "blendauto")
9259         {
9260           aMode = Graphic3d_AlphaMode_BlendAuto;
9261         }
9262         else
9263         {
9264           Message::SendFail() << "Syntax error at '" << aValStr << "'";
9265           return 1;
9266         }
9267         anAspect->SetAlphaMode (aMode);
9268         aClipPlane->SetCappingAspect (anAspect);
9269       }
9270       anArgIter += 1;
9271     }
9272     else if (aChangeArg == "-texname"
9273           || aChangeArg == "texname")
9274     {
9275       if (aNbChangeArgs < 2)
9276       {
9277         Message::SendFail ("Syntax error: need more arguments");
9278         return 1;
9279       }
9280
9281       TCollection_AsciiString aTextureName (aChangeArgs[1]);
9282       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
9283       if (!aTexture->IsDone())
9284       {
9285         aClipPlane->SetCappingTexture (NULL);
9286       }
9287       else
9288       {
9289         aTexture->EnableModulate();
9290         aTexture->EnableRepeat();
9291         aClipPlane->SetCappingTexture (aTexture);
9292       }
9293       anArgIter += 1;
9294     }
9295     else if (aChangeArg == "-texscale"
9296           || aChangeArg == "texscale")
9297     {
9298       if (aClipPlane->CappingTexture().IsNull())
9299       {
9300         Message::SendFail ("Error: no texture is set");
9301         return 1;
9302       }
9303
9304       if (aNbChangeArgs < 3)
9305       {
9306         Message::SendFail ("Syntax error: need more arguments");
9307         return 1;
9308       }
9309
9310       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9311       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9312       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
9313       anArgIter += 2;
9314     }
9315     else if (aChangeArg == "-texorigin"
9316           || aChangeArg == "texorigin") // texture origin
9317     {
9318       if (aClipPlane->CappingTexture().IsNull())
9319       {
9320         Message::SendFail ("Error: no texture is set");
9321         return 1;
9322       }
9323
9324       if (aNbChangeArgs < 3)
9325       {
9326         Message::SendFail ("Syntax error: need more arguments");
9327         return 1;
9328       }
9329
9330       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9331       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9332
9333       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
9334       anArgIter += 2;
9335     }
9336     else if (aChangeArg == "-texrotate"
9337           || aChangeArg == "texrotate") // texture rotation
9338     {
9339       if (aClipPlane->CappingTexture().IsNull())
9340       {
9341         Message::SendFail ("Error: no texture is set");
9342         return 1;
9343       }
9344
9345       if (aNbChangeArgs < 2)
9346       {
9347         Message::SendFail ("Syntax error: need more arguments");
9348         return 1;
9349       }
9350
9351       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9352       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
9353       anArgIter += 1;
9354     }
9355     else if (aChangeArg == "-hatch"
9356           || aChangeArg == "hatch")
9357     {
9358       if (aNbChangeArgs < 2)
9359       {
9360         Message::SendFail ("Syntax error: need more arguments");
9361         return 1;
9362       }
9363
9364       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
9365       aHatchStr.LowerCase();
9366       if (aHatchStr == "on")
9367       {
9368         aClipPlane->SetCappingHatchOn();
9369       }
9370       else if (aHatchStr == "off")
9371       {
9372         aClipPlane->SetCappingHatchOff();
9373       }
9374       else
9375       {
9376         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
9377       }
9378       anArgIter += 1;
9379     }
9380     else if (aChangeArg == "-delete"
9381           || aChangeArg == "delete")
9382     {
9383       removePlane (aRegPlanes, aPlaneName);
9384       return 0;
9385     }
9386     else if (aChangeArg == "-set"
9387           || aChangeArg == "-unset"
9388           || aChangeArg == "-setoverrideglobal")
9389     {
9390       // set / unset plane command
9391       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
9392       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
9393       Standard_Integer anIt = 1;
9394       for (; anIt < aNbChangeArgs; ++anIt)
9395       {
9396         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
9397         if (anEntityName.IsEmpty()
9398          || anEntityName.Value (1) == '-')
9399         {
9400           break;
9401         }
9402         else if (!toOverrideGlobal
9403                && ViewerTest_myViews.IsBound1 (anEntityName))
9404         {
9405           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
9406           if (toSet)
9407           {
9408             aView->AddClipPlane (aClipPlane);
9409           }
9410           else
9411           {
9412             aView->RemoveClipPlane (aClipPlane);
9413           }
9414           continue;
9415         }
9416         else if (GetMapOfAIS().IsBound2 (anEntityName))
9417         {
9418           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
9419           if (toSet)
9420           {
9421             aIObj->AddClipPlane (aClipPlane);
9422           }
9423           else
9424           {
9425             aIObj->RemoveClipPlane (aClipPlane);
9426           }
9427           if (!aIObj->ClipPlanes().IsNull())
9428           {
9429             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
9430           }
9431         }
9432         else
9433         {
9434           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
9435           return 1;
9436         }
9437       }
9438
9439       if (anIt == 1)
9440       {
9441         // apply to active view
9442         if (toSet)
9443         {
9444           anActiveView->AddClipPlane (aClipPlane);
9445         }
9446         else
9447         {
9448           anActiveView->RemoveClipPlane (aClipPlane);
9449         }
9450       }
9451       else
9452       {
9453         anArgIter = anArgIter + anIt - 1;
9454       }
9455     }
9456     else
9457     {
9458       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9459       return 1;
9460     }
9461   }
9462
9463   ViewerTest::RedrawAllViews();
9464   return 0;
9465 }
9466
9467 //===============================================================================================
9468 //function : VZRange
9469 //purpose  :
9470 //===============================================================================================
9471 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9472 {
9473   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9474
9475   if (aCurrentView.IsNull())
9476   {
9477     Message::SendFail ("Error: no active viewer");
9478     return 1;
9479   }
9480
9481   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
9482
9483   if (theArgsNb < 2)
9484   {
9485     theDi << "ZNear: " << aCamera->ZNear() << "\n";
9486     theDi << "ZFar: " << aCamera->ZFar() << "\n";
9487     return 0;
9488   }
9489
9490   if (theArgsNb == 3)
9491   {
9492     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
9493     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
9494
9495     if (aNewZNear >= aNewZFar)
9496     {
9497       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
9498       return 1;
9499     }
9500
9501     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
9502     {
9503       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
9504       return 1;
9505     }
9506
9507     aCamera->SetZRange (aNewZNear, aNewZFar);
9508   }
9509   else
9510   {
9511     Message::SendFail ("Syntax error: wrong command arguments");
9512     return 1;
9513   }
9514
9515   aCurrentView->Redraw();
9516
9517   return 0;
9518 }
9519
9520 //===============================================================================================
9521 //function : VAutoZFit
9522 //purpose  :
9523 //===============================================================================================
9524 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9525 {
9526   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9527
9528   if (aCurrentView.IsNull())
9529   {
9530     Message::SendFail ("Error: no active viewer");
9531     return 1;
9532   }
9533
9534   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
9535
9536   if (theArgsNb > 3)
9537   {
9538     Message::SendFail ("Syntax error: wrong command arguments");
9539     return 1;
9540   }
9541
9542   if (theArgsNb < 2)
9543   {
9544     theDi << "Auto z-fit mode: \n"
9545           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
9546           << "Scale: " << aScale << "\n";
9547     return 0;
9548   }
9549
9550   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
9551
9552   if (theArgsNb >= 3)
9553   {
9554     aScale = Draw::Atoi (theArgVec[2]);
9555   }
9556
9557   aCurrentView->SetAutoZFitMode (isOn, aScale);
9558   aCurrentView->Redraw();
9559   return 0;
9560 }
9561
9562 //! Auxiliary function to print projection type
9563 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
9564 {
9565   switch (theProjType)
9566   {
9567     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
9568     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
9569     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
9570     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
9571     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
9572   }
9573   return "UNKNOWN";
9574 }
9575
9576 //===============================================================================================
9577 //function : VCamera
9578 //purpose  :
9579 //===============================================================================================
9580 static int VCamera (Draw_Interpretor& theDI,
9581                     Standard_Integer  theArgsNb,
9582                     const char**      theArgVec)
9583 {
9584   Handle(V3d_View) aView = ViewerTest::CurrentView();
9585   if (aView.IsNull())
9586   {
9587     Message::SendFail ("Error: no active viewer");
9588     return 1;
9589   }
9590
9591   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9592   if (theArgsNb < 2)
9593   {
9594     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
9595     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
9596     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
9597     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
9598     theDI << "Distance:   " << aCamera->Distance() << "\n";
9599     theDI << "IOD:        " << aCamera->IOD() << "\n";
9600     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
9601     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
9602     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
9603     theDI << "ZNear:      " << aCamera->ZNear() << "\n";
9604     theDI << "ZFar:       " << aCamera->ZFar() << "\n";
9605     return 0;
9606   }
9607
9608   TCollection_AsciiString aPrsName;
9609   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9610   {
9611     Standard_CString        anArg = theArgVec[anArgIter];
9612     TCollection_AsciiString anArgCase (anArg);
9613     anArgCase.LowerCase();
9614     if (anArgCase == "-proj"
9615      || anArgCase == "-projection"
9616      || anArgCase == "-projtype"
9617      || anArgCase == "-projectiontype")
9618     {
9619       theDI << projTypeName (aCamera->ProjectionType()) << " ";
9620     }
9621     else if (anArgCase == "-ortho"
9622           || anArgCase == "-orthographic")
9623     {
9624       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
9625     }
9626     else if (anArgCase == "-persp"
9627           || anArgCase == "-perspective"
9628           || anArgCase == "-perspmono"
9629           || anArgCase == "-perspectivemono"
9630           || anArgCase == "-mono")
9631     {
9632       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9633     }
9634     else if (anArgCase == "-stereo"
9635           || anArgCase == "-stereoscopic"
9636           || anArgCase == "-perspstereo"
9637           || anArgCase == "-perspectivestereo")
9638     {
9639       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9640     }
9641     else if (anArgCase == "-left"
9642           || anArgCase == "-lefteye"
9643           || anArgCase == "-monoleft"
9644           || anArgCase == "-monolefteye"
9645           || anArgCase == "-perpsleft"
9646           || anArgCase == "-perpslefteye")
9647     {
9648       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
9649     }
9650     else if (anArgCase == "-right"
9651           || anArgCase == "-righteye"
9652           || anArgCase == "-monoright"
9653           || anArgCase == "-monorighteye"
9654           || anArgCase == "-perpsright")
9655     {
9656       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
9657     }
9658     else if (anArgCase == "-dist"
9659           || anArgCase == "-distance")
9660     {
9661       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9662       if (anArgValue != NULL
9663       && *anArgValue != '-')
9664       {
9665         ++anArgIter;
9666         aCamera->SetDistance (Draw::Atof (anArgValue));
9667         continue;
9668       }
9669       theDI << aCamera->Distance() << " ";
9670     }
9671     else if (anArgCase == "-iod")
9672     {
9673       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9674       if (anArgValue != NULL
9675       && *anArgValue != '-')
9676       {
9677         ++anArgIter;
9678         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
9679         continue;
9680       }
9681       theDI << aCamera->IOD() << " ";
9682     }
9683     else if (anArgCase == "-iodtype")
9684     {
9685       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9686       TCollection_AsciiString anValueCase (anArgValue);
9687       anValueCase.LowerCase();
9688       if (anValueCase == "abs"
9689        || anValueCase == "absolute")
9690       {
9691         ++anArgIter;
9692         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
9693         continue;
9694       }
9695       else if (anValueCase == "rel"
9696             || anValueCase == "relative")
9697       {
9698         ++anArgIter;
9699         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
9700         continue;
9701       }
9702       else if (*anArgValue != '-')
9703       {
9704         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
9705         return 1;
9706       }
9707       switch (aCamera->GetIODType())
9708       {
9709         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
9710         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
9711       }
9712     }
9713     else if (anArgCase == "-zfocus")
9714     {
9715       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9716       if (anArgValue != NULL
9717       && *anArgValue != '-')
9718       {
9719         ++anArgIter;
9720         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
9721         continue;
9722       }
9723       theDI << aCamera->ZFocus() << " ";
9724     }
9725     else if (anArgCase == "-zfocustype")
9726     {
9727       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
9728       TCollection_AsciiString anValueCase (anArgValue);
9729       anValueCase.LowerCase();
9730       if (anValueCase == "abs"
9731        || anValueCase == "absolute")
9732       {
9733         ++anArgIter;
9734         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
9735         continue;
9736       }
9737       else if (anValueCase == "rel"
9738             || anValueCase == "relative")
9739       {
9740         ++anArgIter;
9741         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
9742         continue;
9743       }
9744       else if (*anArgValue != '-')
9745       {
9746         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
9747         return 1;
9748       }
9749       switch (aCamera->ZFocusType())
9750       {
9751         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
9752         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
9753       }
9754     }
9755     else if (anArgCase == "-lockzup"
9756           || anArgCase == "-turntable")
9757     {
9758       bool toLockUp = true;
9759       if (++anArgIter < theArgsNb
9760       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
9761       {
9762         --anArgIter;
9763       }
9764       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
9765     }
9766     else if (anArgCase == "-fov"
9767           || anArgCase == "-fovy"
9768           || anArgCase == "-fovx"
9769           || anArgCase == "-fov2d")
9770     {
9771       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9772       if (anArgValue != NULL
9773       && *anArgValue != '-')
9774       {
9775         ++anArgIter;
9776         if (anArgCase == "-fov2d")
9777         {
9778           aCamera->SetFOV2d (Draw::Atof (anArgValue));
9779         }
9780         else if (anArgCase == "-fovx")
9781         {
9782           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
9783         }
9784         else
9785         {
9786           aCamera->SetFOVy (Draw::Atof (anArgValue));
9787         }
9788         continue;
9789       }
9790       if (anArgCase == "-fov2d")
9791       {
9792         theDI << aCamera->FOV2d() << " ";
9793       }
9794       else if (anArgCase == "-fovx")
9795       {
9796         theDI << aCamera->FOVx() << " ";
9797       }
9798       else
9799       {
9800         theDI << aCamera->FOVy() << " ";
9801       }
9802     }
9803     else if (anArgIter + 1 < theArgsNb
9804           && anArgCase == "-xrpose")
9805     {
9806       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
9807       anXRArg.LowerCase();
9808       if (anXRArg == "base")
9809       {
9810         aCamera = aView->View()->BaseXRCamera();
9811       }
9812       else if (anXRArg == "head")
9813       {
9814         aCamera = aView->View()->PosedXRCamera();
9815       }
9816       else
9817       {
9818         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
9819         return 1;
9820       }
9821       if (aCamera.IsNull())
9822       {
9823         Message::SendFail() << "Error: undefined XR pose";
9824         return 0;
9825       }
9826       if (aView->AutoZFitMode())
9827       {
9828         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
9829         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
9830         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
9831       }
9832     }
9833     else if (aPrsName.IsEmpty()
9834          && !anArgCase.StartsWith ("-"))
9835     {
9836       aPrsName = anArg;
9837     }
9838     else
9839     {
9840       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
9841       return 1;
9842     }
9843   }
9844
9845   if (aPrsName.IsEmpty()
9846    || theArgsNb > 2)
9847   {
9848     aView->Redraw();
9849   }
9850
9851   if (!aPrsName.IsEmpty())
9852   {
9853     Handle(AIS_CameraFrustum) aCameraFrustum;
9854     if (GetMapOfAIS().IsBound2 (aPrsName))
9855     {
9856       // find existing object
9857       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
9858       if (aCameraFrustum.IsNull())
9859       {
9860         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
9861         return 1;
9862       }
9863     }
9864
9865     if (aCameraFrustum.IsNull())
9866     {
9867       aCameraFrustum = new AIS_CameraFrustum();
9868     }
9869     else
9870     {
9871       // not include displayed object of old camera frustum in the new one.
9872       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
9873       aView->ZFitAll();
9874     }
9875     aCameraFrustum->SetCameraFrustum (aCamera);
9876
9877     ViewerTest::Display (aPrsName, aCameraFrustum);
9878   }
9879
9880   return 0;
9881 }
9882
9883 //! Parse stereo output mode
9884 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
9885                                          Graphic3d_StereoMode& theMode)
9886 {
9887   TCollection_AsciiString aFlag (theArg);
9888   aFlag.LowerCase();
9889   if (aFlag == "quadbuffer")
9890   {
9891     theMode = Graphic3d_StereoMode_QuadBuffer;
9892   }
9893   else if (aFlag == "anaglyph")
9894   {
9895     theMode = Graphic3d_StereoMode_Anaglyph;
9896   }
9897   else if (aFlag == "row"
9898         || aFlag == "rowinterlaced")
9899   {
9900     theMode = Graphic3d_StereoMode_RowInterlaced;
9901   }
9902   else if (aFlag == "col"
9903         || aFlag == "colinterlaced"
9904         || aFlag == "columninterlaced")
9905   {
9906     theMode = Graphic3d_StereoMode_ColumnInterlaced;
9907   }
9908   else if (aFlag == "chess"
9909         || aFlag == "chessboard")
9910   {
9911     theMode = Graphic3d_StereoMode_ChessBoard;
9912   }
9913   else if (aFlag == "sbs"
9914         || aFlag == "sidebyside")
9915   {
9916     theMode = Graphic3d_StereoMode_SideBySide;
9917   }
9918   else if (aFlag == "ou"
9919         || aFlag == "overunder")
9920   {
9921     theMode = Graphic3d_StereoMode_OverUnder;
9922   }
9923   else if (aFlag == "pageflip"
9924         || aFlag == "softpageflip")
9925   {
9926     theMode = Graphic3d_StereoMode_SoftPageFlip;
9927   }
9928   else if (aFlag == "openvr"
9929         || aFlag == "vr")
9930   {
9931     theMode = Graphic3d_StereoMode_OpenVR;
9932   }
9933   else
9934   {
9935     return Standard_False;
9936   }
9937   return Standard_True;
9938 }
9939
9940 //! Parse anaglyph filter
9941 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
9942                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
9943 {
9944   TCollection_AsciiString aFlag (theArg);
9945   aFlag.LowerCase();
9946   if (aFlag == "redcyansimple")
9947   {
9948     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
9949   }
9950   else if (aFlag == "redcyan"
9951         || aFlag == "redcyanoptimized")
9952   {
9953     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
9954   }
9955   else if (aFlag == "yellowbluesimple")
9956   {
9957     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
9958   }
9959   else if (aFlag == "yellowblue"
9960         || aFlag == "yellowblueoptimized")
9961   {
9962     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
9963   }
9964   else if (aFlag == "greenmagenta"
9965         || aFlag == "greenmagentasimple")
9966   {
9967     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
9968   }
9969   else
9970   {
9971     return Standard_False;
9972   }
9973   return Standard_True;
9974 }
9975
9976 //==============================================================================
9977 //function : VStereo
9978 //purpose  :
9979 //==============================================================================
9980
9981 static int VStereo (Draw_Interpretor& theDI,
9982                     Standard_Integer  theArgNb,
9983                     const char**      theArgVec)
9984 {
9985   Handle(V3d_View) aView = ViewerTest::CurrentView();
9986   if (aView.IsNull())
9987   {
9988     Message::SendFail ("Error: no active viewer");
9989     return 0;
9990   }
9991
9992   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9993   Graphic3d_RenderingParams* aParams = &aView->ChangeRenderingParams();
9994   if (theArgNb < 2)
9995   {
9996     Standard_Boolean isActive = aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo;
9997     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
9998     if (isActive)
9999     {
10000       TCollection_AsciiString aMode;
10001       switch (aView->RenderingParams().StereoMode)
10002       {
10003         case Graphic3d_StereoMode_QuadBuffer       : aMode = "quadBuffer";       break;
10004         case Graphic3d_StereoMode_RowInterlaced    : aMode = "rowInterlaced";    break;
10005         case Graphic3d_StereoMode_ColumnInterlaced : aMode = "columnInterlaced"; break;
10006         case Graphic3d_StereoMode_ChessBoard       : aMode = "chessBoard";       break;
10007         case Graphic3d_StereoMode_SideBySide       : aMode = "sideBySide";       break;
10008         case Graphic3d_StereoMode_OverUnder        : aMode = "overUnder";        break;
10009         case Graphic3d_StereoMode_SoftPageFlip     : aMode = "softpageflip";     break;
10010         case Graphic3d_StereoMode_OpenVR           : aMode = "openVR";           break;
10011         case Graphic3d_StereoMode_Anaglyph  :
10012           aMode = "anaglyph";
10013           switch (aView->RenderingParams().AnaglyphFilter)
10014           {
10015             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
10016             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
10017             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
10018             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
10019             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
10020             default: break;
10021           }
10022         default: break;
10023       }
10024       theDI << "Mode " << aMode << "\n";
10025     }
10026     return 0;
10027   }
10028
10029   Graphic3d_StereoMode aMode = aParams->StereoMode;
10030   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10031   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10032   {
10033     Standard_CString        anArg = theArgVec[anArgIter];
10034     TCollection_AsciiString aFlag (anArg);
10035     aFlag.LowerCase();
10036     if (anUpdateTool.parseRedrawMode (aFlag))
10037     {
10038       continue;
10039     }
10040     else if (aFlag == "0"
10041           || aFlag == "off")
10042     {
10043       if (++anArgIter < theArgNb)
10044       {
10045         Message::SendFail ("Error: wrong number of arguments");
10046         return 1;
10047       }
10048
10049       if (aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
10050       {
10051         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10052       }
10053       return 0;
10054     }
10055     else if (aFlag == "1"
10056           || aFlag == "on")
10057     {
10058       if (++anArgIter < theArgNb)
10059       {
10060         Message::SendFail ("Error: wrong number of arguments");
10061         return 1;
10062       }
10063
10064       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10065       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
10066       {
10067         return 0;
10068       }
10069     }
10070     else if (aFlag == "-reverse"
10071           || aFlag == "-reversed"
10072           || aFlag == "-swap")
10073     {
10074       Standard_Boolean toEnable = Standard_True;
10075       if (++anArgIter < theArgNb
10076       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10077       {
10078         --anArgIter;
10079       }
10080       aParams->ToReverseStereo = toEnable;
10081     }
10082     else if (aFlag == "-noreverse"
10083           || aFlag == "-noswap")
10084     {
10085       Standard_Boolean toDisable = Standard_True;
10086       if (++anArgIter < theArgNb
10087       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
10088       {
10089         --anArgIter;
10090       }
10091       aParams->ToReverseStereo = !toDisable;
10092     }
10093     else if (aFlag == "-mode"
10094           || aFlag == "-stereomode")
10095     {
10096       if (++anArgIter >= theArgNb
10097       || !parseStereoMode (theArgVec[anArgIter], aMode))
10098       {
10099         Message::SendFail() << "Syntax error at '" << anArg << "'";
10100         return 1;
10101       }
10102
10103       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10104       {
10105         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
10106       }
10107     }
10108     else if (aFlag == "-anaglyph"
10109           || aFlag == "-anaglyphfilter")
10110     {
10111       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10112       if (++anArgIter >= theArgNb
10113       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
10114       {
10115         Message::SendFail() << "Syntax error at '" << anArg << "'";
10116         return 1;
10117       }
10118
10119       aMode = Graphic3d_StereoMode_Anaglyph;
10120       aParams->AnaglyphFilter = aFilter;
10121     }
10122     else if (parseStereoMode (anArg, aMode)) // short syntax
10123     {
10124       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10125       {
10126         Message::SendInfo() << "Warning: make sure to call 'vcaps -stereo 1' before creating a view";
10127       }
10128     }
10129     else if (anArgIter + 1 < theArgNb
10130           && aFlag == "-hmdfov2d")
10131     {
10132       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
10133       if (aParams->HmdFov2d < 10.0f
10134        || aParams->HmdFov2d > 180.0f)
10135       {
10136         Message::SendFail() << "Error: FOV is out of range";
10137         return 1;
10138       }
10139     }
10140     else if (aFlag == "-mirror"
10141           || aFlag == "-mirrorcomposer")
10142     {
10143       Standard_Boolean toEnable = Standard_True;
10144       if (++anArgIter < theArgNb
10145       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10146       {
10147         --anArgIter;
10148       }
10149       aParams->ToMirrorComposer = toEnable;
10150     }
10151     else if (anArgIter + 1 < theArgNb
10152           && (aFlag == "-unitfactor"
10153            || aFlag == "-unitscale"))
10154     {
10155       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
10156     }
10157     else
10158     {
10159       Message::SendFail() << "Syntax error at '" << anArg << "'";
10160       return 1;
10161     }
10162   }
10163
10164   aParams->StereoMode = aMode;
10165   aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10166   if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
10167   {
10168     // initiate implicit continuous rendering
10169     ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
10170   }
10171   return 0;
10172 }
10173
10174 //===============================================================================================
10175 //function : VDefaults
10176 //purpose  :
10177 //===============================================================================================
10178 static int VDefaults (Draw_Interpretor& theDi,
10179                       Standard_Integer  theArgsNb,
10180                       const char**      theArgVec)
10181 {
10182   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
10183   if (aCtx.IsNull())
10184   {
10185     Message::SendFail ("Error: no active viewer");
10186     return 1;
10187   }
10188
10189   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
10190   if (theArgsNb < 2)
10191   {
10192     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
10193     {
10194       theDi << "DeflType:           relative\n"
10195             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
10196     }
10197     else
10198     {
10199       theDi << "DeflType:           absolute\n"
10200             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
10201     }
10202     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
10203     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
10204     return 0;
10205   }
10206
10207   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
10208   {
10209     TCollection_AsciiString anArg (theArgVec[anArgIter]);
10210     anArg.UpperCase();
10211     if (anArg == "-ABSDEFL"
10212      || anArg == "-ABSOLUTEDEFLECTION"
10213      || anArg == "-DEFL"
10214      || anArg == "-DEFLECTION")
10215     {
10216       if (++anArgIter >= theArgsNb)
10217       {
10218         Message::SendFail() << "Syntax error at " << anArg;
10219         return 1;
10220       }
10221       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
10222       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
10223     }
10224     else if (anArg == "-RELDEFL"
10225           || anArg == "-RELATIVEDEFLECTION"
10226           || anArg == "-DEVCOEFF"
10227           || anArg == "-DEVIATIONCOEFF"
10228           || anArg == "-DEVIATIONCOEFFICIENT")
10229     {
10230       if (++anArgIter >= theArgsNb)
10231       {
10232         Message::SendFail() << "Syntax error at " << anArg;
10233         return 1;
10234       }
10235       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
10236       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
10237     }
10238     else if (anArg == "-ANGDEFL"
10239           || anArg == "-ANGULARDEFL"
10240           || anArg == "-ANGULARDEFLECTION")
10241     {
10242       if (++anArgIter >= theArgsNb)
10243       {
10244         Message::SendFail() << "Syntax error at " << anArg;
10245         return 1;
10246       }
10247       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
10248     }
10249     else if (anArg == "-AUTOTR"
10250           || anArg == "-AUTOTRIANG"
10251           || anArg == "-AUTOTRIANGULATION")
10252     {
10253       ++anArgIter;
10254       bool toTurnOn = true;
10255       if (anArgIter >= theArgsNb
10256       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
10257       {
10258         Message::SendFail() << "Syntax error at '" << anArg << "'";
10259         return 1;
10260       }
10261       aDefParams->SetAutoTriangulation (toTurnOn);
10262     }
10263     else
10264     {
10265       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
10266       return 1;
10267     }
10268   }
10269
10270   return 0;
10271 }
10272
10273 //! Parse light source type from string.
10274 static bool parseLightSourceType (const TCollection_AsciiString& theTypeName,
10275                                   Graphic3d_TypeOfLightSource& theType)
10276 {
10277   TCollection_AsciiString aType (theTypeName);
10278   aType.LowerCase();
10279   if (aType == "amb"
10280    || aType == "ambient"
10281    || aType == "amblight")
10282   {
10283     theType = Graphic3d_TypeOfLightSource_Ambient;
10284   }
10285   else if (aType == "directional"
10286         || aType == "dirlight")
10287   {
10288     theType = Graphic3d_TypeOfLightSource_Directional;
10289   }
10290   else if (aType == "spot"
10291         || aType == "spotlight")
10292   {
10293     theType = Graphic3d_TypeOfLightSource_Spot;
10294   }
10295   else if (aType == "poslight"
10296         || aType == "positional"
10297         || aType == "point"
10298         || aType == "pnt")
10299   {
10300     theType = Graphic3d_TypeOfLightSource_Positional;
10301   }
10302   else
10303   {
10304     return false;
10305   }
10306   return true;
10307 }
10308
10309 //! Find existing light by name or index.
10310 static Handle(V3d_Light) findLightSource (const TCollection_AsciiString& theName)
10311 {
10312   Handle(V3d_Light) aLight;
10313   Standard_Integer aLightIndex = -1;
10314   Draw::ParseInteger (theName.ToCString(), aLightIndex);
10315   Standard_Integer aLightIt = 0;
10316   Handle(V3d_View) aView = ViewerTest::CurrentView();
10317   for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
10318   {
10319     if (aLightIndex != -1)
10320     {
10321       if (aLightIt == aLightIndex)
10322       {
10323         return aLightIter.Value();
10324       }
10325     }
10326     else if (aLightIter.Value()->GetId() == theName
10327           || aLightIter.Value()->Name()  == theName)
10328     {
10329       if (!aLight.IsNull())
10330       {
10331         Message::SendWarning() << "Warning: ambiguous light name '" << theName << "'";
10332         break;
10333       }
10334       aLight = aLightIter.Value();
10335     }
10336   }
10337   return aLight;
10338 }
10339
10340 //===============================================================================================
10341 //function : VLight
10342 //purpose  :
10343 //===============================================================================================
10344 static int VLight (Draw_Interpretor& theDi,
10345                    Standard_Integer  theArgsNb,
10346                    const char**      theArgVec)
10347 {
10348   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
10349   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10350   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
10351   if (aView.IsNull()
10352    || aViewer.IsNull())
10353   {
10354     Message::SendFail ("Error: no active viewer");
10355     return 1;
10356   }
10357
10358   if (theArgsNb < 2)
10359   {
10360     // print lights info
10361     Standard_Integer aLightId = 0;
10362     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
10363     {
10364       Handle(V3d_Light) aLight = aLightIter.Value();
10365       const Quantity_Color aColor = aLight->Color();
10366       theDi << "Light #" << aLightId
10367             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
10368             << " [" << aLight->GetId() << "] "
10369             << (aLight->IsEnabled() ? "ON" : "OFF") << "\n";
10370       switch (aLight->Type())
10371       {
10372         case V3d_AMBIENT:
10373         {
10374           theDi << "  Type:       Ambient\n"
10375                 << "  Intensity:  " << aLight->Intensity() << "\n";
10376           break;
10377         }
10378         case V3d_DIRECTIONAL:
10379         {
10380           theDi << "  Type:       Directional\n"
10381                 << "  Intensity:  " << aLight->Intensity() << "\n"
10382                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
10383                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
10384                 << "  Smoothness: " << aLight->Smoothness() << "\n"
10385                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n";
10386           break;
10387         }
10388         case V3d_POSITIONAL:
10389         {
10390           theDi << "  Type:       Positional\n"
10391                 << "  Intensity:  " << aLight->Intensity() << "\n"
10392                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
10393                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
10394                 << "  Smoothness: " << aLight->Smoothness() << "\n"
10395                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
10396                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
10397                 << "  Range:      " << aLight->Range() << "\n";
10398           break;
10399         }
10400         case V3d_SPOT:
10401         {
10402           theDi << "  Type:       Spot\n"
10403                 << "  Intensity:  " << aLight->Intensity() << "\n"
10404                 << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n"
10405                 << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n"
10406                 << "  Position:   " << aLight->Position().X() << " " << aLight->Position().Y() << " " << aLight->Position().Z() << "\n"
10407                 << "  Direction:  " << aLight->PackedDirection().x() << " " << aLight->PackedDirection().y() << " " << aLight->PackedDirection().z() << "\n"
10408                 << "  Atten.:     " << aLight->ConstAttenuation() << " " << aLight->LinearAttenuation() << "\n"
10409                 << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n"
10410                 << "  Exponent:   " << aLight->Concentration() << "\n"
10411                 << "  Range:      " << aLight->Range() << "\n";
10412           break;
10413         }
10414         default:
10415         {
10416           theDi << "  Type:       UNKNOWN\n";
10417           break;
10418         }
10419       }
10420       theDi << "  Color:      " << aColor.Red() << " " << aColor.Green() << " " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
10421     }
10422   }
10423
10424   Handle(V3d_Light) aLightOld, aLightNew;
10425   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
10426   bool isGlobal = true;
10427   ViewerTest_AutoUpdater anUpdateTool (aCtx, aView);
10428   Handle(AIS_LightSource) aLightPrs;
10429   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
10430   {
10431     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
10432     TCollection_AsciiString anArgCase (anArg);
10433     anArgCase.LowerCase();
10434     if (anUpdateTool.parseRedrawMode (anArg))
10435     {
10436       continue;
10437     }
10438     else if (anArgCase == "-new"
10439           || anArgCase == "-add"
10440           || anArgCase == "-create"
10441           || anArgCase == "-type"
10442           || (anArgCase == "-reset"
10443           && !aLightNew.IsNull())
10444           || (anArgCase == "-defaults"
10445           && !aLightNew.IsNull())
10446           || anArgCase == "add"
10447           || anArgCase == "new"
10448           || anArgCase == "create")
10449     {
10450       Graphic3d_TypeOfLightSource aType = Graphic3d_TypeOfLightSource_Ambient;
10451       if (anArgCase == "-reset")
10452       {
10453         aType = aLightNew->Type();
10454       }
10455       else if (anArgIt + 1 >= theArgsNb
10456            || !parseLightSourceType (theArgVec[++anArgIt], aType))
10457       {
10458         theDi << "Syntax error at '" << theArgVec[anArgIt] << "'\n";
10459         return 1;
10460       }
10461
10462       TCollection_AsciiString aName;
10463       if (!aLightNew.IsNull())
10464       {
10465         aName = aLightNew->Name();
10466       }
10467       switch (aType)
10468       {
10469         case Graphic3d_TypeOfLightSource_Ambient:
10470         {
10471           aLightNew = new V3d_AmbientLight();
10472           break;
10473         }
10474         case Graphic3d_TypeOfLightSource_Directional:
10475         {
10476           aLightNew = new V3d_DirectionalLight();
10477           break;
10478         }
10479         case Graphic3d_TypeOfLightSource_Spot:
10480         {
10481           aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
10482           break;
10483         }
10484         case Graphic3d_TypeOfLightSource_Positional:
10485         {
10486           aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
10487           break;
10488         }
10489       }
10490
10491       if (anArgCase == "-type"
10492       && !aLightOld.IsNull())
10493       {
10494         aLightNew->CopyFrom (aLightOld);
10495       }
10496       aLightNew->SetName (aName);
10497     }
10498     else if ((anArgCase == "-layer"
10499            || anArgCase == "-zlayer")
10500           && anArgIt + 1 < theArgsNb)
10501     {
10502       if (!ViewerTest::ParseZLayer (theArgVec[++anArgIt], aLayer)
10503       ||  aLayer == Graphic3d_ZLayerId_UNKNOWN)
10504       {
10505         Message::SendFail() << "Error: wrong syntax at '" << theArgVec[anArgIt] << "'";
10506         return 1;
10507       }
10508     }
10509     else if (anArgCase == "-glob"
10510           || anArgCase == "-global"
10511           || anArgCase == "-loc"
10512           || anArgCase == "-local")
10513     {
10514       isGlobal = anArgCase.StartsWith ("-glob");
10515     }
10516     else if (anArgCase == "-def"
10517           || anArgCase == "-defaults"
10518           || anArgCase == "-reset")
10519     {
10520       aViewer->SetDefaultLights();
10521       aLightOld.Nullify();
10522       aLightNew.Nullify();
10523       aLightPrs.Nullify();
10524     }
10525     else if (anArgCase == "-clr"
10526           || anArgCase == "-clear"
10527           || anArgCase == "clear")
10528     {
10529       TColStd_SequenceOfInteger aLayers;
10530       aViewer->GetAllZLayers (aLayers);
10531       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10532       {
10533         if (aLayeriter.Value() == aLayer
10534          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10535         {
10536           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10537           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10538           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10539           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10540           {
10541             break;
10542           }
10543         }
10544       }
10545
10546       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10547       {
10548         ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
10549         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10550         {
10551           Handle(V3d_Light) aLight = aLightIter.Value();
10552           Handle(AIS_InteractiveObject) aPrsObject;
10553           GetMapOfAIS().Find2 (aLight->Name(), aPrsObject);
10554           if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10555           {
10556             aCtx->Remove (aLightSourceDel, false);
10557             aMap.UnBind1 (aLightSourceDel);
10558           }
10559           aViewer->DelLight (aLight);
10560           aLightIter = aView->ActiveLightIterator();
10561         }
10562       }
10563
10564       aLightOld.Nullify();
10565       aLightNew.Nullify();
10566       aLightPrs.Nullify();
10567     }
10568     else if (!aLightNew.IsNull()
10569           && (anArgCase == "-display"
10570            || anArgCase == "-disp"
10571            || anArgCase == "-presentation"
10572            || anArgCase == "-prs"))
10573     {
10574       TCollection_AsciiString aLightName = aLightNew->Name();
10575       if (anArgIt + 1 < theArgsNb
10576        && theArgVec[anArgIt + 1][0] != '-')
10577       {
10578         // old syntax
10579         aLightName = theArgVec[++anArgIt];
10580         if (aLightNew->Name() != aLightName)
10581         {
10582           if (Handle(V3d_Light) anOtherLight = findLightSource (aLightName))
10583           {
10584             theDi << "Syntax error: light with name '" << aLightName << "' is already defined";
10585             return 1;
10586           }
10587           aLightNew->SetName (aLightName);
10588         }
10589       }
10590       if (aLightName.IsEmpty())
10591       {
10592         Message::SendFail() << "Error: nameless light source cannot be displayed";
10593         return 1;
10594       }
10595       if (aLightPrs.IsNull())
10596       {
10597         aLightPrs = new AIS_LightSource (aLightNew);
10598       }
10599       theDi << aLightName << " ";
10600     }
10601     else if (!aLightNew.IsNull()
10602           && (anArgCase == "-disable"
10603            || anArgCase == "-disabled"
10604            || anArgCase == "-enable"
10605            || anArgCase == "-enabled"))
10606     {
10607       bool toEnable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10608       if (anArgCase == "-disable"
10609        || anArgCase == "-disabled")
10610       {
10611         toEnable = !toEnable;
10612       }
10613       aLightNew->SetEnabled (toEnable);
10614     }
10615     else if (!aLightNew.IsNull()
10616           && (anArgCase == "-color"
10617            || anArgCase == "-colour"
10618            || anArgCase == "color"))
10619     {
10620       Quantity_Color aColor;
10621       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
10622                                                      theArgVec + anArgIt + 1,
10623                                                      aColor);
10624       anArgIt += aNbParsed;
10625       if (aNbParsed == 0)
10626       {
10627         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10628         return 1;
10629       }
10630       aLightNew->SetColor (aColor);
10631     }
10632     else if (!aLightNew.IsNull()
10633           && (anArgCase == "-pos"
10634            || anArgCase == "-position"
10635            || anArgCase == "-prsposition"
10636            || anArgCase == "-prspos"
10637            || anArgCase == "pos"
10638            || anArgCase == "position")
10639           && (anArgIt + 3) < theArgsNb)
10640     {
10641       gp_XYZ aPosXYZ;
10642       if (!parseXYZ (theArgVec + anArgIt + 1, aPosXYZ))
10643       {
10644         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10645         return 1;
10646       }
10647
10648       anArgIt += 3;
10649       if (anArgCase == "-prsposition"
10650        || anArgCase == "-prspos")
10651       {
10652         aLightNew->SetDisplayPosition (aPosXYZ);
10653       }
10654       else
10655       {
10656         if (aLightNew->Type() != Graphic3d_TypeOfLightSource_Positional
10657          && aLightNew->Type() != Graphic3d_TypeOfLightSource_Spot)
10658         {
10659           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10660           return 1;
10661         }
10662
10663         aLightNew->SetPosition (aPosXYZ);
10664       }
10665     }
10666     else if (!aLightNew.IsNull()
10667           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional
10668            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10669           && (anArgCase == "-dir"
10670            || anArgCase == "-direction")
10671           && (anArgIt + 3) < theArgsNb)
10672     {
10673       gp_XYZ aDirXYZ;
10674       if (!parseXYZ (theArgVec + anArgIt + 1, aDirXYZ))
10675       {
10676         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10677         return 1;
10678       }
10679
10680       anArgIt += 3;
10681       aLightNew->SetDirection (gp_Dir (aDirXYZ));
10682     }
10683     else if (!aLightNew.IsNull()
10684           && (anArgCase == "-smoothangle"
10685            || anArgCase == "-smoothradius"
10686            || anArgCase == "-sm"
10687            || anArgCase == "-smoothness")
10688           && anArgIt + 1 < theArgsNb)
10689     {
10690       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10691       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10692       {
10693         aSmoothness = Standard_ShortReal(aSmoothness * M_PI / 180.0);
10694       }
10695       if (Abs (aSmoothness) <= ShortRealEpsilon())
10696       {
10697         aLightNew->SetIntensity (1.f);
10698       }
10699       else if (Abs (aLightNew->Smoothness()) <= ShortRealEpsilon())
10700       {
10701         aLightNew->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
10702       }
10703       else
10704       {
10705         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightNew->Smoothness());
10706         aLightNew->SetIntensity (aLightNew->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
10707       }
10708
10709       if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10710       {
10711         aLightNew->SetSmoothRadius (aSmoothness);
10712       }
10713       else if (aLightNew->Type() == Graphic3d_TypeOfLightSource_Directional)
10714       {
10715         aLightNew->SetSmoothAngle (aSmoothness);
10716       }
10717     }
10718     else if (!aLightNew.IsNull()
10719           && (anArgCase == "-int"
10720            || anArgCase == "-intensity")
10721           && anArgIt + 1 < theArgsNb)
10722     {
10723       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10724       aLightNew->SetIntensity (aIntensity);
10725     }
10726     else if (!aLightNew.IsNull()
10727           &&  aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10728           && (anArgCase == "-spotangle"
10729            || anArgCase == "-ang"
10730            || anArgCase == "-angle")
10731           && anArgIt + 1 < theArgsNb)
10732     {
10733       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10734       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
10735       aLightNew->SetAngle (anAngle);
10736     }
10737     else if (!aLightNew.IsNull()
10738           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10739            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10740           && (anArgCase == "-constatten"
10741            || anArgCase == "-constattenuation")
10742           && anArgIt + 1 < theArgsNb)
10743     {
10744       const Standard_ShortReal aConstAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10745       aLightNew->SetAttenuation (aConstAtten, aLightNew->LinearAttenuation());
10746     }
10747     else if (!aLightNew.IsNull()
10748           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional
10749            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot)
10750           && (anArgCase == "-linatten"
10751            || anArgCase == "-linearatten"
10752            || anArgCase == "-linearattenuation")
10753           && anArgIt + 1 < theArgsNb)
10754     {
10755       const Standard_ShortReal aLinAtten = (Standard_ShortReal )Atof (theArgVec[++anArgIt]);
10756       aLightNew->SetAttenuation (aLightNew->ConstAttenuation(), aLinAtten);
10757     }
10758     else if (!aLightNew.IsNull()
10759           && aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10760           && (anArgCase == "-spotexp"
10761            || anArgCase == "-spotexponent"
10762            || anArgCase == "-exp"
10763            || anArgCase == "-exponent")
10764           && anArgIt + 1 < theArgsNb)
10765     {
10766       aLightNew->SetConcentration ((Standard_ShortReal )Atof (theArgVec[++anArgIt]));
10767     }
10768     else if (!aLightNew.IsNull()
10769            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10770            && aLightNew->Type() != Graphic3d_TypeOfLightSource_Directional
10771            && anArgCase == "-range"
10772            && anArgIt + 1 < theArgsNb)
10773     {
10774       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[++anArgIt]));
10775       aLightNew->SetRange (aRange);
10776     }
10777     else if (!aLightNew.IsNull()
10778           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10779           && (anArgCase == "-head"
10780            || anArgCase == "-headlight"))
10781     {
10782       Standard_Boolean isHeadLight = Standard_True;
10783       if (anArgIt + 1 < theArgsNb
10784        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
10785       {
10786         ++anArgIt;
10787       }
10788       aLightNew->SetHeadlight (isHeadLight);
10789     }
10790     else if (!aLightNew.IsNull()
10791            && anArgCase == "-name"
10792            && anArgIt + 1 < theArgsNb)
10793     {
10794       const TCollection_AsciiString aName = theArgVec[++anArgIt];
10795       if (aLightNew->Name() == aName)
10796       {
10797         continue;
10798       }
10799
10800       if (Handle(V3d_Light) anOtherLight = findLightSource (aName))
10801       {
10802         theDi << "Syntax error: light with name '" << aName << "' is already defined";
10803         return 1;
10804       }
10805       aLightNew->SetName (aName);
10806     }
10807     else if (!aLightPrs.IsNull()
10808           && (anArgCase == "-showzoomable"
10809            || anArgCase == "-prszoomable"
10810            || anArgCase == "-zoomable"))
10811     {
10812       const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10813       aLightPrs->SetZoomable (isZoomable);
10814     }
10815     else if (!aLightPrs.IsNull()
10816          && (anArgCase == "-showdraggable"
10817           || anArgCase == "-prsdraggable"
10818           || anArgCase == "-draggable"))
10819     {
10820       const bool isDraggable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10821       aLightPrs->SetDraggable (isDraggable);
10822     }
10823     else if (!aLightPrs.IsNull()
10824           && (anArgCase == "-showname"
10825            || anArgCase == "-prsname"))
10826     {
10827       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10828       aLightPrs->SetDisplayName (toDisplay);
10829     }
10830     else if (!aLightPrs.IsNull()
10831           && (aLightNew->Type() == Graphic3d_TypeOfLightSource_Spot
10832            || aLightNew->Type() == Graphic3d_TypeOfLightSource_Positional)
10833           && (anArgCase == "-showrange"
10834            || anArgCase == "-prsrange"))
10835     {
10836       const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
10837       aLightPrs->SetDisplayRange (toDisplay);
10838     }
10839     else if (!aLightPrs.IsNull()
10840           && (anArgCase == "-showsize"
10841            || anArgCase == "-prssize")
10842           && anArgIt + 1 < theArgsNb)
10843     {
10844       Standard_Real aSize = 0.0;
10845       if (!Draw::ParseReal (theArgVec[++anArgIt], aSize)
10846        || aSize <= 0.0
10847        || aLightPrs.IsNull())
10848       {
10849         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10850         return 1;
10851       }
10852
10853       aLightPrs->SetSize (aSize);
10854     }
10855     else if (!aLightPrs.IsNull()
10856           && (anArgCase == "-dirarcsize"
10857            || anArgCase == "-arcsize"
10858            || anArgCase == "-arc")
10859           && anArgIt + 1 < theArgsNb)
10860     {
10861       Standard_Integer aSize = 0;
10862       if (!Draw::ParseInteger (theArgVec[anArgIt + 1], aSize)
10863        || aSize <= 0
10864        || aLightPrs->Light()->Type() != Graphic3d_TypeOfLightSource_Directional)
10865       {
10866         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10867         return 1;
10868       }
10869       ++anArgIt;
10870       aLightPrs->SetArcSize (aSize);
10871     }
10872     else if (!aLightNew.IsNull()
10873           && aLightNew->Type() != Graphic3d_TypeOfLightSource_Ambient
10874           && (anArgCase == "-castshadow"
10875            || anArgCase == "-castshadows"
10876            || anArgCase == "-shadows"))
10877     {
10878       bool toCastShadows = true;
10879       if (anArgIt + 1 < theArgsNb
10880        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
10881       {
10882         ++anArgIt;
10883       }
10884       aLightNew->SetCastShadows (toCastShadows);
10885     }
10886     else if (anArgCase == "-del"
10887           || anArgCase == "-delete"
10888           || anArgCase == "-remove"
10889           || anArgCase == "del"
10890           || anArgCase == "delete"
10891           || anArgCase == "remove")
10892     {
10893       if (aLightOld.IsNull())
10894       {
10895         if (!aLightNew.IsNull())
10896         {
10897           aLightNew.Nullify();
10898           continue;
10899         }
10900
10901         if (++anArgIt >= theArgsNb)
10902         {
10903           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10904           return 1;
10905         }
10906
10907         const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10908         aLightOld = findLightSource (anOldName);
10909         if (aLightOld.IsNull())
10910         {
10911           Message::SendWarning() << "Warning: light '" << anOldName << "' not found";
10912           continue;
10913         }
10914       }
10915
10916       aLightNew.Nullify();
10917       aLightPrs.Nullify();
10918     }
10919     else if (anArgCase == "-change"
10920           || anArgCase == "change")
10921     {
10922       // just skip old syntax
10923     }
10924     else if (aLightNew.IsNull()
10925          && !anArgCase.StartsWith ("-"))
10926     {
10927       if (!aLightNew.IsNull())
10928       {
10929         continue;
10930       }
10931
10932       const TCollection_AsciiString anOldName (theArgVec[anArgIt]);
10933       aLightOld = findLightSource (anOldName);
10934       if (!aLightOld.IsNull())
10935       {
10936         aLightNew = aLightOld;
10937
10938         Handle(AIS_InteractiveObject) aPrsObject;
10939         GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10940         aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsObject);
10941       }
10942       else
10943       {
10944         Standard_Integer aLightIndex = -1;
10945         Draw::ParseInteger (anOldName.ToCString(), aLightIndex);
10946         if (aLightIndex != -1)
10947         {
10948           Message::SendFail() << "Syntax error: light source with index '" << aLightIndex << "' is not found";
10949           return 1;
10950         }
10951
10952         aLightNew = new V3d_AmbientLight();
10953         aLightNew->SetName (anOldName);
10954       }
10955     }
10956     else
10957     {
10958       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
10959       return 1;
10960     }
10961   }
10962
10963   // delete old light source
10964   if (!aLightOld.IsNull()
10965     && aLightOld != aLightNew)
10966   {
10967     TColStd_SequenceOfInteger aLayers;
10968     aViewer->GetAllZLayers (aLayers);
10969     for (TColStd_SequenceOfInteger::Iterator aLayerIter (aLayers); aLayerIter.More(); aLayerIter.Next())
10970     {
10971       if (aLayerIter.Value() == aLayer
10972        || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10973       {
10974         Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerIter.Value());
10975         if (!aSettings.Lights().IsNull())
10976         {
10977           aSettings.Lights()->Remove (aLightOld);
10978           if (aSettings.Lights()->IsEmpty())
10979           {
10980             aSettings.SetLights (Handle(Graphic3d_LightSet)());
10981           }
10982         }
10983         aViewer->SetZLayerSettings (aLayerIter.Value(), aSettings);
10984         if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10985         {
10986           break;
10987         }
10988       }
10989     }
10990
10991     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10992     {
10993       Handle(AIS_InteractiveObject) aPrsObject;
10994       GetMapOfAIS().Find2 (aLightOld->Name(), aPrsObject);
10995       if (Handle(AIS_LightSource) aLightSourceDel = Handle(AIS_LightSource)::DownCast (aPrsObject))
10996       {
10997         aCtx->Remove (aLightSourceDel, false);
10998         GetMapOfAIS().UnBind1 (aLightSourceDel);
10999       }
11000       aViewer->DelLight (aLightOld);
11001     }
11002     aLightOld.Nullify();
11003   }
11004
11005   // add new light source
11006   if (!aLightNew.IsNull())
11007   {
11008     if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
11009     {
11010       aViewer->AddLight (aLightNew);
11011       if (isGlobal)
11012       {
11013         aViewer->SetLightOn (aLightNew);
11014       }
11015       else
11016       {
11017         aView->SetLightOn (aLightNew);
11018       }
11019     }
11020     else
11021     {
11022       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayer);
11023       if (aSettings.Lights().IsNull())
11024       {
11025         aSettings.SetLights (new Graphic3d_LightSet());
11026       }
11027       aSettings.Lights()->Add (aLightNew);
11028       aViewer->SetZLayerSettings (aLayer, aSettings);
11029     }
11030
11031     if (!aLightPrs.IsNull())
11032     {
11033       aLightPrs->SetLight (aLightNew);
11034       ViewerTest::Display (aLightNew->Name(), aLightPrs, false);
11035     }
11036   }
11037
11038   // manage presentations
11039   struct LightPrsSort
11040   {
11041     bool operator() (const Handle(AIS_LightSource)& theLeft,
11042                      const Handle(AIS_LightSource)& theRight)
11043     {
11044       return theLeft->Light()->GetId() < theRight->Light()->GetId();
11045     }
11046   };
11047
11048   AIS_ListOfInteractive aPrsList;
11049   aCtx->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
11050   if (!aPrsList.IsEmpty())
11051   {
11052     // update light source presentations
11053     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
11054     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
11055     {
11056       if (Handle(AIS_LightSource) aLightPrs2 = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
11057       {
11058         aLightPrsVec.push_back (aLightPrs2);
11059       }
11060     }
11061
11062     // sort objects by id as AIS_InteractiveContext stores them in unordered map
11063     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
11064
11065     Standard_Integer aTopStack = 0;
11066     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
11067     {
11068       Handle(AIS_LightSource) aLightPrs2 = *aPrsIter;
11069       if (!aLightPrs2->TransformPersistence().IsNull()
11070         && aLightPrs2->TransformPersistence()->IsTrihedronOr2d())
11071       {
11072         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs2->Size();
11073         aLightPrs2->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
11074         aTopStack += aPrsSize + aPrsSize / 2;
11075       }
11076       aCtx->Redisplay (aLightPrs2, false);
11077       aCtx->SetTransformPersistence (aLightPrs2, aLightPrs2->TransformPersistence());
11078     }
11079   }
11080   return 0;
11081 }
11082
11083 //===============================================================================================
11084 //function : VPBREnvironment
11085 //purpose  :
11086 //===============================================================================================
11087 static int VPBREnvironment (Draw_Interpretor&,
11088                             Standard_Integer theArgsNb,
11089                             const char**     theArgVec)
11090 {
11091   if (theArgsNb > 2)
11092   {
11093     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
11094     return 1;
11095   }
11096
11097   Handle(V3d_View) aView = ViewerTest::CurrentView();
11098   if (aView.IsNull())
11099   {
11100     Message::SendFail ("Error: no active viewer");
11101     return 1;
11102   }
11103
11104   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
11105   anArg.LowerCase();
11106
11107   if (anArg == "-generate"
11108    || anArg == "-gen")
11109   {
11110     aView->GeneratePBREnvironment (Standard_True);
11111   }
11112   else if (anArg == "-clear")
11113   {
11114     aView->ClearPBREnvironment (Standard_True);
11115   }
11116   else
11117   {
11118     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
11119     return 1;
11120   }
11121
11122   return 0;
11123 }
11124
11125 //! Read Graphic3d_RenderingParams::PerfCounters flag.
11126 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
11127                                             Standard_Boolean& theToReset,
11128                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
11129                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
11130 {
11131   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
11132   TCollection_AsciiString aVal = theValue;
11133   Standard_Boolean toReverse = Standard_False;
11134   if (aVal == "none")
11135   {
11136     theToReset = Standard_True;
11137     return Standard_True;
11138   }
11139   else if (aVal.StartsWith ("-"))
11140   {
11141     toReverse = Standard_True;
11142     aVal = aVal.SubString (2, aVal.Length());
11143   }
11144   else if (aVal.StartsWith ("no"))
11145   {
11146     toReverse = Standard_True;
11147     aVal = aVal.SubString (3, aVal.Length());
11148   }
11149   else if (aVal.StartsWith ("+"))
11150   {
11151     aVal = aVal.SubString (2, aVal.Length());
11152   }
11153   else
11154   {
11155     theToReset = Standard_True;
11156   }
11157
11158   if (     aVal == "fps"
11159         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11160   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
11161   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
11162   else if (aVal == "structs"
11163         || aVal == "structures"
11164         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
11165   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
11166   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
11167   else if (aVal == "tris"
11168         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
11169   else if (aVal == "pnts"
11170         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
11171   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
11172   else if (aVal == "mem"
11173         || aVal == "gpumem"
11174         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
11175   else if (aVal == "skipimmediate"
11176         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
11177   else if (aVal == "frametime"
11178         || aVal == "frametimers"
11179         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
11180   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
11181   else if (aVal == "extended"
11182         || aVal == "verbose"
11183         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
11184   else if (aVal == "full"
11185         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
11186   else
11187   {
11188     return Standard_False;
11189   }
11190
11191   if (toReverse)
11192   {
11193     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
11194   }
11195   else
11196   {
11197     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
11198   }
11199   return Standard_True;
11200 }
11201
11202 //! Read Graphic3d_RenderingParams::PerfCounters flags.
11203 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
11204                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
11205 {
11206   TCollection_AsciiString aValue = theValue;
11207   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
11208   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
11209   Standard_Boolean toReset = Standard_False;
11210   for (;;)
11211   {
11212     Standard_Integer aSplitPos = aValue.Search ("|");
11213     if (aSplitPos <= 0)
11214     {
11215       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
11216       {
11217         return Standard_False;
11218       }
11219       if (toReset)
11220       {
11221         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
11222       }
11223       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
11224       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
11225       return Standard_True;
11226     }
11227
11228     if (aSplitPos > 1)
11229     {
11230       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
11231       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
11232       {
11233         return Standard_False;
11234       }
11235     }
11236     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
11237   }
11238 }
11239
11240 //=======================================================================
11241 //function : VRenderParams
11242 //purpose  : Enables/disables rendering features
11243 //=======================================================================
11244
11245 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
11246                                        Standard_Integer  theArgNb,
11247                                        const char**      theArgVec)
11248 {
11249   Handle(V3d_View) aView = ViewerTest::CurrentView();
11250   if (aView.IsNull())
11251   {
11252     Message::SendFail ("Error: no active viewer");
11253     return 1;
11254   }
11255
11256   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
11257   TCollection_AsciiString aCmdName (theArgVec[0]);
11258   aCmdName.LowerCase();
11259   if (aCmdName == "vraytrace")
11260   {
11261     if (theArgNb == 1)
11262     {
11263       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
11264       return 0;
11265     }
11266     else if (theArgNb == 2)
11267     {
11268       TCollection_AsciiString aValue (theArgVec[1]);
11269       aValue.LowerCase();
11270       if (aValue == "on"
11271        || aValue == "1")
11272       {
11273         aParams.Method = Graphic3d_RM_RAYTRACING;
11274         aView->Redraw();
11275         return 0;
11276       }
11277       else if (aValue == "off"
11278             || aValue == "0")
11279       {
11280         aParams.Method = Graphic3d_RM_RASTERIZATION;
11281         aView->Redraw();
11282         return 0;
11283       }
11284       else
11285       {
11286         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
11287         return 1;
11288       }
11289     }
11290     else
11291     {
11292       Message::SendFail ("Syntax error: wrong number of arguments");
11293       return 1;
11294     }
11295   }
11296
11297   if (theArgNb < 2)
11298   {
11299     theDI << "renderMode:  ";
11300     switch (aParams.Method)
11301     {
11302       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11303       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
11304     }
11305     theDI << "\n";
11306     theDI << "transparency:  ";
11307     switch (aParams.TransparencyMethod)
11308     {
11309       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
11310       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
11311                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
11312       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
11313                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
11314     }
11315     theDI << "\n";
11316     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
11317     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
11318     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
11319     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
11320     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
11321     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
11322     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
11323     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
11324     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
11325     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
11326     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
11327     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
11328     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
11329     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
11330     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
11331     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
11332     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
11333     theDI << "shadingModel: ";
11334     switch (aView->ShadingModel())
11335     {
11336       case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
11337       case Graphic3d_TOSM_UNLIT:     theDI << "unlit";     break;
11338       case Graphic3d_TOSM_FACET:     theDI << "flat";      break;
11339       case Graphic3d_TOSM_VERTEX:    theDI << "gouraud";   break;
11340       case Graphic3d_TOSM_FRAGMENT:  theDI << "phong";     break;
11341       case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
11342       case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
11343     }
11344     theDI << "\n";
11345     {
11346       theDI << "perfCounters:";
11347       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
11348       {
11349         theDI << " fps";
11350       }
11351       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
11352       {
11353         theDI << " cpu";
11354       }
11355       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
11356       {
11357         theDI << " structs";
11358       }
11359       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
11360       {
11361         theDI << " groups";
11362       }
11363       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
11364       {
11365         theDI << " arrays";
11366       }
11367       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
11368       {
11369         theDI << " tris";
11370       }
11371       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
11372       {
11373         theDI << " lines";
11374       }
11375       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
11376       {
11377         theDI << " pnts";
11378       }
11379       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
11380       {
11381         theDI << " gpumem";
11382       }
11383       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
11384       {
11385         theDI << " frameTime";
11386       }
11387       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
11388       {
11389         theDI << " skipimmediate";
11390       }
11391       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
11392       {
11393         theDI << " none";
11394       }
11395       theDI << "\n";
11396     }
11397     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
11398     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
11399     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
11400                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
11401                                                                                                                     "noUpdate") << "\n";
11402     theDI << "\n";
11403     return 0;
11404   }
11405
11406   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
11407   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
11408   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11409   {
11410     Standard_CString        anArg (theArgVec[anArgIter]);
11411     TCollection_AsciiString aFlag (anArg);
11412     aFlag.LowerCase();
11413     if (anUpdateTool.parseRedrawMode (aFlag))
11414     {
11415       continue;
11416     }
11417     else if (aFlag == "-echo"
11418           || aFlag == "-print")
11419     {
11420       toPrint = Standard_True;
11421       anUpdateTool.Invalidate();
11422     }
11423     else if (aFlag == "-reset")
11424     {
11425       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
11426     }
11427     else if (aFlag == "-sync"
11428           && (anArgIter + 1 < theArgNb))
11429     {
11430       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
11431       aSyncFlag.LowerCase();
11432       if (aSyncFlag == "default"
11433        || aSyncFlag == "defaults"
11434        || aSyncFlag == "viewer")
11435       {
11436         toSyncDefaults = true;
11437       }
11438       else if (aSyncFlag == "allviews"
11439             || aSyncFlag == "views")
11440       {
11441         toSyncAllViews = true;
11442       }
11443       else
11444       {
11445         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
11446         return 1;
11447       }
11448     }
11449     else if (aFlag == "-mode"
11450           || aFlag == "-rendermode"
11451           || aFlag == "-render_mode")
11452     {
11453       if (toPrint)
11454       {
11455         switch (aParams.Method)
11456         {
11457           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11458           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
11459         }
11460         continue;
11461       }
11462       else
11463       {
11464         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11465         return 1;
11466       }
11467     }
11468     else if (aFlag == "-ray"
11469           || aFlag == "-raytrace")
11470     {
11471       if (toPrint)
11472       {
11473         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
11474         continue;
11475       }
11476
11477       bool isRayTrace = true;
11478       if (anArgIter + 1 < theArgNb
11479        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
11480       {
11481         ++anArgIter;
11482       }
11483       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
11484     }
11485     else if (aFlag == "-rast"
11486           || aFlag == "-raster"
11487           || aFlag == "-rasterization")
11488     {
11489       if (toPrint)
11490       {
11491         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
11492         continue;
11493       }
11494
11495       bool isRaster = true;
11496       if (anArgIter + 1 < theArgNb
11497        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
11498       {
11499         ++anArgIter;
11500       }
11501       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
11502     }
11503     else if (aFlag == "-msaa")
11504     {
11505       if (toPrint)
11506       {
11507         theDI << aParams.NbMsaaSamples << " ";
11508         continue;
11509       }
11510       else if (++anArgIter >= theArgNb)
11511       {
11512         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11513         return 1;
11514       }
11515
11516       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11517       if (aNbSamples < 0)
11518       {
11519         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11520         return 1;
11521       }
11522       else
11523       {
11524         aParams.NbMsaaSamples = aNbSamples;
11525       }
11526     }
11527     else if (aFlag == "-linefeather"
11528           || aFlag == "-edgefeather"
11529           || aFlag == "-feather")
11530     {
11531       if (toPrint)
11532       {
11533         theDI << " " << aParams.LineFeather << " ";
11534         continue;
11535       }
11536       else if (++anArgIter >= theArgNb)
11537       {
11538         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11539         return 1;
11540       }
11541
11542       TCollection_AsciiString aParam = theArgVec[anArgIter];
11543       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11544       if (aFeather <= 0.0f)
11545       {
11546         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
11547         return 1;
11548       }
11549       aParams.LineFeather = aFeather;
11550     }
11551     else if (aFlag == "-oit")
11552     {
11553       if (toPrint)
11554       {
11555         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
11556         {
11557           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
11558         }
11559         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
11560         {
11561           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
11562         }
11563         else
11564         {
11565           theDI << "off" << " ";
11566         }
11567         continue;
11568       }
11569       else if (++anArgIter >= theArgNb)
11570       {
11571         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11572         return 1;
11573       }
11574
11575       TCollection_AsciiString aParam = theArgVec[anArgIter];
11576       aParam.LowerCase();
11577       if (aParam == "peeling"
11578        || aParam == "peel")
11579       {
11580         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
11581         if (anArgIter + 1 < theArgNb
11582          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
11583         {
11584           ++anArgIter;
11585           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11586           if (aNbLayers < 2)
11587           {
11588             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
11589             return 1;
11590           }
11591           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
11592         }
11593       }
11594       else if (aParam == "weighted"
11595             || aParam == "weight")
11596       {
11597         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11598         if (anArgIter + 1 < theArgNb
11599          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
11600         {
11601           ++anArgIter;
11602           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
11603           if (aWeight < 0.f || aWeight > 1.f)
11604           {
11605             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11606             return 1;
11607           }
11608           aParams.OitDepthFactor = aWeight;
11609         }
11610       }
11611       else if (aParam.IsRealValue())
11612       {
11613         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11614         if (aWeight < 0.f || aWeight > 1.f)
11615         {
11616           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11617           return 1;
11618         }
11619
11620         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11621         aParams.OitDepthFactor     = aWeight;
11622       }
11623       else if (aParam == "off")
11624       {
11625         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
11626       }
11627       else
11628       {
11629         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11630         return 1;
11631       }
11632     }
11633     else if (aFlag == "-fonthinting"
11634           || aFlag == "-fonthint")
11635     {
11636       if (toPrint)
11637       {
11638         if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11639         {
11640           theDI << "normal" << " ";
11641         }
11642         else if ((aParams.FontHinting & Font_Hinting_Normal) != 0)
11643         {
11644           theDI << "light" << " ";
11645         }
11646         else
11647         {
11648           theDI << "off" << " ";
11649         }
11650         continue;
11651       }
11652       else if (anArgIter + 1 >= theArgNb)
11653       {
11654         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11655         return 1;
11656       }
11657
11658       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11659       aHintStyle.LowerCase();
11660       if (aHintStyle == "normal"
11661        || aHintStyle == "on"
11662        || aHintStyle == "1")
11663       {
11664         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11665         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Normal);
11666       }
11667       else if (aHintStyle == "light")
11668       {
11669         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11670         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_Light);
11671       }
11672       else if (aHintStyle == "no"
11673             || aHintStyle == "off"
11674             || aHintStyle == "0")
11675       {
11676         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Normal);
11677         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_Light);
11678       }
11679       else
11680       {
11681         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11682         return 1;
11683       }
11684     }
11685     else if (aFlag == "-fontautohinting"
11686           || aFlag == "-fontautohint")
11687     {
11688       if (toPrint)
11689       {
11690         if ((aParams.FontHinting & Font_Hinting_ForceAutohint) != 0)
11691         {
11692           theDI << "force" << " ";
11693         }
11694         else if ((aParams.FontHinting & Font_Hinting_NoAutohint) != 0)
11695         {
11696           theDI << "disallow" << " ";
11697         }
11698         else
11699         {
11700           theDI << "auto" << " ";
11701         }
11702         continue;
11703       }
11704       else if (anArgIter + 1 >= theArgNb)
11705       {
11706         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11707         return 1;
11708       }
11709
11710       TCollection_AsciiString aHintStyle (theArgVec[++anArgIter]);
11711       aHintStyle.LowerCase();
11712       if (aHintStyle == "force")
11713       {
11714         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11715         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_ForceAutohint);
11716       }
11717       else if (aHintStyle == "disallow"
11718             || aHintStyle == "no")
11719       {
11720         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11721         aParams.FontHinting = Font_Hinting(aParams.FontHinting | Font_Hinting_NoAutohint);
11722       }
11723       else if (aHintStyle == "auto")
11724       {
11725         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_ForceAutohint);
11726         aParams.FontHinting = Font_Hinting(aParams.FontHinting & ~Font_Hinting_NoAutohint);
11727       }
11728       else
11729       {
11730         theDI << "Syntax error at '" << theArgVec[anArgIter] << "'";
11731         return 1;
11732       }
11733     }
11734     else if (aFlag == "-depthprepass")
11735     {
11736       if (toPrint)
11737       {
11738         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11739         continue;
11740       }
11741       aParams.ToEnableDepthPrepass = Standard_True;
11742       if (anArgIter + 1 < theArgNb
11743        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11744       {
11745         ++anArgIter;
11746       }
11747     }
11748     else if (aFlag == "-samplealphatocoverage"
11749           || aFlag == "-alphatocoverage")
11750     {
11751       if (toPrint)
11752       {
11753         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11754         continue;
11755       }
11756       aParams.ToEnableAlphaToCoverage = Standard_True;
11757       if (anArgIter + 1 < theArgNb
11758        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11759       {
11760         ++anArgIter;
11761       }
11762     }
11763     else if (aFlag == "-rendscale"
11764           || aFlag == "-renderscale"
11765           || aFlag == "-renderresolutionscale")
11766     {
11767       if (toPrint)
11768       {
11769         theDI << aParams.RenderResolutionScale << " ";
11770         continue;
11771       }
11772       else if (++anArgIter >= theArgNb)
11773       {
11774         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11775         return 1;
11776       }
11777
11778       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11779       if (aScale < 0.01)
11780       {
11781         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11782         return 1;
11783       }
11784       else
11785       {
11786         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11787       }
11788     }
11789     else if (aFlag == "-raydepth"
11790           || aFlag == "-ray_depth")
11791     {
11792       if (toPrint)
11793       {
11794         theDI << aParams.RaytracingDepth << " ";
11795         continue;
11796       }
11797       else if (++anArgIter >= theArgNb)
11798       {
11799         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11800         return 1;
11801       }
11802
11803       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11804
11805       // We allow RaytracingDepth be more than 10 in case of GI enabled
11806       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11807       {
11808         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11809         return 1;
11810       }
11811       else
11812       {
11813         aParams.RaytracingDepth = aDepth;
11814       }
11815     }
11816     else if (aFlag == "-shad"
11817           || aFlag == "-shadows")
11818     {
11819       if (toPrint)
11820       {
11821         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11822         continue;
11823       }
11824
11825       Standard_Boolean toEnable = Standard_True;
11826       if (++anArgIter < theArgNb
11827       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11828       {
11829         --anArgIter;
11830       }
11831       aParams.IsShadowEnabled = toEnable;
11832     }
11833     else if (aFlag == "-shadowmapresolution"
11834           || aFlag == "-shadowmap")
11835     {
11836       if (toPrint)
11837       {
11838         theDI << aParams.ShadowMapResolution << " ";
11839         continue;
11840       }
11841       else if (++anArgIter >= theArgNb)
11842       {
11843         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11844         return 1;
11845       }
11846
11847       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
11848     }
11849     else if (aFlag == "-shadowmapbias")
11850     {
11851       if (toPrint)
11852       {
11853         theDI << aParams.ShadowMapBias << " ";
11854         continue;
11855       }
11856       else if (++anArgIter >= theArgNb)
11857       {
11858         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11859         return 1;
11860       }
11861
11862       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
11863     }
11864     else if (aFlag == "-refl"
11865           || aFlag == "-reflections")
11866     {
11867       if (toPrint)
11868       {
11869         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11870         continue;
11871       }
11872
11873       Standard_Boolean toEnable = Standard_True;
11874       if (++anArgIter < theArgNb
11875       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11876       {
11877         --anArgIter;
11878       }
11879       aParams.IsReflectionEnabled = toEnable;
11880     }
11881     else if (aFlag == "-fsaa")
11882     {
11883       if (toPrint)
11884       {
11885         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11886         continue;
11887       }
11888
11889       Standard_Boolean toEnable = Standard_True;
11890       if (++anArgIter < theArgNb
11891       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11892       {
11893         --anArgIter;
11894       }
11895       aParams.IsAntialiasingEnabled = toEnable;
11896     }
11897     else if (aFlag == "-gleam")
11898     {
11899       if (toPrint)
11900       {
11901         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11902         continue;
11903       }
11904
11905       Standard_Boolean toEnable = Standard_True;
11906       if (++anArgIter < theArgNb
11907       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11908       {
11909         --anArgIter;
11910       }
11911       aParams.IsTransparentShadowEnabled = toEnable;
11912     }
11913     else if (aFlag == "-gi")
11914     {
11915       if (toPrint)
11916       {
11917         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11918         continue;
11919       }
11920
11921       Standard_Boolean toEnable = Standard_True;
11922       if (++anArgIter < theArgNb
11923       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11924       {
11925         --anArgIter;
11926       }
11927       aParams.IsGlobalIlluminationEnabled = toEnable;
11928       if (!toEnable)
11929       {
11930         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11931       }
11932     }
11933     else if (aFlag == "-blockedrng"
11934           || aFlag == "-brng")
11935     {
11936       if (toPrint)
11937       {
11938         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
11939         continue;
11940       }
11941
11942       Standard_Boolean toEnable = Standard_True;
11943       if (++anArgIter < theArgNb
11944         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11945       {
11946         --anArgIter;
11947       }
11948       aParams.CoherentPathTracingMode = toEnable;
11949     }
11950     else if (aFlag == "-maxrad")
11951     {
11952       if (toPrint)
11953       {
11954         theDI << aParams.RadianceClampingValue << " ";
11955         continue;
11956       }
11957       else if (++anArgIter >= theArgNb)
11958       {
11959         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11960         return 1;
11961       }
11962
11963       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11964       if (!aMaxRadStr.IsRealValue (Standard_True))
11965       {
11966         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11967         return 1;
11968       }
11969
11970       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11971       if (aMaxRadiance <= 0.0)
11972       {
11973         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
11974         return 1;
11975       }
11976       else
11977       {
11978         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
11979       }
11980     }
11981     else if (aFlag == "-iss")
11982     {
11983       if (toPrint)
11984       {
11985         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
11986         continue;
11987       }
11988
11989       Standard_Boolean toEnable = Standard_True;
11990       if (++anArgIter < theArgNb
11991         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11992       {
11993         --anArgIter;
11994       }
11995       aParams.AdaptiveScreenSampling = toEnable;
11996     }
11997     else if (aFlag == "-issatomic")
11998     {
11999       if (toPrint)
12000       {
12001         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
12002         continue;
12003       }
12004
12005       Standard_Boolean toEnable = Standard_True;
12006       if (++anArgIter < theArgNb
12007       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12008       {
12009         --anArgIter;
12010       }
12011       aParams.AdaptiveScreenSamplingAtomic = toEnable;
12012     }
12013     else if (aFlag == "-issd")
12014     {
12015       if (toPrint)
12016       {
12017         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
12018         continue;
12019       }
12020
12021       Standard_Boolean toEnable = Standard_True;
12022       if (++anArgIter < theArgNb
12023         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12024       {
12025         --anArgIter;
12026       }
12027       aParams.ShowSamplingTiles = toEnable;
12028     }
12029     else if (aFlag == "-tilesize")
12030     {
12031       if (toPrint)
12032       {
12033         theDI << aParams.RayTracingTileSize << " ";
12034         continue;
12035       }
12036       else if (++anArgIter >= theArgNb)
12037       {
12038         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12039         return 1;
12040       }
12041
12042       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
12043       if (aTileSize < 1)
12044       {
12045         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
12046         return 1;
12047       }
12048       aParams.RayTracingTileSize = aTileSize;
12049     }
12050     else if (aFlag == "-nbtiles")
12051     {
12052       if (toPrint)
12053       {
12054         theDI << aParams.NbRayTracingTiles << " ";
12055         continue;
12056       }
12057       else if (++anArgIter >= theArgNb)
12058       {
12059         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12060         return 1;
12061       }
12062
12063       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
12064       if (aNbTiles < -1)
12065       {
12066         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
12067         return 1;
12068       }
12069       else if (aNbTiles > 0
12070             && (aNbTiles < 64
12071              || aNbTiles > 1024))
12072       {
12073         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
12074       }
12075       aParams.NbRayTracingTiles = aNbTiles;
12076     }
12077     else if (aFlag == "-env")
12078     {
12079       if (toPrint)
12080       {
12081         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
12082         continue;
12083       }
12084
12085       Standard_Boolean toEnable = Standard_True;
12086       if (++anArgIter < theArgNb
12087         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12088       {
12089         --anArgIter;
12090       }
12091       aParams.UseEnvironmentMapBackground = toEnable;
12092     }
12093     else if (aFlag == "-ignorenormalmap")
12094     {
12095       if (toPrint)
12096       {
12097         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
12098         continue;
12099       }
12100
12101       Standard_Boolean toEnable = Standard_True;
12102       if (++anArgIter < theArgNb
12103         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12104       {
12105         --anArgIter;
12106       }
12107       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
12108     }
12109     else if (aFlag == "-twoside")
12110     {
12111       if (toPrint)
12112       {
12113         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
12114         continue;
12115       }
12116
12117       Standard_Boolean toEnable = Standard_True;
12118       if (++anArgIter < theArgNb
12119         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12120       {
12121         --anArgIter;
12122       }
12123       aParams.TwoSidedBsdfModels = toEnable;
12124     }
12125     else if (aFlag == "-shademodel"
12126           || aFlag == "-shadingmodel"
12127           || aFlag == "-shading")
12128     {
12129       if (toPrint)
12130       {
12131         switch (aView->ShadingModel())
12132         {
12133           case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
12134           case Graphic3d_TOSM_UNLIT:     theDI << "unlit ";    break;
12135           case Graphic3d_TOSM_FACET:     theDI << "flat ";     break;
12136           case Graphic3d_TOSM_VERTEX:    theDI << "gouraud ";  break;
12137           case Graphic3d_TOSM_FRAGMENT:  theDI << "phong ";    break;
12138           case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
12139           case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
12140         }
12141         continue;
12142       }
12143
12144       if (++anArgIter >= theArgNb)
12145       {
12146         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12147       }
12148
12149       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TOSM_DEFAULT;
12150       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
12151        && aModel != Graphic3d_TOSM_DEFAULT)
12152       {
12153         aView->SetShadingModel (aModel);
12154       }
12155       else
12156       {
12157         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
12158         return 1;
12159       }
12160     }
12161     else if (aFlag == "-pbrenvpow2size"
12162           || aFlag == "-pbrenvp2s"
12163           || aFlag == "-pep2s")
12164     {
12165       if (++anArgIter >= theArgNb)
12166       {
12167         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12168         return 1;
12169       }
12170
12171       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
12172       if (aPbrEnvPow2Size < 1)
12173       {
12174         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
12175         return 1;
12176       }
12177       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
12178     }
12179     else if (aFlag == "-pbrenvspecmaplevelsnumber"
12180           || aFlag == "-pbrenvspecmapnblevels"
12181           || aFlag == "-pbrenvspecmaplevels"
12182           || aFlag == "-pbrenvsmln"
12183           || aFlag == "-pesmln")
12184     {
12185       if (++anArgIter >= theArgNb)
12186       {
12187         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12188         return 1;
12189       }
12190
12191       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
12192       if (aPbrEnvSpecMapNbLevels < 2)
12193       {
12194         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
12195         return 1;
12196       }
12197       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
12198     }
12199     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
12200           || aFlag == "-pbrenvbakingdiffsamples"
12201           || aFlag == "-pbrenvbdsn")
12202     {
12203       if (++anArgIter >= theArgNb)
12204       {
12205         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12206         return 1;
12207       }
12208
12209       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
12210       if (aPbrEnvBakingDiffNbSamples < 1)
12211       {
12212         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
12213         return 1;
12214       }
12215       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
12216     }
12217     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
12218           || aFlag == "-pbrenvbakingspecsamples"
12219           || aFlag == "-pbrenvbssn")
12220     {
12221     if (++anArgIter >= theArgNb)
12222     {
12223       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12224       return 1;
12225     }
12226
12227     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
12228     if (aPbrEnvBakingSpecNbSamples < 1)
12229     {
12230       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
12231       return 1;
12232     }
12233     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
12234     }
12235     else if (aFlag == "-pbrenvbakingprobability"
12236           || aFlag == "-pbrenvbp")
12237     {
12238       if (++anArgIter >= theArgNb)
12239       {
12240         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12241         return 1;
12242       }
12243       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
12244       if (aPbrEnvBakingProbability < 0.f
12245        || aPbrEnvBakingProbability > 1.f)
12246       {
12247         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
12248         return 1;
12249       }
12250       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
12251     }
12252     else if (aFlag == "-resolution")
12253     {
12254       if (++anArgIter >= theArgNb)
12255       {
12256         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12257         return 1;
12258       }
12259
12260       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
12261       if (aResolution.IsIntegerValue())
12262       {
12263         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
12264       }
12265       else
12266       {
12267         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
12268         return 1;
12269       }
12270     }
12271     else if (aFlag == "-rebuildglsl"
12272           || aFlag == "-rebuild")
12273     {
12274       if (toPrint)
12275       {
12276         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
12277         continue;
12278       }
12279
12280       Standard_Boolean toEnable = Standard_True;
12281       if (++anArgIter < theArgNb
12282           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12283       {
12284         --anArgIter;
12285       }
12286       aParams.RebuildRayTracingShaders = toEnable;
12287     }
12288     else if (aFlag == "-focal")
12289     {
12290       if (++anArgIter >= theArgNb)
12291       {
12292         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12293         return 1;
12294       }
12295
12296       TCollection_AsciiString aParam (theArgVec[anArgIter]);
12297       if (aParam.IsRealValue (Standard_True))
12298       {
12299         float aFocalDist = static_cast<float> (aParam.RealValue());
12300         if (aFocalDist < 0)
12301         {
12302           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12303           return 1;
12304         }
12305         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
12306       }
12307       else
12308       {
12309         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12310         return 1;
12311       }
12312     }
12313     else if (aFlag == "-aperture")
12314     {
12315       if (++anArgIter >= theArgNb)
12316       {
12317         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12318         return 1;
12319       }
12320
12321       TCollection_AsciiString aParam(theArgVec[anArgIter]);
12322       if (aParam.IsRealValue (Standard_True))
12323       {
12324         float aApertureSize = static_cast<float> (aParam.RealValue());
12325         if (aApertureSize < 0)
12326         {
12327           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12328           return 1;
12329         }
12330         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
12331       }
12332       else
12333       {
12334         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12335         return 1;
12336       }
12337     }
12338     else if (aFlag == "-exposure")
12339     {
12340       if (++anArgIter >= theArgNb)
12341       {
12342         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12343         return 1;
12344       }
12345
12346       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
12347       if (anExposure.IsRealValue (Standard_True))
12348       {
12349         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
12350       }
12351       else
12352       {
12353         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12354         return 1;
12355       }
12356     }
12357     else if (aFlag == "-whitepoint")
12358     {
12359       if (++anArgIter >= theArgNb)
12360       {
12361         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12362         return 1;
12363       }
12364
12365       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
12366       if (aWhitePoint.IsRealValue (Standard_True))
12367       {
12368         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
12369       }
12370       else
12371       {
12372         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12373         return 1;
12374       }
12375     }
12376     else if (aFlag == "-tonemapping")
12377     {
12378       if (++anArgIter >= theArgNb)
12379       {
12380         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12381         return 1;
12382       }
12383
12384       TCollection_AsciiString aMode (theArgVec[anArgIter]);
12385       aMode.LowerCase();
12386
12387       if (aMode == "disabled")
12388       {
12389         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
12390       }
12391       else if (aMode == "filmic")
12392       {
12393         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
12394       }
12395       else
12396       {
12397         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12398         return 1;
12399       }
12400     }
12401     else if (aFlag == "-performancestats"
12402           || aFlag == "-performancecounters"
12403           || aFlag == "-perfstats"
12404           || aFlag == "-perfcounters"
12405           || aFlag == "-stats")
12406     {
12407       if (++anArgIter >= theArgNb)
12408       {
12409         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12410         return 1;
12411       }
12412
12413       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
12414       aFlagsStr.LowerCase();
12415       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
12416       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
12417       {
12418         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12419         return 1;
12420       }
12421       aView->ChangeRenderingParams().CollectedStats = aFlags;
12422       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
12423     }
12424     else if (aFlag == "-perfupdateinterval"
12425           || aFlag == "-statsupdateinterval")
12426     {
12427       if (++anArgIter >= theArgNb)
12428       {
12429         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12430         return 1;
12431       }
12432       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12433     }
12434     else if (aFlag == "-perfchart"
12435           || aFlag == "-statschart")
12436     {
12437       if (++anArgIter >= theArgNb)
12438       {
12439         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12440         return 1;
12441       }
12442       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
12443     }
12444     else if (aFlag == "-perfchartmax"
12445           || aFlag == "-statschartmax")
12446     {
12447       if (++anArgIter >= theArgNb)
12448       {
12449         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12450         return 1;
12451       }
12452       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12453     }
12454     else if (aFlag == "-frustumculling"
12455           || aFlag == "-culling")
12456     {
12457       if (toPrint)
12458       {
12459         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
12460                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
12461                                                                                                    "noUpdate") << " ";
12462         continue;
12463       }
12464
12465       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
12466       if (++anArgIter < theArgNb)
12467       {
12468         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
12469         aStateStr.LowerCase();
12470         bool toEnable = true;
12471         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
12472         {
12473           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
12474         }
12475         else if (aStateStr == "noupdate"
12476               || aStateStr == "freeze")
12477         {
12478           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
12479         }
12480         else
12481         {
12482           --anArgIter;
12483         }
12484       }
12485       aParams.FrustumCullingState = aState;
12486     }
12487     else
12488     {
12489       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
12490       return 1;
12491     }
12492   }
12493
12494   // set current view parameters as defaults
12495   if (toSyncDefaults)
12496   {
12497     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
12498   }
12499   if (toSyncAllViews)
12500   {
12501     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
12502     {
12503       aViewIter.Value()->ChangeRenderingParams() = aParams;
12504     }
12505   }
12506   return 0;
12507 }
12508
12509 //=======================================================================
12510 //function : searchInfo
12511 //purpose  :
12512 //=======================================================================
12513 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12514                                            const TCollection_AsciiString&              theKey)
12515 {
12516   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12517   {
12518     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12519     {
12520       return anIter.Value();
12521     }
12522   }
12523   return TCollection_AsciiString();
12524 }
12525
12526 //=======================================================================
12527 //function : VStatProfiler
12528 //purpose  :
12529 //=======================================================================
12530 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12531                                        Standard_Integer  theArgNb,
12532                                        const char**      theArgVec)
12533 {
12534   Handle(V3d_View) aView = ViewerTest::CurrentView();
12535   if (aView.IsNull())
12536   {
12537     Message::SendFail ("Error: no active viewer");
12538     return 1;
12539   }
12540
12541   Standard_Boolean toRedraw = Standard_True;
12542   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12543   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12544   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12545   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12546   {
12547     Standard_CString        anArg (theArgVec[anArgIter]);
12548     TCollection_AsciiString aFlag (anArg);
12549     aFlag.LowerCase();
12550     if (aFlag == "-noredraw")
12551     {
12552       toRedraw = Standard_False;
12553     }
12554     else
12555     {
12556       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12557       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12558       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12559       else if (aFlag == "alllayers"
12560             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12561       else if (aFlag == "allstructs"
12562             || aFlag == "allstructures"
12563             || aFlag == "structs"
12564             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12565       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12566       else if (aFlag == "allarrays"
12567             || aFlag == "fillarrays"
12568             || aFlag == "linearrays"
12569             || aFlag == "pointarrays"
12570             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12571       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12572       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12573       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12574       else if (aFlag == "geommem"
12575             || aFlag == "texturemem"
12576             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12577       else if (aFlag == "elapsedframe"
12578             || aFlag == "cpuframeaverage"
12579             || aFlag == "cpupickingaverage"
12580             || aFlag == "cpucullingaverage"
12581             || aFlag == "cpudynaverage"
12582             || aFlag == "cpuframemax"
12583             || aFlag == "cpupickingmax"
12584             || aFlag == "cpucullingmax"
12585             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12586       else
12587       {
12588         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12589         continue;
12590       }
12591
12592       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12593     }
12594   }
12595
12596   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12597   {
12598     aView->ChangeRenderingParams().CollectedStats =
12599       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12600
12601     if (toRedraw)
12602     {
12603       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12604       aView->Redraw();
12605       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12606     }
12607
12608     TColStd_IndexedDataMapOfStringString aDict;
12609     aView->StatisticInformation (aDict);
12610
12611     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12612
12613     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12614     {
12615       Standard_CString        anArg(theArgVec[anArgIter]);
12616       TCollection_AsciiString aFlag(anArg);
12617       aFlag.LowerCase();
12618       if (aFlag == "fps")
12619       {
12620         theDI << searchInfo (aDict, "FPS") << " ";
12621       }
12622       else if (aFlag == "cpu")
12623       {
12624         theDI << searchInfo (aDict, "CPU FPS") << " ";
12625       }
12626       else if (aFlag == "alllayers")
12627       {
12628         theDI << searchInfo (aDict, "Layers") << " ";
12629       }
12630       else if (aFlag == "layers")
12631       {
12632         theDI << searchInfo (aDict, "Rendered layers") << " ";
12633       }
12634       else if (aFlag == "allstructs"
12635             || aFlag == "allstructures")
12636       {
12637         theDI << searchInfo (aDict, "Structs") << " ";
12638       }
12639       else if (aFlag == "structs"
12640             || aFlag == "structures")
12641       {
12642         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
12643         if (aRend.IsEmpty()) // all structures rendered
12644         {
12645           aRend = searchInfo (aDict, "Structs");
12646         }
12647         theDI << aRend << " ";
12648       }
12649       else if (aFlag == "groups")
12650       {
12651         theDI << searchInfo (aDict, "Rendered groups") << " ";
12652       }
12653       else if (aFlag == "allarrays")
12654       {
12655         theDI << searchInfo (aDict, "Rendered arrays") << " ";
12656       }
12657       else if (aFlag == "fillarrays")
12658       {
12659         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
12660       }
12661       else if (aFlag == "linearrays")
12662       {
12663         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
12664       }
12665       else if (aFlag == "pointarrays")
12666       {
12667         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
12668       }
12669       else if (aFlag == "textarrays")
12670       {
12671         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
12672       }
12673       else if (aFlag == "triangles")
12674       {
12675         theDI << searchInfo (aDict, "Rendered triangles") << " ";
12676       }
12677       else if (aFlag == "points")
12678       {
12679         theDI << searchInfo (aDict, "Rendered points") << " ";
12680       }
12681       else if (aFlag == "geommem")
12682       {
12683         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12684       }
12685       else if (aFlag == "texturemem")
12686       {
12687         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12688       }
12689       else if (aFlag == "framemem")
12690       {
12691         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12692       }
12693       else if (aFlag == "elapsedframe")
12694       {
12695         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12696       }
12697       else if (aFlag == "cpuframe_average")
12698       {
12699         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12700       }
12701       else if (aFlag == "cpupicking_average")
12702       {
12703         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12704       }
12705       else if (aFlag == "cpuculling_average")
12706       {
12707         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12708       }
12709       else if (aFlag == "cpudyn_average")
12710       {
12711         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12712       }
12713       else if (aFlag == "cpuframe_max")
12714       {
12715         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12716       }
12717       else if (aFlag == "cpupicking_max")
12718       {
12719         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12720       }
12721       else if (aFlag == "cpuculling_max")
12722       {
12723         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12724       }
12725       else if (aFlag == "cpudyn_max")
12726       {
12727         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12728       }
12729     }
12730   }
12731   else
12732   {
12733     if (toRedraw)
12734     {
12735       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12736       aView->Redraw();
12737       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12738     }
12739     theDI << "Statistic info:\n" << aView->StatisticInformation();
12740   }
12741   return 0;
12742 }
12743
12744 //=======================================================================
12745 //function : VXRotate
12746 //purpose  :
12747 //=======================================================================
12748 static Standard_Integer VXRotate (Draw_Interpretor& di,
12749                                    Standard_Integer argc,
12750                                    const char ** argv)
12751 {
12752   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12753   if (aContext.IsNull())
12754   {
12755     di << argv[0] << "ERROR : use 'vinit' command before \n";
12756     return 1;
12757   }
12758
12759   if (argc != 3)
12760   {
12761     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12762     return 1;
12763   }
12764
12765   TCollection_AsciiString aName (argv[1]);
12766   Standard_Real anAngle = Draw::Atof (argv[2]);
12767
12768   // find object
12769   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12770   Handle(AIS_InteractiveObject) anIObj;
12771   if (!aMap.Find2 (aName, anIObj))
12772   {
12773     di << "Use 'vdisplay' before\n";
12774     return 1;
12775   }
12776
12777   gp_Trsf aTransform;
12778   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12779   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12780
12781   aContext->SetLocation (anIObj, aTransform);
12782   aContext->UpdateCurrentViewer();
12783   return 0;
12784 }
12785
12786 namespace
12787 {
12788   //! Structure for setting AIS_Manipulator::SetPart() property.
12789   struct ManipAxisModeOnOff
12790   {
12791     Standard_Integer    Axis;
12792     AIS_ManipulatorMode Mode;
12793     Standard_Boolean    ToEnable;
12794
12795     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
12796   };
12797
12798   enum ManipAjustPosition
12799   {
12800     ManipAjustPosition_Off,
12801     ManipAjustPosition_Center,
12802     ManipAjustPosition_Location,
12803     ManipAjustPosition_ShapeLocation,
12804   };
12805 }
12806
12807 //===============================================================================================
12808 //function : VManipulator
12809 //purpose  :
12810 //===============================================================================================
12811 static int VManipulator (Draw_Interpretor& theDi,
12812                          Standard_Integer  theArgsNb,
12813                          const char**      theArgVec)
12814 {
12815   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12816   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12817   if (aCurrentView.IsNull()
12818    || aViewer.IsNull())
12819   {
12820     Message::SendFail ("Error: no active viewer");
12821     return 1;
12822   }
12823
12824   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12825   Standard_Integer anArgIter = 1;
12826   Handle(AIS_Manipulator) aManipulator;
12827   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12828   TCollection_AsciiString aName;
12829   // parameters
12830   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
12831   Standard_Real aGap = -1.0, aSize = -1.0;
12832   NCollection_Sequence<ManipAxisModeOnOff> aParts;
12833   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
12834   //
12835   bool toDetach = false;
12836   AIS_Manipulator::OptionsForAttach anAttachOptions;
12837   Handle(AIS_InteractiveObject) anAttachObject;
12838   Handle(V3d_View) aViewAffinity;
12839   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
12840   //
12841   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
12842   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
12843   Standard_Integer toStopMouseTransform = -1;
12844   // explicit transformation
12845   gp_Trsf aTrsf;
12846   gp_XYZ aTmpXYZ;
12847   Standard_Real aTmpReal = 0.0;
12848   gp_XYZ aRotPnt, aRotAxis;
12849   for (; anArgIter < theArgsNb; ++anArgIter)
12850   {
12851     TCollection_AsciiString anArg (theArgVec[anArgIter]);
12852     anArg.LowerCase();
12853     if (anUpdateTool.parseRedrawMode (anArg))
12854     {
12855       continue;
12856     }
12857     else if (anArg == "-help")
12858     {
12859       theDi.PrintHelp (theArgVec[0]);
12860       return 0;
12861     }
12862     //
12863     else if (anArg == "-autoactivate"
12864           || anArg == "-noautoactivate")
12865     {
12866       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12867     }
12868     else if (anArg == "-followtranslation"
12869           || anArg == "-nofollowtranslation")
12870     {
12871       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12872     }
12873     else if (anArg == "-followrotation"
12874           || anArg == "-nofollowrotation")
12875     {
12876       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12877     }
12878     else if (anArg == "-followdragging"
12879           || anArg == "-nofollowdragging")
12880     {
12881       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12882     }
12883     else if (anArg == "-gap"
12884           && anArgIter + 1 < theArgsNb
12885           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
12886           && aGap >= 0.0)
12887     {
12888       ++anArgIter;
12889     }
12890     else if (anArg == "-size"
12891           && anArgIter + 1 < theArgsNb
12892           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
12893           && aSize > 0.0)
12894     {
12895       ++anArgIter;
12896     }
12897     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
12898           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
12899     {
12900       ManipAxisModeOnOff aPart;
12901       Standard_Integer aMode = 0;
12902       if (anArg == "-part")
12903       {
12904         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
12905           || aPart.Axis < 0 || aPart.Axis > 3)
12906         {
12907           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
12908           return 1;
12909         }
12910       }
12911       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
12912         || aMode < 1 || aMode > 4)
12913       {
12914         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
12915         return 1;
12916       }
12917       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
12918       {
12919         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
12920         return 1;
12921       }
12922       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
12923       aParts.Append (aPart);
12924     }
12925     else if (anArg == "-pos"
12926           && anArgIter + 3 < theArgsNb
12927           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
12928     {
12929       anArgIter += 3;
12930       if (anArgIter + 3 < theArgsNb
12931        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
12932        && aVDir.Modulus() > Precision::Confusion())
12933       {
12934         anArgIter += 3;
12935       }
12936       if (anArgIter + 3 < theArgsNb
12937        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
12938        && anXDir.Modulus() > Precision::Confusion())
12939       {
12940         anArgIter += 3;
12941       }
12942     }
12943     else if (anArg == "-zoomable"
12944           || anArg == "-notzoomable")
12945     {
12946       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
12947     }
12948     //
12949     else if (anArg == "-adjustposition"
12950           || anArg == "-noadjustposition")
12951     {
12952       anAttachPos = ManipAjustPosition_Center;
12953       if (anArgIter + 1 < theArgsNb)
12954       {
12955         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
12956         aPosName.LowerCase();
12957         if (aPosName == "0")
12958         {
12959           anAttachPos = ManipAjustPosition_Off;
12960         }
12961         else if (aPosName == "1"
12962               || aPosName == "center")
12963         {
12964           anAttachPos = ManipAjustPosition_Center;
12965         }
12966         else if (aPosName == "transformation"
12967               || aPosName == "trsf"
12968               || aPosName == "location"
12969               || aPosName == "loc")
12970         {
12971           anAttachPos = ManipAjustPosition_Location;
12972         }
12973         else if (aPosName == "shapelocation"
12974               || aPosName == "shapeloc")
12975         {
12976           anAttachPos = ManipAjustPosition_ShapeLocation;
12977         }
12978         else
12979         {
12980           --anArgIter;
12981         }
12982       }
12983       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
12984     }
12985     else if (anArg == "-adjustsize"
12986           || anArg == "-noadjustsize")
12987     {
12988       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12989     }
12990     else if (anArg == "-enablemodes"
12991           || anArg == "-enablemodes")
12992     {
12993       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
12994     }
12995     //
12996     else if (anArg == "-starttransform"
12997           && anArgIter + 2 < theArgsNb
12998           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
12999           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
13000     {
13001       anArgIter += 2;
13002     }
13003     else if (anArg == "-transform"
13004           && anArgIter + 2 < theArgsNb
13005           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
13006           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
13007     {
13008       anArgIter += 2;
13009     }
13010     else if (anArg == "-stoptransform")
13011     {
13012       toStopMouseTransform = 1;
13013       if (anArgIter + 1 < theArgsNb
13014        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
13015       {
13016         ++anArgIter;
13017         toStopMouseTransform = 0;
13018       }
13019     }
13020     //
13021     else if (anArg == "-move"
13022           && anArgIter + 3 < theArgsNb
13023           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
13024     {
13025       anArgIter += 3;
13026       aTrsf.SetTranslationPart (aTmpXYZ);
13027     }
13028     else if (anArg == "-scale"
13029           && anArgIter + 1 < theArgsNb
13030           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
13031     {
13032       ++anArgIter;
13033       aTrsf.SetScale (gp_Pnt(), aTmpReal);
13034     }
13035     else if (anArg == "-rotate"
13036           && anArgIter + 7 < theArgsNb
13037           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
13038           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
13039           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
13040     {
13041       anArgIter += 7;
13042       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
13043     }
13044     //
13045     else if (anArg == "-detach")
13046     {
13047       toDetach = true;
13048     }
13049     else if (anArg == "-attach"
13050           && anArgIter + 1 < theArgsNb)
13051     {
13052       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
13053       if (!aMapAIS.Find2 (anObjName, anAttachObject))
13054       {
13055         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
13056         return 1;
13057       }
13058
13059       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
13060       {
13061         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
13062         if (!aManip.IsNull()
13063           && aManip->IsAttached()
13064           && aManip->Object() == anAttachObject)
13065         {
13066           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
13067           return 1;
13068         }
13069       }
13070     }
13071     else if (anArg == "-view"
13072           && anArgIter + 1 < theArgsNb
13073           && aViewAffinity.IsNull())
13074     {
13075       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
13076       if (aViewString == "active")
13077       {
13078         aViewAffinity = ViewerTest::CurrentView();
13079       }
13080       else // Check view name
13081       {
13082         ViewerTest_Names aViewNames (aViewString);
13083         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
13084         {
13085           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
13086           return 1;
13087         }
13088         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
13089         if (aViewAffinity.IsNull())
13090         {
13091           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
13092           return 1;
13093         }
13094       }
13095     }
13096     else if (aName.IsEmpty())
13097     {
13098       aName = theArgVec[anArgIter];
13099       if (!aMapAIS.IsBound2 (aName))
13100       {
13101         aManipulator = new AIS_Manipulator();
13102         aManipulator->SetModeActivationOnDetection (true);
13103         aMapAIS.Bind (aManipulator, aName);
13104       }
13105       else
13106       {
13107         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
13108         if (aManipulator.IsNull())
13109         {
13110           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
13111           return 1;
13112         }
13113       }
13114     }
13115     else
13116     {
13117       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13118     }
13119   }
13120
13121   if (aName.IsEmpty())
13122   {
13123     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
13124     return 1;
13125   }
13126   if (!toDetach
13127     && aManipulator.IsNull())
13128   {
13129     aManipulator = new AIS_Manipulator();
13130     aManipulator->SetModeActivationOnDetection (true);
13131     aMapAIS.Bind (aManipulator, aName);
13132   }
13133
13134   // -----------------------------------------
13135   // change properties of manipulator instance
13136   // -----------------------------------------
13137
13138   if (toAutoActivate != -1)
13139   {
13140     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
13141   }
13142   if (toFollowTranslation != -1)
13143   {
13144     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
13145   }
13146   if (toFollowRotation != -1)
13147   {
13148     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
13149   }
13150   if (toFollowDragging != -1)
13151   {
13152     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
13153   }
13154   if (aGap >= 0.0f)
13155   {
13156     aManipulator->SetGap ((float )aGap);
13157   }
13158
13159   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
13160   {
13161     const ManipAxisModeOnOff& aPart = aPartIter.Value();
13162     if (aPart.Axis == -1)
13163     {
13164       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
13165     }
13166     else
13167     {
13168       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
13169     }
13170   }
13171
13172   if (aSize > 0.0)
13173   {
13174     aManipulator->SetSize ((float )aSize);
13175   }
13176   if (isZoomable != -1)
13177   {
13178     aManipulator->SetZoomPersistence (isZoomable == 0);
13179
13180     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
13181     {
13182       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
13183       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
13184     }
13185   }
13186
13187   // ----------------------------------
13188   // detach existing manipulator object
13189   // ----------------------------------
13190
13191   if (toDetach)
13192   {
13193     aManipulator->Detach();
13194     aMapAIS.UnBind2 (aName);
13195     ViewerTest::GetAISContext()->Remove (aManipulator, false);
13196   }
13197
13198   // ---------------------------------------------------
13199   // attach, detach or access manipulator from an object
13200   // ---------------------------------------------------
13201
13202   if (!anAttachObject.IsNull())
13203   {
13204     aManipulator->Attach (anAttachObject, anAttachOptions);
13205   }
13206   if (!aViewAffinity.IsNull())
13207   {
13208     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
13209          anIter.More(); anIter.Next())
13210     {
13211       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
13212     }
13213     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
13214   }
13215
13216   if (anAttachPos != ManipAjustPosition_Off
13217    && aManipulator->IsAttached()
13218    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
13219   {
13220     gp_Ax2 aPosition = gp::XOY();
13221     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
13222     switch (anAttachPos)
13223     {
13224       case ManipAjustPosition_Off:
13225       {
13226         break;
13227       }
13228       case ManipAjustPosition_Location:
13229       {
13230         aPosition = gp::XOY().Transformed (aBaseTrsf);
13231         break;
13232       }
13233       case ManipAjustPosition_ShapeLocation:
13234       {
13235         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
13236         {
13237           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
13238         }
13239         else
13240         {
13241           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
13242           return 1;
13243         }
13244         break;
13245       }
13246       case ManipAjustPosition_Center:
13247       {
13248         Bnd_Box aBox;
13249         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
13250         {
13251           Bnd_Box anObjBox;
13252           anObjIter.Value()->BoundingBox (anObjBox);
13253           aBox.Add (anObjBox);
13254         }
13255         aBox = aBox.FinitePart();
13256         if (!aBox.IsVoid())
13257         {
13258           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
13259           aPosition.SetLocation (aCenter);
13260         }
13261         break;
13262       }
13263     }
13264     aManipulator->SetPosition (aPosition);
13265   }
13266   if (!Precision::IsInfinite (aLocation.X()))
13267   {
13268     if (aVDir.Modulus() <= Precision::Confusion())
13269     {
13270       aVDir = aManipulator->Position().Direction().XYZ();
13271     }
13272     if (anXDir.Modulus() <= Precision::Confusion())
13273     {
13274       anXDir = aManipulator->Position().XDirection().XYZ();
13275     }
13276     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
13277   }
13278
13279   // --------------------------------------
13280   // apply transformation using manipulator
13281   // --------------------------------------
13282
13283   if (aMousePosFrom.x() != IntegerLast())
13284   {
13285     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
13286   }
13287   if (aMousePosTo.x() != IntegerLast())
13288   {
13289     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
13290   }
13291   if (toStopMouseTransform != -1)
13292   {
13293     aManipulator->StopTransform (toStopMouseTransform == 1);
13294   }
13295
13296   if (aTrsf.Form() != gp_Identity)
13297   {
13298     aManipulator->Transform (aTrsf);
13299   }
13300
13301   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
13302   {
13303     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
13304   }
13305   return 0;
13306 }
13307
13308 //===============================================================================================
13309 //function : VSelectionProperties
13310 //purpose  :
13311 //===============================================================================================
13312 static int VSelectionProperties (Draw_Interpretor& theDi,
13313                                  Standard_Integer  theArgsNb,
13314                                  const char**      theArgVec)
13315 {
13316   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
13317   if (aCtx.IsNull())
13318   {
13319     Message::SendFail ("Error: no active viewer");
13320     return 1;
13321   }
13322
13323   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
13324   {
13325     // handle obsolete alias
13326     bool toEnable = true;
13327     if (theArgsNb < 2)
13328     {
13329       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
13330       return 0;
13331     }
13332     else if (theArgsNb != 2
13333          || !Draw::ParseOnOff (theArgVec[1], toEnable))
13334     {
13335       Message::SendFail ("Syntax error: wrong number of parameters");
13336       return 1;
13337     }
13338     if (toEnable != aCtx->ToHilightSelected())
13339     {
13340       aCtx->ClearDetected();
13341       aCtx->SetToHilightSelected (toEnable);
13342     }
13343     return 0;
13344   }
13345
13346   Standard_Boolean toPrint  = theArgsNb == 1;
13347   Standard_Boolean toRedraw = Standard_False;
13348   Standard_Integer anArgIter = 1;
13349   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
13350   if (anArgIter < theArgsNb)
13351   {
13352     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
13353     anArgFirst.LowerCase();
13354     ++anArgIter;
13355     if (anArgFirst == "dynhighlight"
13356      || anArgFirst == "dynhilight"
13357      || anArgFirst == "dynamichighlight"
13358      || anArgFirst == "dynamichilight")
13359     {
13360       aType = Prs3d_TypeOfHighlight_Dynamic;
13361     }
13362     else if (anArgFirst == "localdynhighlight"
13363           || anArgFirst == "localdynhilight"
13364           || anArgFirst == "localdynamichighlight"
13365           || anArgFirst == "localdynamichilight")
13366     {
13367       aType = Prs3d_TypeOfHighlight_LocalDynamic;
13368     }
13369     else if (anArgFirst == "selhighlight"
13370           || anArgFirst == "selhilight"
13371           || anArgFirst == "selectedhighlight"
13372           || anArgFirst == "selectedhilight")
13373     {
13374       aType = Prs3d_TypeOfHighlight_Selected;
13375     }
13376     else if (anArgFirst == "localselhighlight"
13377           || anArgFirst == "localselhilight"
13378           || anArgFirst == "localselectedhighlight"
13379           || anArgFirst == "localselectedhilight")
13380     {
13381       aType = Prs3d_TypeOfHighlight_LocalSelected;
13382     }
13383     else
13384     {
13385       --anArgIter;
13386     }
13387   }
13388   for (; anArgIter < theArgsNb; ++anArgIter)
13389   {
13390     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13391     anArg.LowerCase();
13392     if (anArg == "-help")
13393     {
13394       theDi.PrintHelp (theArgVec[0]);
13395       return 0;
13396     }
13397     else if (anArg == "-print")
13398     {
13399       toPrint = Standard_True;
13400     }
13401     else if (anArg == "-autoactivate")
13402     {
13403       Standard_Boolean toEnable = Standard_True;
13404       if (anArgIter + 1 < theArgsNb
13405        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13406       {
13407         ++anArgIter;
13408       }
13409       aCtx->SetAutoActivateSelection (toEnable);
13410     }
13411     else if (anArg == "-automatichighlight"
13412           || anArg == "-automatichilight"
13413           || anArg == "-autohighlight"
13414           || anArg == "-autohilight")
13415     {
13416       Standard_Boolean toEnable = Standard_True;
13417       if (anArgIter + 1 < theArgsNb
13418        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13419       {
13420         ++anArgIter;
13421       }
13422       aCtx->ClearSelected (false);
13423       aCtx->ClearDetected();
13424       aCtx->SetAutomaticHilight (toEnable);
13425       toRedraw = true;
13426     }
13427     else if (anArg == "-highlightselected"
13428           || anArg == "-hilightselected")
13429     {
13430       Standard_Boolean toEnable = Standard_True;
13431       if (anArgIter + 1 < theArgsNb
13432        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13433       {
13434         ++anArgIter;
13435       }
13436       aCtx->ClearDetected();
13437       aCtx->SetToHilightSelected (toEnable);
13438       toRedraw = true;
13439     }
13440     else if (anArg == "-pickstrategy"
13441           || anArg == "-pickingstrategy")
13442     {
13443       if (++anArgIter >= theArgsNb)
13444       {
13445         Message::SendFail ("Syntax error: type of highlighting is undefined");
13446         return 1;
13447       }
13448
13449       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13450       TCollection_AsciiString aVal (theArgVec[anArgIter]);
13451       aVal.LowerCase();
13452       if (aVal == "first"
13453        || aVal == "firstaccepted"
13454        || aVal == "firstacceptable")
13455       {
13456         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13457       }
13458       else if (aVal == "topmost"
13459             || aVal == "onlyTopmost")
13460       {
13461         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
13462       }
13463       else
13464       {
13465         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
13466         return 1;
13467       }
13468
13469       aCtx->SetPickingStrategy (aStrategy);
13470     }
13471     else if (anArg == "-pixtol"
13472           && anArgIter + 1 < theArgsNb)
13473     {
13474       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
13475     }
13476     else if (anArg == "-preferclosest")
13477     {
13478       bool toPreferClosest = true;
13479       if (anArgIter + 1 < theArgsNb
13480        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
13481       {
13482         ++anArgIter;
13483       }
13484       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
13485     }
13486     else if ((anArg == "-depthtol"
13487            || anArg == "-depthtolerance")
13488           && anArgIter + 1 < theArgsNb)
13489     {
13490       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
13491       aTolType.LowerCase();
13492       if (aTolType == "uniform")
13493       {
13494         if (anArgIter + 1 >= theArgsNb)
13495         {
13496           Message::SendFail() << "Syntax error: wrong number of arguments";
13497           return 1;
13498         }
13499         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
13500                                                  Draw::Atof (theArgVec[++anArgIter]));
13501       }
13502       else if (aTolType == "uniformpx")
13503       {
13504         if (anArgIter + 1 >= theArgsNb)
13505         {
13506           Message::SendFail() << "Syntax error: wrong number of arguments";
13507           return 1;
13508         }
13509         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
13510                                                  Draw::Atof (theArgVec[++anArgIter]));
13511       }
13512       else if (aTolType == "sensfactor")
13513       {
13514         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
13515       }
13516       else
13517       {
13518         Message::SendFail() << "Syntax error at '" << aTolType << "'";
13519         return 1;
13520       }
13521     }
13522     else if ((anArg == "-mode"
13523            || anArg == "-dispmode")
13524           && anArgIter + 1 < theArgsNb)
13525     {
13526       if (aType == Prs3d_TypeOfHighlight_None)
13527       {
13528         Message::SendFail ("Syntax error: type of highlighting is undefined");
13529         return 1;
13530       }
13531
13532       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13533       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13534       aStyle->SetDisplayMode (aDispMode);
13535       toRedraw = Standard_True;
13536     }
13537     else if (anArg == "-layer"
13538           && anArgIter + 1 < theArgsNb)
13539     {
13540       if (aType == Prs3d_TypeOfHighlight_None)
13541       {
13542         Message::SendFail ("Syntax error: type of highlighting is undefined");
13543         return 1;
13544       }
13545
13546       ++anArgIter;
13547       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13548       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13549       {
13550         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13551         return 1;
13552       }
13553
13554       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13555       aStyle->SetZLayer (aNewLayer);
13556       toRedraw = Standard_True;
13557     }
13558     else if (anArg == "-hicolor"
13559           || anArg == "-selcolor"
13560           || anArg == "-color")
13561     {
13562       if (anArg.StartsWith ("-hi"))
13563       {
13564         aType = Prs3d_TypeOfHighlight_Dynamic;
13565       }
13566       else if (anArg.StartsWith ("-sel"))
13567       {
13568         aType = Prs3d_TypeOfHighlight_Selected;
13569       }
13570       else if (aType == Prs3d_TypeOfHighlight_None)
13571       {
13572         Message::SendFail ("Syntax error: type of highlighting is undefined");
13573         return 1;
13574       }
13575
13576       Quantity_Color aColor;
13577       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13578                                                      theArgVec + anArgIter + 1,
13579                                                      aColor);
13580       if (aNbParsed == 0)
13581       {
13582         Message::SendFail ("Syntax error: need more arguments");
13583         return 1;
13584       }
13585       anArgIter += aNbParsed;
13586
13587       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13588       aStyle->SetColor (aColor);
13589       toRedraw = Standard_True;
13590     }
13591     else if ((anArg == "-transp"
13592            || anArg == "-transparency"
13593            || anArg == "-hitransp"
13594            || anArg == "-seltransp"
13595            || anArg == "-hitransplocal"
13596            || anArg == "-seltransplocal")
13597           && anArgIter + 1 < theArgsNb)
13598     {
13599       if (anArg.StartsWith ("-hi"))
13600       {
13601         aType = Prs3d_TypeOfHighlight_Dynamic;
13602       }
13603       else if (anArg.StartsWith ("-sel"))
13604       {
13605         aType = Prs3d_TypeOfHighlight_Selected;
13606       }
13607       else if (aType == Prs3d_TypeOfHighlight_None)
13608       {
13609         Message::SendFail ("Syntax error: type of highlighting is undefined");
13610         return 1;
13611       }
13612
13613       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13614       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13615       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13616       toRedraw = Standard_True;
13617     }
13618     else if ((anArg == "-mat"
13619            || anArg == "-material")
13620           && anArgIter + 1 < theArgsNb)
13621     {
13622       if (aType == Prs3d_TypeOfHighlight_None)
13623       {
13624         Message::SendFail ("Syntax error: type of highlighting is undefined");
13625         return 1;
13626       }
13627
13628       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13629       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13630       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
13631       {
13632         ++anArgIter;
13633         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13634         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13635         Graphic3d_MaterialAspect aMat (aMatName);
13636         aMat.SetColor (aStyle->Color());
13637         aMat.SetTransparency (aStyle->Transparency());
13638         anAspect->SetFrontMaterial (aMat);
13639         anAspect->SetInteriorColor (aStyle->Color());
13640         aStyle->SetBasicFillAreaAspect (anAspect);
13641       }
13642       else
13643       {
13644         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
13645       }
13646       toRedraw = Standard_True;
13647     }
13648     else
13649     {
13650       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
13651       return 1;
13652     }
13653   }
13654
13655   if (toPrint)
13656   {
13657     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
13658     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
13659     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
13660     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
13661     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
13662     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
13663     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
13664     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
13665     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
13666     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
13667     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
13668     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
13669     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
13670     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
13671   }
13672
13673   if (aCtx->NbSelected() != 0 && toRedraw)
13674   {
13675     aCtx->HilightSelected (Standard_True);
13676   }
13677
13678   return 0;
13679 }
13680
13681 //===============================================================================================
13682 //function : VDumpSelectionImage
13683 //purpose  :
13684 //===============================================================================================
13685 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13686                                 Standard_Integer  theArgsNb,
13687                                 const char**      theArgVec)
13688 {
13689   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13690   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13691   if (aContext.IsNull())
13692   {
13693     Message::SendFail ("Error: no active viewer");
13694     return 1;
13695   }
13696
13697   TCollection_AsciiString aFile;
13698   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13699   Handle(Graphic3d_Camera) aCustomCam;
13700   Image_Format anImgFormat = Image_Format_BGR;
13701   Standard_Integer aPickedIndex = 1;
13702   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13703   {
13704     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13705     aParam.LowerCase();
13706     if (aParam == "-type")
13707     {
13708       if (++anArgIter >= theArgsNb)
13709       {
13710         Message::SendFail ("Syntax error: wrong number parameters of flag '-type'");
13711         return 1;
13712       }
13713
13714       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13715       aValue.LowerCase();
13716       if (aValue == "depth"
13717        || aValue == "normdepth"
13718        || aValue == "normalizeddepth")
13719       {
13720         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13721         anImgFormat = Image_Format_GrayF;
13722       }
13723       else if (aValue == "depthinverted"
13724             || aValue == "normdepthinverted"
13725             || aValue == "normalizeddepthinverted"
13726             || aValue == "inverted")
13727       {
13728         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13729         anImgFormat = Image_Format_GrayF;
13730       }
13731       else if (aValue == "unnormdepth"
13732             || aValue == "unnormalizeddepth")
13733       {
13734         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13735         anImgFormat = Image_Format_GrayF;
13736       }
13737       else if (aValue == "objectcolor"
13738             || aValue == "object"
13739             || aValue == "color")
13740       {
13741         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13742       }
13743       else if (aValue == "entitycolor"
13744             || aValue == "entity")
13745       {
13746         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13747       }
13748       else if (aValue == "entitytypecolor"
13749             || aValue == "entitytype")
13750       {
13751         aType = StdSelect_TypeOfSelectionImage_ColoredEntityType;
13752       }
13753       else if (aValue == "ownercolor"
13754             || aValue == "owner")
13755       {
13756         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13757       }
13758       else if (aValue == "selectionmodecolor"
13759             || aValue == "selectionmode"
13760             || aValue == "selmodecolor"
13761             || aValue == "selmode")
13762       {
13763         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13764       }
13765       else if (aValue == "surfnormal"
13766             || aValue == "surfacenormal"
13767             || aValue == "normal")
13768       {
13769         aType = StdSelect_TypeOfSelectionImage_SurfaceNormal;
13770       }
13771       else
13772       {
13773         Message::SendFail() << "Syntax error: unknown type '" << aValue << "'";
13774         return 1;
13775       }
13776     }
13777     else if (aParam == "-picked"
13778           || aParam == "-pickeddepth"
13779           || aParam == "-pickedindex")
13780     {
13781       if (++anArgIter >= theArgsNb)
13782       {
13783         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13784         return 1;
13785       }
13786
13787       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13788     }
13789     else if (anArgIter + 1 < theArgsNb
13790           && aParam == "-xrpose")
13791     {
13792       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13793       anXRArg.LowerCase();
13794       if (anXRArg == "base")
13795       {
13796         aCustomCam = aView->View()->BaseXRCamera();
13797       }
13798       else if (anXRArg == "head")
13799       {
13800         aCustomCam = aView->View()->PosedXRCamera();
13801       }
13802       else
13803       {
13804         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13805         return 1;
13806       }
13807       if (aCustomCam.IsNull())
13808       {
13809         Message::SendFail() << "Error: undefined XR pose";
13810         return 0;
13811       }
13812     }
13813     else if (aFile.IsEmpty())
13814     {
13815       aFile = theArgVec[anArgIter];
13816     }
13817     else
13818     {
13819       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13820       return 1;
13821     }
13822   }
13823   if (aFile.IsEmpty())
13824   {
13825     Message::SendFail ("Syntax error: image file name is missing");
13826     return 1;
13827   }
13828
13829   Standard_Integer aWidth = 0, aHeight = 0;
13830   aView->Window()->Size (aWidth, aHeight);
13831
13832   Image_AlienPixMap aPixMap;
13833   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13834   {
13835     Message::SendFail ("Error: can't allocate image");
13836     return 1;
13837   }
13838
13839   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13840   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13841   if (!aCustomCam.IsNull())
13842   {
13843     aView->SetCamera (aCustomCam);
13844   }
13845   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13846   {
13847     Message::SendFail ("Error: can't generate selection image");
13848     return 1;
13849   }
13850   if (!aCustomCam.IsNull())
13851   {
13852     aView->SetCamera (aCamBack);
13853   }
13854   aView->SetImmediateUpdate (wasImmUpdate);
13855
13856   if (!aPixMap.Save (aFile))
13857   {
13858     Message::SendFail ("Error: can't save selection image");
13859     return 0;
13860   }
13861   return 0;
13862 }
13863
13864 //===============================================================================================
13865 //function : VViewCube
13866 //purpose  :
13867 //===============================================================================================
13868 static int VViewCube (Draw_Interpretor& ,
13869                       Standard_Integer  theNbArgs,
13870                       const char**      theArgVec)
13871 {
13872   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13873   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13874   if (aContext.IsNull() || aView.IsNull())
13875   {
13876     Message::SendFail ("Error: no active viewer");
13877     return 1;
13878   }
13879   else if (theNbArgs < 2)
13880   {
13881     Message::SendFail ("Syntax error: wrong number arguments");
13882     return 1;
13883   }
13884
13885   Handle(AIS_ViewCube) aViewCube;
13886   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13887   Quantity_Color aColorRgb;
13888   TCollection_AsciiString aName;
13889   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13890   {
13891     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13892     anArg.LowerCase();
13893     if (anUpdateTool.parseRedrawMode (anArg))
13894     {
13895       //
13896     }
13897     else if (aViewCube.IsNull())
13898     {
13899       aName = theArgVec[anArgIter];
13900       if (aName.StartsWith ("-"))
13901       {
13902         Message::SendFail ("Syntax error: object name should be specified");
13903         return 1;
13904       }
13905       Handle(AIS_InteractiveObject) aPrs;
13906       GetMapOfAIS().Find2 (aName, aPrs);
13907       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13908       if (aViewCube.IsNull())
13909       {
13910         aViewCube = new AIS_ViewCube();
13911         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13912         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13913         aViewCube->SetFixedAnimationLoop (false);
13914       }
13915     }
13916     else if (anArg == "-reset")
13917     {
13918       aViewCube->ResetStyles();
13919     }
13920     else if (anArg == "-color"
13921           || anArg == "-boxcolor"
13922           || anArg == "-boxsidecolor"
13923           || anArg == "-sidecolor"
13924           || anArg == "-boxedgecolor"
13925           || anArg == "-edgecolor"
13926           || anArg == "-boxcornercolor"
13927           || anArg == "-cornercolor"
13928           || anArg == "-innercolor"
13929           || anArg == "-textcolor"
13930           || anArg == "-xaxistextcolor"
13931           || anArg == "-yaxistextcolor"
13932           || anArg == "-zaxistextcolor")
13933     {
13934       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
13935                                                      theArgVec + anArgIter + 1,
13936                                                      aColorRgb);
13937       if (aNbParsed == 0)
13938       {
13939         Message::SendFail() << "Syntax error at '" << anArg << "'";
13940         return 1;
13941       }
13942       anArgIter += aNbParsed;
13943       if (anArg == "-boxcolor")
13944       {
13945         aViewCube->SetBoxColor (aColorRgb);
13946       }
13947       else if (anArg == "-boxsidecolor"
13948             || anArg == "-sidecolor")
13949       {
13950         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13951         aViewCube->SynchronizeAspects();
13952       }
13953       else if (anArg == "-boxedgecolor"
13954             || anArg == "-edgecolor")
13955       {
13956         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13957         aViewCube->SynchronizeAspects();
13958       }
13959       else if (anArg == "-boxcornercolor"
13960             || anArg == "-cornercolor")
13961       {
13962         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13963         aViewCube->SynchronizeAspects();
13964       }
13965       else if (anArg == "-innercolor")
13966       {
13967         aViewCube->SetInnerColor (aColorRgb);
13968       }
13969       else if (anArg == "-textcolor")
13970       {
13971         aViewCube->SetTextColor (aColorRgb);
13972       }
13973       else if (anArg == "-xaxistextcolor"
13974             || anArg == "-yaxistextcolor"
13975             || anArg == "-zaxistextcolor")
13976       {
13977         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
13978                                 ? Prs3d_DatumParts_XAxis
13979                                 : (anArg.Value (2) == 'y'
13980                                  ? Prs3d_DatumParts_YAxis
13981                                  : Prs3d_DatumParts_ZAxis);
13982         aViewCube->Attributes()->SetOwnDatumAspects();
13983         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
13984       }
13985       else
13986       {
13987         aViewCube->SetColor (aColorRgb);
13988       }
13989     }
13990     else if (anArgIter + 1 < theNbArgs
13991           && (anArg == "-transparency"
13992            || anArg == "-boxtransparency"))
13993     {
13994       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13995       if (aValue < 0.0 || aValue > 1.0)
13996       {
13997         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13998         return 1;
13999       }
14000
14001       if (anArg == "-boxtransparency")
14002       {
14003         aViewCube->SetBoxTransparency (aValue);
14004       }
14005       else
14006       {
14007         aViewCube->SetTransparency (aValue);
14008       }
14009     }
14010     else if (anArg == "-axes"
14011           || anArg == "-edges"
14012           || anArg == "-vertices"
14013           || anArg == "-vertexes"
14014           || anArg == "-fixedanimation")
14015     {
14016       bool toShow = true;
14017       if (anArgIter + 1 < theNbArgs
14018        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
14019       {
14020         ++anArgIter;
14021       }
14022       if (anArg == "-fixedanimation")
14023       {
14024         aViewCube->SetFixedAnimationLoop (toShow);
14025       }
14026       else if (anArg == "-axes")
14027       {
14028         aViewCube->SetDrawAxes (toShow);
14029       }
14030       else if (anArg == "-edges")
14031       {
14032         aViewCube->SetDrawEdges (toShow);
14033       }
14034       else
14035       {
14036         aViewCube->SetDrawVertices (toShow);
14037       }
14038     }
14039     else if (anArg == "-yup"
14040           || anArg == "-zup")
14041     {
14042       bool isOn = true;
14043       if (anArgIter + 1 < theNbArgs
14044        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
14045       {
14046         ++anArgIter;
14047       }
14048       if (anArg == "-yup")
14049       {
14050         aViewCube->SetYup (isOn);
14051       }
14052       else
14053       {
14054         aViewCube->SetYup (!isOn);
14055       }
14056     }
14057     else if (anArgIter + 1 < theNbArgs
14058           && anArg == "-font")
14059     {
14060       aViewCube->SetFont (theArgVec[++anArgIter]);
14061     }
14062     else if (anArgIter + 1 < theNbArgs
14063           && anArg == "-fontheight")
14064     {
14065       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
14066     }
14067     else if (anArgIter + 1 < theNbArgs
14068           && (anArg == "-size"
14069            || anArg == "-boxsize"))
14070     {
14071       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
14072                           anArg != "-boxsize");
14073     }
14074     else if (anArgIter + 1 < theNbArgs
14075           && (anArg == "-boxfacet"
14076            || anArg == "-boxfacetextension"
14077            || anArg == "-facetextension"
14078            || anArg == "-extension"))
14079     {
14080       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
14081     }
14082     else if (anArgIter + 1 < theNbArgs
14083           && (anArg == "-boxedgegap"
14084            || anArg == "-edgegap"))
14085     {
14086       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
14087     }
14088     else if (anArgIter + 1 < theNbArgs
14089           && (anArg == "-boxedgeminsize"
14090            || anArg == "-edgeminsize"))
14091     {
14092       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
14093     }
14094     else if (anArgIter + 1 < theNbArgs
14095           && (anArg == "-boxcornerminsize"
14096            || anArg == "-cornerminsize"))
14097     {
14098       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
14099     }
14100     else if (anArgIter + 1 < theNbArgs
14101           && anArg == "-axespadding")
14102     {
14103       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
14104     }
14105     else if (anArgIter + 1 < theNbArgs
14106           && anArg == "-roundradius")
14107     {
14108       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
14109     }
14110     else if (anArgIter + 1 < theNbArgs
14111           && anArg == "-duration")
14112     {
14113       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
14114     }
14115     else if (anArgIter + 1 < theNbArgs
14116           && anArg == "-axesradius")
14117     {
14118       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
14119     }
14120     else if (anArgIter + 1 < theNbArgs
14121           && anArg == "-axesconeradius")
14122     {
14123       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
14124     }
14125     else if (anArgIter + 1 < theNbArgs
14126           && anArg == "-axessphereradius")
14127     {
14128       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
14129     }
14130     else
14131     {
14132       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14133       return 1;
14134     }
14135   }
14136   if (aViewCube.IsNull())
14137   {
14138     Message::SendFail ("Syntax error: wrong number of arguments");
14139     return 1;
14140   }
14141
14142   ViewerTest::Display (aName, aViewCube, false);
14143   return 0;
14144 }
14145
14146 //===============================================================================================
14147 //function : VColorConvert
14148 //purpose  :
14149 //===============================================================================================
14150 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
14151 {
14152   if (theNbArgs != 6)
14153   {
14154     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
14155     return 1;
14156   }
14157
14158   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
14159   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
14160   {
14161     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
14162     return 1;
14163   }
14164
14165   const char* aTypeStr = theArgVec[2];
14166   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
14167   if (! strcasecmp (aTypeStr, "srgb"))
14168   {
14169     aType = Quantity_TOC_sRGB;
14170   }
14171   else if (! strcasecmp (aTypeStr, "hls"))
14172   {
14173     aType = Quantity_TOC_HLS;
14174   }
14175   else if (! strcasecmp (aTypeStr, "lab"))
14176   {
14177     aType = Quantity_TOC_CIELab;
14178   }
14179   else if (! strcasecmp (aTypeStr, "lch"))
14180   {
14181     aType = Quantity_TOC_CIELch;
14182   }
14183   else
14184   {
14185     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
14186     return 1;
14187   }
14188
14189   double aC1 = Draw::Atof (theArgVec[3]);
14190   double aC2 = Draw::Atof (theArgVec[4]);
14191   double aC3 = Draw::Atof (theArgVec[5]);
14192
14193   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
14194   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
14195
14196   // print values with 6 decimal digits
14197   char buffer[1024];
14198   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
14199   theDI << buffer;
14200
14201   return 0;
14202 }
14203  
14204 //===============================================================================================
14205 //function : VColorDiff
14206 //purpose  :
14207 //===============================================================================================
14208 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
14209 {
14210   if (theNbArgs != 7)
14211   {
14212     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
14213     return 1;
14214   }
14215
14216   double aR1 = Draw::Atof (theArgVec[1]);
14217   double aG1 = Draw::Atof (theArgVec[2]);
14218   double aB1 = Draw::Atof (theArgVec[3]);
14219   double aR2 = Draw::Atof (theArgVec[4]);
14220   double aG2 = Draw::Atof (theArgVec[5]);
14221   double aB2 = Draw::Atof (theArgVec[6]);
14222
14223   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
14224   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
14225
14226   theDI << aColor1.DeltaE2000 (aColor2);
14227
14228   return 0;
14229 }
14230  
14231 //===============================================================================================
14232 //function : VSelBvhBuild
14233 //purpose  :
14234 //===============================================================================================
14235 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
14236 {
14237   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
14238   if (aCtx.IsNull())
14239   {
14240     Message::SendFail ("Error: no active viewer");
14241     return 1;
14242   }
14243
14244   if (theNbArgs < 2)
14245   {
14246     Message::SendFail ("Error: command syntax is incorrect, see help");
14247     return 1;
14248   }
14249
14250   Standard_Integer toEnable = -1;
14251   Standard_Integer aThreadsNb = -1;
14252   Standard_Boolean toWait = Standard_False;
14253
14254   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
14255   {
14256     TCollection_AsciiString anArg (theArgVec[anArgIter]);
14257     anArg.LowerCase();
14258
14259     if (anArg == "-nbthreads"
14260         && anArgIter + 1 < theNbArgs)
14261     {
14262       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
14263       if (aThreadsNb < 1)
14264       {
14265         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
14266       }
14267     }
14268     else if (anArg == "-wait")
14269     {
14270       toWait = Standard_True;
14271     }
14272     else if (toEnable == -1)
14273     {
14274       Standard_Boolean toEnableValue = Standard_True;
14275       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
14276       {
14277         toEnable = toEnableValue ? 1 : 0;
14278       }
14279       else
14280       {
14281         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14282         return 1;
14283       }
14284     }
14285     else
14286     {
14287       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14288       return 1;
14289     }
14290   }
14291
14292   if (aThreadsNb == -1)
14293   {
14294     aThreadsNb = 1;
14295   }
14296   if (toEnable != -1)
14297   {
14298     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
14299   }
14300   if (toWait)
14301   {
14302     aCtx->MainSelector()->WaitForBVHBuild();
14303   }
14304
14305   return 0;
14306 }
14307
14308 //=======================================================================
14309 //function : ViewerTest_ExitProc
14310 //purpose  :
14311 //=======================================================================
14312 static void ViewerTest_ExitProc (ClientData )
14313 {
14314   NCollection_List<TCollection_AsciiString> aViewList;
14315   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
14316        anIter.More(); anIter.Next())
14317   {
14318     aViewList.Append (anIter.Key1());
14319   }
14320
14321   for (NCollection_List<TCollection_AsciiString>::Iterator anIter (aViewList);
14322        anIter.More(); anIter.Next())
14323   {
14324     ViewerTest::RemoveView (anIter.Value(), true);
14325   }
14326 }
14327
14328 //=======================================================================
14329 //function : ViewerCommands
14330 //purpose  :
14331 //=======================================================================
14332
14333 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
14334 {
14335   static bool TheIsInitialized = false;
14336   if (TheIsInitialized)
14337   {
14338     return;
14339   }
14340
14341   TheIsInitialized = true;
14342   // define destruction callback to destroy views in a well-defined order
14343   Tcl_CreateExitHandler (ViewerTest_ExitProc, 0);
14344
14345   const char *group = "ZeViewer";
14346   theCommands.Add("vdriver",
14347           "vdriver [-list] [-default DriverName] [-load DriverName]"
14348     "\n\t\t: Manages active graphic driver factory."
14349     "\n\t\t: Prints current active driver when called without arguments."
14350     "\n\t\t: Makes specified driver active when ActiveName argument is specified."
14351     "\n\t\t:  -list    print registered factories"
14352     "\n\t\t:  -default define which factory should be used by default (to be used by next vinit call)"
14353     "\n\t\t:  -load    try loading factory plugin and set it as default one",
14354                   __FILE__, VDriver, group);
14355   theCommands.Add("vinit",
14356           "vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]"
14357     "\n\t\t:     [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {on|off}=off] [-2d_mode {on|off}=off]"
14358   #if defined(HAVE_XLIB)
14359     "\n\t\t:     [-display displayName]"
14360   #endif
14361     "\n\t\t: Creates new View window with specified name viewName."
14362     "\n\t\t: By default the new view is created in the viewer and in"
14363     "\n\t\t: graphic driver shared with active view."
14364     "\n\t\t:  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}"
14365     "\n\t\t: If driverName isn't specified the driver will be shared with active view."
14366     "\n\t\t: If viewerName isn't specified the viewer will be shared with active view."
14367 #if defined(HAVE_XLIB)
14368     "\n\t\t:  -display HostName.DisplayNumber[:ScreenNumber]"
14369     "\n\t\t: Display name will be used within creation of graphic driver, when specified."
14370 #endif
14371     "\n\t\t:  -left,  -top    pixel position of left top corner of the window."
14372     "\n\t\t:  -width, -height width and height of window respectively."
14373     "\n\t\t:  -cloneActive flag to copy camera and dimensions of active view."
14374     "\n\t\t:  -exitOnClose when specified, closing the view will exit application."
14375     "\n\t\t:  -closeOnEscape when specified, view will be closed on pressing Escape."
14376     "\n\t\t:  -virtual create an offscreen window within interactive session"
14377     "\n\t\t:  -2d_mode when on, view will not react on rotate scene events"
14378     "\n\t\t: Additional commands for operations with views: vclose, vactivate, vviewlist.",
14379     __FILE__,VInit,group);
14380   theCommands.Add("vclose" ,
14381     "[view_id [keep_context=0|1]]\n"
14382     "or vclose ALL - to remove all created views\n"
14383     " - removes view(viewer window) defined by its view_id.\n"
14384     " - keep_context: by default 0; if 1 and the last view is deleted"
14385     " the current context is not removed.",
14386     __FILE__,VClose,group);
14387   theCommands.Add("vactivate" ,
14388     "vactivate view_id [-noUpdate]"
14389     " - activates view(viewer window) defined by its view_id",
14390     __FILE__,VActivate,group);
14391   theCommands.Add("vviewlist",
14392     "vviewlist [format={tree, long}]"
14393     " - prints current list of views per viewer and graphic_driver ID shared between viewers"
14394     " - format: format of result output, if tree the output is a tree view;"
14395     "otherwise it's a list of full view names. By default format = tree",
14396     __FILE__,VViewList,group);
14397   theCommands.Add("vhelp" ,
14398     "vhelp            : display help on the viewer commands",
14399     __FILE__,VHelp,group);
14400   theCommands.Add("vviewproj",
14401           "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]"
14402     "\n\t\t:         [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]"
14403     "\n\t\t: Setup view direction"
14404     "\n\t\t:   -Yup      use Y-up convention instead of Zup (which is default)."
14405     "\n\t\t:   +-X+-Y+-Z define direction as combination of DX, DY and DZ;"
14406     "\n\t\t:             for example '+Z' will show front of the model,"
14407     "\n\t\t:             '-X-Y+Z' will define left axonometrical view."
14408     "\n\t\t:   -frame    define camera Up and Right directions (regardless Up convention);"
14409     "\n\t\t:             for example '+X+Z' will show front of the model with Z-up."
14410     __FILE__,VViewProj,group);
14411   theCommands.Add("vtop" ,
14412     "vtop or <T>      : Top view. Orientation +X+Y" ,
14413     __FILE__,VViewProj,group);
14414   theCommands.Add("vbottom" ,
14415     "vbottom          : Bottom view. Orientation +X-Y" ,
14416     __FILE__,VViewProj,group);
14417   theCommands.Add("vleft" ,
14418     "vleft            : Left view. Orientation -Y+Z" ,
14419     __FILE__,VViewProj,group);
14420   theCommands.Add("vright" ,
14421     "vright           : Right view. Orientation +Y+Z" ,
14422     __FILE__,VViewProj,group);
14423   theCommands.Add("vaxo" ,
14424     " vaxo or <A>     : Axonometric view. Orientation +X-Y+Z",
14425     __FILE__,VViewProj,group);
14426   theCommands.Add("vfront" ,
14427     "vfront           : Front view. Orientation +X+Z" ,
14428     __FILE__,VViewProj,group);
14429   theCommands.Add("vback" ,
14430     "vback            : Back view. Orientation -X+Z" ,
14431     __FILE__,VViewProj,group);
14432   theCommands.Add("vpick" ,
14433     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
14434     VPick,group);
14435   theCommands.Add("vfit",
14436     "vfit or <F> [-selected] [-noupdate]"
14437     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
14438     __FILE__,VFit,group);
14439   theCommands.Add ("vfitarea",
14440     "vfitarea x1 y1 x2 y2"
14441     "\n\t\t: vfitarea x1 y1 z1 x2 y2 z2"
14442     "\n\t\t: Fit view to show area located between two points"
14443     "\n\t\t: given in world 2D or 3D corrdinates.",
14444     __FILE__, VFitArea, group);
14445   theCommands.Add ("vzfit", "vzfit [scale]\n"
14446     "   Matches Z near, Z far view volume planes to the displayed objects.\n"
14447     "   \"scale\" - specifies factor to scale computed z range.\n",
14448     __FILE__, VZFit, group);
14449   theCommands.Add("vrepaint",
14450             "vrepaint [-immediate] [-continuous FPS]"
14451     "\n\t\t: force redraw of active View"
14452     "\n\t\t:   -immediate  flag performs redraw of immediate layers only;"
14453     "\n\t\t:   -continuous activates/deactivates continuous redraw of active View,"
14454     "\n\t\t:                0 means no continuous rendering,"
14455     "\n\t\t:               -1 means non-stop redraws,"
14456     "\n\t\t:               >0 specifies target framerate,",
14457     __FILE__,VRepaint,group);
14458   theCommands.Add("vclear",
14459     "vclear          : vclear"
14460     "\n\t\t: remove all the object from the viewer",
14461     __FILE__,VClear,group);
14462   theCommands.Add (
14463     "vbackground",
14464     "Changes background or some background settings.\n"
14465     "\n"
14466     "Usage:\n"
14467     "  vbackground -imageFile ImageFile [-imageMode FillType]\n"
14468     "  vbackground -imageMode FillType\n"
14469     "  vbackground -gradient Color1 Color2 [-gradientMode FillMethod]\n"
14470     "  vbackground -gradientMode FillMethod\n"
14471     "  vbackground -cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]\n"
14472     "  vbackground -color Color\n"
14473     "  vbackground -default -gradient Color1 Color2 [-gradientMode FillType]\n"
14474     "  vbackground -default -color Color\n"
14475     "  vbackground -help\n"
14476     "\n"
14477     "Options:\n"
14478     "  -imageFile    (-imgFile, -image, -img):             sets filename of image used as background\n"
14479     "  -imageMode    (-imgMode, -imageMd, -imgMd):         sets image fill type\n"
14480     "  -gradient     (-grad, -gr):                         sets background gradient starting and ending colors\n"
14481     "  -gradientMode (-gradMode, -gradMd, -grMode, -grMd): sets gradient fill method\n"
14482     "  -cubemap      (-cmap, -cm):                         sets environment cubemap as background\n"
14483     "  -invertedz    (-invz, -iz):                         sets inversion of Z axis for background cubemap rendering\n"
14484     "  -order        (-o):                                 defines order of tiles in one image cubemap\n"
14485     "                                                      (has no effect in case of multi image cubemaps)\n"
14486     "  -color        (-col):                               sets background color\n"
14487     "  -default      (-def):                               sets background default gradient or color\n"
14488     "  -help         (-h):                                 outputs short help message\n"
14489     "\n"
14490     "Arguments:\n"
14491     "  Color:        Red Green Blue  - where Red, Green, Blue must be integers within the range [0, 255]\n"
14492     "                                  or reals within the range [0.0, 1.0]\n"
14493     "                ColorName       - one of WHITE, BLACK, RED, GREEN, BLUE, etc.\n"
14494     "                #HHH, [#]HHHHHH - where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F)\n"
14495     "  FillMethod:   one of NONE, HOR[IZONTAL], VER[TICAL], DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, "
14496     "CORNER4\n"
14497     "  FillType:     one of CENTERED, TILED, STRETCH, NONE\n"
14498     "  ImageFile:    a name of the file with the image used as a background\n"
14499     "  CubemapFilei: a name of the file with one image packed cubemap or names of separate files with every cubemap side\n"
14500     "  TileIndexi:   a cubemap side index in range [0, 5] for i tile of one image packed cubemap\n",
14501     __FILE__,
14502     vbackground,
14503     group);
14504   theCommands.Add ("vsetbg",
14505                    "Loads image as background."
14506                    "\n\t\t: vsetbg ImageFile [FillType]"
14507                    "\n\t\t: vsetbg -imageFile ImageFile [-imageMode FillType]"
14508                    "\n\t\t: Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.",
14509                    __FILE__,
14510                    vbackground,
14511                    group);
14512   theCommands.Add ("vsetbgmode",
14513                    "Changes background image fill type."
14514                    "\n\t\t: vsetbgmode [-imageMode] FillType"
14515                    "\n\t\t: Alias for 'vbackground -imageMode FillType'.",
14516                    __FILE__,
14517                    vbackground,
14518                    group);
14519   theCommands.Add ("vsetgradientbg",
14520                    "Mounts gradient background."
14521                    "\n\t\t: vsetgradientbg Color1 Color2 [FillMethod]"
14522                    "\n\t\t: vsetgradientbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14523                    "\n\t\t: Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.",
14524                    __FILE__,
14525                    vbackground,
14526                    group);
14527   theCommands.Add ("vsetgrbgmode",
14528                    "Changes gradient background fill method."
14529                    "\n\t\t: vsetgrbgmode [-gradientMode] FillMethod"
14530                    "\n\t\t: Alias for 'vbackground -gradientMode FillMethod'.",
14531                    __FILE__,
14532                    vbackground,
14533                    group);
14534   theCommands.Add ("vsetcolorbg",
14535                    "Sets background color."
14536                    "\n\t\t: vsetcolorbg [-color] Color."
14537                    "\n\t\t: Alias for 'vbackground -color Color'.",
14538                    __FILE__,
14539                    vbackground,
14540                    group);
14541   theCommands.Add ("vsetdefaultbg",
14542                    "Sets default viewer background fill color (flat/gradient)."
14543                    "\n\t\t: vsetdefaultbg Color1 Color2 [FillMethod]"
14544                    "\n\t\t: vsetdefaultbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14545                    "\n\t\t: Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'."
14546                    "\n\t\t: vsetdefaultbg [-color] Color"
14547                    "\n\t\t: Alias for 'vbackground -default -color Color'.",
14548                    __FILE__,
14549                    vbackground,
14550                    group);
14551   theCommands.Add("vscale",
14552     "vscale          : vscale X Y Z",
14553     __FILE__,VScale,group);
14554   theCommands.Add("vzbufftrihedron",
14555             "vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]"
14556     "\n\t\t:       [-position center|left_lower|left_upper|right_lower|right_upper]"
14557     "\n\t\t:       [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]"
14558     "\n\t\t:       [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]"
14559     "\n\t\t:       [-nbfacets value=12] [-colorLabels color=WHITE]"
14560     "\n\t\t:       [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]"
14561     "\n\t\t: Displays a trihedron",
14562     __FILE__,VZBuffTrihedron,group);
14563   theCommands.Add("vrotate",
14564     "vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]"
14565     "\n                : Option -mouseStart starts rotation according to the mouse position"
14566     "\n                : Option -mouseMove continues rotation with angle computed"
14567     "\n                : from last and new mouse position."
14568     "\n                : vrotate AX AY AZ [X Y Z]",
14569     __FILE__,VRotate,group);
14570   theCommands.Add("vzoom",
14571     "vzoom           : vzoom coef",
14572     __FILE__,VZoom,group);
14573   theCommands.Add("vpan",
14574     "vpan            : vpan dx dy",
14575     __FILE__,VPan,group);
14576   theCommands.Add("vcolorscale",
14577     "vcolorscale name [-noupdate|-update] [-demo]"
14578     "\n\t\t:       [-range RangeMin=0 RangeMax=1 NbIntervals=10]"
14579     "\n\t\t:       [-font HeightFont=20]"
14580     "\n\t\t:       [-logarithmic {on|off}=off] [-reversed {on|off}=off]"
14581     "\n\t\t:       [-smoothTransition {on|off}=off]"
14582     "\n\t\t:       [-hueRange MinAngle=230 MaxAngle=0]"
14583     "\n\t\t:       [-colorRange MinColor=BLUE1 MaxColor=RED]"
14584     "\n\t\t:       [-textpos {left|right|center|none}=right]"
14585     "\n\t\t:       [-labelAtBorder {on|off}=on]"
14586     "\n\t\t:       [-colors Color1 Color2 ...] [-color Index Color]"
14587     "\n\t\t:       [-labels Label1 Label2 ...] [-label Index Label]"
14588     "\n\t\t:       [-freeLabels NbOfLabels Label1 Label2 ...]"
14589     "\n\t\t:       [-xy Left=0 Bottom=0]"
14590     "\n\t\t:       [-uniform lightness hue_from hue_to]"
14591     "\n\t\t:  -demo     - displays a color scale with demonstratio values"
14592     "\n\t\t:  -colors   - set colors for all intervals"
14593     "\n\t\t:  -color    - set color for specific interval"
14594     "\n\t\t:  -uniform  - generate colors with the same lightness"
14595     "\n\t\t:  -textpos  - horizontal label position relative to color scale bar"
14596     "\n\t\t:  -labelAtBorder - vertical label position relative to color interval;"
14597     "\n\t\t:              at border means the value inbetween neighbor intervals,"
14598     "\n\t\t:              at center means the center value within current interval"
14599     "\n\t\t:  -labels   - set labels for all intervals"
14600     "\n\t\t:  -freeLabels - same as -labels but does not require"
14601     "\n\t\t:              matching the number of intervals"
14602     "\n\t\t:  -label    - set label for specific interval"
14603     "\n\t\t:  -title    - set title"
14604     "\n\t\t:  -reversed - setup smooth color transition between intervals"
14605     "\n\t\t:  -smoothTransition - swap colorscale direction"
14606     "\n\t\t:  -hueRange - set hue angles corresponding to minimum and maximum values",
14607     __FILE__, VColorScale, group);
14608   theCommands.Add("vgraduatedtrihedron",
14609     "vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
14610     "\t[-namefont Name] [-valuesfont Name]\n"
14611     "\t[-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]\n"
14612     "\t[-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]"
14613     "\t[-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]\n"
14614     "\t[-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]\n"
14615     "\t[-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]"
14616     "\t[-xcolor Color] [-ycolor Color] [-zcolor Color]\n"
14617     "\t[-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]\n"
14618     "\t[-xticks Number] [-yticks Number] [-zticks Number]\n"
14619     "\t[-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]\n"
14620     "\t[-drawgrid on/off] [-drawaxes on/off]\n"
14621     " - Displays or erases graduated trihedron"
14622     " - xname, yname, zname - names of axes, default: X, Y, Z\n"
14623     " - namefont - font of axes names. Default: Arial\n"
14624     " - xnameoffset, ynameoffset, znameoffset - offset of name from values or tickmarks or axis. Default: 30\n"
14625     " - xnamecolor, ynamecolor, znamecolor - colors of axes names\n"
14626     " - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values from tickmarks or axis. Default: 10\n"
14627     " - valuesfont - font of axes values. Default: Arial\n"
14628     " - xcolor, ycolor, zcolor - color of axis and values\n"
14629     " - xticks, yticks, xzicks - number of tickmark on axes. Default: 5\n"
14630     " - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10\n",
14631     __FILE__,VGraduatedTrihedron,group);
14632   theCommands.Add("vtile" ,
14633             "vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]"
14634     "\n\t\t: Setup view to draw a tile (a part of virtual bigger viewport)."
14635     "\n\t\t:  -totalSize the size of virtual bigger viewport"
14636     "\n\t\t:  -tileSize  tile size (the view size will be used if omitted)"
14637     "\n\t\t:  -lowerLeft tile offset as lower left corner"
14638     "\n\t\t:  -upperLeft tile offset as upper left corner",
14639     __FILE__, VTile, group);
14640   theCommands.Add("vzlayer",
14641               "vzlayer [layerId]"
14642       "\n\t\t:         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]"
14643       "\n\t\t:         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]"
14644       "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
14645       "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]"
14646       "\n\t\t: ZLayer list management:"
14647       "\n\t\t:   -add      add new z layer to viewer and print its id"
14648       "\n\t\t:   -insertBefore add new z layer and insert it before existing one"
14649       "\n\t\t:   -insertAfter  add new z layer and insert it after  existing one"
14650       "\n\t\t:   -delete   delete z layer"
14651       "\n\t\t:   -get      print sequence of z layers"
14652       "\n\t\t:   -settings print status of z layer settings"
14653       "\n\t\t:   -disable  disables given setting"
14654       "\n\t\t:   -enable   enables  given setting",
14655     __FILE__,VZLayer,group);
14656   theCommands.Add("vlayerline",
14657     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
14658     __FILE__,VLayerLine,group);
14659   theCommands.Add("vgrid",
14660               "vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]"
14661       "\n\t\t:       [-step X Y] [-size DX DY]"
14662       "\n\t\t:       [-step StepRadius NbDivisions] [-radius Radius]",
14663     __FILE__, VGrid, group);
14664   theCommands.Add ("vpriviledgedplane",
14665     "vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]"
14666     "\n\t\t:   Ox, Oy, Oz - plane origin"
14667     "\n\t\t:   Nx, Ny, Nz - plane normal direction"
14668     "\n\t\t:   Xx, Xy, Xz - plane x-reference axis direction"
14669     "\n\t\t: Sets or prints viewer's priviledged plane geometry.",
14670     __FILE__, VPriviledgedPlane, group);
14671   theCommands.Add ("vconvert",
14672     "vconvert v [Mode={window|view}]"
14673     "\n\t\t: vconvert x y [Mode={window|view|grid|ray}]"
14674     "\n\t\t: vconvert x y z [Mode={window|grid}]"
14675     "\n\t\t:   window - convert to window coordinates, pixels"
14676     "\n\t\t:   view   - convert to view projection plane"
14677     "\n\t\t:   grid   - convert to model coordinates, given on grid"
14678     "\n\t\t:   ray    - convert projection ray to model coordinates"
14679     "\n\t\t: - vconvert v window : convert view to window;"
14680     "\n\t\t: - vconvert v view   : convert window to view;"
14681     "\n\t\t: - vconvert x y window : convert view to window;"
14682     "\n\t\t: - vconvert x y view : convert window to view;"
14683     "\n\t\t: - vconvert x y : convert window to model;"
14684     "\n\t\t: - vconvert x y grid : convert window to model using grid;"
14685     "\n\t\t: - vconvert x y ray : convert window projection line to model;"
14686     "\n\t\t: - vconvert x y z window : convert model to window;"
14687     "\n\t\t: - vconvert x y z grid : convert view to model using grid;"
14688     "\n\t\t: Converts the given coordinates to window/view/model space.",
14689     __FILE__, VConvert, group);
14690   theCommands.Add ("vfps",
14691     "vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view",
14692     __FILE__, VFps, group);
14693   theCommands.Add ("vstereo",
14694             "vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
14695     "\n\t\t:         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]"
14696     "\n\t\t:         [-anaglyph Filter]"
14697     "\n\t\t: Control stereo output mode."
14698     "\n\t\t: When -mirrorComposer is specified, VR rendered frame will be mirrored in window (debug)."
14699     "\n\t\t: Parameter -unitFactor specifies meters scale factor for mapping VR input."
14700     "\n\t\t: Available modes for -mode:"
14701     "\n\t\t:  quadBuffer        - OpenGL QuadBuffer stereo,"
14702     "\n\t\t:                     requires driver support."
14703     "\n\t\t:                     Should be called BEFORE vinit!"
14704     "\n\t\t:  anaglyph         - Anaglyph glasses"
14705     "\n\t\t:  rowInterlaced    - row-interlaced display"
14706     "\n\t\t:  columnInterlaced - column-interlaced display"
14707     "\n\t\t:  chessBoard       - chess-board output"
14708     "\n\t\t:  sideBySide       - horizontal pair"
14709     "\n\t\t:  overUnder        - vertical   pair"
14710     "\n\t\t:  openVR           - OpenVR (HMD)"
14711     "\n\t\t: Available Anaglyph filters for -anaglyph:"
14712     "\n\t\t:  redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
14713     "\n\t\t:  greenMagentaSimple",
14714     __FILE__, VStereo, group);
14715   theCommands.Add ("vmemgpu",
14716     "vmemgpu [f]: print system-dependent GPU memory information if available;"
14717     " with f option returns free memory in bytes",
14718     __FILE__, VMemGpu, group);
14719   theCommands.Add ("vreadpixel",
14720     "vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]"
14721     " : Read pixel value for active view",
14722     __FILE__, VReadPixel, group);
14723   theCommands.Add("diffimage",
14724             "diffimage imageFile1 imageFile2 [diffImageFile]"
14725     "\n\t\t:           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]"
14726     "\n\t\t:           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]"
14727     "\n\t\t: Compare two images by content and generate difference image."
14728     "\n\t\t: When -exitOnClose is specified, closing the view will exit application."
14729     "\n\t\t: When -closeOnEscape is specified, view will be closed on pressing Escape.",
14730     __FILE__, VDiffImage, group);
14731   theCommands.Add ("vselect",
14732     "vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1] [-replace|-replaceextra|-xor|-add|-remove]\n"
14733     "- emulates different types of selection:\n"
14734     "- 1) single click selection\n"
14735     "- 2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)\n"
14736     "- 3) selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn)\n"
14737     "- 4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.\n"
14738     "     If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined \n"
14739     "     rectangle or polygon will be detected, otherwise algorithm will chose only fully included sensitives.\n"
14740     "     Default behavior is to detect only full inclusion. (partial inclusion - overlap - is not allowed by default)\n"
14741     "- 5) selection scheme replace, replaceextra, xor, add or remove (replace by default)",
14742     __FILE__, VSelect, group);
14743   theCommands.Add ("vmoveto",
14744     "vmoveto [x y] [-reset]"
14745     "\n\t\t: Emulates cursor movement to pixel position (x,y)."
14746     "\n\t\t:   -reset resets current highlighting",
14747     __FILE__, VMoveTo, group);
14748   theCommands.Add ("vselaxis",
14749               "vselaxis x y z dx dy dz [-onlyTop 0|1] [-display Name] [-showNormal 0|1]"
14750     "\n\t\t: Provides intersection by given axis and print result intersection points"
14751     "\n\t\t:   -onlyTop       switches On/Off mode to find only top point or all"
14752     "\n\t\t:   -display Name  displays intersecting axis and result intersection points for debug goals"
14753     "\n\t\t:   -showNormal    adds displaying of normal in intersection point or not",
14754     __FILE__, VSelectByAxis, group);
14755   theCommands.Add ("vviewparams",
14756               "vviewparams [-args] [-scale [s]]"
14757       "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
14758       "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
14759       "\n\t\t: Manage current view parameters or prints all"
14760       "\n\t\t: current values when called without argument."
14761       "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
14762       "\n\t\t:   -eye  [x y z] prints or sets eye location"
14763       "\n\t\t:   -at   [x y z] prints or sets center of look"
14764       "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
14765       "\n\t\t:   -proj [x y z] prints or sets direction of look"
14766       "\n\t\t:   -center x y   sets location of center of the screen in pixels"
14767       "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
14768       "\n\t\t:                 or changes the size of its maximum dimension"
14769       "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
14770     __FILE__, VViewParams, group);
14771
14772   theCommands.Add("v2dmode",
14773     "v2dmode [-name viewName] [-mode {-on|-off}=-on]"
14774     "\n\t\t:   name   - name of existing view, if not defined, the active view is changed"
14775     "\n\t\t:   mode   - switches On/Off rotation mode"
14776     "\n\t\t: Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:"
14777     "\n\t\t:   - rotation of the view by 3rd mouse button with Ctrl active"
14778     "\n\t\t:   - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right"
14779     "\n\t\t: View camera position might be changed only by commands.",
14780     __FILE__, V2DMode, group);
14781
14782   theCommands.Add("vanimation", "Alias for vanim",
14783     __FILE__, VAnimation, group);
14784
14785   theCommands.Add("vanim",
14786             "List existing animations:"
14787     "\n\t\t:  vanim"
14788     "\n\t\t: Animation playback:"
14789     "\n\t\t:  vanim name {-play|-resume|-pause|-stop} [playFrom [playDuration]]"
14790     "\n\t\t:            [-speed Coeff] [-freeLook] [-noPauseOnClick] [-lockLoop]"
14791     "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
14792     "\n\t\t:   -freeLook skip camera animations"
14793     "\n\t\t:   -noPauseOnClick do not pause animation on mouse click"
14794     "\n\t\t:   -lockLoop disable any interactions"
14795     "\n\t\t:"
14796     "\n\t\t: Animation definition:"
14797     "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
14798     "\n\t\t:        [start TimeSec] [duration TimeSec]"
14799     "\n\t\t:"
14800     "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
14801     "\n\t\t: specifies nested animations."
14802     "\n\t\t: There is no syntax to explicitly add new animation,"
14803     "\n\t\t: and all non-existing animations within the name will be"
14804     "\n\t\t: implicitly created on first use (including parents)."
14805     "\n\t\t:"
14806     "\n\t\t: Each animation might define the SINGLE action (see below),"
14807     "\n\t\t: like camera transition, object transformation or custom callback."
14808     "\n\t\t: Child animations can be used for defining concurrent actions."
14809     "\n\t\t:"
14810     "\n\t\t: Camera animation:"
14811     "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
14812     "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
14813     "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
14814     "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
14815     "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
14816     "\n\t\t:   -atX    camera Center positions pair"
14817     "\n\t\t:   -upX    camera Up directions pair"
14818     "\n\t\t:   -scaleX camera Scale factors pair"
14819     "\n\t\t: Object animation:"
14820     "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
14821     "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
14822     "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
14823     "\n\t\t:   -locX   object Location points pair (translation)"
14824     "\n\t\t:   -rotX   object Orientations pair (quaternions)"
14825     "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
14826     "\n\t\t: Custom callback:"
14827     "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
14828     "\n\t\t:   %Pts        overall animation presentation timestamp"
14829     "\n\t\t:   %LocalPts   local animation timestamp"
14830     "\n\t\t:   %Normalized local animation normalized value in range 0..1"
14831     "\n\t\t:"
14832     "\n\t\t: Video recording:"
14833     "\n\t\t:  vanim name -record FileName [Width Height] [-fps FrameRate=24]"
14834     "\n\t\t:             [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]"
14835     "\n\t\t:             [-crf Value] [-preset Preset]"
14836     "\n\t\t:   -fps     video framerate"
14837     "\n\t\t:   -format  file format, container (matroska, etc.)"
14838     "\n\t\t:   -vcodec  video codec identifier (ffv1, mjpeg, etc.)"
14839     "\n\t\t:   -pix_fmt image pixel format (yuv420p, rgb24, etc.)"
14840     "\n\t\t:   -crf     constant rate factor (specific to codec)"
14841     "\n\t\t:   -preset  codec parameters preset (specific to codec)",
14842     __FILE__, VAnimation, group);
14843
14844   theCommands.Add("vchangeselected",
14845     "vchangeselected shape"
14846     "- adds to shape to selection or remove one from it",
14847                 __FILE__, VChangeSelected, group);
14848   theCommands.Add ("vnbselected",
14849     "vnbselected"
14850     "\n\t\t: Returns number of selected objects", __FILE__, VNbSelected, group);
14851   theCommands.Add ("vcamera",
14852               "vcamera [PrsName] [-ortho] [-projtype]"
14853       "\n\t\t:         [-persp]"
14854       "\n\t\t:         [-fovy   [Angle]] [-distance [Distance]]"
14855       "\n\t\t:         [-stereo] [-leftEye] [-rightEye]"
14856       "\n\t\t:         [-iod [Distance]] [-iodType    [absolute|relative]]"
14857       "\n\t\t:         [-zfocus [Value]] [-zfocusType [absolute|relative]]"
14858       "\n\t\t:         [-fov2d  [Angle]] [-lockZup {0|1}]"
14859       "\n\t\t:         [-xrPose base|head=base]"
14860       "\n\t\t: Manages camera parameters."
14861       "\n\t\t: Displays frustum when presentation name PrsName is specified."
14862       "\n\t\t: Prints current value when option called without argument."
14863       "\n\t\t: Orthographic camera:"
14864       "\n\t\t:   -ortho      activate orthographic projection"
14865       "\n\t\t: Perspective camera:"
14866       "\n\t\t:   -persp      activate perspective  projection (mono)"
14867       "\n\t\t:   -fovy       field of view in y axis, in degrees"
14868       "\n\t\t:   -fov2d      field of view limit for 2d on-screen elements"
14869       "\n\t\t:   -distance   distance of eye from camera center"
14870       "\n\t\t:   -lockZup    lock Z up (tunrtable mode)"
14871       "\n\t\t: Stereoscopic camera:"
14872       "\n\t\t:   -stereo     perspective  projection (stereo)"
14873       "\n\t\t:   -leftEye    perspective  projection (left  eye)"
14874       "\n\t\t:   -rightEye   perspective  projection (right eye)"
14875       "\n\t\t:   -iod        intraocular distance value"
14876       "\n\t\t:   -iodType    distance type, absolute or relative"
14877       "\n\t\t:   -zfocus     stereographic focus value"
14878       "\n\t\t:   -zfocusType focus type, absolute or relative",
14879     __FILE__, VCamera, group);
14880   theCommands.Add ("vautozfit", "command to enable or disable automatic z-range adjusting\n"
14881     "- vautozfit [on={1|0}] [scale]\n"
14882     "    Prints or changes parameters of automatic z-fit mode:\n"
14883     "   \"on\" - turns automatic z-fit on or off\n"
14884     "   \"scale\" - specifies factor to scale computed z range.\n",
14885     __FILE__, VAutoZFit, group);
14886   theCommands.Add ("vzrange", "command to manually access znear and zfar values\n"
14887     "   vzrange                - without parameters shows current values\n"
14888     "   vzrange [znear] [zfar] - applies provided values to view",
14889     __FILE__,VZRange, group);
14890   theCommands.Add("vsetviewsize",
14891     "vsetviewsize size",
14892     __FILE__,VSetViewSize,group);
14893   theCommands.Add("vmoveview",
14894     "vmoveview Dx Dy Dz [Start = 1|0]",
14895     __FILE__,VMoveView,group);
14896   theCommands.Add("vtranslateview",
14897     "vtranslateview Dx Dy Dz [Start = 1|0)]",
14898     __FILE__,VTranslateView,group);
14899   theCommands.Add("vturnview",
14900     "vturnview Ax Ay Az [Start = 1|0]",
14901     __FILE__,VTurnView,group);
14902   theCommands.Add("vtextureenv",
14903     "Enables or disables environment mapping in the 3D view, loading the texture from the given standard "
14904     "or user-defined file and optionally applying texture mapping parameters\n"
14905     "                  Usage:\n"
14906     "                  vtextureenv off - disables environment mapping\n"
14907     "                  vtextureenv on {std_texture|texture_file_name} [rep mod flt ss st ts tt rot] - enables environment mapping\n"
14908     "                              std_texture = (0..7)\n"
14909     "                              rep         = {clamp|repeat}\n"
14910     "                              mod         = {decal|modulate}\n"
14911     "                              flt         = {nearest|bilinear|trilinear}\n"
14912     "                              ss, st      - scale factors for s and t texture coordinates\n"
14913     "                              ts, tt      - translation for s and t texture coordinates\n"
14914     "                              rot         - texture rotation angle in degrees",
14915     __FILE__, VTextureEnv, group);
14916   theCommands.Add("vhlr",
14917             "vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]"
14918       "\n\t\t: Hidden Line Removal algorithm."
14919       "\n\t\t:   -showHidden if set ON, hidden lines are drawn as dotted ones"
14920       "\n\t\t:   -algoType   type of HLR algorithm.\n",
14921     __FILE__,VHLR,group);
14922   theCommands.Add("vhlrtype",
14923               "vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]"
14924       "\n\t\t: Changes the type of HLR algorithm using for shapes:"
14925       "\n\t\t:   'algo' - exact HLR algorithm is applied"
14926       "\n\t\t:   'polyAlgo' - polygonal HLR algorithm is applied"
14927       "\n\t\t: If shapes are not given - option is applied to all shapes in the view",
14928     __FILE__,VHLRType,group);
14929   theCommands.Add("vclipplane",
14930               "vclipplane planeName [{0|1}]"
14931       "\n\t\t:   [-equation1 A B C D]"
14932       "\n\t\t:   [-equation2 A B C D]"
14933       "\n\t\t:   [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]"
14934       "\n\t\t:   [-set|-unset|-setOverrideGlobal [objects|views]]"
14935       "\n\t\t:   [-maxPlanes]"
14936       "\n\t\t:   [-capping {0|1}]"
14937       "\n\t\t:     [-color R G B] [-transparency Value] [-hatch {on|off|ID}]"
14938       "\n\t\t:     [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]"
14939       "\n\t\t:       [-texRotate Angle]"
14940       "\n\t\t:     [-useObjMaterial {0|1}] [-useObjTexture {0|1}]"
14941       "\n\t\t:       [-useObjShader {0|1}]"
14942       "\n\t\t: Clipping planes management:"
14943       "\n\t\t:   -maxPlanes   print plane limit for view"
14944       "\n\t\t:   -delete      delete plane with given name"
14945       "\n\t\t:   {off|on|0|1} turn clipping on/off"
14946       "\n\t\t:   -set|-unset  set/unset plane for Object or View list;"
14947       "\n\t\t:                applied to active View when list is omitted"
14948       "\n\t\t:   -equation A B C D change plane equation"
14949       "\n\t\t:   -clone SourcePlane NewPlane clone the plane definition."
14950       "\n\t\t: Capping options:"
14951       "\n\t\t:   -capping {off|on|0|1} turn capping on/off"
14952       "\n\t\t:   -color R G B          set capping color"
14953       "\n\t\t:   -transparency Value   set capping transparency 0..1"
14954       "\n\t\t:   -texName Texture      set capping texture"
14955       "\n\t\t:   -texScale SX SY       set capping tex scale"
14956       "\n\t\t:   -texOrigin TX TY      set capping tex origin"
14957       "\n\t\t:   -texRotate Angle      set capping tex rotation"
14958       "\n\t\t:   -hatch {on|off|ID}    set capping hatching mask"
14959       "\n\t\t:   -useObjMaterial {off|on|0|1} use material of clipped object"
14960       "\n\t\t:   -useObjTexture  {off|on|0|1} use texture of clipped object"
14961       "\n\t\t:   -useObjShader   {off|on|0|1} use shader program of object",
14962       __FILE__, VClipPlane, group);
14963   theCommands.Add("vdefaults",
14964                "vdefaults [-absDefl value]"
14965        "\n\t\t:           [-devCoeff value]"
14966        "\n\t\t:           [-angDefl value]"
14967        "\n\t\t:           [-autoTriang {off/on | 0/1}]"
14968     , __FILE__, VDefaults, group);
14969   theCommands.Add("vlight",
14970               "vlight [lightName] [-noupdate]"
14971       "\n\t\t:   [-clear|-defaults] [-layer Id] [-local|-global] [-disable|-enable]"
14972       "\n\t\t:   [-type {ambient|directional|spotlight|positional}] [-name value]"
14973       "\n\t\t:   [-position X Y Z] [-direction X Y Z] [-color colorName] [-intensity value]"
14974       "\n\t\t:   [-headlight 0|1] [-castShadows 0|1]"
14975       "\n\t\t:   [-range value] [-constAttenuation value] [-linearAttenuation value]"
14976       "\n\t\t:   [-spotExponent value] [-spotAngle angleDeg]"
14977       "\n\t\t:   [-smoothAngle value] [-smoothRadius value]"
14978       "\n\t\t:   [-display] [-showName 1|0] [-showRange 1|0] [-prsZoomable 1|0] [-prsSize Value]"
14979       "\n\t\t:   [-arcSize Value]"
14980       "\n\t\t: Command manages light sources. Without arguments shows list of lights."
14981       "\n\t\t: Arguments affecting the list of defined/active lights:"
14982       "\n\t\t:   -clear       remove all light sources"
14983       "\n\t\t:   -defaults    defines two standard light sources"
14984       "\n\t\t:   -reset       resets light source parameters to default values"
14985       "\n\t\t:   -type        sets type of light source"
14986       "\n\t\t:   -name        sets new name to light source"
14987       "\n\t\t:   -global      assigns light source to all views (default state)"
14988       "\n\t\t:   -local       assigns light source to active view"
14989       "\n\t\t:   -zlayer      assigns light source to specified Z-Layer"
14990       "\n\t\t: Ambient light parameters:"
14991       "\n\t\t:   -color       sets (normalized) light color"
14992       "\n\t\t:   -intensity   sets intensity of light source, 1.0 by default;"
14993       "\n\t\t:                affects also environment cubemap intensity"
14994       "\n\t\t: Point light parameters:"
14995       "\n\t\t:   -color       sets (normalized) light color"
14996       "\n\t\t:   -intensity   sets PBR intensity"
14997       "\n\t\t:   -range       sets clamping distance"
14998       "\n\t\t:   -constAtten  (obsolete) sets constant attenuation factor"
14999       "\n\t\t:   -linearAtten (obsolete) sets linear   attenuation factor"
15000       "\n\t\t:   -smoothRadius sets PBR smoothing radius"
15001       "\n\t\t: Directional light parameters:"
15002       "\n\t\t:   -color       sets (normalized) light color"
15003       "\n\t\t:   -intensity   sets PBR intensity"
15004       "\n\t\t:   -direction   sets direction"
15005       "\n\t\t:   -headlight   sets headlight flag"
15006       "\n\t\t:   -castShadows enables/disables shadow casting"
15007       "\n\t\t:   -smoothAngle sets PBR smoothing angle (in degrees) within 0..90 range"
15008       "\n\t\t: Spot light parameters:"
15009       "\n\t\t:   -color       sets (normalized) light color"
15010       "\n\t\t:   -intensity   sets PBR intensity"
15011       "\n\t\t:   -range       sets clamping distance"
15012       "\n\t\t:   -position    sets position"
15013       "\n\t\t:   -direction   sets direction"
15014       "\n\t\t:   -spotAngle   sets spotlight angle"
15015       "\n\t\t:   -spotExp     sets spotlight exponenta"
15016       "\n\t\t:   -headlight   sets headlight flag"
15017       "\n\t\t:   -constAtten  (obsolete) sets constant attenuation factor"
15018       "\n\t\t:   -linearAtten (obsolete) sets linear   attenuation factor"
15019       "\n\t\t: Light presentation parameters:"
15020       "\n\t\t:   -display     adds light source presentation"
15021       "\n\t\t:   -showName    shows/hides the name of light source; 1 by default"
15022       "\n\t\t:   -showRange   shows/hides the range of spot/positional light source; 1 by default"
15023       "\n\t\t:   -prsZoomable makes light presentation zoomable/non-zoomable"
15024       "\n\t\t:   -prsDraggable makes light presentation draggable/non-draggable"
15025       "\n\t\t:   -prsSize     sets light presentation size"
15026       "\n\t\t:   -arcSize     sets arc presentation size(in pixels) for rotation directional light source; 25 by default"
15027       "\n\t\t: Examples:"
15028       "\n\t\t:   vlight redlight -type POSITIONAL -headlight 1 -pos 0 1 1 -color RED"
15029       "\n\t\t:   vlight redlight -delete",
15030     __FILE__, VLight, group);
15031   theCommands.Add("vpbrenv",
15032     "vpbrenv -clear|-generate"
15033     "\n\t\t: Clears or generates PBR environment map of active view."
15034     "\n\t\t:  -clear clears PBR environment (fills by white color)"
15035     "\n\t\t:  -generate generates PBR environment from current background cubemap",
15036     __FILE__, VPBREnvironment, group);
15037   theCommands.Add("vraytrace",
15038             "vraytrace [0|1]"
15039     "\n\t\t: Turns on/off ray-tracing renderer."
15040     "\n\t\t:   'vraytrace 0' alias for 'vrenderparams -raster'."
15041     "\n\t\t:   'vraytrace 1' alias for 'vrenderparams -rayTrace'.",
15042     __FILE__, VRenderParams, group);
15043   theCommands.Add("vrenderparams",
15044     "\n\t\t: Manages rendering parameters, affecting visual appearance, quality and performance."
15045     "\n\t\t: Should be applied taking into account GPU hardware capabilities and performance."
15046     "\n\t\t: Common parameters:"
15047     "\n\t\t: vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]"
15048     "\n\t\t:               [-msaa 0..8=0] [-rendScale scale=1]"
15049     "\n\t\t:               [-resolution value=72] [-fontHinting {off|normal|light}=off]"
15050     "\n\t\t:               [-fontAutoHinting {auto|force|disallow}=auto]"
15051     "\n\t\t:               [-oit {off|weight|peel}] [-oit weighted [depthFactor=0.0]] [-oit peeling [nbLayers=4]]"
15052     "\n\t\t:               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]"
15053     "\n\t\t:               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]"
15054     "\n\t\t:               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]"
15055     "\n\t\t:               [-sync {default|views}] [-reset]"
15056     "\n\t\t:   -raster          Disables GPU ray-tracing."
15057     "\n\t\t:   -shadingModel    Controls shading model."
15058     "\n\t\t:   -msaa            Specifies number of samples for MSAA."
15059     "\n\t\t:   -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA)."
15060     "\n\t\t:   -resolution      Sets new pixels density (PPI) used as text scaling factor."
15061     "\n\t\t:   -fontHinting     Enables/disables font hinting for better readability on low-resolution screens."
15062     "\n\t\t:   -fontAutoHinting Manages font autohinting."
15063     "\n\t\t:   -lineFeather     Sets line feather factor while displaying mesh edges."
15064     "\n\t\t:   -alphaToCoverage Enables/disables alpha to coverage (needs MSAA)."
15065     "\n\t\t:   -oit             Enables/disables order-independent transparency (OIT) rendering;"
15066     "\n\t\t:        off         unordered transparency (but opaque objects implicitly draw first);"
15067     "\n\t\t:        weighted    weight OIT is managed by depth weight factor 0.0..1.0;"
15068     "\n\t\t:        peeling     depth peeling OIT is managed by number of peeling layers."
15069     "\n\t\t:   -shadows         Enables/disables shadows rendering."
15070     "\n\t\t:   -shadowMapResolution Shadow texture map resolution."
15071     "\n\t\t:   -shadowMapBias   Shadow map bias."
15072     "\n\t\t:   -depthPrePass    Enables/disables depth pre-pass."
15073     "\n\t\t:   -frustumCulling  Enables/disables objects frustum clipping or"
15074     "\n\t\t:                    sets state to check structures culled previously."
15075     "\n\t\t:   -sync            Sets active View parameters as Viewer defaults / to other Views."
15076     "\n\t\t:   -reset           Resets active View parameters to Viewer defaults."
15077     "\n\t\t: Diagnostic output (on-screen overlay):"
15078     "\n\t\t: vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points"
15079     "\n\t\t:                             |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]"
15080     "\n\t\t:               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]"
15081     "\n\t\t:   -perfCounters       Show/hide performance counters (flags can be combined)."
15082     "\n\t\t:   -perfUpdateInterval Performance counters update interval."
15083     "\n\t\t:   -perfChart          Show frame timers chart limited by specified number of frames."
15084     "\n\t\t:   -perfChartMax       Maximum time in seconds with the chart."
15085     "\n\t\t: Ray-Tracing options:"
15086     "\n\t\t: vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]"
15087     "\n\t\t:               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]"
15088     "\n\t\t:               [-gi {on|off}=off] [-brng {on|off}=off]"
15089     "\n\t\t:               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]"
15090     "\n\t\t:               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]"
15091     "\n\t\t:               [-maxRad {value>0}=30.0]"
15092     "\n\t\t:               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]"
15093     "\n\t\t:               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]"
15094     "\n\t\t:   -rayTrace     Enables  GPU ray-tracing."
15095     "\n\t\t:   -rayDepth     Defines maximum ray-tracing depth."
15096     "\n\t\t:   -reflections  Enables/disables specular reflections."
15097     "\n\t\t:   -fsaa         Enables/disables adaptive anti-aliasing."
15098     "\n\t\t:   -gleam        Enables/disables transparency shadow effects."
15099     "\n\t\t:   -gi           Enables/disables global illumination effects (Path-Tracing)."
15100     "\n\t\t:   -env          Enables/disables environment map background."
15101     "\n\t\t:   -ignoreNormalMap Enables/disables normal map ignoring during path tracing."
15102     "\n\t\t:   -twoSide      Enables/disables two-sided BSDF models (PT mode)."
15103     "\n\t\t:   -iss          Enables/disables adaptive screen sampling (PT mode)."
15104     "\n\t\t:   -maxRad       Value used for clamping radiance estimation (PT mode)."
15105     "\n\t\t:   -tileSize     Specifies   size of screen tiles in ISS mode (32 by default)."
15106     "\n\t\t:   -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default)."
15107     "\n\t\t:   -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF)."
15108     "\n\t\t:   -focal        Focal distance of perspective camera for depth-of-field effect."
15109     "\n\t\t:   -exposure     Exposure value for tone mapping (0.0 value disables the effect)."
15110     "\n\t\t:   -whitePoint   White point value for filmic tone mapping."
15111     "\n\t\t:   -toneMapping  Tone mapping mode (disabled, filmic)."
15112     "\n\t\t: PBR environment baking parameters (advanced/debug):"
15113     "\n\t\t: vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]"
15114     "\n\t\t:               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]"
15115     "\n\t\t:   -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size)."
15116     "\n\t\t:   -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map."
15117     "\n\t\t:   -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during"
15118     "\n\t\t:                   diffuse IBL map's sherical harmonics calculation."
15119     "\n\t\t:   -pbrEnvBSSN     Controls maximum number of samples per mipmap level"
15120     "\n\t\t:                   in Monte-Carlo integration during specular IBL maps generation."
15121     "\n\t\t:   -pbrEnvBP       Controls strength of samples number reducing"
15122     "\n\t\t:                   during specular IBL maps generation (1 disables reducing)."
15123     "\n\t\t: Debug options:"
15124     "\n\t\t: vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]"
15125     "\n\t\t:   -issd         Shows screen sampling distribution in ISS mode."
15126     "\n\t\t:   -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging)."
15127     "\n\t\t:   -brng         Enables/disables blocked RNG (fast coherent PT).",
15128     __FILE__, VRenderParams, group);
15129   theCommands.Add("vstatprofiler",
15130     "\n vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups"
15131     "\n                |allArrays|fillArrays|lineArrays|pointArrays|textArrays"
15132     "\n                |triangles|points|geomMem|textureMem|frameMem"
15133     "\n                |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage"
15134     "\n                |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]"
15135     "\n                [-noredraw]"
15136     "\n\t\t: Prints rendering statistics."
15137     "\n\t\t:   If there are some parameters - print corresponding statistic counters values,"
15138     "\n\t\t:   else - print all performance counters set previously."
15139     "\n\t\t:   '-noredraw' Flag to avoid additional redraw call and use already collected values.\n",
15140     __FILE__, VStatProfiler, group);
15141   theCommands.Add ("vplace",
15142             "vplace dx dy"
15143     "\n\t\t: Places the point (in pixels) at the center of the window",
15144     __FILE__, VPlace, group);
15145   theCommands.Add("vxrotate",
15146     "vxrotate",
15147     __FILE__,VXRotate,group);
15148
15149     theCommands.Add("vmanipulator",
15150       "\n    vmanipulator Name [-attach AISObject | -detach | ...]"
15151       "\n    tool to create and manage AIS manipulators."
15152       "\n    Options: "
15153       "\n      '-attach AISObject'                 attach manipulator to AISObject"
15154       "\n      '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching"
15155       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
15156       "\n      '-enableModes    {0|1}'             enable modes when attaching"
15157       "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
15158       "\n                                          by default it is displayed in all views of the current viewer"
15159       "\n      '-detach'                           detach manipulator"
15160       "\n      '-startTransform mouse_x mouse_y' - invoke start of transformation"
15161       "\n      '-transform      mouse_x mouse_y' - invoke transformation"
15162       "\n      '-stopTransform  [abort]'         - invoke stop of transformation"
15163       "\n      '-move x y z'                     - move attached object"
15164       "\n      '-rotate x y z dx dy dz angle'    - rotate attached object"
15165       "\n      '-scale factor'                   - scale attached object"
15166       "\n      '-autoActivate      {0|1}'        - set activation on detection"
15167       "\n      '-followTranslation {0|1}'        - set following translation transform"
15168       "\n      '-followRotation    {0|1}'        - set following rotation transform"
15169       "\n      '-followDragging    {0|1}'        - set following dragging transform"
15170       "\n      '-gap value'                      - set gap between sub-parts"
15171       "\n      '-part axis mode    {0|1}'        - set visual part"
15172       "\n      '-parts axis mode   {0|1}'        - set visual part"
15173       "\n      '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator"
15174       "\n      '-size value'                     - set size of manipulator"
15175       "\n      '-zoomable {0|1}'                 - set zoom persistence",
15176     __FILE__, VManipulator, group);
15177
15178   theCommands.Add("vselprops",
15179     "\n    vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]"
15180     "\n    Customizes selection and dynamic highlight parameters for the whole interactive context:"
15181     "\n    -autoActivate {0|1}     : disables|enables default computation and activation of global selection mode"
15182     "\n    -autoHighlight {0|1}    : disables|enables automatic highlighting in 3D Viewer"
15183     "\n    -highlightSelected {0|1}: disables|enables highlighting of detected object in selected state"
15184     "\n    -pickStrategy {first|topmost} : defines picking strategy"
15185     "\n                            'first'   to pick first acceptable (default)"
15186     "\n                            'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)"
15187     "\n    -pixTol    value        : sets up pixel tolerance"
15188     "\n    -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth"
15189     "\n    -depthTol {sensfactor}  : use sensitive factor for sorting results by depth"
15190     "\n    -preferClosest {0|1}    : sets if depth should take precedence over priority while sorting results"
15191     "\n    -dispMode  dispMode     : sets display mode for highlighting"
15192     "\n    -layer     ZLayer       : sets ZLayer for highlighting"
15193     "\n    -color     {name|r g b} : sets highlight color"
15194     "\n    -transp    value        : sets transparency coefficient for highlight"
15195     "\n    -material  material     : sets highlight material"
15196     "\n    -print                  : prints current state of all mentioned parameters",
15197     __FILE__, VSelectionProperties, group);
15198   theCommands.Add ("vhighlightselected",
15199                    "vhighlightselected [0|1]: alias for vselprops -highlightSelected.\n",
15200                    __FILE__, VSelectionProperties, group);
15201
15202   theCommands.Add ("vseldump",
15203                    "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity|entityType|surfNormal}=depth -pickedIndex Index=1"
15204                    "\n\t\t:       [-xrPose base|head=base]"
15205                    "\n\t\t: Generate an image based on detection results:"
15206                    "\n\t\t:   depth       normalized depth values"
15207                    "\n\t\t:   unnormDepth unnormalized depth values"
15208                    "\n\t\t:   object      color of detected object"
15209                    "\n\t\t:   owner       color of detected owner"
15210                    "\n\t\t:   selMode     color of selection mode"
15211                    "\n\t\t:   entity      color of detected entity"
15212                    "\n\t\t:   entityType  color of detected entity type"
15213                    "\n\t\t:   surfNormal  normal direction values",
15214                    __FILE__, VDumpSelectionImage, group);
15215
15216   theCommands.Add ("vviewcube",
15217                    "vviewcube name"
15218                    "\n\t\t: Displays interactive view manipualtion object."
15219                    "\n\t\t: Options: "
15220                    "\n\t\t:   -reset                   reset geomertical and visual attributes'"
15221                    "\n\t\t:   -size Size               adapted size of View Cube"
15222                    "\n\t\t:   -boxSize Size            box size"
15223                    "\n\t\t:   -axes  {0|1}             show/hide axes (trihedron)"
15224                    "\n\t\t:   -edges {0|1}             show/hide edges of View Cube"
15225                    "\n\t\t:   -vertices {0|1}          show/hide vertices of View Cube"
15226                    "\n\t\t:   -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation"
15227                    "\n\t\t:   -color Color             color of View Cube"
15228                    "\n\t\t:   -boxColor Color          box color"
15229                    "\n\t\t:   -boxSideColor Color      box sides color"
15230                    "\n\t\t:   -boxEdgeColor Color      box edges color"
15231                    "\n\t\t:   -boxCornerColor Color    box corner color"
15232                    "\n\t\t:   -textColor Color         color of side text of view cube"
15233                    "\n\t\t:   -innerColor Color        inner box color"
15234                    "\n\t\t:   -transparency Value      transparency of object within [0, 1] range"
15235                    "\n\t\t:   -boxTransparency Value   transparency of box    within [0, 1] range"
15236                    "\n\t\t:   -xAxisTextColor Color    color of X axis label"
15237                    "\n\t\t:   -yAxisTextColor Color    color of Y axis label"
15238                    "\n\t\t:   -zAxisTextColor Color    color of Z axis label"
15239                    "\n\t\t:   -font Name               font name"
15240                    "\n\t\t:   -fontHeight Value        font height"
15241                    "\n\t\t:   -boxFacetExtension Value box facet extension"
15242                    "\n\t\t:   -boxEdgeGap Value        gap between box edges and box sides"
15243                    "\n\t\t:   -boxEdgeMinSize Value    minimal box edge size"
15244                    "\n\t\t:   -boxCornerMinSize Value  minimal box corner size"
15245                    "\n\t\t:   -axesPadding Value       padding between box and arrows"
15246                    "\n\t\t:   -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range"
15247                    "\n\t\t:   -axesRadius Value        radius of axes of the trihedron"
15248                    "\n\t\t:   -axesConeRadius Value    radius of the cone (arrow) of the trihedron"
15249                    "\n\t\t:   -axesSphereRadius Value  radius of the sphere (central point) of trihedron"
15250                    "\n\t\t:   -fixedanimation {0|1}    uninterruptible animation loop"
15251                    "\n\t\t:   -duration Seconds        animation duration in seconds",
15252     __FILE__, VViewCube, group);
15253
15254   theCommands.Add("vcolorconvert" ,
15255                   "vcolorconvert {from|to} type C1 C2 C2"
15256                   "\n\t\t: vcolorconvert from type C1 C2 C2: Converts color from specified color space to linear RGB"
15257                   "\n\t\t: vcolorconvert to type R G B: Converts linear RGB color to specified color space"
15258                   "\n\t\t: type can be sRGB, HLS, Lab, or Lch",
15259                   __FILE__,VColorConvert,group);
15260   theCommands.Add("vcolordiff" ,
15261                   "vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
15262                   __FILE__,VColorDiff,group);
15263   theCommands.Add("vselbvhbuild",
15264                   "vselbvhbuild [{0|1}] [-nbThreads value] [-wait]"
15265                   "\n\t\t: Turns on/off prebuilding of BVH within background thread(s)"
15266                   "\n\t\t:   -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1)"
15267                   "\n\t\t:   -wait        waits for building all of BVH",
15268                   __FILE__,VSelBvhBuild,group);
15269 }