0031621: Draw Harness - handle navigation keys
[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 #include <OpenGl_GlCore20.hxx>
18 #include <ViewerTest.hxx>
19
20 #include <AIS_AnimationCamera.hxx>
21 #include <AIS_AnimationObject.hxx>
22 #include <AIS_CameraFrustum.hxx>
23 #include <AIS_ColorScale.hxx>
24 #include <AIS_InteractiveContext.hxx>
25 #include <AIS_ListOfInteractive.hxx>
26 #include <AIS_ListIteratorOfListOfInteractive.hxx>
27 #include <AIS_Manipulator.hxx>
28 #include <AIS_ViewCube.hxx>
29 #include <AIS_Shape.hxx>
30 #include <Aspect_DisplayConnection.hxx>
31 #include <Aspect_Grid.hxx>
32 #include <Aspect_TypeOfLine.hxx>
33 #include <Draw.hxx>
34 #include <Draw_Appli.hxx>
35 #include <Draw_Interpretor.hxx>
36 #include <Draw_ProgressIndicator.hxx>
37 #include <gp_Dir.hxx>
38 #include <gp_Pln.hxx>
39 #include <gp_Pnt.hxx>
40 #include <Graphic3d_ArrayOfPolylines.hxx>
41 #include <Graphic3d_AspectFillArea3d.hxx>
42 #include <Graphic3d_AspectMarker3d.hxx>
43 #include <Graphic3d_ClipPlane.hxx>
44 #include <Graphic3d_CubeMapPacked.hxx>
45 #include <Graphic3d_CubeMapSeparate.hxx>
46 #include <Graphic3d_GraduatedTrihedron.hxx>
47 #include <Graphic3d_NameOfTextureEnv.hxx>
48 #include <Graphic3d_Texture2Dmanual.hxx>
49 #include <Graphic3d_TextureEnv.hxx>
50 #include <Graphic3d_TextureParams.hxx>
51 #include <Graphic3d_TypeOfTextureFilter.hxx>
52 #include <Image_AlienPixMap.hxx>
53 #include <Image_Diff.hxx>
54 #include <Image_VideoRecorder.hxx>
55 #include <Message_ProgressSentry.hxx>
56 #include <NCollection_DataMap.hxx>
57 #include <NCollection_List.hxx>
58 #include <NCollection_Vector.hxx>
59 #include <OSD.hxx>
60 #include <OSD_Timer.hxx>
61 #include <OpenGl_GraphicDriver.hxx>
62 #include <Prs3d_ShadingAspect.hxx>
63 #include <Prs3d_Drawer.hxx>
64 #include <Prs3d_LineAspect.hxx>
65 #include <Prs3d_Root.hxx>
66 #include <Prs3d_Text.hxx>
67 #include <Select3D_SensitivePrimitiveArray.hxx>
68 #include <TColStd_HSequenceOfAsciiString.hxx>
69 #include <TColStd_SequenceOfInteger.hxx>
70 #include <TColStd_HSequenceOfReal.hxx>
71 #include <TColgp_Array1OfPnt2d.hxx>
72 #include <TColStd_MapOfAsciiString.hxx>
73 #include <ViewerTest_AutoUpdater.hxx>
74 #include <ViewerTest_ContinuousRedrawer.hxx>
75 #include <ViewerTest_EventManager.hxx>
76 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
77 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
78 #include <ViewerTest_CmdParser.hxx>
79 #include <ViewerTest_V3dView.hxx>
80 #include <V3d_AmbientLight.hxx>
81 #include <V3d_DirectionalLight.hxx>
82 #include <V3d_PositionalLight.hxx>
83 #include <V3d_SpotLight.hxx>
84
85 #include <tcl.h>
86
87 #include <cstdlib>
88
89 #if defined(_WIN32)
90   #include <WNT_WClass.hxx>
91   #include <WNT_Window.hxx>
92 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
93   #include <Cocoa_Window.hxx>
94 #else
95   #include <Xw_Window.hxx>
96   #include <X11/Xlib.h> /* contains some dangerous #defines such as Status, True etc. */
97   #include <X11/Xutil.h>
98   #include <tk.h>
99 #endif
100
101 //==============================================================================
102 //  VIEWER GLOBAL VARIABLES
103 //==============================================================================
104
105 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
106 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
107
108 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
109 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
110
111 #if defined(_WIN32)
112 static Handle(WNT_Window)& VT_GetWindow() {
113   static Handle(WNT_Window) WNTWin;
114   return WNTWin;
115 }
116 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
117 static Handle(Cocoa_Window)& VT_GetWindow()
118 {
119   static Handle(Cocoa_Window) aWindow;
120   return aWindow;
121 }
122 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
123 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
124
125 #else
126 static Handle(Xw_Window)& VT_GetWindow(){
127   static Handle(Xw_Window) XWWin;
128   return XWWin;
129 }
130
131 static void VProcessEvents(ClientData,int);
132 #endif
133
134 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
135 {
136   static Handle(Aspect_DisplayConnection) aDisplayConnection;
137   return aDisplayConnection;
138 }
139
140 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
141 {
142   GetDisplayConnection() = theDisplayConnection;
143 }
144
145 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
146 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
147 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
148 static OpenGl_Caps ViewerTest_myDefaultCaps;
149
150 static void OSWindowSetup();
151
152 static struct
153 {
154   Quantity_Color FlatColor;
155   Quantity_Color GradientColor1;
156   Quantity_Color GradientColor2;
157   Aspect_GradientFillMethod FillMethod;
158 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
159
160 //==============================================================================
161 //  EVENT GLOBAL VARIABLES
162 //==============================================================================
163
164 Standard_Boolean TheIsAnimating = Standard_False;
165
166 namespace
167 {
168
169   //! Checks if some set is a subset of other set
170   //! @tparam TheSuperSet the type of the superset
171   //! @tparam TheSubSet the type of the subset
172   //! @param theSuperSet the superset
173   //! @param theSubSet the subset to be checked
174   //! @return true if the superset includes subset, or false otherwise
175   template <typename TheSuperSet, typename TheSubSet>
176   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
177   {
178     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
179   }
180
181   //! A variable set of keys for command-line options.
182   //! It includes a set of mandatory keys and a set of all possible keys.
183   class CommandOptionKeyVariableSet
184   {
185   public:
186     //! Default constructor
187     CommandOptionKeyVariableSet()
188     {
189     }
190
191     //! Constructor
192     //! @param theMandatoryKeySet the set of the mandatory option keys
193     //! @param theAdditionalKeySet the set of additional options that could be omitted
194     CommandOptionKeyVariableSet (
195       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
196       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
197     : myMandatoryKeySet (theMandatoryKeySet)
198     {
199       std::set_union (theMandatoryKeySet.begin(),
200                       theMandatoryKeySet.end(),
201                       theAdditionalKeySet.begin(),
202                       theAdditionalKeySet.end(),
203                       std::inserter (myFullKeySet, myFullKeySet.begin()));
204     }
205
206     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
207     //! and be contained in the full key set)
208     //! @param theCheckedKeySet the set of option keys to be checked
209     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
210     {
211       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
212     }
213
214   private:
215     //! A set of mandatory command-line option keys
216     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
217
218     //! A full set of command-line option keys (includes mandatory and additional option keys)
219     ViewerTest_CommandOptionKeySet myFullKeySet;
220   };
221
222   //! Gets some code by its name
223   //! @tparam TheCode the type of a code to be found
224   //! @param theCodeNameMap the map from code names to codes
225   //! @param theCodeName the name of a code to be found
226   //! @param theCode the code to be found
227   //! @return true if a code is found, or false otherwise
228   template <typename TheCode>
229   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
230                                  TCollection_AsciiString                           theCodeName,
231                                  TheCode&                                          theCode)
232   {
233     theCodeName.LowerCase();
234     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
235       theCodeName);
236     if (aCodeIterator == theCodeNameMap.end())
237     {
238       return false;
239     }
240     theCode = aCodeIterator->second;
241     return true;
242   }
243
244   // Defines possible commands related to background changing
245   enum BackgroundCommand
246   {
247     BackgroundCommand_Main,              //!< The main command that manages other commands through options
248     BackgroundCommand_Image,             //!< Sets an image as a background
249     BackgroundCommand_ImageMode,         //!< Changes a background image mode
250     BackgroundCommand_Gradient,          //!< Sets a gradient as a background
251     BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
252     BackgroundCommand_Color,             //!< Fills background with a specified color
253     BackgroundCommand_Default            //!< Sets the background default color or gradient
254   };
255
256   //! Map from background command names to its codes
257   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
258
259   //! Creates a map from background command names to its codes
260   //! @return a map from background command names to its codes
261   static BackgroundCommandNameMap createBackgroundCommandNameMap()
262   {
263     BackgroundCommandNameMap aBackgroundCommandNameMap;
264     aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
265     aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
266     aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
267     aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
268     aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
269     aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
270     aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
271     return aBackgroundCommandNameMap;
272   }
273
274   //! Gets a background command by its name
275   //! @param theBackgroundCommandName the name of the background command
276   //! @param theBackgroundCommand the background command to be found
277   //! @return true if a background command is found, or false otherwise
278   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
279                                           BackgroundCommand&             theBackgroundCommand)
280   {
281     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
282     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
283   }
284
285   //! Map from background image fill method names to its codes
286   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
287
288   //! Creates a map from background image fill method names to its codes
289   //! @return a map from background image fill method names to its codes
290   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
291   {
292     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
293     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
294     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
295     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
296     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
297     return aBackgroundImageFillMethodNameMap;
298   }
299
300   //! Gets a background image fill method by its name
301   //! @param theBackgroundImageFillMethodName the name of the background image fill method
302   //! @param theBackgroundImageFillMethod the background image fill method to be found
303   //! @return true if a background image fill method is found, or false otherwise
304   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
305                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
306   {
307     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
308       createBackgroundImageFillMethodNameMap();
309     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
310                               theBackgroundImageFillMethodName,
311                               theBackgroundImageFillMethod);
312   }
313
314   //! Map from background gradient fill method names to its codes
315   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
316
317   //! Creates a map from background gradient fill method names to its codes
318   //! @return a map from background gradient fill method names to its codes
319   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
320   {
321     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
322     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
323     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
324     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
325     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
326     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
327     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
328     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
329     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
330     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
331     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
332     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
333     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
334     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
335     return aBackgroundGradientFillMethodNameMap;
336   }
337
338   //! Gets a gradient fill method by its name
339   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
340   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
341   //! @return true if a gradient fill method is found, or false otherwise
342   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
343                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
344   {
345     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
346       createBackgroundGradientFillMethodNameMap();
347     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
348                               theBackgroundGradientFillMethodName,
349                               theBackgroundGradientFillMethod);
350   }
351
352   //! Changes the background in accordance with passed command line options
353   class BackgroundChanger
354   {
355   public:
356     //! Constructor. Prepares the command parser
357     BackgroundChanger()
358     {
359       prepareCommandParser();
360     }
361
362     //! Processes the command line and changes the background
363     //! @param theDrawInterpretor the interpreter of the Draw Harness application
364     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
365     //! @param theCommandLineArguments the array of command line arguments
366     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
367                              const Standard_Integer   theNumberOfCommandLineArguments,
368                              const char* const* const theCommandLineArguments)
369     {
370       const char* const aBackgroundCommandName = theCommandLineArguments[0];
371       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
372       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
373       {
374         return false;
375       }
376       addCommandDescription (aBackgroundCommand);
377       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
378       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
379     }
380
381   private:
382     //! The type of functions that are able to set gradient background filling
383     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
384                                       const Quantity_Color& /* theColor2 */,
385                                       const Aspect_GradientFillMethod /* theGradientMode */);
386
387     //! The type of functions that are able to fill a background with a specific color
388     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
389
390     //! the command parser used to parse command line options and its arguments
391     ViewerTest_CmdParser myCommandParser;
392
393     //! the option key for the command that sets an image as a background
394     ViewerTest_CommandOptionKey myImageOptionKey;
395
396     //! the option key for the command that sets a background image fill type
397     ViewerTest_CommandOptionKey myImageModeOptionKey;
398
399     //! the option key for the command that sets a gradient filling for the background
400     ViewerTest_CommandOptionKey myGradientOptionKey;
401
402     //! the option key for the command that sets a background gradient filling method
403     ViewerTest_CommandOptionKey myGradientModeOptionKey;
404
405     //! the option key for the command that fills background with a specific color
406     ViewerTest_CommandOptionKey myColorOptionKey;
407
408     //! the option key for the command that sets default background gradient or color
409     ViewerTest_CommandOptionKey myDefaultOptionKey;
410
411     //! the option key for the command that sets an environment cubemap as a background
412     ViewerTest_CommandOptionKey myCubeMapOptionKey;
413
414     //! the option key for the command that defines order of tiles in one image packed cubemap
415     ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
416
417     //! the option key for the command that sets inversion of Z axis for background cubemap
418     ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
419
420     //! the option key for the command that allows skip IBL map generation
421     ViewerTest_CommandOptionKey myCubeMapDoNotGenPBREnvOptionKey;
422
423     //! the variable set of options that are allowed for the old scenario (without any option passed)
424     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
425
426     //! the variable set of options that are allowed for setting an environment cubemap as background
427     CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
428
429     //! the variable set of options that are allowed for setting an image as a background
430     CommandOptionKeyVariableSet myImageOptionVariableSet;
431
432     //! the variable set of options that are allowed for setting a background image fill type
433     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
434
435     //! the variable set of options that are allowed for setting a gradient filling for the background
436     CommandOptionKeyVariableSet myGradientOptionVariableSet;
437
438     //! the variable set of options that are allowed for setting a background gradient filling method
439     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
440
441     //! the variable set of options that are allowed for filling a background with a specific color
442     CommandOptionKeyVariableSet myColorOptionVariableSet;
443
444     //! the variable set of options that are allowed for setting a default background gradient
445     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
446
447     //! the variable set of options that are allowed for setting a default background color
448     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
449
450     //! the variable set of options that are allowed for printing help
451     CommandOptionKeyVariableSet myHelpOptionVariableSet;
452
453     //! Adds options to command parser
454     void addOptionsToCommandParser()
455     {
456       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
457                                                     "filename of image used as background");
458       myImageModeOptionKey = myCommandParser.AddOption (
459         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
460       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
461                                                        "sets background gradient starting and ending colors");
462       myGradientModeOptionKey =
463         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
464                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
465                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
466       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
467       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
468
469       myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
470       myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
471       myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
472         "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
473       myCubeMapDoNotGenPBREnvOptionKey = myCommandParser.AddOption ("nopbrenv", "whether IBL map generation should be skipped");
474     }
475
476     //! Creates option sets used to determine if a passed option set is valid or not
477     void createOptionSets()
478     {
479       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
480       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
481       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
482
483       ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
484       aCubeMapOptionSet.insert (myCubeMapOptionKey);
485       ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
486       aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
487       aCubeMapAdditionalOptionKeySet.insert (myCubeMapDoNotGenPBREnvOptionKey);
488       aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
489       myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
490
491       ViewerTest_CommandOptionKeySet anImageOptionSet;
492       anImageOptionSet.insert (myImageOptionKey);
493       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
494       anImageModeOptionSet.insert (myImageModeOptionKey);
495       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
496       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
497
498       ViewerTest_CommandOptionKeySet aGradientOptionSet;
499       aGradientOptionSet.insert (myGradientOptionKey);
500       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
501       aGradientModeOptionSet.insert (myGradientModeOptionKey);
502       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
503       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
504
505       ViewerTest_CommandOptionKeySet aColorOptionSet;
506       aColorOptionSet.insert (myColorOptionKey);
507       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
508
509       aGradientOptionSet.insert (myDefaultOptionKey);
510       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
511       aColorOptionSet.insert (myDefaultOptionKey);
512       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
513
514       ViewerTest_CommandOptionKeySet aHelpOptionSet;
515       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
516       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
517     }
518
519     //! Prepares the command parser. Adds options and creates option sets used to determine
520     //! if a passed option set is valid or not
521     void prepareCommandParser()
522     {
523       addOptionsToCommandParser();
524       createOptionSets();
525     }
526
527     //! Adds a command description to the command parser
528     //! @param theBackgroundCommand the key of the command which description is added to the command parser
529     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
530     {
531       std::string aDescription;
532       bool        isMainCommand = false;
533       switch (theBackgroundCommand)
534       {
535         case BackgroundCommand_Main:
536           aDescription  = "Command: vbackground (changes background or some background settings)";
537           isMainCommand = true;
538           break;
539         case BackgroundCommand_Image:
540           aDescription = "Command: vsetbg (loads image as a background)";
541           break;
542         case BackgroundCommand_ImageMode:
543           aDescription = "Command: vsetbgmode (changes background fill type)";
544           break;
545         case BackgroundCommand_Gradient:
546           aDescription = "Command: vsetgradientbg (mounts gradient background)";
547           break;
548         case BackgroundCommand_GradientMode:
549           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
550           break;
551         case BackgroundCommand_Color:
552           aDescription = "Command: vsetcolorbg (sets color background)";
553           break;
554         case BackgroundCommand_Default:
555           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
556           break;
557         default:
558           return;
559       }
560       if (!isMainCommand)
561       {
562         aDescription += "\nThis command is obsolete. Use vbackground instead.";
563       }
564       myCommandParser.SetDescription (aDescription);
565     }
566
567     //! Check if a viewer is needed to be initialized
568     //! @param theBackgroundCommand the key of the command that changes the background
569     //! @return true if processing was successful, or false otherwise
570     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
571     {
572       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
573       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
574       const bool                           aViewerIsNotNeeded =
575         (theBackgroundCommand == BackgroundCommand_Default)
576         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
577         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
578         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
579       return !aViewerIsNotNeeded;
580     }
581
582     //! Check if a viewer is initialized
583     //! @param theBackgroundCommandName the name of the command that changes the background
584     //! @param theDrawInterpretor the interpreter of the Draw Harness application
585     //! @return true if a viewer is initialized, or false otherwise
586     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
587                                           Draw_Interpretor& theDrawInterpretor)
588     {
589       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
590       if (anAISContext.IsNull())
591       {
592         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
593         return false;
594       }
595       return true;
596     }
597
598     //! Processes command options
599     //! @param theBackgroundCommandName the name of the command that changes the background
600     //! @param theBackgroundCommand the key of the command that changes the background
601     //! @param theDrawInterpretor the interpreter of the Draw Harness application
602     //! @return true if processing was successful, or false otherwise
603     bool processCommandOptions (const char* const       theBackgroundCommandName,
604                                 const BackgroundCommand theBackgroundCommand,
605                                 Draw_Interpretor&       theDrawInterpretor) const
606     {
607       if (myCommandParser.HasNoOption())
608       {
609         return printHelp (theBackgroundCommandName, theDrawInterpretor);
610       }
611       if (checkViewerIsNeeded (theBackgroundCommand)
612           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
613       {
614         return false;
615       }
616       if (myCommandParser.HasOnlyUnnamedOption())
617       {
618         return processUnnamedOption (theBackgroundCommand);
619       }
620       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
621     }
622
623     //! Processes the unnamed option
624     //! @param theBackgroundCommand the key of the command that changes the background
625     //! @return true if processing was successful, or false otherwise
626     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
627     {
628       switch (theBackgroundCommand)
629       {
630         case BackgroundCommand_Main:
631           return false;
632         case BackgroundCommand_Image:
633           return processImageUnnamedOption();
634         case BackgroundCommand_ImageMode:
635           return processImageModeUnnamedOption();
636         case BackgroundCommand_Gradient:
637           return processGradientUnnamedOption();
638         case BackgroundCommand_GradientMode:
639           return processGradientModeUnnamedOption();
640         case BackgroundCommand_Color:
641           return processColorUnnamedOption();
642         case BackgroundCommand_Default:
643           return processDefaultUnnamedOption();
644         default:
645           return false;
646       }
647     }
648
649     //! Processes the image unnamed option
650     //! @return true if processing was successful, or false otherwise
651     bool processImageUnnamedOption() const
652     {
653       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
654         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
655       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
656       {
657         return false;
658       }
659       std::string anImageFileName;
660       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
661       {
662         return false;
663       }
664       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
665       if (aNumberOfImageUnnamedOptionArguments == 2)
666       {
667         std::string anImageModeString;
668         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
669         {
670           return false;
671         }
672         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
673         {
674           return false;
675         }
676       }
677       setImage (anImageFileName.c_str(), anImageMode);
678       return true;
679     }
680
681     //! Processes the image mode unnamed option
682     //! @return true if processing was successful, or false otherwise
683     bool processImageModeUnnamedOption() const
684     {
685       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
686     }
687
688     //! Processes the gradient unnamed option
689     //! @param theSetGradient the function used to set a background gradient filling
690     //! @return true if processing was successful, or false otherwise
691     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
692     {
693       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
694         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
695       if (aNumberOfGradientUnnamedOptionArguments < 2)
696       {
697         return false;
698       }
699
700       Standard_Integer anArgumentIndex = 0;
701       Quantity_Color   aColor1;
702       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
703       {
704         return false;
705       }
706       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
707       {
708         return false;
709       }
710
711       Quantity_Color aColor2;
712       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
713       {
714         return false;
715       }
716       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
717       {
718         return false;
719       }
720
721       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
722       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
723       {
724         std::string anGradientModeString;
725
726         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
727                                   anArgumentIndex,
728                                   anGradientModeString))
729         {
730           return false;
731         }
732         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
733         {
734           return false;
735         }
736         ++anArgumentIndex;
737       }
738       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
739       {
740         return false;
741       }
742       theSetGradient (aColor1, aColor2, aGradientMode);
743       return true;
744     }
745
746     //! Processes the gradient mode unnamed option
747     //! @return true if processing was successful, or false otherwise
748     bool processGradientModeUnnamedOption() const
749     {
750       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
751     }
752
753     //! Processes the color unnamed option
754     //! @param theSetColor the function used to set a background color
755     //! @return true if processing was successful, or false otherwise
756     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
757     {
758       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
759     }
760
761     //! Processes the default back unnamed option
762     //! @return true if processing was successful, or false otherwise
763     bool processDefaultUnnamedOption() const
764     {
765       if (processGradientUnnamedOption (setDefaultGradient))
766       {
767         return true;
768       }
769       return processColorUnnamedOption (setDefaultColor);
770     }
771
772     //! Processes named options
773     //! @param theBackgroundCommandName the name of the command that changes the background
774     //! @param theBackgroundCommand the key of the command that changes the background
775     //! @param theDrawInterpretor the interpreter of the Draw Harness application
776     //! @return true if processing was successful, or false otherwise
777     bool processNamedOptions (const char* const       theBackgroundCommandName,
778                               const BackgroundCommand theBackgroundCommand,
779                               Draw_Interpretor&       theDrawInterpretor) const
780     {
781       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
782       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
783       if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
784       {
785         return processCubeMapOptionSet();
786       }
787       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
788           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
789       {
790         return processImageOptionSet();
791       }
792       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
793           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
794       {
795         return processImageModeOptionSet();
796       }
797       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
798           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
799       {
800         return processGradientOptionSet();
801       }
802       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
803           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
804       {
805         return processGradientModeOptionSet();
806       }
807       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
808           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
809       {
810         return processColorOptionSet();
811       }
812       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
813           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
814               && (theBackgroundCommand == BackgroundCommand_Default)))
815       {
816         return processDefaultGradientOptionSet();
817       }
818       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
819           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
820       {
821         return processDefaultColorOptionSet();
822       }
823       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
824       {
825         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
826       }
827       return false;
828     }
829
830     //! Process the cubemap option set in named and unnamed case.
831     //! @return true if processing was successful, or false otherwise
832     bool processCubeMapOptionSet() const
833     {
834       NCollection_Array1<TCollection_AsciiString> aFilePaths;
835
836       if (!processCubeMapOptions (aFilePaths))
837       {
838         return false;
839       }
840
841       Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
842
843       if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
844       {
845         if (!processCubeMapOrderOptions (anOrder))
846         {
847           return false;
848         }
849       }
850
851       bool aZIsInverted = false;
852       if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
853       {
854         if (!processCubeMapInvertedZOptionSet())
855         {
856           return false;
857         }
858         aZIsInverted = true;
859       }
860
861       bool aToGenPBREnv = true;
862       if (myCommandParser.HasOption (myCubeMapDoNotGenPBREnvOptionKey))
863       {
864         if (!processCubeMapDoNotGenPBREnvOptionSet())
865         {
866           return false;
867         }
868         aToGenPBREnv = false;
869       }
870
871       setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted, aToGenPBREnv);
872       return true;
873     }
874
875     //! Processes the image option set
876     //! @return true if processing was successful, or false otherwise
877     bool processImageOptionSet() const
878     {
879       std::string anImageFileName;
880       if (!processImageOption (anImageFileName))
881       {
882         return false;
883       }
884       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
885       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
886       {
887         return false;
888       }
889       setImage (anImageFileName.c_str(), anImageMode);
890       return true;
891     }
892
893     //! Processes the image mode option set
894     //! @return true if processing was successful, or false otherwise
895     bool processImageModeOptionSet() const
896     {
897       return processImageModeOptionSet (myImageModeOptionKey);
898     }
899
900     //! Processes the image mode option set
901     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
902     //! @return true if processing was successful, or false otherwise
903     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
904     {
905       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
906       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
907       {
908         return false;
909       }
910       setImageMode (anImageMode);
911       return true;
912     }
913
914     //! Processes the gradient option set
915     //! @param theSetGradient the function used to set a background gradient filling
916     //! @return true if processing was successful, or false otherwise
917     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
918     {
919       Quantity_Color aColor1;
920       Quantity_Color aColor2;
921       if (!processGradientOption (aColor1, aColor2))
922       {
923         return false;
924       }
925       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
926       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
927       {
928         return false;
929       }
930       theSetGradient (aColor1, aColor2, aGradientMode);
931       return true;
932     }
933
934     //! Processes the gradient mode option set
935     //! @return true if processing was successful, or false otherwise
936     bool processGradientModeOptionSet() const
937     {
938       return processGradientModeOptionSet (myGradientModeOptionKey);
939     }
940
941     //! Processes the gradient mode option set
942     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
943     //! @return true if processing was successful, or false otherwise
944     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
945     {
946       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
947       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
948       {
949         return false;
950       }
951       setGradientMode (aGradientMode);
952       return true;
953     }
954
955     //! Processes the color option set
956     //! @param theSetColor the function used to set a background color
957     //! @return true if processing was successful, or false otherwise
958     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
959     {
960       return processColorOptionSet (myColorOptionKey, theSetColor);
961     }
962
963     //! Processes the default color option set
964     //! @return true if processing was successful, or false otherwise
965     bool processDefaultGradientOptionSet() const
966     {
967       return processGradientOptionSet (setDefaultGradient);
968     }
969
970     //! Processes the default gradient option set
971     //! @return true if processing was successful, or false otherwise
972     bool processDefaultColorOptionSet() const
973     {
974       return processColorOptionSet (setDefaultColor);
975     }
976
977     //! Processes the color option set
978     //! @param theColorOptionKey the key of the option that is interpreted as a color option
979     //! @param theSetColor the function used to set a background color
980     //! @return true if processing was successful, or false otherwise
981     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
982                                 SetColorFunction* const           theSetColor = setColor) const
983     {
984       Quantity_Color aColor;
985       if (!processColorOption (theColorOptionKey, aColor))
986       {
987         return false;
988       }
989       theSetColor (aColor);
990       return true;
991     }
992
993     //! Processes the help option set
994     //! @param theBackgroundCommandName the name of the command that changes the background
995     //! @param theDrawInterpretor the interpreter of the Draw Harness application
996     //! @return true if processing was successful, or false otherwise
997     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
998     {
999       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1000         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
1001       if (aNumberOfHelpOptionArguments != 0)
1002       {
1003         return false;
1004       }
1005       return printHelp (theBackgroundCommandName, theDrawInterpretor);
1006     }
1007
1008     //! Processes the cubemap option
1009     //! @param theFilePaths the array of filenames of cubemap sides
1010     //! @return true if processing was successful, or false otherwise
1011     bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
1012     {
1013       const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
1014
1015       if (aNumberOfCubeMapOptionArguments != 1
1016        && aNumberOfCubeMapOptionArguments != 6)
1017       {
1018         return false;
1019       }
1020
1021       theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
1022
1023       for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
1024       {
1025         std::string aCubeMapFileName;
1026         if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
1027         {
1028           return false;
1029         }
1030         theFilePaths[i] = aCubeMapFileName.c_str();
1031       }
1032
1033       return true;
1034     }
1035
1036     //! Processes the inverted z cubemap option
1037     //! @return true if processing was successful, or false otherwise
1038     bool processCubeMapInvertedZOptionSet () const
1039     {
1040       const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
1041         myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
1042
1043       if (aNumberOfCubeMapZInversionOptionArguments != 0)
1044       {
1045         return false;
1046       }
1047
1048       return true;
1049     }
1050
1051     //! Processes the option allowing to skip IBM maps generation
1052     //! @return true if processing was successful, or false otherwise
1053     bool processCubeMapDoNotGenPBREnvOptionSet() const
1054     {
1055       const Standard_Integer aNumberOfCubeMapDoNotGenPBREnvOptionArguments =
1056         myCommandParser.GetNumberOfOptionArguments(myCubeMapDoNotGenPBREnvOptionKey);
1057
1058       if (aNumberOfCubeMapDoNotGenPBREnvOptionArguments != 0)
1059       {
1060         return false;
1061       }
1062
1063       return true;
1064     }
1065
1066     //! Processes the tiles order option
1067     //! @param theOrder the array of indexes if cubemap sides in tile grid
1068     //! @return true if processing was successful, or false otherwise
1069     bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
1070     {
1071       const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
1072         myCubeMapOrderOptionKey);
1073
1074       if (aNumberOfCubeMapOrderOptionArguments != 6)
1075       {
1076         return false;
1077       }
1078
1079
1080       for (unsigned int i = 0; i < 6; ++i)
1081       {
1082         std::string anOrderItem;
1083         if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
1084         {
1085           return false;
1086         }
1087
1088         theOrder.Set (Graphic3d_CubeMapSide (i),
1089                       static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
1090       }
1091
1092       return theOrder.IsValid();
1093     }
1094
1095     //! Processes the image option
1096     //! @param theImageFileName the filename of the image to be used as a background
1097     //! @return true if processing was successful, or false otherwise
1098     bool processImageOption (std::string& theImageFileName) const
1099     {
1100       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1101         myImageOptionKey);
1102       if (aNumberOfImageOptionArguments != 1)
1103       {
1104         return false;
1105       }
1106       std::string anImageFileName;
1107       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
1108       {
1109         return false;
1110       }
1111       theImageFileName = anImageFileName;
1112       return true;
1113     }
1114
1115     //! Processes the image mode option
1116     //! @param theImageMode the fill type used for a background image
1117     //! @return true if processing was successful, or false otherwise
1118     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
1119     {
1120       return processImageModeOption (myImageModeOptionKey, theImageMode);
1121     }
1122
1123     //! Processes the image mode option
1124     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
1125     //! @param theImageMode the fill type used for a background image
1126     //! @return true if processing was successful, or false otherwise
1127     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
1128                                  Aspect_FillMethod&                theImageMode) const
1129     {
1130       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
1131     }
1132
1133     //! Processes the gradient option
1134     //! @param theColor1 the gradient starting color
1135     //! @param theColor2 the gradient ending color
1136     //! @return true if processing was successful, or false otherwise
1137     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
1138     {
1139       Standard_Integer anArgumentIndex = 0;
1140       Quantity_Color   aColor1;
1141       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
1142       {
1143         return false;
1144       }
1145       Quantity_Color aColor2;
1146       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
1147       {
1148         return false;
1149       }
1150       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1151         myGradientOptionKey);
1152       if (anArgumentIndex != aNumberOfGradientOptionArguments)
1153       {
1154         return false;
1155       }
1156       theColor1 = aColor1;
1157       theColor2 = aColor2;
1158       return true;
1159     }
1160
1161     //! Processes the gradient mode option
1162     //! @param theGradientMode the fill method used for a background gradient filling
1163     //! @return true if processing was successful, or false otherwise
1164     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
1165     {
1166       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
1167     }
1168
1169     //! Processes the gradient mode option
1170     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1171     //! @param theGradientMode the fill method used for a background gradient filling
1172     //! @return true if processing was successful, or false otherwise
1173     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1174                                     Aspect_GradientFillMethod&        theGradientMode) const
1175     {
1176       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1177     }
1178
1179     //! Processes some mode option
1180     //! @tparam TheMode the type of a mode to be processed
1181     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1182     //! @param theMode a mode to be processed
1183     //! @return true if processing was successful, or false otherwise
1184     template <typename TheMode>
1185     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1186                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1187                                                             TheMode& /* theMode */),
1188                             TheMode& theMode) const
1189     {
1190       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1191         theModeOptionKey);
1192       if (aNumberOfModeOptionArguments != 1)
1193       {
1194         return false;
1195       }
1196       std::string aModeString;
1197       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1198       {
1199         return false;
1200       }
1201       TheMode aMode = TheMode();
1202       if (!theGetModeByName (aModeString.c_str(), aMode))
1203       {
1204         return false;
1205       }
1206       theMode = aMode;
1207       return true;
1208     }
1209
1210     //! Processes the color option
1211     //! @param theColor a color used for filling a background
1212     //! @return true if processing was successful, or false otherwise
1213     bool processColorOption (Quantity_Color& theColor) const
1214     {
1215       return processColorOption (myColorOptionKey, theColor);
1216     }
1217
1218     //! Processes the color option
1219     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1220     //! @param theColor a color used for filling a background
1221     //! @return true if processing was successful, or false otherwise
1222     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1223     {
1224       Standard_Integer anArgumentIndex = 0;
1225       Quantity_Color   aColor;
1226       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1227       {
1228         return false;
1229       }
1230       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1231         theColorOptionKey);
1232       if (anArgumentIndex != aNumberOfColorOptionArguments)
1233       {
1234         return false;
1235       }
1236       theColor = aColor;
1237       return true;
1238     }
1239
1240     //! Prints helping message
1241     //! @param theBackgroundCommandName the name of the command that changes the background
1242     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1243     //! @return true if printing was successful, or false otherwise
1244     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1245     {
1246       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1247     }
1248
1249     //! Sets the cubemap as a background
1250     //! @param theFileNames the array of filenames of packed or multifile cubemap
1251     //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
1252     static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
1253                             const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
1254                             bool                                               theZIsInverted = false,
1255                             bool                                               theToGenPBREnv = true)
1256     {
1257       const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
1258       Handle(Graphic3d_CubeMap) aCubeMap;
1259
1260       if (theFileNames.Size() == 1)
1261         aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
1262       else
1263         aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
1264
1265       aCubeMap->SetZInversion (theZIsInverted);
1266
1267       aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
1268       aCubeMap->GetParams()->SetRepeat(Standard_False);
1269       aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
1270
1271       aCurrentView->SetBackgroundCubeMap (aCubeMap, theToGenPBREnv, Standard_True);
1272     }
1273
1274     //! Sets the image as a background
1275     //! @param theImageFileName the filename of the image to be used as a background
1276     //! @param theImageMode the fill type used for a background image
1277     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1278     {
1279       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1280       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1281     }
1282
1283     //! Sets the fill type used for a background image
1284     //! @param theImageMode the fill type used for a background image
1285     static void setImageMode (const Aspect_FillMethod theImageMode)
1286     {
1287       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1288       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1289     }
1290
1291     //! Sets the gradient filling for a background
1292     //! @param theColor1 the gradient starting color
1293     //! @param theColor2 the gradient ending color
1294     //! @param theGradientMode the fill method used for a background gradient filling
1295     static void setGradient (const Quantity_Color&           theColor1,
1296                              const Quantity_Color&           theColor2,
1297                              const Aspect_GradientFillMethod theGradientMode)
1298     {
1299       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1300       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1301     }
1302
1303     //! Sets the fill method used for a background gradient filling
1304     //! @param theGradientMode the fill method used for a background gradient filling
1305     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1306     {
1307       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1308       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1309     }
1310
1311     //! Sets the color used for filling a background
1312     //! @param theColor the color used for filling a background
1313     static void setColor (const Quantity_Color& theColor)
1314     {
1315       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1316       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1317       aCurrentView->SetBackgroundColor (theColor);
1318       aCurrentView->Update();
1319     }
1320
1321     //! Sets the gradient filling for a background in a default viewer
1322     //! @param theColor1 the gradient starting color
1323     //! @param theColor2 the gradient ending color
1324     //! @param theGradientMode the fill method used for a background gradient filling
1325     static void setDefaultGradient (const Quantity_Color&           theColor1,
1326                                     const Quantity_Color&           theColor2,
1327                                     const Aspect_GradientFillMethod theGradientMode)
1328     {
1329       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1330       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1331       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1332       setDefaultGradient();
1333     }
1334
1335     //! Sets the color used for filling a background in a default viewer
1336     //! @param theColor the color used for filling a background
1337     static void setDefaultColor (const Quantity_Color& theColor)
1338     {
1339       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1340       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1341       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1342       ViewerTest_DefaultBackground.FlatColor      = theColor;
1343       setDefaultGradient();
1344       setDefaultColor();
1345     }
1346
1347     //! Sets the gradient filling for a background in a default viewer.
1348     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1349     static void setDefaultGradient()
1350     {
1351       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1352              anInteractiveContextIterator (ViewerTest_myContexts);
1353            anInteractiveContextIterator.More();
1354            anInteractiveContextIterator.Next())
1355       {
1356         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1357         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1358                                              ViewerTest_DefaultBackground.GradientColor2,
1359                                              ViewerTest_DefaultBackground.FillMethod);
1360       }
1361     }
1362
1363     //! Sets the color used for filling a background in a default viewer.
1364     //! The color value is taken from ViewerTest_DefaultBackground structure
1365     static void setDefaultColor()
1366     {
1367       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1368              anInteractiveContextIterator (ViewerTest_myContexts);
1369            anInteractiveContextIterator.More();
1370            anInteractiveContextIterator.Next())
1371       {
1372         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1373         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1374       }
1375     }
1376   };
1377
1378 } // namespace
1379
1380 //==============================================================================
1381
1382 #ifdef _WIN32
1383 static LRESULT WINAPI ViewerWindowProc(
1384                                        HWND hwnd,
1385                                        UINT uMsg,
1386                                        WPARAM wParam,
1387                                        LPARAM lParam );
1388 static LRESULT WINAPI AdvViewerWindowProc(
1389   HWND hwnd,
1390   UINT uMsg,
1391   WPARAM wParam,
1392   LPARAM lParam );
1393 #endif
1394
1395
1396 //==============================================================================
1397 //function : WClass
1398 //purpose  :
1399 //==============================================================================
1400
1401 const Handle(WNT_WClass)& ViewerTest::WClass()
1402 {
1403   static Handle(WNT_WClass) theWClass;
1404 #if defined(_WIN32)
1405   if (theWClass.IsNull())
1406   {
1407     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1408                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1409                                 ::LoadCursor (NULL, IDC_ARROW));
1410   }
1411 #endif
1412   return theWClass;
1413 }
1414
1415 //==============================================================================
1416 //function : CreateName
1417 //purpose  : Create numerical name for new object in theMap
1418 //==============================================================================
1419 template <typename ObjectType>
1420 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1421                                     const TCollection_AsciiString& theDefaultString)
1422 {
1423   if (theObjectMap.IsEmpty())
1424     return theDefaultString + TCollection_AsciiString(1);
1425
1426   Standard_Integer aNextKey = 1;
1427   Standard_Boolean isFound = Standard_False;
1428   while (!isFound)
1429   {
1430     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1431     // Look for objects with default names
1432     if (theObjectMap.IsBound1(aStringKey))
1433     {
1434       aNextKey++;
1435     }
1436     else
1437       isFound = Standard_True;
1438   }
1439
1440   return theDefaultString + TCollection_AsciiString(aNextKey);
1441 }
1442
1443 //==============================================================================
1444 //structure : ViewerTest_Names
1445 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1446 //==============================================================================
1447 struct ViewerTest_Names
1448 {
1449 private:
1450   TCollection_AsciiString myDriverName;
1451   TCollection_AsciiString myViewerName;
1452   TCollection_AsciiString myViewName;
1453
1454 public:
1455
1456   const TCollection_AsciiString& GetDriverName () const
1457   {
1458     return myDriverName;
1459   }
1460   void SetDriverName (const TCollection_AsciiString& theDriverName)
1461   {
1462     myDriverName = theDriverName;
1463   }
1464   const TCollection_AsciiString& GetViewerName () const
1465   {
1466     return myViewerName;
1467   }
1468   void SetViewerName (const TCollection_AsciiString& theViewerName)
1469   {
1470     myViewerName = theViewerName;
1471   }
1472   const TCollection_AsciiString& GetViewName () const
1473   {
1474     return myViewName;
1475   }
1476   void SetViewName (const TCollection_AsciiString& theViewName)
1477   {
1478     myViewName = theViewName;
1479   }
1480
1481   //===========================================================================
1482   //function : Constructor for ViewerTest_Names
1483   //purpose  : Get view, viewer, driver names from custom string
1484   //===========================================================================
1485
1486   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1487   {
1488     TCollection_AsciiString aName(theInputString);
1489     if (theInputString.IsEmpty())
1490     {
1491       // Get current configuration
1492       if (ViewerTest_myDrivers.IsEmpty())
1493         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1494           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1495       else
1496         myDriverName = ViewerTest_myDrivers.Find2
1497         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1498
1499       if(ViewerTest_myContexts.IsEmpty())
1500       {
1501         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1502           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1503       }
1504       else
1505       {
1506         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1507       }
1508
1509       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1510     }
1511     else
1512     {
1513       // There is at least view name
1514       Standard_Integer aParserNumber = 0;
1515       for (Standard_Integer i = 0; i < 3; ++i)
1516       {
1517         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1518         if(aParserPos != -1)
1519         {
1520           aParserNumber++;
1521           aName.Split(aParserPos-1);
1522         }
1523         else
1524           break;
1525       }
1526       if (aParserNumber == 0)
1527       {
1528         // Only view name
1529         if (!ViewerTest::GetAISContext().IsNull())
1530         {
1531           myDriverName = ViewerTest_myDrivers.Find2
1532           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1533           myViewerName = ViewerTest_myContexts.Find2
1534           (ViewerTest::GetAISContext());
1535         }
1536         else
1537         {
1538           // There is no opened contexts here, need to create names for viewer and driver
1539           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1540             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1541
1542           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1543             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1544         }
1545         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1546       }
1547       else if (aParserNumber == 1)
1548       {
1549         // Here is viewerName/viewName
1550         if (!ViewerTest::GetAISContext().IsNull())
1551           myDriverName = ViewerTest_myDrivers.Find2
1552           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1553         else
1554         {
1555           // There is no opened contexts here, need to create name for driver
1556           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1557             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1558         }
1559         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1560
1561         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1562       }
1563       else
1564       {
1565         //Here is driverName/viewerName/viewName
1566         myDriverName = TCollection_AsciiString(aName);
1567
1568         TCollection_AsciiString aViewerName(theInputString);
1569         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1570         myViewerName = TCollection_AsciiString(aViewerName);
1571
1572         myViewName = TCollection_AsciiString(theInputString);
1573       }
1574     }
1575   }
1576 };
1577
1578 //==============================================================================
1579 //function : FindContextByView
1580 //purpose  : Find AIS_InteractiveContext by View
1581 //==============================================================================
1582
1583 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1584 {
1585   Handle(AIS_InteractiveContext) anAISContext;
1586
1587   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1588        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1589   {
1590     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1591        return anIter.Key2();
1592   }
1593   return anAISContext;
1594 }
1595
1596 //==============================================================================
1597 //function : IsWindowOverlapped
1598 //purpose  : Check if theWindow overlapp another view
1599 //==============================================================================
1600
1601 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1602                                      const Standard_Integer thePxTop,
1603                                      const Standard_Integer thePxRight,
1604                                      const Standard_Integer thePxBottom,
1605                                      TCollection_AsciiString& theViewId)
1606 {
1607   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1608       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1609   {
1610     Standard_Integer aTop = 0,
1611       aLeft = 0,
1612       aRight = 0,
1613       aBottom = 0;
1614     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1615     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1616         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1617         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1618         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1619     {
1620       theViewId = anIter.Key1();
1621       return Standard_True;
1622     }
1623   }
1624   return Standard_False;
1625 }
1626
1627 // Workaround: to create and delete non-orthographic views outside ViewerTest
1628 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1629 {
1630   ViewerTest_myViews.UnBind1 (theName);
1631 }
1632
1633 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1634                                const Handle(V3d_View)& theView)
1635 {
1636   ViewerTest_myViews.Bind (theName, theView);
1637 }
1638
1639 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1640 {
1641   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1642 }
1643
1644 //==============================================================================
1645 //function : ViewerInit
1646 //purpose  : Create the window viewer and initialize all the global variable
1647 //==============================================================================
1648
1649 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1650                                                 const Standard_Integer thePxTop,
1651                                                 const Standard_Integer thePxWidth,
1652                                                 const Standard_Integer thePxHeight,
1653                                                 const TCollection_AsciiString& theViewName,
1654                                                 const TCollection_AsciiString& theDisplayName,
1655                                                 const Handle(V3d_View)& theViewToClone)
1656 {
1657   // Default position and dimension of the viewer window.
1658   // Note that left top corner is set to be sufficiently small to have
1659   // window fit in the small screens (actual for remote desktops, see #23003).
1660   // The position corresponds to the window's client area, thus some
1661   // gap is added for window frame to be visible.
1662   Standard_Integer aPxLeft   = 20;
1663   Standard_Integer aPxTop    = 40;
1664   Standard_Integer aPxWidth  = 409;
1665   Standard_Integer aPxHeight = 409;
1666   Standard_Boolean toCreateViewer = Standard_False;
1667   if (!theViewToClone.IsNull())
1668   {
1669     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1670   }
1671
1672   Handle(OpenGl_GraphicDriver) aGraphicDriver;
1673   ViewerTest_Names aViewNames(theViewName);
1674   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1675     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1676
1677   if (thePxLeft != 0)
1678     aPxLeft = thePxLeft;
1679   if (thePxTop != 0)
1680     aPxTop = thePxTop;
1681   if (thePxWidth != 0)
1682     aPxWidth = thePxWidth;
1683   if (thePxHeight != 0)
1684     aPxHeight = thePxHeight;
1685
1686   // Get graphic driver (create it or get from another view)
1687   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1688   if (isNewDriver)
1689   {
1690     // Get connection string
1691   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1692     if (!theDisplayName.IsEmpty())
1693     {
1694       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1695     }
1696     else
1697     {
1698       ::Display* aDispX = NULL;
1699       // create dedicated display connection instead of reusing Tk connection
1700       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
1701       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1702       Tcl_Interp* aTclInterp = aCommands.Interp();
1703       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1704       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1705       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1706     }
1707   #else
1708     (void)theDisplayName; // avoid warning on unused argument
1709     SetDisplayConnection (new Aspect_DisplayConnection ());
1710   #endif
1711
1712     if (Draw_VirtualWindows)
1713     {
1714       // don't waste the time waiting for VSync when window is not displayed on the screen
1715       ViewerTest_myDefaultCaps.swapInterval = 0;
1716       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
1717       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
1718     }
1719     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
1720     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
1721     aGraphicDriver->InitContext();
1722
1723     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1724     toCreateViewer = Standard_True;
1725   }
1726   else
1727   {
1728     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
1729   }
1730
1731   //Dispose the window if input parameters are default
1732   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1733   {
1734     Standard_Integer aTop = 0,
1735                      aLeft = 0,
1736                      aRight = 0,
1737                      aBottom = 0,
1738                      aScreenWidth = 0,
1739                      aScreenHeight = 0;
1740
1741     // Get screen resolution
1742 #if defined(_WIN32) || defined(__WIN32__)
1743     RECT aWindowSize;
1744     GetClientRect(GetDesktopWindow(), &aWindowSize);
1745     aScreenHeight = aWindowSize.bottom;
1746     aScreenWidth = aWindowSize.right;
1747 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1748     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1749 #else
1750     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
1751     aScreenWidth = WidthOfScreen(aScreen);
1752     aScreenHeight = HeightOfScreen(aScreen);
1753 #endif
1754
1755     TCollection_AsciiString anOverlappedViewId("");
1756
1757     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1758     {
1759       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1760
1761       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1762         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1763       {
1764         if (aBottom + aPxHeight + 40 > aScreenHeight)
1765         {
1766           aPxLeft = 20;
1767           aPxTop = 40;
1768           break;
1769         }
1770         aPxLeft = 20;
1771         aPxTop = aBottom + 40;
1772       }
1773       else
1774         aPxLeft = aRight + 20;
1775     }
1776   }
1777
1778   // Get viewer name
1779   TCollection_AsciiString aTitle("3D View - ");
1780   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1781
1782   // Change name of current active window
1783   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1784   {
1785     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1786   }
1787
1788   // Create viewer
1789   Handle(V3d_Viewer) a3DViewer;
1790   // If it's the single view, we first look for empty context
1791   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1792   {
1793     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1794       anIter(ViewerTest_myContexts);
1795     if (anIter.More())
1796       ViewerTest::SetAISContext (anIter.Value());
1797     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1798   }
1799   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1800   {
1801     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1802     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1803   }
1804   else if (a3DViewer.IsNull())
1805   {
1806     toCreateViewer = Standard_True;
1807     a3DViewer = new V3d_Viewer(aGraphicDriver);
1808     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1809     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1810                                            ViewerTest_DefaultBackground.GradientColor2,
1811                                            ViewerTest_DefaultBackground.FillMethod);
1812   }
1813
1814   // AIS context setup
1815   if (ViewerTest::GetAISContext().IsNull() ||
1816       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1817   {
1818     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1819     ViewerTest::SetAISContext (aContext);
1820     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1821   }
1822   else
1823   {
1824     ViewerTest::ResetEventManager();
1825   }
1826
1827   // Create window
1828 #if defined(_WIN32)
1829   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
1830                                     Draw_VirtualWindows ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1831                                     aPxLeft, aPxTop,
1832                                     aPxWidth, aPxHeight,
1833                                     Quantity_NOC_BLACK);
1834 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1835   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1836                                      aPxLeft, aPxTop,
1837                                      aPxWidth, aPxHeight);
1838   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1839 #else
1840   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1841                                   aTitle.ToCString(),
1842                                   aPxLeft, aPxTop,
1843                                   aPxWidth, aPxHeight);
1844 #endif
1845   VT_GetWindow()->SetVirtual (Draw_VirtualWindows);
1846
1847   // View setup
1848   Handle(V3d_View) aView;
1849   if (!theViewToClone.IsNull())
1850   {
1851     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1852   }
1853   else
1854   {
1855     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1856   }
1857
1858   aView->SetWindow (VT_GetWindow());
1859   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1860
1861   ViewerTest::CurrentView(aView);
1862   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1863
1864   // Setup for X11 or NT
1865   OSWindowSetup();
1866
1867   // Set parameters for V3d_View and V3d_Viewer
1868   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1869   aV3dView->SetComputedMode(Standard_False);
1870
1871   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1872   if (toCreateViewer)
1873   {
1874     a3DViewer->SetDefaultLights();
1875     a3DViewer->SetLightOn();
1876   }
1877
1878 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1879   if (isNewDriver)
1880   {
1881     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
1882     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1883   }
1884 #endif
1885
1886   VT_GetWindow()->Map();
1887
1888   // Set the handle of created view in the event manager
1889   ViewerTest::ResetEventManager();
1890
1891   ViewerTest::CurrentView()->Redraw();
1892
1893   aView.Nullify();
1894   a3DViewer.Nullify();
1895
1896   return aViewNames.GetViewName();
1897 }
1898
1899 //==============================================================================
1900 //function : RedrawAllViews
1901 //purpose  : Redraw all created views
1902 //==============================================================================
1903 void ViewerTest::RedrawAllViews()
1904 {
1905   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1906   for (; aViewIt.More(); aViewIt.Next())
1907   {
1908     const Handle(V3d_View)& aView = aViewIt.Key2();
1909     aView->Redraw();
1910   }
1911 }
1912
1913 //==============================================================================
1914 //function : Vinit
1915 //purpose  : Create the window viewer and initialize all the global variable
1916 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
1917 //==============================================================================
1918
1919 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1920 {
1921   TCollection_AsciiString aViewName, aDisplayName;
1922   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
1923   Handle(V3d_View) aCopyFrom;
1924   TCollection_AsciiString aName, aValue;
1925   int is2dMode = -1;
1926   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
1927   {
1928     const TCollection_AsciiString anArg = theArgVec[anArgIt];
1929     TCollection_AsciiString anArgCase = anArg;
1930     anArgCase.LowerCase();
1931     if (anArgIt + 1 < theArgsNb
1932      && anArgCase == "-name")
1933     {
1934       aViewName = theArgVec[++anArgIt];
1935     }
1936     else if (anArgIt + 1 < theArgsNb
1937           && (anArgCase == "-left"
1938            || anArgCase == "-l"))
1939     {
1940       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
1941     }
1942     else if (anArgIt + 1 < theArgsNb
1943           && (anArgCase == "-top"
1944            || anArgCase == "-t"))
1945     {
1946       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
1947     }
1948     else if (anArgIt + 1 < theArgsNb
1949           && (anArgCase == "-width"
1950            || anArgCase == "-w"))
1951     {
1952       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
1953     }
1954     else if (anArgIt + 1 < theArgsNb
1955           && (anArgCase == "-height"
1956            || anArgCase == "-h"))
1957     {
1958       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
1959     }
1960     else if (anArgCase == "-exitonclose")
1961     {
1962       ViewerTest_EventManager::ToExitOnCloseView() = true;
1963       if (anArgIt + 1 < theArgsNb
1964        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
1965       {
1966         ++anArgIt;
1967       }
1968     }
1969     else if (anArgCase == "-closeonescape"
1970           || anArgCase == "-closeonesc")
1971     {
1972       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
1973       if (anArgIt + 1 < theArgsNb
1974        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
1975       {
1976         ++anArgIt;
1977       }
1978     }
1979     else if (anArgCase == "-2d_mode"
1980           || anArgCase == "-2dmode"
1981           || anArgCase == "-2d")
1982     {
1983       bool toEnable = true;
1984       if (anArgIt + 1 < theArgsNb
1985        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
1986       {
1987         ++anArgIt;
1988       }
1989       is2dMode = toEnable ? 1 : 0;
1990     }
1991     else if (anArgIt + 1 < theArgsNb
1992           && (anArgCase == "-disp"
1993            || anArgCase == "-display"))
1994     {
1995       aDisplayName = theArgVec[++anArgIt];
1996     }
1997     else if (!ViewerTest::CurrentView().IsNull()
1998           &&  aCopyFrom.IsNull()
1999           && (anArgCase == "-copy"
2000            || anArgCase == "-clone"
2001            || anArgCase == "-cloneactive"
2002            || anArgCase == "-cloneactiveview"))
2003     {
2004       aCopyFrom = ViewerTest::CurrentView();
2005     }
2006     // old syntax
2007     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2008     {
2009       aName.LowerCase();
2010       if (aName == "name")
2011       {
2012         aViewName = aValue;
2013       }
2014       else if (aName == "l"
2015             || aName == "left")
2016       {
2017         aPxLeft = aValue.IntegerValue();
2018       }
2019       else if (aName == "t"
2020             || aName == "top")
2021       {
2022         aPxTop = aValue.IntegerValue();
2023       }
2024       else if (aName == "disp"
2025             || aName == "display")
2026       {
2027         aDisplayName = aValue;
2028       }
2029       else if (aName == "w"
2030             || aName == "width")
2031       {
2032         aPxWidth = aValue.IntegerValue();
2033       }
2034       else if (aName == "h"
2035             || aName == "height")
2036       {
2037         aPxHeight = aValue.IntegerValue();
2038       }
2039       else
2040       {
2041         Message::SendFail() << "Syntax error: unknown argument " << anArg;
2042         return 1;
2043       }
2044     }
2045     else if (aViewName.IsEmpty())
2046     {
2047       aViewName = anArg;
2048     }
2049     else
2050     {
2051       Message::SendFail() << "Syntax error: unknown argument " << anArg;
2052       return 1;
2053     }
2054   }
2055
2056 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
2057   if (!aDisplayName.IsEmpty())
2058   {
2059     aDisplayName.Clear();
2060     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
2061   }
2062 #endif
2063
2064   ViewerTest_Names aViewNames (aViewName);
2065   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2066   {
2067     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2068     theDi.Eval (aCommand.ToCString());
2069     if (is2dMode != -1)
2070     {
2071       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2072     }
2073     return 0;
2074   }
2075
2076   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2077                                                             aViewName, aDisplayName, aCopyFrom);
2078   if (is2dMode != -1)
2079   {
2080     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2081   }
2082   theDi << aViewId;
2083   return 0;
2084 }
2085
2086 //! Parse HLR algo type.
2087 static Standard_Boolean parseHlrAlgoType (const char* theName,
2088                                           Prs3d_TypeOfHLR& theType)
2089 {
2090   TCollection_AsciiString aName (theName);
2091   aName.LowerCase();
2092   if (aName == "polyalgo")
2093   {
2094     theType = Prs3d_TOH_PolyAlgo;
2095   }
2096   else if (aName == "algo")
2097   {
2098     theType = Prs3d_TOH_Algo;
2099   }
2100   else
2101   {
2102     return Standard_False;
2103   }
2104   return Standard_True;
2105 }
2106
2107 //==============================================================================
2108 //function : VHLR
2109 //purpose  : hidden lines removal algorithm
2110 //==============================================================================
2111
2112 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2113 {
2114   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2115   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2116   if (aView.IsNull())
2117   {
2118     Message::SendFail ("Error: no active viewer");
2119     return 1;
2120   }
2121
2122   Standard_Boolean hasHlrOnArg = Standard_False;
2123   Standard_Boolean hasShowHiddenArg = Standard_False;
2124   Standard_Boolean isHLROn = Standard_False;
2125   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2126   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2127   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2128   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2129   {
2130     TCollection_AsciiString anArg (argv[anArgIter]);
2131     anArg.LowerCase();
2132     if (anUpdateTool.parseRedrawMode (anArg))
2133     {
2134       continue;
2135     }
2136     else if (anArg == "-showhidden"
2137           && anArgIter + 1 < argc
2138           && ViewerTest::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2139     {
2140       ++anArgIter;
2141       hasShowHiddenArg = Standard_True;
2142       continue;
2143     }
2144     else if ((anArg == "-type"
2145            || anArg == "-algo"
2146            || anArg == "-algotype")
2147           && anArgIter + 1 < argc
2148           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2149     {
2150       ++anArgIter;
2151       continue;
2152     }
2153     else if (!hasHlrOnArg
2154           && ViewerTest::ParseOnOff (argv[anArgIter], isHLROn))
2155     {
2156       hasHlrOnArg = Standard_True;
2157       continue;
2158     }
2159     // old syntax
2160     else if (!hasShowHiddenArg
2161           && ViewerTest::ParseOnOff(argv[anArgIter], toShowHidden))
2162     {
2163       hasShowHiddenArg = Standard_True;
2164       continue;
2165     }
2166     else
2167     {
2168       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
2169       return 1;
2170     }
2171   }
2172   if (!hasHlrOnArg)
2173   {
2174     di << "HLR:        " << aView->ComputedMode() << "\n";
2175     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2176     di << "HlrAlgo:    ";
2177     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2178     {
2179       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2180       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2181       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2182     }
2183     anUpdateTool.Invalidate();
2184     return 0;
2185   }
2186
2187   Standard_Boolean toRecompute = Standard_False;
2188   if (aTypeOfHLR != Prs3d_TOH_NotSet
2189    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2190   {
2191     toRecompute = Standard_True;
2192     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2193   }
2194   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2195   {
2196     toRecompute = Standard_True;
2197     if (toShowHidden)
2198     {
2199       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2200     }
2201     else
2202     {
2203       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2204     }
2205   }
2206
2207   // redisplay shapes
2208   if (aView->ComputedMode() && isHLROn && toRecompute)
2209   {
2210     AIS_ListOfInteractive aListOfShapes;
2211     aCtx->DisplayedObjects (aListOfShapes);
2212     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2213     {
2214       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2215       {
2216         aCtx->Redisplay (aShape, Standard_False);
2217       }
2218     }
2219   }
2220
2221   aView->SetComputedMode (isHLROn);
2222   return 0;
2223 }
2224
2225 //==============================================================================
2226 //function : VHLRType
2227 //purpose  : change type of using HLR algorithm
2228 //==============================================================================
2229
2230 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2231 {
2232   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2233   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2234   if (aView.IsNull())
2235   {
2236     Message::SendFail ("Error: no active viewer");
2237     return 1;
2238   }
2239
2240   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2241   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2242   AIS_ListOfInteractive aListOfShapes;
2243   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2244   {
2245     TCollection_AsciiString anArg (argv[anArgIter]);
2246     anArg.LowerCase();
2247     if (anUpdateTool.parseRedrawMode (anArg))
2248     {
2249       continue;
2250     }
2251     else if ((anArg == "-type"
2252            || anArg == "-algo"
2253            || anArg == "-algotype")
2254           && anArgIter + 1 < argc
2255           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2256     {
2257       ++anArgIter;
2258       continue;
2259     }
2260     // old syntax
2261     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2262           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2263     {
2264       continue;
2265     }
2266     else
2267     {
2268       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2269       TCollection_AsciiString aName (argv[anArgIter]);
2270       if (!aMap.IsBound2 (aName))
2271       {
2272         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
2273         return 1;
2274       }
2275
2276       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2277       if (aShape.IsNull())
2278       {
2279         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
2280         return 1;
2281       }
2282       aListOfShapes.Append (aShape);
2283       continue;
2284     }
2285   }
2286   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2287   {
2288     Message::SendFail ("Syntax error: wrong number of arguments");
2289     return 1;
2290   }
2291
2292   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2293   if (isGlobal)
2294   {
2295     aCtx->DisplayedObjects (aListOfShapes);
2296     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2297   }
2298
2299   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2300   {
2301     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2302     if (aShape.IsNull())
2303     {
2304       continue;
2305     }
2306
2307     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2308                             && aView->ComputedMode();
2309     if (!isGlobal
2310      || aShape->TypeOfHLR() != aTypeOfHLR)
2311     {
2312       aShape->SetTypeOfHLR (aTypeOfHLR);
2313     }
2314     if (toUpdateShape)
2315     {
2316       aCtx->Redisplay (aShape, Standard_False);
2317     }
2318   }
2319   return 0;
2320 }
2321
2322 //==============================================================================
2323 //function : FindViewIdByWindowHandle
2324 //purpose  : Find theView Id in the map of views by window handle
2325 //==============================================================================
2326 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2327 TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2328 {
2329   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2330        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2331   {
2332     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2333     if (aWindowHandle == theWindowHandle)
2334       return anIter.Key1();
2335   }
2336   return TCollection_AsciiString("");
2337 }
2338 #endif
2339
2340 //! Make the view active
2341 void ActivateView (const TCollection_AsciiString& theViewName,
2342                    Standard_Boolean theToUpdate = Standard_True)
2343 {
2344   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2345   if (aView.IsNull())
2346   {
2347     return;
2348   }
2349
2350   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2351   if (!anAISContext.IsNull())
2352   {
2353     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2354     {
2355       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2356     }
2357
2358     ViewerTest::CurrentView (aView);
2359     ViewerTest::SetAISContext (anAISContext);
2360     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2361 #if defined(_WIN32)
2362     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2363 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
2364     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2365 #else
2366     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2367 #endif
2368     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2369     if (theToUpdate)
2370     {
2371       ViewerTest::CurrentView()->Redraw();
2372     }
2373   }
2374 }
2375
2376 //==============================================================================
2377 //function : RemoveView
2378 //purpose  :
2379 //==============================================================================
2380 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2381                              const Standard_Boolean  theToRemoveContext)
2382 {
2383   if (!ViewerTest_myViews.IsBound2 (theView))
2384   {
2385     return;
2386   }
2387
2388   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2389   RemoveView (aViewName, theToRemoveContext);
2390 }
2391
2392 //==============================================================================
2393 //function : RemoveView
2394 //purpose  : Close and remove view from display, clear maps if neccessary
2395 //==============================================================================
2396 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2397 {
2398   if (!ViewerTest_myViews.IsBound1(theViewName))
2399   {
2400     Message::SendFail() << "Wrong view name";
2401     return;
2402   }
2403
2404   // Activate another view if it's active now
2405   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2406   {
2407     if (ViewerTest_myViews.Extent() > 1)
2408     {
2409       TCollection_AsciiString aNewViewName;
2410       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2411            anIter.More(); anIter.Next())
2412       {
2413         if (anIter.Key1() != theViewName)
2414         {
2415           aNewViewName = anIter.Key1();
2416           break;
2417         }
2418       }
2419       ActivateView (aNewViewName);
2420     }
2421     else
2422     {
2423       VT_GetWindow().Nullify();
2424       ViewerTest::CurrentView (Handle(V3d_View)());
2425       if (isContextRemoved)
2426       {
2427         Handle(AIS_InteractiveContext) anEmptyContext;
2428         ViewerTest::SetAISContext(anEmptyContext);
2429       }
2430     }
2431   }
2432
2433   // Delete view
2434   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2435   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2436   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2437   aRedrawer.Stop (aView->Window());
2438
2439   // Remove view resources
2440   ViewerTest_myViews.UnBind1(theViewName);
2441   aView->Window()->Unmap();
2442   aView->Remove();
2443
2444 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2445   XFlush (GetDisplayConnection()->GetDisplay());
2446 #endif
2447
2448   // Keep context opened only if the closed view is last to avoid
2449   // unused empty contexts
2450   if (!aCurrentContext.IsNull())
2451   {
2452     // Check if there are more difined views in the viewer
2453     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
2454      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
2455     {
2456       // Remove driver if there is no viewers that use it
2457       Standard_Boolean isRemoveDriver = Standard_True;
2458       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2459           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2460       {
2461         if (aCurrentContext != anIter.Key2() &&
2462           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2463         {
2464           isRemoveDriver = Standard_False;
2465           break;
2466         }
2467       }
2468
2469       aCurrentContext->RemoveAll (Standard_False);
2470       if(isRemoveDriver)
2471       {
2472         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2473       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2474         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
2475       #endif
2476       }
2477
2478       ViewerTest_myContexts.UnBind2(aCurrentContext);
2479     }
2480   }
2481   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
2482   if (ViewerTest_EventManager::ToExitOnCloseView())
2483   {
2484     Draw_Interprete ("exit");
2485   }
2486 }
2487
2488 //==============================================================================
2489 //function : VClose
2490 //purpose  : Remove the view defined by its name
2491 //==============================================================================
2492
2493 static int VClose (Draw_Interpretor& /*theDi*/,
2494                    Standard_Integer  theArgsNb,
2495                    const char**      theArgVec)
2496 {
2497   NCollection_List<TCollection_AsciiString> aViewList;
2498   if (theArgsNb > 1)
2499   {
2500     TCollection_AsciiString anArg (theArgVec[1]);
2501     anArg.UpperCase();
2502     if (anArg.IsEqual ("ALL")
2503      || anArg.IsEqual ("*"))
2504     {
2505       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2506            anIter.More(); anIter.Next())
2507       {
2508         aViewList.Append (anIter.Key1());
2509       }
2510       if (aViewList.IsEmpty())
2511       {
2512         std::cout << "No view to close\n";
2513         return 0;
2514       }
2515     }
2516     else
2517     {
2518       ViewerTest_Names aViewName (theArgVec[1]);
2519       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2520       {
2521         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
2522         return 1;
2523       }
2524       aViewList.Append (aViewName.GetViewName());
2525     }
2526   }
2527   else
2528   {
2529     // close active view
2530     if (ViewerTest::CurrentView().IsNull())
2531     {
2532       Message::SendFail ("Error: no active view");
2533       return 1;
2534     }
2535     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2536   }
2537
2538   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2539   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2540        anIter.More(); anIter.Next())
2541   {
2542     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2543   }
2544
2545   return 0;
2546 }
2547
2548 //==============================================================================
2549 //function : VActivate
2550 //purpose  : Activate the view defined by its ID
2551 //==============================================================================
2552
2553 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2554 {
2555   if (theArgsNb == 1)
2556   {
2557     theDi.Eval("vviewlist");
2558     return 0;
2559   }
2560
2561   TCollection_AsciiString aNameString;
2562   Standard_Boolean toUpdate = Standard_True;
2563   Standard_Boolean toActivate = Standard_True;
2564   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2565   {
2566     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2567     anArg.LowerCase();
2568     if (toUpdate
2569      && anArg == "-noupdate")
2570     {
2571       toUpdate = Standard_False;
2572     }
2573     else if (toActivate
2574           && aNameString.IsEmpty()
2575           && anArg == "none")
2576     {
2577       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2578       VT_GetWindow().Nullify();
2579       ViewerTest::CurrentView (Handle(V3d_View)());
2580       ViewerTest::ResetEventManager();
2581       theDi << theArgVec[0] << ": all views are inactive\n";
2582       toActivate = Standard_False;
2583     }
2584     else if (toActivate
2585           && aNameString.IsEmpty())
2586     {
2587       aNameString = theArgVec[anArgIter];
2588     }
2589     else
2590     {
2591       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2592       return 1;
2593     }
2594   }
2595
2596   if (!toActivate)
2597   {
2598     return 0;
2599   }
2600   else if (aNameString.IsEmpty())
2601   {
2602     Message::SendFail ("Syntax error: wrong number of arguments");
2603     return 1;
2604   }
2605
2606   // Check if this view exists in the viewer with the driver
2607   ViewerTest_Names aViewNames (aNameString);
2608   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2609   {
2610     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2611     return 1;
2612   }
2613
2614   // Check if it is active already
2615   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2616   {
2617     theDi << theArgVec[0] << ": the view is active already\n";
2618     return 0;
2619   }
2620
2621   ActivateView (aViewNames.GetViewName(), toUpdate);
2622   return 0;
2623 }
2624
2625 //==============================================================================
2626 //function : VViewList
2627 //purpose  : Print current list of views per viewer and graphic driver ID
2628 //           shared between viewers
2629 //==============================================================================
2630
2631 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2632 {
2633   if (theArgsNb > 2)
2634   {
2635     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2636           << "Usage: " << theArgVec[0] << " name";
2637     return 1;
2638   }
2639   if (ViewerTest_myContexts.Size() < 1)
2640     return 0;
2641
2642   Standard_Boolean isTreeView =
2643     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2644
2645   if (isTreeView)
2646   {
2647     theDi << theArgVec[0] <<":\n";
2648   }
2649
2650   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2651        aDriverIter.More(); aDriverIter.Next())
2652   {
2653     if (isTreeView)
2654       theDi << aDriverIter.Key1() << ":\n";
2655
2656     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2657       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2658     {
2659       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2660       {
2661         if (isTreeView)
2662         {
2663           TCollection_AsciiString aContextName(aContextIter.Key1());
2664           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2665         }
2666
2667         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2668              aViewIter.More(); aViewIter.Next())
2669         {
2670           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2671           {
2672             TCollection_AsciiString aViewName(aViewIter.Key1());
2673             if (isTreeView)
2674             {
2675               if (aViewIter.Value() == ViewerTest::CurrentView())
2676                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2677               else
2678                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2679             }
2680             else
2681             {
2682               theDi << aViewName << " ";
2683             }
2684           }
2685         }
2686       }
2687     }
2688   }
2689   return 0;
2690 }
2691
2692 //==============================================================================
2693 //function : GetMousePosition
2694 //purpose  :
2695 //==============================================================================
2696 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2697                                    Standard_Integer& theY)
2698 {
2699   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2700   {
2701     theX = aViewCtrl->LastMousePosition().x();
2702     theY = aViewCtrl->LastMousePosition().y();
2703   }
2704 }
2705
2706 //==============================================================================
2707 //function : VViewProj
2708 //purpose  : Switch view projection
2709 //==============================================================================
2710 static int VViewProj (Draw_Interpretor& ,
2711                       Standard_Integer theNbArgs,
2712                       const char** theArgVec)
2713 {
2714   static Standard_Boolean isYup = Standard_False;
2715   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2716   if (aView.IsNull())
2717   {
2718     Message::SendFail ("Error: no active viewer");
2719     return 1;
2720   }
2721
2722   TCollection_AsciiString aCmdName (theArgVec[0]);
2723   Standard_Boolean isGeneralCmd = Standard_False;
2724   if (aCmdName == "vfront")
2725   {
2726     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2727   }
2728   else if (aCmdName == "vback")
2729   {
2730     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2731   }
2732   else if (aCmdName == "vtop")
2733   {
2734     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2735   }
2736   else if (aCmdName == "vbottom")
2737   {
2738     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2739   }
2740   else if (aCmdName == "vleft")
2741   {
2742     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2743   }
2744   else if (aCmdName == "vright")
2745   {
2746     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2747   }
2748   else if (aCmdName == "vaxo")
2749   {
2750     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2751   }
2752   else
2753   {
2754     isGeneralCmd = Standard_True;
2755     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2756     {
2757       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2758       anArgCase.LowerCase();
2759       if (anArgCase == "-zup")
2760       {
2761         isYup = Standard_False;
2762       }
2763       else if (anArgCase == "-yup")
2764       {
2765         isYup = Standard_True;
2766       }
2767       else if (anArgCase == "-front"
2768             || anArgCase == "front"
2769             || anArgCase == "-f"
2770             || anArgCase == "f")
2771       {
2772         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2773       }
2774       else if (anArgCase == "-back"
2775             || anArgCase == "back"
2776             || anArgCase == "-b"
2777             || anArgCase == "b")
2778       {
2779         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2780       }
2781       else if (anArgCase == "-top"
2782             || anArgCase == "top"
2783             || anArgCase == "-t"
2784             || anArgCase == "t")
2785       {
2786         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2787       }
2788       else if (anArgCase == "-bottom"
2789             || anArgCase == "bottom"
2790             || anArgCase == "-bot"
2791             || anArgCase == "bot"
2792             || anArgCase == "-b"
2793             || anArgCase == "b")
2794       {
2795         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2796       }
2797       else if (anArgCase == "-left"
2798             || anArgCase == "left"
2799             || anArgCase == "-l"
2800             || anArgCase == "l")
2801       {
2802         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2803       }
2804       else if (anArgCase == "-right"
2805             || anArgCase == "right"
2806             || anArgCase == "-r"
2807             || anArgCase == "r")
2808       {
2809         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2810       }
2811       else if (anArgCase == "-axoleft"
2812             || anArgCase == "-leftaxo"
2813             || anArgCase == "axoleft"
2814             || anArgCase == "leftaxo")
2815       {
2816         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
2817       }
2818       else if (anArgCase == "-axo"
2819             || anArgCase == "axo"
2820             || anArgCase == "-a"
2821             || anArgCase == "a"
2822             || anArgCase == "-axoright"
2823             || anArgCase == "-rightaxo"
2824             || anArgCase == "axoright"
2825             || anArgCase == "rightaxo")
2826       {
2827         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2828       }
2829       else if (anArgCase == "+x")
2830       {
2831         aView->SetProj (V3d_Xpos, isYup);
2832       }
2833       else if (anArgCase == "-x")
2834       {
2835         aView->SetProj (V3d_Xneg, isYup);
2836       }
2837       else if (anArgCase == "+y")
2838       {
2839         aView->SetProj (V3d_Ypos, isYup);
2840       }
2841       else if (anArgCase == "-y")
2842       {
2843         aView->SetProj (V3d_Yneg, isYup);
2844       }
2845       else if (anArgCase == "+z")
2846       {
2847         aView->SetProj (V3d_Zpos, isYup);
2848       }
2849       else if (anArgCase == "-z")
2850       {
2851         aView->SetProj (V3d_Zneg, isYup);
2852       }
2853       else if (anArgCase == "+x+y+z")
2854       {
2855         aView->SetProj (V3d_XposYposZpos, isYup);
2856       }
2857       else if (anArgCase == "+x+y-z")
2858       {
2859         aView->SetProj (V3d_XposYposZneg, isYup);
2860       }
2861       else if (anArgCase == "+x-y+z")
2862       {
2863         aView->SetProj (V3d_XposYnegZpos, isYup);
2864       }
2865       else if (anArgCase == "+x-y-z")
2866       {
2867         aView->SetProj (V3d_XposYnegZneg, isYup);
2868       }
2869       else if (anArgCase == "-x+y+z")
2870       {
2871         aView->SetProj (V3d_XnegYposZpos, isYup);
2872       }
2873       else if (anArgCase == "-x+y-z")
2874       {
2875         aView->SetProj (V3d_XnegYposZneg, isYup);
2876       }
2877       else if (anArgCase == "-x-y+z")
2878       {
2879         aView->SetProj (V3d_XnegYnegZpos, isYup);
2880       }
2881       else if (anArgCase == "-x-y-z")
2882       {
2883         aView->SetProj (V3d_XnegYnegZneg, isYup);
2884       }
2885       else if (anArgCase == "+x+y")
2886       {
2887         aView->SetProj (V3d_XposYpos, isYup);
2888       }
2889       else if (anArgCase == "+x-y")
2890       {
2891         aView->SetProj (V3d_XposYneg, isYup);
2892       }
2893       else if (anArgCase == "-x+y")
2894       {
2895         aView->SetProj (V3d_XnegYpos, isYup);
2896       }
2897       else if (anArgCase == "-x-y")
2898       {
2899         aView->SetProj (V3d_XnegYneg, isYup);
2900       }
2901       else if (anArgCase == "+x+z")
2902       {
2903         aView->SetProj (V3d_XposZpos, isYup);
2904       }
2905       else if (anArgCase == "+x-z")
2906       {
2907         aView->SetProj (V3d_XposZneg, isYup);
2908       }
2909       else if (anArgCase == "-x+z")
2910       {
2911         aView->SetProj (V3d_XnegZpos, isYup);
2912       }
2913       else if (anArgCase == "-x-z")
2914       {
2915         aView->SetProj (V3d_XnegZneg, isYup);
2916       }
2917       else if (anArgCase == "+y+z")
2918       {
2919         aView->SetProj (V3d_YposZpos, isYup);
2920       }
2921       else if (anArgCase == "+y-z")
2922       {
2923         aView->SetProj (V3d_YposZneg, isYup);
2924       }
2925       else if (anArgCase == "-y+z")
2926       {
2927         aView->SetProj (V3d_YnegZpos, isYup);
2928       }
2929       else if (anArgCase == "-y-z")
2930       {
2931         aView->SetProj (V3d_YnegZneg, isYup);
2932       }
2933       else if (anArgIter + 1 < theNbArgs
2934             && anArgCase == "-frame"
2935             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2936       {
2937         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2938         aFrameDef.LowerCase();
2939         gp_Dir aRight, anUp;
2940         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2941         {
2942           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2943           return 1;
2944         }
2945
2946         if (aFrameDef.Value (2) == 'x')
2947         {
2948           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2949         }
2950         else if (aFrameDef.Value (2) == 'y')
2951         {
2952           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2953         }
2954         else if (aFrameDef.Value (2) == 'z')
2955         {
2956           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2957         }
2958         else
2959         {
2960           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2961           return 1;
2962         }
2963
2964         if (aFrameDef.Value (4) == 'x')
2965         {
2966           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2967         }
2968         else if (aFrameDef.Value (4) == 'y')
2969         {
2970           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2971         }
2972         else if (aFrameDef.Value (4) == 'z')
2973         {
2974           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2975         }
2976         else
2977         {
2978           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2979           return 1;
2980         }
2981
2982         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2983         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2984         const gp_Dir aDir = anUp.Crossed (aRight);
2985         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2986         aCamera->SetDirection (aDir);
2987         aCamera->SetUp (anUp);
2988         aCamera->OrthogonalizeUp();
2989
2990         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2991         aView->Update();
2992       }
2993       else
2994       {
2995         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2996         return 1;
2997       }
2998     }
2999   }
3000
3001   if (!isGeneralCmd
3002     && theNbArgs != 1)
3003   {
3004     Message::SendFail ("Syntax error: wrong number of arguments");
3005     return 1;
3006   }
3007   return 0;
3008 }
3009
3010 //==============================================================================
3011 //function : VHelp
3012 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3013 //Draw arg : No args
3014 //==============================================================================
3015
3016 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3017 {
3018   di << "=========================\n";
3019   di << "F : FitAll\n";
3020   di << "T : TopView\n";
3021   di << "B : BottomView\n";
3022   di << "R : RightView\n";
3023   di << "L : LeftView\n";
3024   di << "Backspace : AxonometricView\n";
3025
3026   di << "=========================\n";
3027   di << "W, S : Fly   forward/backward\n";
3028   di << "A, D : Slide left/right\n";
3029   di << "Q, E : Bank  left/right\n";
3030   di << "-, + : Change flying speed\n";
3031   di << "Arrows : look left/right/up/down\n";
3032   di << "Arrows+Shift : slide left/right/up/down\n";
3033
3034   di << "=========================\n";
3035   di << "S + Ctrl : Shading\n";
3036   di << "W + Ctrl : Wireframe\n";
3037   di << "H : HiddenLineRemoval\n";
3038   di << "U : Unset display mode\n";
3039   di << "Delete : Remove selection from viewer\n";
3040
3041   di << "=========================\n";
3042   di << "Selection mode \n";
3043   di << "0 : Shape\n";
3044   di << "1 : Vertex\n";
3045   di << "2 : Edge\n";
3046   di << "3 : Wire\n";
3047   di << "4 : Face\n";
3048   di << "5 : Shell\n";
3049   di << "6 : Solid\n";
3050   di << "7 : Compound\n";
3051
3052   di << "=========================\n";
3053   di << "< : Hilight next detected\n";
3054   di << "> : Hilight previous detected\n";
3055
3056   return 0;
3057 }
3058
3059 #ifdef _WIN32
3060
3061 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3062                                            UINT theMsg,
3063                                            WPARAM wParam,
3064                                            LPARAM lParam )
3065 {
3066   if (ViewerTest_myViews.IsEmpty())
3067   {
3068     return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3069   }
3070
3071   switch (theMsg)
3072   {
3073     case WM_CLOSE:
3074     {
3075       // Delete view from map of views
3076       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3077       return 0;
3078     }
3079     case WM_ACTIVATE:
3080     {
3081       if (LOWORD(wParam) == WA_CLICKACTIVE
3082        || LOWORD(wParam) == WA_ACTIVE
3083        || ViewerTest::CurrentView().IsNull())
3084       {
3085         // Activate inactive window
3086         if (VT_GetWindow().IsNull()
3087          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3088         {
3089           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3090         }
3091       }
3092       break;
3093     }
3094     default:
3095     {
3096       return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3097     }
3098   }
3099   return 0;
3100 }
3101
3102 static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
3103                                         UINT theMsg,
3104                                         WPARAM wParam,
3105                                         LPARAM lParam)
3106 {
3107   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3108   if (aView.IsNull())
3109   {
3110     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3111   }
3112
3113   switch (theMsg)
3114   {
3115     case WM_PAINT:
3116     {
3117       PAINTSTRUCT aPaint;
3118       BeginPaint(theWinHandle, &aPaint);
3119       EndPaint  (theWinHandle, &aPaint);
3120       ViewerTest::CurrentEventManager()->ProcessExpose();
3121       break;
3122     }
3123     case WM_SIZE:
3124     {
3125       ViewerTest::CurrentEventManager()->ProcessConfigure();
3126       break;
3127     }
3128     case WM_MOVE:
3129     case WM_MOVING:
3130     case WM_SIZING:
3131     {
3132       switch (aView->RenderingParams().StereoMode)
3133       {
3134         case Graphic3d_StereoMode_RowInterlaced:
3135         case Graphic3d_StereoMode_ColumnInterlaced:
3136         case Graphic3d_StereoMode_ChessBoard:
3137         {
3138           // track window moves to reverse stereo pair
3139           aView->MustBeResized();
3140           aView->Update();
3141           break;
3142         }
3143         default:
3144           break;
3145       }
3146       break;
3147     }
3148     case WM_KEYUP:
3149     case WM_KEYDOWN:
3150     {
3151       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
3152       if (aVKey != Aspect_VKey_UNKNOWN)
3153       {
3154         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3155         if (theMsg == WM_KEYDOWN)
3156         {
3157           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3158         }
3159         else
3160         {
3161           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3162         }
3163         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3164       }
3165       break;
3166     }
3167     case WM_LBUTTONUP:
3168     case WM_MBUTTONUP:
3169     case WM_RBUTTONUP:
3170     case WM_LBUTTONDOWN:
3171     case WM_MBUTTONDOWN:
3172     case WM_RBUTTONDOWN:
3173     {
3174       const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3175       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3176       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3177       switch (theMsg)
3178       {
3179         case WM_LBUTTONUP:
3180         case WM_LBUTTONDOWN:
3181           aButton = Aspect_VKeyMouse_LeftButton;
3182           break;
3183         case WM_MBUTTONUP:
3184         case WM_MBUTTONDOWN:
3185           aButton = Aspect_VKeyMouse_MiddleButton;
3186           break;
3187         case WM_RBUTTONUP:
3188         case WM_RBUTTONDOWN:
3189           aButton = Aspect_VKeyMouse_RightButton;
3190           break;
3191       }
3192       if (theMsg == WM_LBUTTONDOWN
3193        || theMsg == WM_MBUTTONDOWN
3194        || theMsg == WM_RBUTTONDOWN)
3195       {
3196         if (aButton == Aspect_VKeyMouse_LeftButton)
3197         {
3198           TheIsAnimating = Standard_False;
3199         }
3200
3201         SetFocus  (theWinHandle);
3202         SetCapture(theWinHandle);
3203         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3204       }
3205       else
3206       {
3207         ReleaseCapture();
3208         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3209       }
3210       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3211       break;
3212     }
3213     case WM_MOUSEWHEEL:
3214     {
3215       const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
3216       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
3217       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3218       Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
3219       POINT aCursorPnt = { aPos.x(), aPos.y() };
3220       if (ScreenToClient (theWinHandle, &aCursorPnt))
3221       {
3222         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3223       }
3224
3225       ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3226       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3227       break;
3228     }
3229     case WM_MOUSEMOVE:
3230     {
3231       Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3232       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
3233       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
3234
3235       // don't make a slide-show from input events - fetch the actual mouse cursor position
3236       CURSORINFO aCursor;
3237       aCursor.cbSize = sizeof(aCursor);
3238       if (::GetCursorInfo (&aCursor) != FALSE)
3239       {
3240         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
3241         if (ScreenToClient (theWinHandle, &aCursorPnt))
3242         {
3243           // as we override mouse position, we need overriding also mouse state
3244           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3245           aButtons = WNT_Window::MouseButtonsAsync();
3246           aFlags   = WNT_Window::MouseKeyFlagsAsync();
3247         }
3248       }
3249
3250       if (VT_GetWindow().IsNull()
3251       || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3252       {
3253         // mouse move events come also for inactive windows
3254         break;
3255       }
3256
3257       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3258       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
3259       break;
3260     }
3261     default:
3262     {
3263       return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3264     }
3265   }
3266   return 0L;
3267 }
3268
3269 //==============================================================================
3270 //function : ViewerMainLoop
3271 //purpose  : Get a Event on the view and dispatch it
3272 //==============================================================================
3273
3274 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3275 {
3276   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3277   if (aViewCtrl.IsNull()
3278    || theNbArgs < 4)
3279   {
3280     return 0;
3281   }
3282
3283   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3284
3285   std::cout << "Start picking\n";
3286
3287   MSG aMsg;
3288   aMsg.wParam = 1;
3289   while (aViewCtrl->ToPickPoint())
3290   {
3291     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3292     if (GetMessageW (&aMsg, NULL, 0, 0))
3293     {
3294       TranslateMessage (&aMsg);
3295       DispatchMessageW (&aMsg);
3296     }
3297   }
3298
3299   std::cout << "Picking done\n";
3300   return 0;
3301 }
3302
3303 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
3304
3305 int min( int a, int b )
3306 {
3307   if( a<b )
3308     return a;
3309   else
3310     return b;
3311 }
3312
3313 int max( int a, int b )
3314 {
3315   if( a>b )
3316     return a;
3317   else
3318     return b;
3319 }
3320
3321 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3322 {
3323   static XEvent aReport;
3324   const Standard_Boolean toPick = theNbArgs > 0;
3325   if (theNbArgs > 0)
3326   {
3327     if (ViewerTest::CurrentEventManager().IsNull())
3328     {
3329       return 0;
3330     }
3331     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3332   }
3333
3334   Display* aDisplay = GetDisplayConnection()->GetDisplay();
3335   XNextEvent (aDisplay, &aReport);
3336
3337   // Handle event for the chosen display connection
3338   switch (aReport.type)
3339   {
3340     case ClientMessage:
3341     {
3342       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3343       {
3344         // Close the window
3345         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3346         return toPick ? 0 : 1;
3347       }
3348       break;
3349     }
3350     case FocusIn:
3351     {
3352       // Activate inactive view
3353       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3354       if (aWindow != aReport.xfocus.window)
3355       {
3356         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3357       }
3358       break;
3359     }
3360     case Expose:
3361     {
3362       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3363       if (anXWindow == aReport.xexpose.window)
3364       {
3365         ViewerTest::CurrentEventManager()->ProcessExpose();
3366       }
3367
3368       // remove all the ExposureMask and process them at once
3369       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3370       {
3371         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
3372         {
3373           break;
3374         }
3375       }
3376
3377       break;
3378     }
3379     case ConfigureNotify:
3380     {
3381       // remove all the StructureNotifyMask and process them at once
3382       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3383       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3384       {
3385         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
3386         {
3387           break;
3388         }
3389       }
3390
3391       if (anXWindow == aReport.xconfigure.window)
3392       {
3393         ViewerTest::CurrentEventManager()->ProcessConfigure();
3394       }
3395       break;
3396     }
3397     case KeyPress:
3398     case KeyRelease:
3399     {
3400       XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
3401       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
3402       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
3403       if (aVKey != Aspect_VKey_UNKNOWN)
3404       {
3405         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3406         if (aReport.type == KeyPress)
3407         {
3408           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3409         }
3410         else
3411         {
3412           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3413         }
3414         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3415       }
3416       break;
3417     }
3418     case ButtonPress:
3419     case ButtonRelease:
3420     {
3421       const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
3422       Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
3423       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3424       if (aReport.xbutton.button == Button1)
3425       {
3426         aButton = Aspect_VKeyMouse_LeftButton;
3427       }
3428       if (aReport.xbutton.button == Button2)
3429       {
3430         aButton = Aspect_VKeyMouse_MiddleButton;
3431       }
3432       if (aReport.xbutton.button == Button3)
3433       {
3434         aButton = Aspect_VKeyMouse_RightButton;
3435       }
3436
3437       if (aReport.xbutton.state & ControlMask)
3438       {
3439         aFlags |= Aspect_VKeyFlags_CTRL;
3440       }
3441       if (aReport.xbutton.state & ShiftMask)
3442       {
3443         aFlags |= Aspect_VKeyFlags_SHIFT;
3444       }
3445       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3446       {
3447         aFlags |= Aspect_VKeyFlags_ALT;
3448       }
3449
3450       if (aReport.xbutton.button == Button4
3451        || aReport.xbutton.button == Button5)
3452       {
3453         if (aReport.type != ButtonPress)
3454         {
3455           break;
3456         }
3457
3458         const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0);
3459         ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3460       }
3461       else if (aReport.type == ButtonPress)
3462       {
3463         if (aButton == Aspect_VKeyMouse_LeftButton)
3464         {
3465           TheIsAnimating = Standard_False;
3466         }
3467         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3468       }
3469       else
3470       {
3471         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3472       }
3473       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3474       break;
3475     }
3476     case MotionNotify:
3477     {
3478       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3479       if (anXWindow != aReport.xmotion.window)
3480       {
3481         break;
3482       }
3483
3484       // remove all the ButtonMotionMask and process them at once
3485       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3486       {
3487         if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
3488         {
3489           break;
3490         }
3491       }
3492
3493       Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y);
3494       Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
3495       Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
3496       if ((aReport.xmotion.state & Button1Mask) != 0)
3497       {
3498         aButtons |= Aspect_VKeyMouse_LeftButton;
3499       }
3500       else if ((aReport.xmotion.state & Button2Mask) != 0)
3501       {
3502         aButtons |= Aspect_VKeyMouse_MiddleButton;
3503       }
3504       else if ((aReport.xmotion.state & Button3Mask) != 0)
3505       {
3506         aButtons |= Aspect_VKeyMouse_RightButton;
3507       }
3508
3509       if (aReport.xmotion.state & ControlMask)
3510       {
3511         aFlags |= Aspect_VKeyFlags_CTRL;
3512       }
3513       if (aReport.xmotion.state & ShiftMask)
3514       {
3515         aFlags |= Aspect_VKeyFlags_SHIFT;
3516       }
3517       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3518       {
3519         aFlags |= Aspect_VKeyFlags_ALT;
3520       }
3521
3522       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3523       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3524       break;
3525     }
3526   }
3527   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
3528 }
3529
3530 //==============================================================================
3531 //function : VProcessEvents
3532 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
3533 //==============================================================================
3534 static void VProcessEvents (ClientData theDispX, int)
3535 {
3536   Display* aDispX = (Display* )theDispX;
3537   Handle(Aspect_DisplayConnection) aDispConn;
3538   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
3539        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
3540   {
3541     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
3542     if (aDispConnTmp->GetDisplay() == aDispX)
3543     {
3544       aDispConn = aDispConnTmp;
3545       break;
3546     }
3547   }
3548   if (aDispConn.IsNull())
3549   {
3550     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
3551     return;
3552   }
3553
3554   // process new events in queue
3555   SetDisplayConnection (aDispConn);
3556   int aNbRemain = 0;
3557   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
3558   {
3559     const int anEventResult = ViewerMainLoop (0, NULL);
3560     if (anEventResult == 0)
3561     {
3562       return;
3563     }
3564
3565     aNbRemain = XPending (aDispX);
3566     if (++anEventIter >= aNbEventsMax
3567      || aNbRemain <= 0)
3568     {
3569       break;
3570     }
3571   }
3572
3573   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
3574   // it is possible that new events will arrive to queue before the end of this callback
3575   // so that either this callback should go into an infinite loop (blocking processing of other events)
3576   // or to keep unprocessed events till the next queue update (which can arrive not soon).
3577   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
3578   if (aNbRemain != 0)
3579   {
3580     XEvent aDummyEvent;
3581     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
3582     aDummyEvent.type = ClientMessage;
3583     aDummyEvent.xclient.format = 32;
3584     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
3585     XFlush (aDispX);
3586   }
3587
3588   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
3589   {
3590     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
3591   }
3592 }
3593 #endif
3594
3595 //==============================================================================
3596 //function : OSWindowSetup
3597 //purpose  : Setup for the X11 window to be able to cath the event
3598 //==============================================================================
3599
3600
3601 static void OSWindowSetup()
3602 {
3603 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
3604   // X11
3605
3606   Window  window   = VT_GetWindow()->XWindow();
3607   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
3608   Display *aDisplay = GetDisplayConnection()->GetDisplay();
3609   XSynchronize(aDisplay, 1);
3610
3611   // X11 : For keyboard on SUN
3612   XWMHints wmhints;
3613   wmhints.flags = InputHint;
3614   wmhints.input = 1;
3615
3616   XSetWMHints( aDisplay, window, &wmhints);
3617
3618   XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask | KeyReleaseMask |
3619     ButtonPressMask | ButtonReleaseMask |
3620     StructureNotifyMask |
3621     PointerMotionMask |
3622     Button1MotionMask | Button2MotionMask |
3623     Button3MotionMask | FocusChangeMask
3624     );
3625   Atom aDeleteWindowAtom = GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW);
3626   XSetWMProtocols(aDisplay, window, &aDeleteWindowAtom, 1);
3627
3628   XSynchronize(aDisplay, 0);
3629
3630 #else
3631   // _WIN32
3632 #endif
3633
3634 }
3635
3636 //==============================================================================
3637 //function : VFit
3638 //purpose  :
3639 //==============================================================================
3640
3641 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3642 {
3643   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3644   if (aView.IsNull())
3645   {
3646     Message::SendFail ("Error: no active viewer");
3647     return 1;
3648   }
3649
3650   Standard_Boolean toFit = Standard_True;
3651   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3652   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3653   {
3654     TCollection_AsciiString anArg (theArgv[anArgIter]);
3655     anArg.LowerCase();
3656     if (anUpdateTool.parseRedrawMode (anArg))
3657     {
3658       continue;
3659     }
3660     else if (anArg == "-selected")
3661     {
3662       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3663       toFit = Standard_False;
3664     }
3665     else
3666     {
3667       Message::SendFail() << "Syntax error at '" << anArg << "'";
3668     }
3669   }
3670
3671   if (toFit)
3672   {
3673     aView->FitAll (0.01, Standard_False);
3674   }
3675   return 0;
3676 }
3677
3678 //=======================================================================
3679 //function : VFitArea
3680 //purpose  : Fit view to show area located between two points
3681 //         : given in world 2D or 3D coordinates.
3682 //=======================================================================
3683 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3684 {
3685   Handle(V3d_View) aView = ViewerTest::CurrentView();
3686   if (aView.IsNull())
3687   {
3688     Message::SendFail ("Error: No active viewer");
3689     return 1;
3690   }
3691
3692   // Parse arguments.
3693   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3694   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3695
3696   if (theArgNb == 5)
3697   {
3698     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3699     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3700     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3701     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3702   }
3703   else if (theArgNb == 7)
3704   {
3705     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3706     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3707     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3708     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3709     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3710     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3711   }
3712   else
3713   {
3714     Message::SendFail ("Syntax error: Invalid number of arguments");
3715     theDI.PrintHelp(theArgVec[0]);
3716     return 1;
3717   }
3718
3719   // Convert model coordinates to view space
3720   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3721   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3722   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3723
3724   // Determine fit area
3725   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3726   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3727
3728   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3729
3730   if (aDiagonal < Precision::Confusion())
3731   {
3732     Message::SendFail ("Error: view area is too small");
3733     return 1;
3734   }
3735
3736   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3737   return 0;
3738 }
3739
3740 //==============================================================================
3741 //function : VZFit
3742 //purpose  : ZFitall, no DRAW arguments
3743 //Draw arg : No args
3744 //==============================================================================
3745 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3746 {
3747   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3748
3749   if (aCurrentView.IsNull())
3750   {
3751     Message::SendFail ("Error: no active viewer");
3752     return 1;
3753   }
3754
3755   if (theArgsNb == 1)
3756   {
3757     aCurrentView->ZFitAll();
3758     aCurrentView->Redraw();
3759     return 0;
3760   }
3761
3762   Standard_Real aScale = 1.0;
3763
3764   if (theArgsNb >= 2)
3765   {
3766     aScale = Draw::Atoi (theArgVec[1]);
3767   }
3768
3769   aCurrentView->ZFitAll (aScale);
3770   aCurrentView->Redraw();
3771
3772   return 0;
3773 }
3774
3775 //==============================================================================
3776 //function : VRepaint
3777 //purpose  :
3778 //==============================================================================
3779 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3780 {
3781   Handle(V3d_View) aView = ViewerTest::CurrentView();
3782   if (aView.IsNull())
3783   {
3784     Message::SendFail ("Error: no active viewer");
3785     return 1;
3786   }
3787
3788   Standard_Boolean isImmediateUpdate = Standard_False;
3789   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3790   {
3791     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3792     anArg.LowerCase();
3793     if (anArg == "-immediate"
3794      || anArg == "-imm")
3795     {
3796       isImmediateUpdate = Standard_True;
3797       if (anArgIter + 1 < theArgNb
3798        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3799       {
3800         ++anArgIter;
3801       }
3802     }
3803     else if (anArg == "-continuous"
3804           || anArg == "-cont"
3805           || anArg == "-fps"
3806           || anArg == "-framerate")
3807     {
3808       Standard_Real aFps = -1.0;
3809       if (anArgIter + 1 < theArgNb
3810        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
3811       {
3812         aFps = Draw::Atof (theArgVec[++anArgIter]);
3813       }
3814
3815       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3816       if (Abs (aFps) >= 1.0)
3817       {
3818         aRedrawer.Start (aView->Window(), aFps);
3819       }
3820       else
3821       {
3822         aRedrawer.Stop();
3823       }
3824     }
3825     else
3826     {
3827       Message::SendFail() << "Syntax error at '" << anArg << "'";
3828       return 1;
3829     }
3830   }
3831
3832   if (isImmediateUpdate)
3833   {
3834     aView->RedrawImmediate();
3835   }
3836   else
3837   {
3838     aView->Redraw();
3839   }
3840   return 0;
3841 }
3842
3843 //==============================================================================
3844 //function : VClear
3845 //purpose  : Remove all the object from the viewer
3846 //Draw arg : No args
3847 //==============================================================================
3848
3849 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3850 {
3851   Handle(V3d_View) V = ViewerTest::CurrentView();
3852   if(!V.IsNull())
3853     ViewerTest::Clear();
3854   return 0;
3855 }
3856
3857 //==============================================================================
3858 //function : VPick
3859 //purpose  :
3860 //==============================================================================
3861
3862 static int VPick (Draw_Interpretor& ,
3863                   Standard_Integer theNbArgs,
3864                   const char** theArgVec)
3865 {
3866   if (ViewerTest::CurrentView().IsNull())
3867   {
3868     return 1;
3869   }
3870
3871   if (theNbArgs < 4)
3872   {
3873     Message::SendFail ("Syntax error: wrong number of arguments");
3874     return 1;
3875   }
3876
3877   while (ViewerMainLoop (theNbArgs, theArgVec))
3878   {
3879     //
3880   }
3881
3882   return 0;
3883 }
3884
3885 namespace
3886 {
3887
3888   //! Changes the background
3889   //! @param theDrawInterpretor the interpreter of the Draw Harness application
3890   //! @param theNumberOfCommandLineArguments the number of passed command line arguments
3891   //! @param theCommandLineArguments the array of command line arguments
3892   //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
3893   static int vbackground (Draw_Interpretor&      theDrawInterpretor,
3894                           const Standard_Integer theNumberOfCommandLineArguments,
3895                           const char** const     theCommandLineArguments)
3896   {
3897     if (theNumberOfCommandLineArguments < 1)
3898     {
3899       return TCL_ERROR;
3900     }
3901     BackgroundChanger aBackgroundChanger;
3902     if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
3903                                                 theNumberOfCommandLineArguments,
3904                                                 theCommandLineArguments))
3905     {
3906       theDrawInterpretor << "Wrong command arguments.\n"
3907                             "Type 'help "
3908                          << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
3909       return TCL_ERROR;
3910     }
3911     return TCL_OK;
3912   }
3913
3914 } // namespace
3915
3916 //==============================================================================
3917 //function : VScale
3918 //purpose  : View Scaling
3919 //==============================================================================
3920
3921 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3922 {
3923   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3924   if ( V3dView.IsNull() ) return 1;
3925
3926   if ( argc != 4 ) {
3927     di << argv[0] << "Invalid number of arguments\n";
3928     return 1;
3929   }
3930   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3931   return 0;
3932 }
3933 //==============================================================================
3934 //function : VZBuffTrihedron
3935 //purpose  :
3936 //==============================================================================
3937
3938 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3939                             Standard_Integer  theArgNb,
3940                             const char**      theArgVec)
3941 {
3942   Handle(V3d_View) aView = ViewerTest::CurrentView();
3943   if (aView.IsNull())
3944   {
3945     Message::SendFail ("Error: no active viewer");
3946     return 1;
3947   }
3948
3949   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3950
3951   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3952   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3953   Quantity_Color                aLabelsColor  = Quantity_NOC_WHITE;
3954   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3955   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3956   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3957   Standard_Real                 aScale        = 0.1;
3958   Standard_Real                 aSizeRatio    = 0.8;
3959   Standard_Real                 anArrowDiam   = 0.05;
3960   Standard_Integer              aNbFacets     = 12;
3961   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3962   {
3963     Standard_CString        anArg = theArgVec[anArgIter];
3964     TCollection_AsciiString aFlag (anArg);
3965     aFlag.LowerCase();
3966     if (anUpdateTool.parseRedrawMode (aFlag))
3967     {
3968       continue;
3969     }
3970     else if (aFlag == "-on")
3971     {
3972       continue;
3973     }
3974     else if (aFlag == "-off")
3975     {
3976       aView->TriedronErase();
3977       return 0;
3978     }
3979     else if (aFlag == "-pos"
3980           || aFlag == "-position"
3981           || aFlag == "-corner")
3982     {
3983       if (++anArgIter >= theArgNb)
3984       {
3985         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
3986         return 1;
3987       }
3988
3989       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
3990       aPosName.LowerCase();
3991       if (aPosName == "center")
3992       {
3993         aPosition = Aspect_TOTP_CENTER;
3994       }
3995       else if (aPosName == "left_lower"
3996             || aPosName == "lower_left"
3997             || aPosName == "leftlower"
3998             || aPosName == "lowerleft")
3999       {
4000         aPosition = Aspect_TOTP_LEFT_LOWER;
4001       }
4002       else if (aPosName == "left_upper"
4003             || aPosName == "upper_left"
4004             || aPosName == "leftupper"
4005             || aPosName == "upperleft")
4006       {
4007         aPosition = Aspect_TOTP_LEFT_UPPER;
4008       }
4009       else if (aPosName == "right_lower"
4010             || aPosName == "lower_right"
4011             || aPosName == "rightlower"
4012             || aPosName == "lowerright")
4013       {
4014         aPosition = Aspect_TOTP_RIGHT_LOWER;
4015       }
4016       else if (aPosName == "right_upper"
4017             || aPosName == "upper_right"
4018             || aPosName == "rightupper"
4019             || aPosName == "upperright")
4020       {
4021         aPosition = Aspect_TOTP_RIGHT_UPPER;
4022       }
4023       else
4024       {
4025         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
4026         return 1;
4027       }
4028     }
4029     else if (aFlag == "-type")
4030     {
4031       if (++anArgIter >= theArgNb)
4032       {
4033         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4034         return 1;
4035       }
4036
4037       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
4038       aTypeName.LowerCase();
4039       if (aTypeName == "wireframe"
4040        || aTypeName == "wire")
4041       {
4042         aVisType = V3d_WIREFRAME;
4043       }
4044       else if (aTypeName == "zbuffer"
4045             || aTypeName == "shaded")
4046       {
4047         aVisType = V3d_ZBUFFER;
4048       }
4049       else
4050       {
4051         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
4052       }
4053     }
4054     else if (aFlag == "-scale")
4055     {
4056       if (++anArgIter >= theArgNb)
4057       {
4058         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4059         return 1;
4060       }
4061
4062       aScale = Draw::Atof (theArgVec[anArgIter]);
4063     }
4064     else if (aFlag == "-size"
4065           || aFlag == "-sizeratio")
4066     {
4067       if (++anArgIter >= theArgNb)
4068       {
4069         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4070         return 1;
4071       }
4072
4073       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
4074     }
4075     else if (aFlag == "-arrowdiam"
4076           || aFlag == "-arrowdiameter")
4077     {
4078       if (++anArgIter >= theArgNb)
4079       {
4080         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4081         return 1;
4082       }
4083
4084       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
4085     }
4086     else if (aFlag == "-nbfacets")
4087     {
4088       if (++anArgIter >= theArgNb)
4089       {
4090         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4091         return 1;
4092       }
4093
4094       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
4095     }
4096     else if (aFlag == "-colorlabel"
4097           || aFlag == "-colorlabels")
4098     {
4099       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4100                                                            theArgVec + anArgIter + 1,
4101                                                            aLabelsColor);
4102       if (aNbParsed == 0)
4103       {
4104         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4105         return 1;
4106       }
4107       anArgIter += aNbParsed;
4108     }
4109     else if (aFlag == "-colorarrowx")
4110     {
4111       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4112                                                            theArgVec + anArgIter + 1,
4113                                                            anArrowColorX);
4114       if (aNbParsed == 0)
4115       {
4116         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4117         return 1;
4118       }
4119       anArgIter += aNbParsed;
4120     }
4121     else if (aFlag == "-colorarrowy")
4122     {
4123       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4124                                                            theArgVec + anArgIter + 1,
4125                                                            anArrowColorY);
4126       if (aNbParsed == 0)
4127       {
4128         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4129         return 1;
4130       }
4131       anArgIter += aNbParsed;
4132     }
4133     else if (aFlag == "-colorarrowz")
4134     {
4135       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4136                                                            theArgVec + anArgIter + 1,
4137                                                            anArrowColorZ);
4138       if (aNbParsed == 0)
4139       {
4140         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4141         return 1;
4142       }
4143       anArgIter += aNbParsed;
4144     }
4145     else
4146     {
4147       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4148       return 1;
4149     }
4150   }
4151
4152   aView->ZBufferTriedronSetup (anArrowColorX.Name(), anArrowColorY.Name(), anArrowColorZ.Name(),
4153                                aSizeRatio, anArrowDiam, aNbFacets);
4154   aView->TriedronDisplay (aPosition, aLabelsColor.Name(), aScale, aVisType);
4155   aView->ZFitAll();
4156   return 0;
4157 }
4158
4159 //==============================================================================
4160 //function : VRotate
4161 //purpose  : Camera Rotating
4162 //==============================================================================
4163
4164 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
4165 {
4166   Handle(V3d_View) aView = ViewerTest::CurrentView();
4167   if (aView.IsNull())
4168   {
4169     Message::SendFail ("Error: no active viewer");
4170     return 1;
4171   }
4172
4173   Standard_Boolean hasFlags = Standard_False;
4174   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4175   {
4176     Standard_CString        anArg (theArgVec[anArgIter]);
4177     TCollection_AsciiString aFlag (anArg);
4178     aFlag.LowerCase();
4179     if (aFlag == "-mousestart"
4180      || aFlag == "-mousefrom")
4181     {
4182       hasFlags = Standard_True;
4183       if (anArgIter + 2 >= theArgNb)
4184       {
4185         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4186         return 1;
4187       }
4188
4189       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4190       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4191       aView->StartRotation (anX, anY);
4192     }
4193     else if (aFlag == "-mousemove")
4194     {
4195       hasFlags = Standard_True;
4196       if (anArgIter + 2 >= theArgNb)
4197       {
4198         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4199         return 1;
4200       }
4201
4202       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4203       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4204       aView->Rotation (anX, anY);
4205     }
4206     else if (theArgNb != 4
4207           && theArgNb != 7)
4208     {
4209       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4210       return 1;
4211     }
4212   }
4213
4214   if (hasFlags)
4215   {
4216     return 0;
4217   }
4218   else if (theArgNb == 4)
4219   {
4220     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4221     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4222     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4223     aView->Rotate (anAX, anAY, anAZ);
4224     return 0;
4225   }
4226   else if (theArgNb == 7)
4227   {
4228     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4229     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4230     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4231
4232     Standard_Real anX = Draw::Atof (theArgVec[4]);
4233     Standard_Real anY = Draw::Atof (theArgVec[5]);
4234     Standard_Real anZ = Draw::Atof (theArgVec[6]);
4235
4236     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
4237     return 0;
4238   }
4239
4240   Message::SendFail ("Error: Invalid number of arguments");
4241   return 1;
4242 }
4243
4244 //==============================================================================
4245 //function : VZoom
4246 //purpose  : View zoom in / out (relative to current zoom)
4247 //==============================================================================
4248
4249 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4250   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4251   if ( V3dView.IsNull() ) {
4252     return 1;
4253   }
4254
4255   if ( argc == 2 ) {
4256     Standard_Real coef = Draw::Atof(argv[1]);
4257     if ( coef <= 0.0 ) {
4258       di << argv[1] << "Invalid value\n";
4259       return 1;
4260     }
4261     V3dView->SetZoom( Draw::Atof(argv[1]) );
4262     return 0;
4263   } else {
4264     di << argv[0] << " Invalid number of arguments\n";
4265     return 1;
4266   }
4267 }
4268
4269 //==============================================================================
4270 //function : VPan
4271 //purpose  : View panning (in pixels)
4272 //==============================================================================
4273
4274 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4275   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4276   if ( V3dView.IsNull() ) return 1;
4277
4278   if ( argc == 3 ) {
4279     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
4280     return 0;
4281   } else {
4282     di << argv[0] << " Invalid number of arguments\n";
4283     return 1;
4284   }
4285 }
4286
4287 //==============================================================================
4288 //function : VPlace
4289 //purpose  : Place the point (in pixels) at the center of the window
4290 //==============================================================================
4291 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
4292 {
4293   Handle(V3d_View) aView = ViewerTest::CurrentView();
4294   if (aView.IsNull())
4295   {
4296     Message::SendFail ("Error: no active viewer");
4297     return 1;
4298   }
4299
4300   if (theArgNb != 3)
4301   {
4302     Message::SendFail ("Syntax error: wrong number of arguments");
4303     return 1;
4304   }
4305
4306   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
4307
4308   return 0;
4309 }
4310
4311 static int VColorScale (Draw_Interpretor& theDI,
4312                         Standard_Integer  theArgNb,
4313                         const char**      theArgVec)
4314 {
4315   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4316   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
4317   if (aContext.IsNull())
4318   {
4319     Message::SendFail ("Error: no active viewer");
4320     return 1;
4321   }
4322   if (theArgNb <= 1)
4323   {
4324     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
4325     return 1;
4326   }
4327
4328   Handle(AIS_ColorScale) aColorScale;
4329   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
4330   {
4331     // find existing object
4332     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
4333     if (aColorScale.IsNull())
4334     {
4335       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
4336       return 1;
4337     }
4338   }
4339
4340   if (theArgNb <= 2)
4341   {
4342     if (aColorScale.IsNull())
4343     {
4344       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
4345       return 1;
4346     }
4347
4348     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
4349           << "Min range: "            << aColorScale->GetMin() << "\n"
4350           << "Max range: "            << aColorScale->GetMax() << "\n"
4351           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
4352           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
4353           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
4354           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
4355           << "Label position: ";
4356     switch (aColorScale->GetLabelPosition())
4357     {
4358       case Aspect_TOCSP_NONE:
4359         theDI << "None\n";
4360         break;
4361       case Aspect_TOCSP_LEFT:
4362         theDI << "Left\n";
4363         break;
4364       case Aspect_TOCSP_RIGHT:
4365         theDI << "Right\n";
4366         break;
4367       case Aspect_TOCSP_CENTER:
4368         theDI << "Center\n";
4369         break;
4370     }
4371     return 0;
4372   }
4373
4374   if (aColorScale.IsNull())
4375   {
4376     aColorScale = new AIS_ColorScale();
4377     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4378     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4379   }
4380
4381   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
4382   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
4383   {
4384     Standard_CString        anArg = theArgVec[anArgIter];
4385     TCollection_AsciiString aFlag (anArg);
4386     aFlag.LowerCase();
4387     if (anUpdateTool.parseRedrawMode (aFlag))
4388     {
4389       continue;
4390     }
4391     else if (aFlag == "-range")
4392     {
4393       if (anArgIter + 3 >= theArgNb)
4394       {
4395         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
4396         return 1;
4397       }
4398
4399       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
4400       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
4401       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
4402       if (!aRangeMin.IsRealValue()
4403        || !aRangeMax.IsRealValue())
4404       {
4405         Message::SendFail ("Syntax error: the range values should be real");
4406         return 1;
4407       }
4408       else if (!aNbIntervals.IsIntegerValue())
4409       {
4410         Message::SendFail ("Syntax error: the number of intervals should be integer");
4411         return 1;
4412       }
4413
4414       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
4415       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
4416     }
4417     else if (aFlag == "-font")
4418     {
4419       if (anArgIter + 1 >= theArgNb)
4420       {
4421         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4422         return 1;
4423       }
4424       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
4425       if (!aFontArg.IsIntegerValue())
4426       {
4427         Message::SendFail ("Syntax error: HeightFont value should be integer");
4428         return 1;
4429       }
4430
4431       aColorScale->SetTextHeight (aFontArg.IntegerValue());
4432       anArgIter += 1;
4433     }
4434     else if (aFlag == "-textpos")
4435     {
4436       if (anArgIter + 1 >= theArgNb)
4437       {
4438         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4439         return 1;
4440       }
4441
4442       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
4443       aTextPosArg.LowerCase();
4444       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
4445       if (aTextPosArg == "none")
4446       {
4447         aLabPosition = Aspect_TOCSP_NONE;
4448       }
4449       else if (aTextPosArg == "left")
4450       {
4451         aLabPosition = Aspect_TOCSP_LEFT;
4452       }
4453       else if (aTextPosArg == "right")
4454       {
4455         aLabPosition = Aspect_TOCSP_RIGHT;
4456       }
4457       else if (aTextPosArg == "center")
4458       {
4459         aLabPosition = Aspect_TOCSP_CENTER;
4460       }
4461       else
4462       {
4463         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
4464         return 1;
4465       }
4466       aColorScale->SetLabelPosition (aLabPosition);
4467     }
4468     else if (aFlag == "-logarithmic"
4469           || aFlag == "-log")
4470     {
4471       if (anArgIter + 1 >= theArgNb)
4472       {
4473         Message::SendFail() << "Synta error at argument '" << anArg << "'";
4474         return 1;
4475       }
4476
4477       Standard_Boolean IsLog;
4478       if (!ViewerTest::ParseOnOff(theArgVec[++anArgIter], IsLog))
4479       {
4480         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4481         return 1;
4482       }
4483       aColorScale->SetLogarithmic (IsLog);
4484     }
4485     else if (aFlag == "-huerange"
4486           || aFlag == "-hue")
4487     {
4488       if (anArgIter + 2 >= theArgNb)
4489       {
4490         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4491         return 1;
4492       }
4493
4494       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
4495       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
4496       aColorScale->SetHueRange (aHueMin, aHueMax);
4497     }
4498     else if (aFlag == "-colorrange")
4499     {
4500       Quantity_Color aColorMin, aColorMax;
4501       Standard_Integer aNbParsed1 = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
4502                                                             theArgVec + (anArgIter + 1),
4503                                                             aColorMin);
4504       anArgIter += aNbParsed1;
4505       Standard_Integer aNbParsed2 = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
4506                                                             theArgVec + (anArgIter + 1),
4507                                                             aColorMax);
4508       anArgIter += aNbParsed2;
4509       if (aNbParsed1 == 0
4510        || aNbParsed2 == 0)
4511       {
4512         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4513         return 1;
4514       }
4515
4516       aColorScale->SetColorRange (aColorMin, aColorMax);
4517     }
4518     else if (aFlag == "-reversed"
4519           || aFlag == "-inverted"
4520           || aFlag == "-topdown"
4521           || aFlag == "-bottomup")
4522     {
4523       Standard_Boolean toEnable = Standard_True;
4524       if (anArgIter + 1 < theArgNb
4525        && ViewerTest::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
4526       {
4527         ++anArgIter;
4528       }
4529       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
4530     }
4531     else if (aFlag == "-smooth"
4532           || aFlag == "-smoothtransition")
4533     {
4534       Standard_Boolean toEnable = Standard_True;
4535       if (anArgIter + 1 < theArgNb
4536        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4537       {
4538         ++anArgIter;
4539       }
4540       aColorScale->SetSmoothTransition (toEnable);
4541     }
4542     else if (aFlag == "-xy")
4543     {
4544       if (anArgIter + 2 >= theArgNb)
4545       {
4546         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4547         return 1;
4548       }
4549
4550       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
4551       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
4552       if (!anX.IsIntegerValue()
4553        || !anY.IsIntegerValue())
4554       {
4555         Message::SendFail ("Syntax error: coordinates should be integer values");
4556         return 1;
4557       }
4558
4559       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
4560     }
4561     else if (aFlag == "-width"
4562           || aFlag == "-w"
4563           || aFlag == "-breadth")
4564     {
4565       if (anArgIter + 1 >= theArgNb)
4566       {
4567         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4568         return 1;
4569       }
4570
4571       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
4572       if (!aBreadth.IsIntegerValue())
4573       {
4574         Message::SendFail ("Syntax error: a width should be an integer value");
4575         return 1;
4576       }
4577       aColorScale->SetBreadth (aBreadth.IntegerValue());
4578     }
4579     else if (aFlag == "-height"
4580           || aFlag == "-h")
4581     {
4582       if (anArgIter + 1 >= theArgNb)
4583       {
4584         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4585         return 1;
4586       }
4587
4588       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
4589       if (!aHeight.IsIntegerValue())
4590       {
4591         Message::SendFail ("Syntax error: a width should be an integer value");
4592         return 1;
4593       }
4594       aColorScale->SetHeight (aHeight.IntegerValue());
4595     }
4596     else if (aFlag == "-color")
4597     {
4598       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4599       {
4600         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
4601         return 1;
4602       }
4603       else if (anArgIter + 2 >= theArgNb)
4604       {
4605         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4606         return 1;
4607       }
4608
4609       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
4610       if (!anInd.IsIntegerValue())
4611       {
4612         Message::SendFail ("Syntax error: Index value should be integer");
4613         return 1;
4614       }
4615       const Standard_Integer anIndex = anInd.IntegerValue();
4616       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
4617       {
4618         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
4619         return 1;
4620       }
4621
4622       Quantity_Color aColor;
4623       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
4624                                                            theArgVec + (anArgIter + 1),
4625                                                            aColor);
4626       if (aNbParsed == 0)
4627       {
4628         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4629         return 1;
4630       }
4631       aColorScale->SetIntervalColor (aColor, anIndex);
4632       aColorScale->SetColorType (Aspect_TOCSD_USER);
4633       anArgIter += aNbParsed;
4634     }
4635     else if (aFlag == "-label")
4636     {
4637       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4638       {
4639         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
4640         return 1;
4641       }
4642       else if (anArgIter + 2 >= theArgNb)
4643       {
4644         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4645         return 1;
4646       }
4647
4648       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
4649       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
4650       {
4651         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
4652         return 1;
4653       }
4654
4655       TCollection_ExtendedString aText (theArgVec[anArgIter + 2]);
4656       aColorScale->SetLabel     (aText, anIndex);
4657       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4658       anArgIter += 2;
4659     }
4660     else if (aFlag == "-labelat"
4661           || aFlag == "-labat"
4662           || aFlag == "-labelatborder"
4663           || aFlag == "-labatborder"
4664           || aFlag == "-labelatcenter"
4665           || aFlag == "-labatcenter")
4666     {
4667       Standard_Boolean toEnable = Standard_True;
4668       if (aFlag == "-labelat"
4669        || aFlag == "-labat")
4670       {
4671         Standard_Integer aLabAtBorder = -1;
4672         if (++anArgIter >= theArgNb)
4673         {
4674           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
4675           anAtBorder.LowerCase();
4676           if (anAtBorder == "border")
4677           {
4678             aLabAtBorder = 1;
4679           }
4680           else if (anAtBorder == "center")
4681           {
4682             aLabAtBorder = 0;
4683           }
4684         }
4685         if (aLabAtBorder == -1)
4686         {
4687           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4688           return 1;
4689         }
4690         toEnable = (aLabAtBorder == 1);
4691       }
4692       else if (anArgIter + 1 < theArgNb
4693             && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4694       {
4695         ++anArgIter;
4696       }
4697       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
4698                                   || aFlag == "-labatcenter"
4699                                    ? !toEnable
4700                                    :  toEnable);
4701     }
4702     else if (aFlag == "-colors")
4703     {
4704       Aspect_SequenceOfColor aSeq;
4705       for (;;)
4706       {
4707         Quantity_Color aColor;
4708         Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
4709                                                              theArgVec + (anArgIter + 1),
4710                                                              aColor);
4711         if (aNbParsed == 0)
4712         {
4713           break;
4714         }
4715         anArgIter += aNbParsed;
4716         aSeq.Append (aColor);
4717       }
4718       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4719       {
4720         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4721                             << aColorScale->GetNumberOfIntervals() << " intervals";
4722         return 1;
4723       }
4724
4725       aColorScale->SetColors    (aSeq);
4726       aColorScale->SetColorType (Aspect_TOCSD_USER);
4727     }
4728     else if (aFlag == "-uniform")
4729     {
4730       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4731       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4732       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4733       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4734       aColorScale->SetColorType (Aspect_TOCSD_USER);
4735     }
4736     else if (aFlag == "-labels"
4737           || aFlag == "-freelabels")
4738     {
4739       if (anArgIter + 1 >= theArgNb)
4740       {
4741         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4742         return 1;
4743       }
4744
4745       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4746                                  ? aColorScale->GetNumberOfIntervals() + 1
4747                                  : aColorScale->GetNumberOfIntervals();
4748       if (aFlag == "-freelabels")
4749       {
4750         ++anArgIter;
4751         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4752       }
4753       if (anArgIter + aNbLabels >= theArgNb)
4754       {
4755         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4756         return 1;
4757       }
4758
4759       TColStd_SequenceOfExtendedString aSeq;
4760       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4761       {
4762         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter]));
4763       }
4764       aColorScale->SetLabels (aSeq);
4765       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4766     }
4767     else if (aFlag == "-title")
4768     {
4769       if (anArgIter + 1 >= theArgNb)
4770       {
4771         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4772         return 1;
4773       }
4774
4775       Standard_Boolean isTwoArgs = Standard_False;
4776       if (anArgIter + 2 < theArgNb)
4777       {
4778         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4779         aSecondArg.LowerCase();
4780       Standard_DISABLE_DEPRECATION_WARNINGS
4781         if (aSecondArg == "none")
4782         {
4783           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4784           isTwoArgs = Standard_True;
4785         }
4786         else if (aSecondArg == "left")
4787         {
4788           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4789           isTwoArgs = Standard_True;
4790         }
4791         else if (aSecondArg == "right")
4792         {
4793           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4794           isTwoArgs = Standard_True;
4795         }
4796         else if (aSecondArg == "center")
4797         {
4798           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4799           isTwoArgs = Standard_True;
4800         }
4801       Standard_ENABLE_DEPRECATION_WARNINGS
4802       }
4803
4804       aColorScale->SetTitle (theArgVec[anArgIter + 1]);
4805       if (isTwoArgs)
4806       {
4807         anArgIter += 1;
4808       }
4809       anArgIter += 1;
4810     }
4811     else if (aFlag == "-demoversion"
4812           || aFlag == "-demo")
4813     {
4814       aColorScale->SetPosition (0, 0);
4815       aColorScale->SetTextHeight (16);
4816       aColorScale->SetRange (0.0, 100.0);
4817       aColorScale->SetNumberOfIntervals (10);
4818       aColorScale->SetBreadth (0);
4819       aColorScale->SetHeight  (0);
4820       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4821       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4822       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4823     }
4824     else if (aFlag == "-findcolor")
4825     {
4826       if (anArgIter + 1 >= theArgNb)
4827       {
4828         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4829         return 1;
4830       }
4831
4832       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4833
4834       if (!anArg1.IsRealValue())
4835       {
4836         Message::SendFail ("Syntax error: the value should be real");
4837         return 1;
4838       }
4839
4840       Quantity_Color aColor;
4841       aColorScale->FindColor (anArg1.RealValue(), aColor);
4842       theDI << Quantity_Color::StringName (aColor.Name());
4843       return 0;
4844     }
4845     else
4846     {
4847       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4848       return 1;
4849     }
4850   }
4851
4852   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4853   aView->Window()->Size (aWinWidth, aWinHeight);
4854   if (aColorScale->GetBreadth() == 0)
4855   {
4856     aColorScale->SetBreadth (aWinWidth);
4857   }
4858   if (aColorScale->GetHeight() == 0)
4859   {
4860     aColorScale->SetHeight (aWinHeight);
4861   }
4862   aColorScale->SetToUpdate();
4863   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4864   return 0;
4865 }
4866
4867 //==============================================================================
4868 //function : VGraduatedTrihedron
4869 //purpose  : Displays or hides a graduated trihedron
4870 //==============================================================================
4871 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4872                                   Quantity_Color& theColor)
4873 {
4874   Quantity_NameOfColor aColorName;
4875   TCollection_AsciiString aVal = theValue;
4876   aVal.UpperCase();
4877   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4878   {
4879     return Standard_False;
4880   }
4881   theColor = Quantity_Color (aColorName);
4882   return Standard_True;
4883 }
4884
4885 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4886 {
4887   if (theArgNum < 2)
4888   {
4889     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4890                         << theArgs[0] <<"' for more information";
4891     return 1;
4892   }
4893
4894   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4895   TCollection_AsciiString aParseKey;
4896   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4897   {
4898     TCollection_AsciiString anArg (theArgs [anArgIt]);
4899
4900     if (anArg.Value (1) == '-' && !anArg.IsRealValue())
4901     {
4902       aParseKey = anArg;
4903       aParseKey.Remove (1);
4904       aParseKey.LowerCase();
4905       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4906       continue;
4907     }
4908
4909     if (aParseKey.IsEmpty())
4910     {
4911       continue;
4912     }
4913
4914     aMapOfArgs(aParseKey)->Append (anArg);
4915   }
4916
4917   // Check parameters
4918   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4919        aMapIt.More(); aMapIt.Next())
4920   {
4921     const TCollection_AsciiString& aKey = aMapIt.Key();
4922     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4923
4924     // Bool key, without arguments
4925     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4926         && anArgs->IsEmpty())
4927     {
4928       continue;
4929     }
4930
4931     // One argument
4932     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4933           && anArgs->Length() == 1)
4934     {
4935       continue;
4936     }
4937
4938     // On/off arguments
4939     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4940         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4941         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4942         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4943         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4944     {
4945       continue;
4946     }
4947
4948     // One string argument
4949     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4950           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4951           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue())
4952     {
4953       continue;
4954     }
4955
4956     // One integer argument
4957     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4958           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4959           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4960           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4961          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4962     {
4963       continue;
4964     }
4965
4966     // One real argument
4967     if ( aKey.IsEqual ("arrowlength")
4968          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue()))
4969     {
4970       continue;
4971     }
4972
4973     // Two string arguments
4974     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
4975          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue())
4976     {
4977       continue;
4978     }
4979
4980     TCollection_AsciiString aLowerKey;
4981     aLowerKey  = "-";
4982     aLowerKey += aKey;
4983     aLowerKey.LowerCase();
4984     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
4985                         << "Type help for more information";
4986     return 1;
4987   }
4988
4989   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
4990   if (anAISContext.IsNull())
4991   {
4992     Message::SendFail ("Error: no active viewer");
4993     return 1;
4994   }
4995
4996   Standard_Boolean toDisplay = Standard_True;
4997   Quantity_Color aColor;
4998   Graphic3d_GraduatedTrihedron aTrihedronData;
4999   // Process parameters
5000   Handle(TColStd_HSequenceOfAsciiString) aValues;
5001   if (aMapOfArgs.Find ("off", aValues))
5002   {
5003     toDisplay = Standard_False;
5004   }
5005
5006   // AXES NAMES
5007   if (aMapOfArgs.Find ("xname", aValues))
5008   {
5009     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
5010   }
5011   if (aMapOfArgs.Find ("yname", aValues))
5012   {
5013     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
5014   }
5015   if (aMapOfArgs.Find ("zname", aValues))
5016   {
5017     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
5018   }
5019   if (aMapOfArgs.Find ("xdrawname", aValues))
5020   {
5021     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5022   }
5023   if (aMapOfArgs.Find ("ydrawname", aValues))
5024   {
5025     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5026   }
5027   if (aMapOfArgs.Find ("zdrawname", aValues))
5028   {
5029     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5030   }
5031   if (aMapOfArgs.Find ("xnameoffset", aValues))
5032   {
5033     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5034   }
5035   if (aMapOfArgs.Find ("ynameoffset", aValues))
5036   {
5037     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5038   }
5039   if (aMapOfArgs.Find ("znameoffset", aValues))
5040   {
5041     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5042   }
5043
5044   // COLORS
5045   if (aMapOfArgs.Find ("xnamecolor", aValues))
5046   {
5047     if (!GetColor (aValues->Value(1), aColor))
5048     {
5049       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
5050       return 1;
5051     }
5052     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
5053   }
5054   if (aMapOfArgs.Find ("ynamecolor", aValues))
5055   {
5056     if (!GetColor (aValues->Value(1), aColor))
5057     {
5058       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
5059       return 1;
5060     }
5061     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
5062   }
5063   if (aMapOfArgs.Find ("znamecolor", aValues))
5064   {
5065     if (!GetColor (aValues->Value(1), aColor))
5066     {
5067       Message::SendFail ("Syntax error: -znamecolor wrong color name");
5068       return 1;
5069     }
5070     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
5071   }
5072   if (aMapOfArgs.Find ("xcolor", aValues))
5073   {
5074     if (!GetColor (aValues->Value(1), aColor))
5075     {
5076       Message::SendFail ("Syntax error: -xcolor wrong color name");
5077       return 1;
5078     }
5079     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
5080   }
5081   if (aMapOfArgs.Find ("ycolor", aValues))
5082   {
5083     if (!GetColor (aValues->Value(1), aColor))
5084     {
5085       Message::SendFail ("Syntax error: -ycolor wrong color name");
5086       return 1;
5087     }
5088     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
5089   }
5090   if (aMapOfArgs.Find ("zcolor", aValues))
5091   {
5092     if (!GetColor (aValues->Value(1), aColor))
5093     {
5094       Message::SendFail ("Syntax error: -zcolor wrong color name");
5095       return 1;
5096     }
5097     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
5098   }
5099
5100   // TICKMARKS
5101   if (aMapOfArgs.Find ("xticks", aValues))
5102   {
5103     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5104   }
5105   if (aMapOfArgs.Find ("yticks", aValues))
5106   {
5107     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5108   }
5109   if (aMapOfArgs.Find ("zticks", aValues))
5110   {
5111     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5112   }
5113   if (aMapOfArgs.Find ("xticklength", aValues))
5114   {
5115     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5116   }
5117   if (aMapOfArgs.Find ("yticklength", aValues))
5118   {
5119     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5120   }
5121   if (aMapOfArgs.Find ("zticklength", aValues))
5122   {
5123     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5124   }
5125   if (aMapOfArgs.Find ("xdrawticks", aValues))
5126   {
5127     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5128   }
5129   if (aMapOfArgs.Find ("ydrawticks", aValues))
5130   {
5131     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5132   }
5133   if (aMapOfArgs.Find ("zdrawticks", aValues))
5134   {
5135     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5136   }
5137
5138   // VALUES
5139   if (aMapOfArgs.Find ("xdrawvalues", aValues))
5140   {
5141     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5142   }
5143   if (aMapOfArgs.Find ("ydrawvalues", aValues))
5144   {
5145     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5146   }
5147   if (aMapOfArgs.Find ("zdrawvalues", aValues))
5148   {
5149     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5150   }
5151   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
5152   {
5153     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5154   }
5155   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
5156   {
5157     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5158   }
5159   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
5160   {
5161     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5162   }
5163
5164   // ARROWS
5165   if (aMapOfArgs.Find ("arrowlength", aValues))
5166   {
5167     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
5168   }
5169
5170   // FONTS
5171   if (aMapOfArgs.Find ("namefont", aValues))
5172   {
5173     aTrihedronData.SetNamesFont (aValues->Value(1));
5174   }
5175   if (aMapOfArgs.Find ("valuesfont", aValues))
5176   {
5177     aTrihedronData.SetValuesFont (aValues->Value(1));
5178   }
5179
5180   if (aMapOfArgs.Find ("drawgrid", aValues))
5181   {
5182     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
5183   }
5184   if (aMapOfArgs.Find ("drawaxes", aValues))
5185   {
5186     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
5187   }
5188
5189   // The final step: display of erase trihedron
5190   if (toDisplay)
5191   {
5192     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
5193   }
5194   else
5195   {
5196     ViewerTest::CurrentView()->GraduatedTrihedronErase();
5197   }
5198
5199   ViewerTest::GetAISContext()->UpdateCurrentViewer();
5200   ViewerTest::CurrentView()->Redraw();
5201
5202   return 0;
5203 }
5204
5205 //==============================================================================
5206 //function : VTile
5207 //purpose  :
5208 //==============================================================================
5209 static int VTile (Draw_Interpretor& theDI,
5210                   Standard_Integer  theArgNb,
5211                   const char**      theArgVec)
5212 {
5213   Handle(V3d_View) aView = ViewerTest::CurrentView();
5214   if (aView.IsNull())
5215   {
5216     Message::SendFail ("Error: no active viewer");
5217     return 1;
5218   }
5219
5220   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
5221   if (theArgNb < 2)
5222   {
5223     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
5224           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
5225           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
5226     return 0;
5227   }
5228
5229   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
5230   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5231   {
5232     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5233     anArg.LowerCase();
5234     if (anArg == "-lowerleft"
5235      || anArg == "-upperleft")
5236     {
5237       if (anArgIter + 3 < theArgNb)
5238       {
5239         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5240         return 1;
5241       }
5242       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
5243       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5244       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5245     }
5246     else if (anArg == "-total"
5247           || anArg == "-totalsize"
5248           || anArg == "-viewsize")
5249     {
5250       if (anArgIter + 3 < theArgNb)
5251       {
5252         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5253         return 1;
5254       }
5255       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5256       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5257       if (aTile.TotalSize.x() < 1
5258        || aTile.TotalSize.y() < 1)
5259       {
5260         Message::SendFail ("Error: total size is incorrect");
5261         return 1;
5262       }
5263     }
5264     else if (anArg == "-tilesize")
5265     {
5266       if (anArgIter + 3 < theArgNb)
5267       {
5268         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5269         return 1;
5270       }
5271
5272       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5273       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5274       if (aTile.TileSize.x() < 1
5275        || aTile.TileSize.y() < 1)
5276       {
5277         Message::SendFail ("Error: tile size is incorrect");
5278         return 1;
5279       }
5280     }
5281     else if (anArg == "-unset")
5282     {
5283       aView->Camera()->SetTile (Graphic3d_CameraTile());
5284       aView->Redraw();
5285       return 0;
5286     }
5287   }
5288
5289   if (aTile.TileSize.x() < 1
5290    || aTile.TileSize.y() < 1)
5291   {
5292     Message::SendFail ("Error: tile size is undefined");
5293     return 1;
5294   }
5295   else if (aTile.TotalSize.x() < 1
5296         || aTile.TotalSize.y() < 1)
5297   {
5298     Message::SendFail ("Error: total size is undefined");
5299     return 1;
5300   }
5301
5302   aView->Camera()->SetTile (aTile);
5303   aView->Redraw();
5304   return 0;
5305 }
5306
5307 //! Format ZLayer ID.
5308 inline const char* formZLayerId (const Standard_Integer theLayerId)
5309 {
5310   switch (theLayerId)
5311   {
5312     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
5313     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
5314     case Graphic3d_ZLayerId_Top:     return "[TOP]";
5315     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
5316     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
5317     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
5318   }
5319   return "";
5320 }
5321
5322 //! Print the ZLayer information.
5323 inline void printZLayerInfo (Draw_Interpretor& theDI,
5324                              const Graphic3d_ZLayerSettings& theLayer)
5325 {
5326   if (!theLayer.Name().IsEmpty())
5327   {
5328     theDI << "  Name: " << theLayer.Name() << "\n";
5329   }
5330   if (theLayer.IsImmediate())
5331   {
5332     theDI << "  Immediate: TRUE\n";
5333   }
5334   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
5335   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
5336   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
5337   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
5338   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
5339   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
5340   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
5341   {
5342     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
5343   }
5344 }
5345
5346 //==============================================================================
5347 //function : VZLayer
5348 //purpose  : Test z layer operations for v3d viewer
5349 //==============================================================================
5350 static int VZLayer (Draw_Interpretor& theDI,
5351                     Standard_Integer  theArgNb,
5352                     const char**      theArgVec)
5353 {
5354   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5355   if (aContextAIS.IsNull())
5356   {
5357     Message::SendFail ("Error: no active viewer");
5358     return 1;
5359   }
5360
5361   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
5362   if (theArgNb < 2)
5363   {
5364     TColStd_SequenceOfInteger aLayers;
5365     aViewer->GetAllZLayers (aLayers);
5366     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5367     {
5368       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
5369       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
5370       printZLayerInfo (theDI, aSettings);
5371     }
5372     return 1;
5373   }
5374
5375   Standard_Integer anArgIter = 1;
5376   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5377   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
5378   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5379   {
5380     ++anArgIter;
5381   }
5382
5383   {
5384     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
5385     if (aFirstArg.IsIntegerValue())
5386     {
5387       ++anArgIter;
5388       aLayerId = aFirstArg.IntegerValue();
5389     }
5390     else
5391     {
5392       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
5393       {
5394         ++anArgIter;
5395       }
5396     }
5397   }
5398
5399   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
5400   for (; anArgIter < theArgNb; ++anArgIter)
5401   {
5402     // perform operation
5403     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5404     anArg.LowerCase();
5405     if (anUpdateTool.parseRedrawMode (anArg))
5406     {
5407       //
5408     }
5409     else if (anArg == "-add"
5410           || anArg == "add")
5411     {
5412       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5413       if (!aViewer->AddZLayer (aLayerId))
5414       {
5415         Message::SendFail ("Error: can not add a new z layer");
5416         return 0;
5417       }
5418
5419       theDI << aLayerId;
5420     }
5421     else if (anArg == "-insertbefore"
5422           && anArgIter + 1 < theArgNb
5423           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5424     {
5425       ++anArgIter;
5426       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5427       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5428       {
5429         Message::SendFail ("Error: can not add a new z layer");
5430         return 0;
5431       }
5432
5433       theDI << aLayerId;
5434     }
5435     else if (anArg == "-insertafter"
5436           && anArgIter + 1 < theArgNb
5437           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5438     {
5439       ++anArgIter;
5440       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5441       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5442       {
5443         Message::SendFail ("Error: can not add a new z layer");
5444         return 0;
5445       }
5446
5447       theDI << aLayerId;
5448     }
5449     else if (anArg == "-del"
5450           || anArg == "-delete"
5451           || anArg == "del")
5452     {
5453       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5454       {
5455         if (++anArgIter >= theArgNb)
5456         {
5457           Message::SendFail ("Syntax error: id of z layer to remove is missing");
5458           return 1;
5459         }
5460
5461         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5462       }
5463
5464       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
5465        || aLayerId == Graphic3d_ZLayerId_Default
5466        || aLayerId == Graphic3d_ZLayerId_Top
5467        || aLayerId == Graphic3d_ZLayerId_Topmost
5468        || aLayerId == Graphic3d_ZLayerId_TopOSD
5469        || aLayerId == Graphic3d_ZLayerId_BotOSD)
5470       {
5471         Message::SendFail ("Syntax error: standard Z layer can not be removed");
5472         return 1;
5473       }
5474
5475       // move all object displayed in removing layer to default layer
5476       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
5477            anObjIter.More(); anObjIter.Next())
5478       {
5479         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
5480         if (aPrs.IsNull()
5481          || aPrs->ZLayer() != aLayerId)
5482         {
5483           continue;
5484         }
5485         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
5486       }
5487
5488       if (!aViewer->RemoveZLayer (aLayerId))
5489       {
5490         Message::SendFail ("Z layer can not be removed");
5491       }
5492       else
5493       {
5494         theDI << aLayerId << " ";
5495       }
5496     }
5497     else if (anArg == "-get"
5498           || anArg == "get")
5499     {
5500       TColStd_SequenceOfInteger aLayers;
5501       aViewer->GetAllZLayers (aLayers);
5502       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5503       {
5504         theDI << aLayeriter.Value() << " ";
5505       }
5506
5507       theDI << "\n";
5508     }
5509     else if (anArg == "-name")
5510     {
5511       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5512       {
5513         Message::SendFail ("Syntax error: id of Z layer is missing");
5514         return 1;
5515       }
5516
5517       if (++anArgIter >= theArgNb)
5518       {
5519         Message::SendFail ("Syntax error: name is missing");
5520         return 1;
5521       }
5522
5523       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5524       aSettings.SetName (theArgVec[anArgIter]);
5525       aViewer->SetZLayerSettings (aLayerId, aSettings);
5526     }
5527     else if (anArg == "-origin")
5528     {
5529       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5530       {
5531         Message::SendFail ("Syntax error: id of Z layer is missing");
5532         return 1;
5533       }
5534
5535       if (anArgIter + 2 >= theArgNb)
5536       {
5537         Message::SendFail ("Syntax error: origin coordinates are missing");
5538         return 1;
5539       }
5540
5541       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5542       gp_XYZ anOrigin;
5543       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
5544       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
5545       anOrigin.SetZ (0.0);
5546       if (anArgIter + 3 < theArgNb)
5547       {
5548         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
5549         anArgIter += 3;
5550       }
5551       else
5552       {
5553         anArgIter += 2;
5554       }
5555       aSettings.SetOrigin (anOrigin);
5556       aViewer->SetZLayerSettings (aLayerId, aSettings);
5557     }
5558     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5559           && anArgIter + 1 < theArgNb
5560           && (anArg == "-cullingdistance"
5561            || anArg == "-cullingdist"
5562            || anArg == "-culldistance"
5563            || anArg == "-culldist"
5564            || anArg == "-distcull"
5565            || anArg == "-distculling"
5566            || anArg == "-distanceculling"))
5567     {
5568       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5569       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
5570       aSettings.SetCullingDistance (aDist);
5571       aViewer->SetZLayerSettings (aLayerId, aSettings);
5572     }
5573     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5574           && anArgIter + 1 < theArgNb
5575           && (anArg == "-cullingsize"
5576            || anArg == "-cullsize"
5577            || anArg == "-sizecull"
5578            || anArg == "-sizeculling"))
5579     {
5580       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5581       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
5582       aSettings.SetCullingSize (aSize);
5583       aViewer->SetZLayerSettings (aLayerId, aSettings);
5584     }
5585     else if (anArg == "-settings"
5586           || anArg == "settings")
5587     {
5588       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5589       {
5590         if (++anArgIter >= theArgNb)
5591         {
5592           Message::SendFail ("Syntax error: id of Z layer is missing");
5593           return 1;
5594         }
5595
5596         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5597       }
5598
5599       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5600       printZLayerInfo (theDI, aSettings);
5601     }
5602     else if (anArg == "-enable"
5603           || anArg == "enable"
5604           || anArg == "-disable"
5605           || anArg == "disable")
5606     {
5607       const Standard_Boolean toEnable = anArg == "-enable"
5608                                      || anArg == "enable";
5609       if (++anArgIter >= theArgNb)
5610       {
5611         Message::SendFail ("Syntax error: option name is missing");
5612         return 1;
5613       }
5614
5615       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
5616       aSubOp.LowerCase();
5617       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5618       {
5619         if (++anArgIter >= theArgNb)
5620         {
5621           Message::SendFail ("Syntax error: id of Z layer is missing");
5622           return 1;
5623         }
5624
5625         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5626       }
5627
5628       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5629       if (aSubOp == "depthtest"
5630        || aSubOp == "test")
5631       {
5632         aSettings.SetEnableDepthTest (toEnable);
5633       }
5634       else if (aSubOp == "depthwrite"
5635             || aSubOp == "write")
5636       {
5637         aSettings.SetEnableDepthWrite (toEnable);
5638       }
5639       else if (aSubOp == "depthclear"
5640             || aSubOp == "clear")
5641       {
5642         aSettings.SetClearDepth (toEnable);
5643       }
5644       else if (aSubOp == "depthoffset"
5645             || aSubOp == "offset")
5646       {
5647         Graphic3d_PolygonOffset aParams;
5648         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
5649         if (toEnable)
5650         {
5651           if (anArgIter + 2 >= theArgNb)
5652           {
5653             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
5654             return 1;
5655           }
5656
5657           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5658           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5659         }
5660         aSettings.SetPolygonOffset (aParams);
5661       }
5662       else if (aSubOp == "positiveoffset"
5663             || aSubOp == "poffset")
5664       {
5665         if (toEnable)
5666         {
5667           aSettings.SetDepthOffsetPositive();
5668         }
5669         else
5670         {
5671           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
5672         }
5673       }
5674       else if (aSubOp == "negativeoffset"
5675             || aSubOp == "noffset")
5676       {
5677         if (toEnable)
5678         {
5679           aSettings.SetDepthOffsetNegative();
5680         }
5681         else
5682         {
5683           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
5684         }
5685       }
5686       else if (aSubOp == "textureenv")
5687       {
5688         aSettings.SetEnvironmentTexture (toEnable);
5689       }
5690       else if (aSubOp == "raytracing")
5691       {
5692         aSettings.SetRaytracable (toEnable);
5693       }
5694
5695       aViewer->SetZLayerSettings (aLayerId, aSettings);
5696     }
5697     else
5698     {
5699       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
5700       return 1;
5701     }
5702   }
5703
5704   return 0;
5705 }
5706
5707 // The interactive presentation of 2d layer item
5708 // for "vlayerline" command it provides a presentation of
5709 // line with user-defined linewidth, linetype and transparency.
5710 class V3d_LineItem : public AIS_InteractiveObject
5711 {
5712 public:
5713   // CASCADE RTTI
5714   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
5715
5716   // constructor
5717   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5718                                Standard_Real X2, Standard_Real Y2,
5719                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5720                                Standard_Real theWidth    = 0.5,
5721                                Standard_Real theTransp   = 1.0);
5722
5723   private:
5724
5725   void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
5726                 const Handle(Prs3d_Presentation)& thePresentation,
5727                 const Standard_Integer theMode) Standard_OVERRIDE;
5728
5729   void ComputeSelection (const Handle(SelectMgr_Selection)& /*aSelection*/,
5730                          const Standard_Integer /*aMode*/) Standard_OVERRIDE
5731   {}
5732
5733 private:
5734
5735   Standard_Real       myX1, myY1, myX2, myY2;
5736   Aspect_TypeOfLine   myType;
5737   Standard_Real       myWidth;
5738 };
5739
5740 // default constructor for line item
5741 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5742                            Standard_Real X2, Standard_Real Y2,
5743                            Aspect_TypeOfLine theType,
5744                            Standard_Real theWidth,
5745                            Standard_Real theTransp) :
5746   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5747   myType(theType), myWidth(theWidth)
5748 {
5749   SetTransparency (1-theTransp);
5750 }
5751
5752 // render line
5753 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePresentationManager*/,
5754                             const Handle(Prs3d_Presentation)& thePresentation,
5755                             const Standard_Integer /*theMode*/)
5756 {
5757   thePresentation->Clear();
5758   Quantity_Color aColor (Quantity_NOC_RED);
5759   Standard_Integer aWidth, aHeight;
5760   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5761   Handle (Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup (thePresentation);
5762   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5763   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5764   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5765   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5766   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5767   aGroup->AddPrimitiveArray (aPrim);
5768 }
5769
5770 //=============================================================================
5771 //function : VLayerLine
5772 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5773 //         : linewidth, transparency coefficient
5774 //============================================================================
5775 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5776 {
5777   // get the active view
5778   Handle(V3d_View) aView = ViewerTest::CurrentView();
5779   if (aView.IsNull())
5780   {
5781     di << "Call vinit before!\n";
5782     return 1;
5783   }
5784   else if (argc < 5)
5785   {
5786     di << "Use: " << argv[0];
5787     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5788     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5789     di << "              0 - solid  \n";
5790     di << "              1 - dashed \n";
5791     di << "              2 - dot    \n";
5792     di << "              3 - dashdot\n";
5793     di << " transparency : { 0.0 - 1.0 } \n";
5794     di << "                  0.0 - transparent\n";
5795     di << "                  1.0 - visible    \n";
5796     return 1;
5797   }
5798
5799   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5800   // get the input params
5801   Standard_Real X1 = Draw::Atof(argv[1]);
5802   Standard_Real Y1 = Draw::Atof(argv[2]);
5803   Standard_Real X2 = Draw::Atof(argv[3]);
5804   Standard_Real Y2 = Draw::Atof(argv[4]);
5805
5806   Standard_Real aWidth = 0.5;
5807   Standard_Real aTransparency = 1.0;
5808
5809   // has width
5810   if (argc > 5)
5811     aWidth = Draw::Atof(argv[5]);
5812
5813   // select appropriate line type
5814   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5815   if (argc > 6
5816   && !ViewerTest::ParseLineType (argv[6], aLineType))
5817   {
5818     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5819     return 1;
5820   }
5821
5822   // has transparency
5823   if (argc > 7)
5824   {
5825     aTransparency = Draw::Atof(argv[7]);
5826     if (aTransparency < 0 || aTransparency > 1.0)
5827       aTransparency = 1.0;
5828   }
5829
5830   static Handle (V3d_LineItem) aLine;
5831   if (!aLine.IsNull())
5832   {
5833     aContext->Erase (aLine, Standard_False);
5834   }
5835   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5836                             aLineType, aWidth,
5837                             aTransparency);
5838
5839   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5840   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5841   aLine->SetToUpdate();
5842   aContext->Display (aLine, Standard_True);
5843
5844   return 0;
5845 }
5846
5847
5848 //==============================================================================
5849 //function : VGrid
5850 //purpose  :
5851 //==============================================================================
5852
5853 static int VGrid (Draw_Interpretor& /*theDI*/,
5854                   Standard_Integer  theArgNb,
5855                   const char**      theArgVec)
5856 {
5857   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5858   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5859   if (aView.IsNull() || aViewer.IsNull())
5860   {
5861     Message::SendFail ("Error: no active viewer");
5862     return 1;
5863   }
5864
5865   Aspect_GridType     aType = aViewer->GridType();
5866   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5867   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5868   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5869   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5870   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5871   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5872   {
5873     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5874     anArg.LowerCase();
5875     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5876     {
5877       continue;
5878     }
5879     else if (anArgIter + 1 < theArgNb
5880           && anArg == "-type")
5881     {
5882       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5883       anArgNext.LowerCase();
5884       if (anArgNext == "r"
5885        || anArgNext == "rect"
5886        || anArgNext == "rectangular")
5887       {
5888         aType = Aspect_GT_Rectangular;
5889       }
5890       else if (anArgNext == "c"
5891             || anArgNext == "circ"
5892             || anArgNext == "circular")
5893       {
5894         aType = Aspect_GT_Circular;
5895       }
5896       else
5897       {
5898         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5899         return 1;
5900       }
5901     }
5902     else if (anArgIter + 1 < theArgNb
5903           && anArg == "-mode")
5904     {
5905       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5906       anArgNext.LowerCase();
5907       if (anArgNext == "l"
5908        || anArgNext == "line"
5909        || anArgNext == "lines")
5910       {
5911         aMode = Aspect_GDM_Lines;
5912       }
5913       else if (anArgNext == "p"
5914             || anArgNext == "point"
5915             || anArgNext == "points")
5916       {
5917         aMode = Aspect_GDM_Points;
5918       }
5919       else
5920       {
5921         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5922         return 1;
5923       }
5924     }
5925     else if (anArgIter + 2 < theArgNb
5926           && (anArg == "-origin"
5927            || anArg == "-orig"))
5928     {
5929       hasOrigin = true;
5930       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5931                               Draw::Atof (theArgVec[anArgIter + 2]));
5932       anArgIter += 2;
5933     }
5934     else if (anArgIter + 2 < theArgNb
5935           && anArg == "-step")
5936     {
5937       hasStep = true;
5938       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5939                             Draw::Atof (theArgVec[anArgIter + 2]));
5940       if (aNewStepXY.x() <= 0.0
5941        || aNewStepXY.y() <= 0.0)
5942       {
5943         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5944         return 1;
5945       }
5946       anArgIter += 2;
5947     }
5948     else if (anArgIter + 1 < theArgNb
5949           && (anArg == "-angle"
5950            || anArg == "-rotangle"
5951            || anArg == "-rotationangle"))
5952     {
5953       hasRotAngle = true;
5954       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5955     }
5956     else if (anArgIter + 1 < theArgNb
5957           && (anArg == "-zoffset"
5958            || anArg == "-dz"))
5959     {
5960       hasZOffset = true;
5961       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5962     }
5963     else if (anArgIter + 1 < theArgNb
5964           && anArg == "-radius")
5965     {
5966       hasSize = true;
5967       ++anArgIter;
5968       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
5969       if (aNewStepXY.x() <= 0.0)
5970       {
5971         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
5972         return 1;
5973       }
5974     }
5975     else if (anArgIter + 2 < theArgNb
5976           && anArg == "-size")
5977     {
5978       hasSize = true;
5979       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5980                             Draw::Atof (theArgVec[anArgIter + 2]));
5981       if (aNewStepXY.x() <= 0.0
5982        || aNewStepXY.y() <= 0.0)
5983       {
5984         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5985         return 1;
5986       }
5987       anArgIter += 2;
5988     }
5989     else if (anArg == "r"
5990           || anArg == "rect"
5991           || anArg == "rectangular")
5992     {
5993       aType = Aspect_GT_Rectangular;
5994     }
5995     else if (anArg == "c"
5996           || anArg == "circ"
5997           || anArg == "circular")
5998     {
5999       aType = Aspect_GT_Circular;
6000     }
6001     else if (anArg == "l"
6002           || anArg == "line"
6003           || anArg == "lines")
6004     {
6005       aMode = Aspect_GDM_Lines;
6006     }
6007     else if (anArg == "p"
6008           || anArg == "point"
6009           || anArg == "points")
6010     {
6011       aMode = Aspect_GDM_Points;
6012     }
6013     else if (anArgIter + 1 >= theArgNb
6014           && anArg == "off")
6015     {
6016       aViewer->DeactivateGrid();
6017       return 0;
6018     }
6019     else
6020     {
6021       Message::SendFail() << "Syntax error at '" << anArg << "'";
6022       return 1;
6023     }
6024   }
6025
6026   if (aType == Aspect_GT_Rectangular)
6027   {
6028     Graphic3d_Vec2d anOrigXY, aStepXY;
6029     Standard_Real aRotAngle = 0.0;
6030     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6031     if (hasOrigin)
6032     {
6033       anOrigXY = aNewOriginXY;
6034     }
6035     if (hasStep)
6036     {
6037       aStepXY = aNewStepXY;
6038     }
6039     if (hasRotAngle)
6040     {
6041       aRotAngle = aNewRotAngle;
6042     }
6043     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6044     if (hasSize || hasZOffset)
6045     {
6046       Graphic3d_Vec3d aSize;
6047       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6048       if (hasSize)
6049       {
6050         aSize.x() = aNewSizeXY.x();
6051         aSize.y() = aNewSizeXY.y();
6052       }
6053       if (hasZOffset)
6054       {
6055         aSize.z() = aNewZOffset;
6056       }
6057       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6058     }
6059   }
6060   else if (aType == Aspect_GT_Circular)
6061   {
6062     Graphic3d_Vec2d anOrigXY;
6063     Standard_Real aRadiusStep;
6064     Standard_Integer aDivisionNumber;
6065     Standard_Real aRotAngle = 0.0;
6066     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6067     if (hasOrigin)
6068     {
6069       anOrigXY = aNewOriginXY;
6070     }
6071     if (hasStep)
6072     {
6073       aRadiusStep     = aNewStepXY[0];
6074       aDivisionNumber = (int )aNewStepXY[1];
6075       if (aDivisionNumber < 1)
6076       {
6077         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
6078         return 1;
6079       }
6080     }
6081     if (hasRotAngle)
6082     {
6083       aRotAngle = aNewRotAngle;
6084     }
6085
6086     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6087     if (hasSize || hasZOffset)
6088     {
6089       Standard_Real aRadius = 0.0, aZOffset = 0.0;
6090       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
6091       if (hasSize)
6092       {
6093         aRadius = aNewSizeXY.x();
6094         if (aNewSizeXY.y() != 0.0)
6095         {
6096           Message::SendFail ("Syntax error: circular size should be specified as radius");
6097           return 1;
6098         }
6099       }
6100       if (hasZOffset)
6101       {
6102         aZOffset = aNewZOffset;
6103       }
6104       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
6105     }
6106   }
6107   aViewer->ActivateGrid (aType, aMode);
6108   return 0;
6109 }
6110
6111 //==============================================================================
6112 //function : VPriviledgedPlane
6113 //purpose  :
6114 //==============================================================================
6115
6116 static int VPriviledgedPlane (Draw_Interpretor& theDI,
6117                               Standard_Integer  theArgNb,
6118                               const char**      theArgVec)
6119 {
6120   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
6121   {
6122     Message::SendFail ("Error: wrong number of arguments! See usage:");
6123     theDI.PrintHelp (theArgVec[0]);
6124     return 1;
6125   }
6126
6127   // get the active viewer
6128   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
6129   if (aViewer.IsNull())
6130   {
6131     Message::SendFail ("Error: no active viewer");
6132     return 1;
6133   }
6134
6135   if (theArgNb == 1)
6136   {
6137     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
6138     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
6139     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
6140     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
6141     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
6142           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
6143           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
6144     return 0;
6145   }
6146
6147   Standard_Integer anArgIdx = 1;
6148   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
6149   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
6150   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
6151   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
6152   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
6153   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
6154
6155   gp_Ax3 aPriviledgedPlane;
6156   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
6157   gp_Dir aNorm (aNormX, aNormY, aNormZ);
6158   if (theArgNb > 7)
6159   {
6160     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
6161     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
6162     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
6163     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
6164     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
6165   }
6166   else
6167   {
6168     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
6169   }
6170
6171   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
6172
6173   return 0;
6174 }
6175
6176 //==============================================================================
6177 //function : VConvert
6178 //purpose  :
6179 //==============================================================================
6180
6181 static int VConvert (Draw_Interpretor& theDI,
6182                      Standard_Integer  theArgNb,
6183                      const char**      theArgVec)
6184 {
6185   // get the active view
6186   Handle(V3d_View) aView = ViewerTest::CurrentView();
6187   if (aView.IsNull())
6188   {
6189     Message::SendFail ("Error: no active viewer");
6190     return 1;
6191   }
6192
6193   enum { Model, Ray, View, Window, Grid } aMode = Model;
6194
6195   // access coordinate arguments
6196   TColStd_SequenceOfReal aCoord;
6197   Standard_Integer anArgIdx = 1;
6198   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
6199   {
6200     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6201     if (!anArg.IsRealValue())
6202     {
6203       break;
6204     }
6205     aCoord.Append (anArg.RealValue());
6206   }
6207
6208   // non-numeric argument too early
6209   if (aCoord.IsEmpty())
6210   {
6211     Message::SendFail ("Error: wrong number of arguments! See usage:");
6212     theDI.PrintHelp (theArgVec[0]);
6213     return 1;
6214   }
6215
6216   // collect all other arguments and options
6217   for (; anArgIdx < theArgNb; ++anArgIdx)
6218   {
6219     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6220     anArg.LowerCase();
6221     if      (anArg == "window") aMode = Window;
6222     else if (anArg == "view")   aMode = View;
6223     else if (anArg == "grid")   aMode = Grid;
6224     else if (anArg == "ray")    aMode = Ray;
6225     else
6226     {
6227       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
6228       theDI.PrintHelp (theArgVec[0]);
6229       return 1;
6230     }
6231   }
6232
6233   // complete input checks
6234   if ((aCoord.Length() == 1 && theArgNb > 3) ||
6235       (aCoord.Length() == 2 && theArgNb > 4) ||
6236       (aCoord.Length() == 3 && theArgNb > 5))
6237   {
6238     Message::SendFail ("Error: wrong number of arguments! See usage:");
6239     theDI.PrintHelp (theArgVec[0]);
6240     return 1;
6241   }
6242
6243   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
6244   Standard_Integer aXYp[2] = {0, 0};
6245
6246   // convert one-dimensional coordinate
6247   if (aCoord.Length() == 1)
6248   {
6249     switch (aMode)
6250     {
6251       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
6252       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
6253       default:
6254         Message::SendFail ("Error: wrong arguments! See usage:");
6255         theDI.PrintHelp (theArgVec[0]);
6256         return 1;
6257     }
6258   }
6259
6260   // convert 2D coordinates from projection or view reference space
6261   if (aCoord.Length() == 2)
6262   {
6263     switch (aMode)
6264     {
6265       case Model :
6266         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6267         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6268         return 0;
6269
6270       case View :
6271         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
6272         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
6273         return 0;
6274
6275       case Window :
6276         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
6277         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6278         return 0;
6279
6280       case Grid :
6281         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6282         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
6283         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6284         return 0;
6285
6286       case Ray :
6287         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
6288                                 (Standard_Integer) aCoord (2),
6289                                 aXYZ[0], aXYZ[1], aXYZ[2],
6290                                 aXYZ[3], aXYZ[4], aXYZ[5]);
6291         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6292         return 0;
6293
6294       default:
6295         Message::SendFail ("Error: wrong arguments! See usage:");
6296         theDI.PrintHelp (theArgVec[0]);
6297         return 1;
6298     }
6299   }
6300
6301   // convert 3D coordinates from view reference space
6302   else if (aCoord.Length() == 3)
6303   {
6304     switch (aMode)
6305     {
6306       case Window :
6307         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
6308         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6309         return 0;
6310
6311       case Grid :
6312         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
6313         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6314         return 0;
6315
6316       default:
6317         Message::SendFail ("Error: wrong arguments! See usage:");
6318         theDI.PrintHelp (theArgVec[0]);
6319         return 1;
6320     }
6321   }
6322
6323   return 0;
6324 }
6325
6326 //==============================================================================
6327 //function : VFps
6328 //purpose  :
6329 //==============================================================================
6330
6331 static int VFps (Draw_Interpretor& theDI,
6332                  Standard_Integer  theArgNb,
6333                  const char**      theArgVec)
6334 {
6335   // get the active view
6336   Handle(V3d_View) aView = ViewerTest::CurrentView();
6337   if (aView.IsNull())
6338   {
6339     Message::SendFail ("Error: no active viewer");
6340     return 1;
6341   }
6342
6343   Standard_Integer aFramesNb = -1;
6344   Standard_Real aDuration = -1.0;
6345   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6346   {
6347     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6348     anArg.LowerCase();
6349     if (aDuration < 0.0
6350      && anArgIter + 1 < theArgNb
6351      && (anArg == "-duration"
6352       || anArg == "-dur"
6353       || anArg == "-time"))
6354     {
6355       aDuration = Draw::Atof (theArgVec[++anArgIter]);
6356     }
6357     else if (aFramesNb < 0
6358           && anArg.IsIntegerValue())
6359     {
6360       aFramesNb = anArg.IntegerValue();
6361       if (aFramesNb <= 0)
6362       {
6363         Message::SendFail() << "Syntax error at '" << anArg << "'";
6364         return 1;
6365       }
6366     }
6367     else
6368     {
6369       Message::SendFail() << "Syntax error at '" << anArg << "'";
6370       return 1;
6371     }
6372   }
6373   if (aFramesNb < 0 && aDuration < 0.0)
6374   {
6375     aFramesNb = 100;
6376   }
6377
6378   // the time is meaningless for first call
6379   // due to async OpenGl rendering
6380   aView->Redraw();
6381
6382   // redraw view in loop to estimate average values
6383   OSD_Timer aTimer;
6384   aTimer.Start();
6385   Standard_Integer aFrameIter = 1;
6386   for (;; ++aFrameIter)
6387   {
6388     aView->Redraw();
6389     if ((aFramesNb > 0
6390       && aFrameIter >= aFramesNb)
6391      || (aDuration > 0.0
6392       && aTimer.ElapsedTime() >= aDuration))
6393     {
6394       break;
6395     }
6396   }
6397   aTimer.Stop();
6398   Standard_Real aCpu;
6399   const Standard_Real aTime = aTimer.ElapsedTime();
6400   aTimer.OSD_Chronometer::Show (aCpu);
6401
6402   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
6403   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
6404
6405   // return statistics
6406   theDI << "FPS: " << aFpsAver << "\n"
6407         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
6408
6409   // compute additional statistics in ray-tracing mode
6410   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
6411   if (aParams.Method == Graphic3d_RM_RAYTRACING)
6412   {
6413     Graphic3d_Vec2i aWinSize (0, 0);
6414     aView->Window()->Size (aWinSize.x(), aWinSize.y());
6415
6416     // 1 shadow ray and 1 secondary ray pew each bounce
6417     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
6418     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
6419   }
6420
6421   return 0;
6422 }
6423
6424 //! Auxiliary function for parsing glsl dump level argument.
6425 static Standard_Boolean parseGlslSourceFlag (Standard_CString               theArg,
6426                                              OpenGl_ShaderProgramDumpLevel& theGlslDumpLevel)
6427 {
6428   TCollection_AsciiString aTypeStr (theArg);
6429   aTypeStr.LowerCase();
6430   if (aTypeStr == "off"
6431    || aTypeStr == "0")
6432   {
6433     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6434   }
6435   else if (aTypeStr == "short")
6436   {
6437     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Short;
6438   }
6439   else if (aTypeStr == "full"
6440         || aTypeStr == "1")
6441   {
6442     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6443   }
6444   else
6445   {
6446     return Standard_False;
6447   }
6448   return Standard_True;
6449 }
6450
6451 //==============================================================================
6452 //function : VGlDebug
6453 //purpose  :
6454 //==============================================================================
6455
6456 static int VGlDebug (Draw_Interpretor& theDI,
6457                      Standard_Integer  theArgNb,
6458                      const char**      theArgVec)
6459 {
6460   Handle(OpenGl_GraphicDriver) aDriver;
6461   Handle(V3d_View) aView = ViewerTest::CurrentView();
6462   if (!aView.IsNull())
6463   {
6464     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aView->Viewer()->Driver());
6465   }
6466   OpenGl_Caps* aDefCaps = &ViewerTest_myDefaultCaps;
6467   OpenGl_Caps* aCaps    = !aDriver.IsNull() ? &aDriver->ChangeOptions() : NULL;
6468
6469   if (theArgNb < 2)
6470   {
6471     TCollection_AsciiString aDebActive, aSyncActive;
6472     if (aCaps == NULL)
6473     {
6474       aCaps = aDefCaps;
6475     }
6476     else
6477     {
6478       Standard_Boolean isActive = OpenGl_Context::CheckExtension ((const char* )::glGetString (GL_EXTENSIONS),
6479                                                                   "GL_ARB_debug_output");
6480       aDebActive = isActive ? " (active)" : " (inactive)";
6481       if (isActive)
6482       {
6483         // GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
6484         aSyncActive = ::glIsEnabled (0x8242) == GL_TRUE ? " (active)" : " (inactive)";
6485       }
6486     }
6487
6488     TCollection_AsciiString aGlslCodeDebugStatus = TCollection_AsciiString()
6489       + "glslSourceCode: "
6490       + (aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Off
6491          ? "Off"
6492          : aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short
6493           ? "Short"
6494           : "Full")
6495       + "\n";
6496     theDI << "debug:          " << (aCaps->contextDebug      ? "1" : "0") << aDebActive  << "\n"
6497           << "sync:           " << (aCaps->contextSyncDebug  ? "1" : "0") << aSyncActive << "\n"
6498           << "glslWarn:       " << (aCaps->glslWarnings      ? "1" : "0") << "\n"
6499           << aGlslCodeDebugStatus
6500           << "extraMsg:       " << (aCaps->suppressExtraMsg  ? "0" : "1") << "\n";
6501     return 0;
6502   }
6503
6504   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6505   {
6506     Standard_CString        anArg     = theArgVec[anArgIter];
6507     TCollection_AsciiString anArgCase (anArg);
6508     anArgCase.LowerCase();
6509     Standard_Boolean toEnableDebug = Standard_True;
6510     if (anArgCase == "-glsl"
6511      || anArgCase == "-glslwarn"
6512      || anArgCase == "-glslwarns"
6513      || anArgCase == "-glslwarnings")
6514     {
6515       Standard_Boolean toShowWarns = Standard_True;
6516       if (++anArgIter < theArgNb
6517       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toShowWarns))
6518       {
6519         --anArgIter;
6520       }
6521       aDefCaps->glslWarnings = toShowWarns;
6522       if (aCaps != NULL)
6523       {
6524         aCaps->glslWarnings = toShowWarns;
6525       }
6526     }
6527     else if (anArgCase == "-extra"
6528           || anArgCase == "-extramsg"
6529           || anArgCase == "-extramessages")
6530     {
6531       Standard_Boolean toShow = Standard_True;
6532       if (++anArgIter < theArgNb
6533       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toShow))
6534       {
6535         --anArgIter;
6536       }
6537       aDefCaps->suppressExtraMsg = !toShow;
6538       if (aCaps != NULL)
6539       {
6540         aCaps->suppressExtraMsg = !toShow;
6541       }
6542     }
6543     else if (anArgCase == "-noextra"
6544           || anArgCase == "-noextramsg"
6545           || anArgCase == "-noextramessages")
6546     {
6547       Standard_Boolean toSuppress = Standard_True;
6548       if (++anArgIter < theArgNb
6549       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toSuppress))
6550       {
6551         --anArgIter;
6552       }
6553       aDefCaps->suppressExtraMsg = toSuppress;
6554       if (aCaps != NULL)
6555       {
6556         aCaps->suppressExtraMsg = toSuppress;
6557       }
6558     }
6559     else if (anArgCase == "-sync")
6560     {
6561       Standard_Boolean toSync = Standard_True;
6562       if (++anArgIter < theArgNb
6563       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toSync))
6564       {
6565         --anArgIter;
6566       }
6567       aDefCaps->contextSyncDebug = toSync;
6568       if (toSync)
6569       {
6570         aDefCaps->contextDebug = Standard_True;
6571       }
6572     }
6573     else if (anArgCase == "-glslsourcecode"
6574           || anArgCase == "-glslcode")
6575     {
6576       OpenGl_ShaderProgramDumpLevel aGslsDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6577       if (++anArgIter < theArgNb
6578       && !parseGlslSourceFlag (theArgVec[anArgIter], aGslsDumpLevel))
6579       {
6580         --anArgIter;
6581       }
6582       aDefCaps->glslDumpLevel = aGslsDumpLevel;
6583       if (aCaps != NULL)
6584       {
6585         aCaps->glslDumpLevel = aGslsDumpLevel;
6586       }
6587     }
6588     else if (anArgCase == "-debug")
6589     {
6590       if (++anArgIter < theArgNb
6591       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnableDebug))
6592       {
6593         --anArgIter;
6594       }
6595       aDefCaps->contextDebug = toEnableDebug;
6596     }
6597     else if (ViewerTest::ParseOnOff (anArg, toEnableDebug)
6598           && (anArgIter + 1 == theArgNb))
6599     {
6600       // simple alias to turn on almost everything
6601       aDefCaps->contextDebug     = toEnableDebug;
6602       aDefCaps->contextSyncDebug = toEnableDebug;
6603       aDefCaps->glslWarnings     = toEnableDebug;
6604       if (!toEnableDebug)
6605       {
6606         aDefCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6607       }
6608       aDefCaps->suppressExtraMsg = !toEnableDebug;
6609       if (aCaps != NULL)
6610       {
6611         aCaps->contextDebug     = toEnableDebug;
6612         aCaps->contextSyncDebug = toEnableDebug;
6613         aCaps->glslWarnings     = toEnableDebug;
6614         if (!toEnableDebug)
6615         {
6616           aCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6617         }
6618         aCaps->suppressExtraMsg = !toEnableDebug;
6619       }
6620     }
6621     else
6622     {
6623       Message::SendFail() << "Syntax error at '" << anArg << "'";
6624       return 1;
6625     }
6626   }
6627
6628   return 0;
6629 }
6630
6631 //==============================================================================
6632 //function : VVbo
6633 //purpose  :
6634 //==============================================================================
6635
6636 static int VVbo (Draw_Interpretor& theDI,
6637                  Standard_Integer  theArgNb,
6638                  const char**      theArgVec)
6639 {
6640   const Standard_Boolean toSet    = (theArgNb > 1);
6641   const Standard_Boolean toUseVbo = toSet ? (Draw::Atoi (theArgVec[1]) == 0) : 1;
6642   if (toSet)
6643   {
6644     ViewerTest_myDefaultCaps.vboDisable = toUseVbo;
6645   }
6646
6647   // get the context
6648   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6649   if (aContextAIS.IsNull())
6650   {
6651     if (!toSet)
6652     {
6653       Message::SendFail ("Error: no active viewer");
6654     }
6655     return 1;
6656   }
6657   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContextAIS->CurrentViewer()->Driver());
6658   if (!aDriver.IsNull())
6659   {
6660     if (!toSet)
6661     {
6662       theDI << (aDriver->Options().vboDisable ? "0" : "1") << "\n";
6663     }
6664     else
6665     {
6666       aDriver->ChangeOptions().vboDisable = toUseVbo;
6667     }
6668   }
6669
6670   return 0;
6671 }
6672
6673 //==============================================================================
6674 //function : VCaps
6675 //purpose  :
6676 //==============================================================================
6677
6678 static int VCaps (Draw_Interpretor& theDI,
6679                   Standard_Integer  theArgNb,
6680                   const char**      theArgVec)
6681 {
6682   OpenGl_Caps* aCaps = &ViewerTest_myDefaultCaps;
6683   Handle(OpenGl_GraphicDriver)   aDriver;
6684   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
6685   if (!aContext.IsNull())
6686   {
6687     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
6688     aCaps   = &aDriver->ChangeOptions();
6689   }
6690
6691   if (theArgNb < 2)
6692   {
6693     theDI << "sRGB:    " << (aCaps->sRGBDisable       ? "0" : "1") << "\n";
6694     theDI << "VBO:     " << (aCaps->vboDisable        ? "0" : "1") << "\n";
6695     theDI << "Sprites: " << (aCaps->pntSpritesDisable ? "0" : "1") << "\n";
6696     theDI << "SoftMode:" << (aCaps->contextNoAccel    ? "1" : "0") << "\n";
6697     theDI << "FFP:     " << (aCaps->ffpEnable         ? "1" : "0") << "\n";
6698     theDI << "PolygonMode: " << (aCaps->usePolygonMode ? "1" : "0") << "\n";
6699     theDI << "VSync:   " <<  aCaps->swapInterval                   << "\n";
6700     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
6701     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
6702     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
6703     theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
6704     theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
6705     theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n";
6706     return 0;
6707   }
6708
6709   ViewerTest_AutoUpdater anUpdateTool (aContext, ViewerTest::CurrentView());
6710   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6711   {
6712     Standard_CString        anArg     = theArgVec[anArgIter];
6713     TCollection_AsciiString anArgCase (anArg);
6714     anArgCase.LowerCase();
6715     if (anUpdateTool.parseRedrawMode (anArg))
6716     {
6717       continue;
6718     }
6719     else if (anArgCase == "-vsync"
6720           || anArgCase == "-swapinterval")
6721     {
6722       Standard_Boolean toEnable = Standard_True;
6723       if (++anArgIter < theArgNb
6724       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6725       {
6726         --anArgIter;
6727       }
6728       aCaps->swapInterval = toEnable;
6729     }
6730     else if (anArgCase == "-ffp")
6731     {
6732       Standard_Boolean toEnable = Standard_True;
6733       if (++anArgIter < theArgNb
6734       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6735       {
6736         --anArgIter;
6737       }
6738       aCaps->ffpEnable = toEnable;
6739     }
6740     else if (anArgCase == "-polygonmode")
6741     {
6742       Standard_Boolean toEnable = Standard_True;
6743       if (++anArgIter < theArgNb
6744       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6745       {
6746         --anArgIter;
6747       }
6748       aCaps->usePolygonMode = toEnable;
6749     }
6750     else if (anArgCase == "-srgb")
6751     {
6752       Standard_Boolean toEnable = Standard_True;
6753       if (++anArgIter < theArgNb
6754       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6755       {
6756         --anArgIter;
6757       }
6758       aCaps->sRGBDisable = !toEnable;
6759     }
6760     else if (anArgCase == "-compressedtextures")
6761     {
6762       Standard_Boolean toEnable = Standard_True;
6763       if (++anArgIter < theArgNb
6764       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6765       {
6766         --anArgIter;
6767       }
6768       aCaps->compressedTexturesDisable = !toEnable;
6769     }
6770     else if (anArgCase == "-vbo")
6771     {
6772       Standard_Boolean toEnable = Standard_True;
6773       if (++anArgIter < theArgNb
6774       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6775       {
6776         --anArgIter;
6777       }
6778       aCaps->vboDisable = !toEnable;
6779     }
6780     else if (anArgCase == "-sprite"
6781           || anArgCase == "-sprites")
6782     {
6783       Standard_Boolean toEnable = Standard_True;
6784       if (++anArgIter < theArgNb
6785       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6786       {
6787         --anArgIter;
6788       }
6789       aCaps->pntSpritesDisable = !toEnable;
6790     }
6791     else if (anArgCase == "-softmode")
6792     {
6793       Standard_Boolean toEnable = Standard_True;
6794       if (++anArgIter < theArgNb
6795       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6796       {
6797         --anArgIter;
6798       }
6799       aCaps->contextNoAccel = toEnable;
6800     }
6801     else if (anArgCase == "-winbuffer"
6802           || anArgCase == "-windowbuffer"
6803           || anArgCase == "-usewinbuffer"
6804           || anArgCase == "-usewindowbuffer"
6805           || anArgCase == "-usesystembuffer")
6806     {
6807       Standard_Boolean toEnable = Standard_True;
6808       if (++anArgIter < theArgNb
6809       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6810       {
6811         --anArgIter;
6812       }
6813       aCaps->useSystemBuffer = toEnable;
6814     }
6815     else if (anArgCase == "-accel"
6816           || anArgCase == "-acceleration")
6817     {
6818       Standard_Boolean toEnable = Standard_True;
6819       if (++anArgIter < theArgNb
6820       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6821       {
6822         --anArgIter;
6823       }
6824       aCaps->contextNoAccel = !toEnable;
6825     }
6826     else if (anArgCase == "-compat"
6827           || anArgCase == "-compatprofile"
6828           || anArgCase == "-compatible"
6829           || anArgCase == "-compatibleprofile")
6830     {
6831       Standard_Boolean toEnable = Standard_True;
6832       if (++anArgIter < theArgNb
6833       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6834       {
6835         --anArgIter;
6836       }
6837       aCaps->contextCompatible = toEnable;
6838       if (!aCaps->contextCompatible)
6839       {
6840         aCaps->ffpEnable = Standard_False;
6841       }
6842     }
6843     else if (anArgCase == "-core"
6844           || anArgCase == "-coreprofile")
6845     {
6846       Standard_Boolean toEnable = Standard_True;
6847       if (++anArgIter < theArgNb
6848       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6849       {
6850         --anArgIter;
6851       }
6852       aCaps->contextCompatible = !toEnable;
6853       if (!aCaps->contextCompatible)
6854       {
6855         aCaps->ffpEnable = Standard_False;
6856       }
6857     }
6858     else if (anArgCase == "-stereo"
6859           || anArgCase == "-quadbuffer")
6860     {
6861       Standard_Boolean toEnable = Standard_True;
6862       if (++anArgIter < theArgNb
6863       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
6864       {
6865         --anArgIter;
6866       }
6867       aCaps->contextStereo = toEnable;
6868     }
6869     else if (anArgCase == "-noext"
6870           || anArgCase == "-noextensions"
6871           || anArgCase == "-noextension")
6872     {
6873       Standard_Boolean toDisable = Standard_True;
6874       if (++anArgIter < theArgNb
6875       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toDisable))
6876       {
6877         --anArgIter;
6878       }
6879       aCaps->contextNoExtensions = toDisable;
6880     }
6881     else if (anArgCase == "-maxversion"
6882           || anArgCase == "-upperversion"
6883           || anArgCase == "-limitversion")
6884     {
6885       Standard_Integer aVer[2] = { -2, -1 };
6886       for (Standard_Integer aValIter = 0; aValIter < 2; ++aValIter)
6887       {
6888         if (anArgIter + 1 < theArgNb)
6889         {
6890           const TCollection_AsciiString aStr (theArgVec[anArgIter + 1]);
6891           if (aStr.IsIntegerValue())
6892           {
6893             aVer[aValIter] = aStr.IntegerValue();
6894             ++anArgIter;
6895           }
6896         }
6897       }
6898       if (aVer[0] < -1
6899        || aVer[1] < -1)
6900       {
6901         Message::SendFail() << "Syntax error at '" << anArgCase << "'";
6902         return 1;
6903       }
6904       aCaps->contextMajorVersionUpper = aVer[0];
6905       aCaps->contextMinorVersionUpper = aVer[1];
6906     }
6907     else
6908     {
6909       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
6910       return 1;
6911     }
6912   }
6913   if (aCaps != &ViewerTest_myDefaultCaps)
6914   {
6915     ViewerTest_myDefaultCaps = *aCaps;
6916   }
6917   return 0;
6918 }
6919
6920 //==============================================================================
6921 //function : VMemGpu
6922 //purpose  :
6923 //==============================================================================
6924
6925 static int VMemGpu (Draw_Interpretor& theDI,
6926                     Standard_Integer  theArgNb,
6927                     const char**      theArgVec)
6928 {
6929   // get the context
6930   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6931   if (aContextAIS.IsNull())
6932   {
6933     Message::SendFail ("Error: no active viewer");
6934     return 1;
6935   }
6936
6937   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
6938   if (aDriver.IsNull())
6939   {
6940     Message::SendFail ("Error: graphic driver not available");
6941     return 1;
6942   }
6943
6944   Standard_Size aFreeBytes = 0;
6945   TCollection_AsciiString anInfo;
6946   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
6947   {
6948     Message::SendFail ("Error: information not available");
6949     return 1;
6950   }
6951
6952   if (theArgNb > 1 && *theArgVec[1] == 'f')
6953   {
6954     theDI << Standard_Real (aFreeBytes);
6955   }
6956   else
6957   {
6958     theDI << anInfo;
6959   }
6960
6961   return 0;
6962 }
6963
6964 // ==============================================================================
6965 // function : VReadPixel
6966 // purpose  :
6967 // ==============================================================================
6968 static int VReadPixel (Draw_Interpretor& theDI,
6969                        Standard_Integer  theArgNb,
6970                        const char**      theArgVec)
6971 {
6972   // get the active view
6973   Handle(V3d_View) aView = ViewerTest::CurrentView();
6974   if (aView.IsNull())
6975   {
6976     Message::SendFail ("Error: no active viewer");
6977     return 1;
6978   }
6979   else if (theArgNb < 3)
6980   {
6981     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
6982                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
6983     return 1;
6984   }
6985
6986   Image_Format         aFormat     = Image_Format_RGBA;
6987   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
6988
6989   Standard_Integer aWidth, aHeight;
6990   aView->Window()->Size (aWidth, aHeight);
6991   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
6992   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
6993   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
6994   {
6995     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
6996     return 1;
6997   }
6998
6999   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
7000   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
7001   {
7002     TCollection_AsciiString aParam (theArgVec[anIter]);
7003     aParam.LowerCase();
7004     if (aParam == "-rgb"
7005      || aParam == "rgb"
7006      || aParam == "-srgb"
7007      || aParam == "srgb")
7008     {
7009       aFormat     = Image_Format_RGB;
7010       aBufferType = Graphic3d_BT_RGB;
7011       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
7012     }
7013     else if (aParam == "-hls"
7014           || aParam == "hls")
7015     {
7016       aFormat     = Image_Format_RGB;
7017       aBufferType = Graphic3d_BT_RGB;
7018       toShowHls   = Standard_True;
7019     }
7020     else if (aParam == "-rgbf"
7021           || aParam == "rgbf")
7022     {
7023       aFormat     = Image_Format_RGBF;
7024       aBufferType = Graphic3d_BT_RGB;
7025     }
7026     else if (aParam == "-rgba"
7027           || aParam == "rgba"
7028           || aParam == "-srgba"
7029           || aParam == "srgba")
7030     {
7031       aFormat     = Image_Format_RGBA;
7032       aBufferType = Graphic3d_BT_RGBA;
7033       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
7034     }
7035     else if (aParam == "-rgbaf"
7036           || aParam == "rgbaf")
7037     {
7038       aFormat     = Image_Format_RGBAF;
7039       aBufferType = Graphic3d_BT_RGBA;
7040     }
7041     else if (aParam == "-depth"
7042           || aParam == "depth")
7043     {
7044       aFormat     = Image_Format_GrayF;
7045       aBufferType = Graphic3d_BT_Depth;
7046     }
7047     else if (aParam == "-name"
7048           || aParam == "name")
7049     {
7050       toShowName = Standard_True;
7051     }
7052     else if (aParam == "-hex"
7053           || aParam == "hex")
7054     {
7055       toShowHex = Standard_True;
7056     }
7057     else
7058     {
7059       Message::SendFail() << "Syntax error at '" << aParam << "'";
7060       return 1;
7061     }
7062   }
7063
7064   Image_PixMap anImage;
7065   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
7066   {
7067     Message::SendFail ("Error: image allocation failed");
7068     return 1;
7069   }
7070   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
7071   {
7072     Message::SendFail ("Error: image dump failed");
7073     return 1;
7074   }
7075
7076   // redirect possible warning messages that could have been added by ToPixMap
7077   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
7078   // contaminate result of the command
7079   Standard_CString aWarnLog = theDI.Result();
7080   if (aWarnLog != NULL && aWarnLog[0] != '\0')
7081   {
7082     std::cout << aWarnLog << std::endl;
7083   }
7084   theDI.Reset();
7085
7086   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
7087   if (toShowName)
7088   {
7089     if (aBufferType == Graphic3d_BT_RGBA)
7090     {
7091       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
7092     }
7093     else
7094     {
7095       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
7096     }
7097   }
7098   else if (toShowHex)
7099   {
7100     if (aBufferType == Graphic3d_BT_RGBA)
7101     {
7102       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
7103     }
7104     else
7105     {
7106       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
7107     }
7108   }
7109   else
7110   {
7111     switch (aBufferType)
7112     {
7113       default:
7114       case Graphic3d_BT_RGB:
7115       {
7116         if (toShowHls)
7117         {
7118           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
7119         }
7120         else if (toShow_sRGB)
7121         {
7122           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
7123           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
7124         }
7125         else
7126         {
7127           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
7128         }
7129         break;
7130       }
7131       case Graphic3d_BT_RGBA:
7132       {
7133         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
7134         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
7135         break;
7136       }
7137       case Graphic3d_BT_Depth:
7138       {
7139         theDI << aColor.GetRGB().Red();
7140         break;
7141       }
7142     }
7143   }
7144
7145   return 0;
7146 }
7147
7148 //! Auxiliary presentation for an image plane.
7149 class ViewerTest_ImagePrs : public AIS_InteractiveObject
7150 {
7151 public:
7152   //! Main constructor.
7153   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
7154                        const Standard_Real theWidth,
7155                        const Standard_Real theHeight,
7156                        const TCollection_AsciiString& theLabel)
7157   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
7158   {
7159     SetDisplayMode (0);
7160     SetHilightMode (1);
7161     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
7162     {
7163       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
7164       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
7165       Graphic3d_MaterialAspect aMat;
7166       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
7167       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
7168       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
7169       aMat.SetSpecularColor (Quantity_NOC_BLACK);
7170       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
7171       aFillAspect->SetFrontMaterial (aMat);
7172       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
7173       aFillAspect->SetTextureMapOn();
7174     }
7175     {
7176       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
7177       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
7178       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
7179       myDrawer->SetTextAspect (aTextAspect);
7180     }
7181     {
7182       const gp_Dir aNorm (0.0, 0.0, 1.0);
7183       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
7184       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
7185       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
7186       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
7187       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
7188       myTris->AddEdge (1);
7189       myTris->AddEdge (2);
7190       myTris->AddEdge (3);
7191       myTris->AddEdge (3);
7192       myTris->AddEdge (2);
7193       myTris->AddEdge (4);
7194
7195       myRect = new Graphic3d_ArrayOfPolylines (4);
7196       myRect->AddVertex (myTris->Vertice (1));
7197       myRect->AddVertex (myTris->Vertice (3));
7198       myRect->AddVertex (myTris->Vertice (4));
7199       myRect->AddVertex (myTris->Vertice (2));
7200     }
7201   }
7202
7203   //! Returns TRUE for accepted display modes.
7204   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
7205
7206   //! Compute presentation.
7207   virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& , const Handle(Prs3d_Presentation)& thePrs, const Standard_Integer theMode) Standard_OVERRIDE
7208   {
7209     switch (theMode)
7210     {
7211       case 0:
7212       {
7213         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7214         aGroup->AddPrimitiveArray (myTris);
7215         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
7216         aGroup->AddPrimitiveArray (myRect);
7217         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7218         return;
7219       }
7220       case 1:
7221       {
7222         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
7223         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7224         aGroup->AddPrimitiveArray (myRect);
7225         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7226         return;
7227       }
7228     }
7229   }
7230
7231   //! Compute selection.
7232   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
7233   {
7234     if (theMode == 0)
7235     {
7236       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
7237       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
7238       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
7239       theSel->Add (aSensitive);
7240     }
7241   }
7242
7243 private:
7244   Handle(Graphic3d_ArrayOfTriangles) myTris;
7245   Handle(Graphic3d_ArrayOfPolylines) myRect;
7246   TCollection_AsciiString myLabel;
7247   Standard_Real myWidth;
7248   Standard_Real myHeight;
7249 };
7250
7251 //==============================================================================
7252 //function : VDiffImage
7253 //purpose  : The draw-command compares two images.
7254 //==============================================================================
7255
7256 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
7257 {
7258   if (theArgNb < 3)
7259   {
7260     Message::SendFail ("Syntax error: not enough arguments");
7261     return 1;
7262   }
7263
7264   Standard_Integer anArgIter = 1;
7265   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
7266   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
7267   TCollection_AsciiString aDiffImagePath;
7268   Standard_Real    aTolColor        = -1.0;
7269   Standard_Integer toBlackWhite     = -1;
7270   Standard_Integer isBorderFilterOn = -1;
7271   Standard_Boolean isOldSyntax = Standard_False;
7272   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
7273   for (; anArgIter < theArgNb; ++anArgIter)
7274   {
7275     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7276     anArg.LowerCase();
7277     if (anArgIter + 1 < theArgNb
7278      && (anArg == "-toleranceofcolor"
7279       || anArg == "-tolerancecolor"
7280       || anArg == "-tolerance"
7281       || anArg == "-toler"))
7282     {
7283       aTolColor = Atof (theArgVec[++anArgIter]);
7284       if (aTolColor < 0.0 || aTolColor > 1.0)
7285       {
7286         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7287         return 1;
7288       }
7289     }
7290     else if (anArg == "-blackwhite")
7291     {
7292       Standard_Boolean toEnable = Standard_True;
7293       if (anArgIter + 1 < theArgNb
7294        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7295       {
7296         ++anArgIter;
7297       }
7298       toBlackWhite = toEnable ? 1 : 0;
7299     }
7300     else if (anArg == "-borderfilter")
7301     {
7302       Standard_Boolean toEnable = Standard_True;
7303       if (anArgIter + 1 < theArgNb
7304        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7305       {
7306         ++anArgIter;
7307       }
7308       isBorderFilterOn = toEnable ? 1 : 0;
7309     }
7310     else if (anArg == "-exitonclose")
7311     {
7312       ViewerTest_EventManager::ToExitOnCloseView() = true;
7313       if (anArgIter + 1 < theArgNb
7314        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
7315       {
7316         ++anArgIter;
7317       }
7318     }
7319     else if (anArg == "-closeonescape"
7320           || anArg == "-closeonesc")
7321     {
7322       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
7323       if (anArgIter + 1 < theArgNb
7324        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
7325       {
7326         ++anArgIter;
7327       }
7328     }
7329     else if (anArgIter + 3 < theArgNb
7330           && anArg == "-display")
7331     {
7332       aViewName   = theArgVec[++anArgIter];
7333       aPrsNameRef = theArgVec[++anArgIter];
7334       aPrsNameNew = theArgVec[++anArgIter];
7335       if (anArgIter + 1 < theArgNb
7336       && *theArgVec[anArgIter + 1] != '-')
7337       {
7338         aPrsNameDiff = theArgVec[++anArgIter];
7339       }
7340     }
7341     else if (aTolColor < 0.0
7342           && anArg.IsRealValue())
7343     {
7344       isOldSyntax = Standard_True;
7345       aTolColor = anArg.RealValue();
7346       if (aTolColor < 0.0 || aTolColor > 1.0)
7347       {
7348         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7349         return 1;
7350       }
7351     }
7352     else if (isOldSyntax
7353           && toBlackWhite == -1
7354           && (anArg == "0" || anArg == "1"))
7355     {
7356       toBlackWhite = anArg == "1" ? 1 : 0;
7357     }
7358     else if (isOldSyntax
7359           && isBorderFilterOn == -1
7360           && (anArg == "0" || anArg == "1"))
7361     {
7362       isBorderFilterOn = anArg == "1" ? 1 : 0;
7363     }
7364     else if (aDiffImagePath.IsEmpty())
7365     {
7366       aDiffImagePath = theArgVec[anArgIter];
7367     }
7368     else
7369     {
7370       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7371       return 1;
7372     }
7373   }
7374
7375   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
7376   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
7377   if (!anImgRef->Load (anImgPathRef))
7378   {
7379     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
7380     return 1;
7381   }
7382   if (!anImgNew->Load (anImgPathNew))
7383   {
7384     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
7385     return 1;
7386   }
7387
7388   // compare the images
7389   Image_Diff aComparer;
7390   Standard_Integer aDiffColorsNb = -1;
7391   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
7392   {
7393     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
7394     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
7395     aDiffColorsNb = aComparer.Compare();
7396     theDI << aDiffColorsNb << "\n";
7397   }
7398
7399   // save image of difference
7400   Handle(Image_AlienPixMap) aDiff;
7401   if (aDiffColorsNb > 0
7402   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
7403   {
7404     aDiff = new Image_AlienPixMap();
7405     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
7406     {
7407       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
7408       return 1;
7409     }
7410     aComparer.SaveDiffImage (*aDiff);
7411     if (!aDiffImagePath.IsEmpty()
7412      && !aDiff->Save (aDiffImagePath))
7413     {
7414       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
7415       return 1;
7416     }
7417   }
7418
7419   if (aViewName.IsEmpty())
7420   {
7421     return 0;
7422   }
7423
7424   ViewerTest_Names aViewNames (aViewName);
7425   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
7426   {
7427     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
7428     theDI.Eval (aCommand.ToCString());
7429   }
7430
7431   Standard_Integer aPxLeft = 0;
7432   Standard_Integer aPxTop  = 0;
7433   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
7434   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
7435                               ? int(anImgRef->SizeY() * 2)
7436                               : int(anImgRef->SizeY());
7437   TCollection_AsciiString aDisplayName;
7438   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
7439                                                             aViewName, aDisplayName);
7440
7441   Standard_Real aRatio = anImgRef->Ratio();
7442   Standard_Real aSizeX = 1.0;
7443   Standard_Real aSizeY = aSizeX / aRatio;
7444   {
7445     OSD_Path aPath (anImgPathRef);
7446     TCollection_AsciiString aLabelRef;
7447     if (!aPath.Name().IsEmpty())
7448     {
7449       aLabelRef = aPath.Name() + aPath.Extension();
7450     }
7451     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
7452
7453     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
7454     gp_Trsf aTrsfRef;
7455     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
7456     anImgRefPrs->SetLocalTransformation (aTrsfRef);
7457     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
7458   }
7459   {
7460     OSD_Path aPath (anImgPathNew);
7461     TCollection_AsciiString aLabelNew;
7462     if (!aPath.Name().IsEmpty())
7463     {
7464       aLabelNew = aPath.Name() + aPath.Extension();
7465     }
7466     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
7467
7468     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
7469     gp_Trsf aTrsfRef;
7470     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
7471     anImgNewPrs->SetLocalTransformation (aTrsfRef);
7472     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
7473   }
7474   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
7475   if (!aDiff.IsNull())
7476   {
7477     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
7478     gp_Trsf aTrsfDiff;
7479     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
7480     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
7481   }
7482   if (!aPrsNameDiff.IsEmpty())
7483   {
7484     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
7485   }
7486   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
7487   ViewerTest::CurrentView()->FitAll();
7488   return 0;
7489 }
7490
7491 //=======================================================================
7492 //function : VSelect
7493 //purpose  : Emulates different types of selection by mouse:
7494 //           1) single click selection
7495 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
7496 //           3) selection with polygon having corners at
7497 //           pixel positions (x1,y1),...,(xn,yn)
7498 //           4) any of these selections with shift button pressed
7499 //=======================================================================
7500 static Standard_Integer VSelect (Draw_Interpretor& ,
7501                                  Standard_Integer theNbArgs,
7502                                  const char** theArgVec)
7503 {
7504   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
7505   if (aCtx.IsNull())
7506   {
7507     Message::SendFail ("Error: no active viewer");
7508     return 1;
7509   }
7510
7511   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
7512   bool isShiftSelection = false, toAllowOverlap = false;
7513   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7514   {
7515     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7516     anArg.LowerCase();
7517     if (anArg == "-allowoverlap")
7518     {
7519       toAllowOverlap = true;
7520       if (anArgIter + 1 < theNbArgs
7521        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
7522       {
7523         ++anArgIter;
7524       }
7525     }
7526     else if (anArgIter + 1 < theNbArgs
7527           && anArg.IsIntegerValue()
7528           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
7529     {
7530       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
7531       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
7532     }
7533     else if (anArgIter + 1 == theNbArgs
7534           && anArg.IsIntegerValue())
7535     {
7536       isShiftSelection = anArg.IntegerValue() == 1;
7537     }
7538     else
7539     {
7540       Message::SendFail() << "Syntax error at '" << anArg << "'";
7541       return 1;
7542     }
7543   }
7544
7545   if (toAllowOverlap)
7546   {
7547     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
7548   }
7549
7550   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
7551   if (aPnts.IsEmpty())
7552   {
7553     if (isShiftSelection)
7554     {
7555       aCtx->ShiftSelect (false);
7556     }
7557     else
7558     {
7559       aCtx->Select (false);
7560     }
7561     aCtx->CurrentViewer()->Invalidate();
7562   }
7563   else if (aPnts.Length() == 2)
7564   {
7565     if (toAllowOverlap
7566      && aPnts.First().y() < aPnts.Last().y())
7567     {
7568       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7569     }
7570     else if (!toAllowOverlap
7571            && aPnts.First().y() > aPnts.Last().y())
7572     {
7573       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7574     }
7575     aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection);
7576   }
7577   else
7578   {
7579     aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection);
7580   }
7581   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
7582   return 0;
7583 }
7584
7585 //=======================================================================
7586 //function : VMoveTo
7587 //purpose  : Emulates cursor movement to defined pixel position
7588 //=======================================================================
7589 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
7590                                 Standard_Integer theNbArgs,
7591                                 const char**     theArgVec)
7592 {
7593   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
7594   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
7595   if (aContext.IsNull())
7596   {
7597     Message::SendFail ("Error: no active viewer");
7598     return 1;
7599   }
7600
7601   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
7602   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7603   {
7604     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
7605     anArgStr.LowerCase();
7606     if (anArgStr == "-reset"
7607      || anArgStr == "-clear")
7608     {
7609       if (anArgIter + 1 < theNbArgs)
7610       {
7611         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
7612         return 1;
7613       }
7614
7615       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->Grid()->IsActive()
7616                                        && aContext->CurrentViewer()->GridEcho();
7617       if (toEchoGrid)
7618       {
7619         aContext->CurrentViewer()->HideGridEcho (aView);
7620       }
7621       if (aContext->ClearDetected() || toEchoGrid)
7622       {
7623         aContext->CurrentViewer()->RedrawImmediate();
7624       }
7625       return 0;
7626     }
7627     else if (aMousePos.x() == IntegerLast()
7628           && anArgStr.IsIntegerValue())
7629     {
7630       aMousePos.x() = anArgStr.IntegerValue();
7631     }
7632     else if (aMousePos.y() == IntegerLast()
7633           && anArgStr.IsIntegerValue())
7634     {
7635       aMousePos.y() = anArgStr.IntegerValue();
7636     }
7637     else
7638     {
7639       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7640       return 1;
7641     }
7642   }
7643
7644   if (aMousePos.x() == IntegerLast()
7645    || aMousePos.y() == IntegerLast())
7646   {
7647     Message::SendFail ("Syntax error: wrong number of arguments");
7648     return 1;
7649   }
7650
7651   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
7652   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
7653   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
7654
7655   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
7656   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
7657   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
7658   {
7659     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
7660     {
7661       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
7662       break;
7663     }
7664   }
7665   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
7666   return 0;
7667 }
7668
7669 namespace
7670 {
7671   //! Global map storing all animations registered in ViewerTest.
7672   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
7673
7674   //! The animation calling the Draw Harness command.
7675   class ViewerTest_AnimationProc : public AIS_Animation
7676   {
7677   public:
7678
7679     //! Main constructor.
7680     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
7681                               Draw_Interpretor* theDI,
7682                               const TCollection_AsciiString& theCommand)
7683     : AIS_Animation (theAnimationName),
7684       myDrawInter(theDI),
7685       myCommand  (theCommand)
7686     {
7687       //
7688     }
7689
7690   protected:
7691
7692     //! Evaluate the command.
7693     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
7694     {
7695       TCollection_AsciiString aCmd = myCommand;
7696       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
7697       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
7698       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
7699       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
7700       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
7701       myDrawInter->Eval (aCmd.ToCString());
7702     }
7703
7704     //! Find the keyword in the command and replace it with value.
7705     //! @return the position of the keyword to pass value
7706     void replace (TCollection_AsciiString&       theCmd,
7707                   const TCollection_AsciiString& theKey,
7708                   const TCollection_AsciiString& theVal)
7709     {
7710       TCollection_AsciiString aCmd (theCmd);
7711       aCmd.LowerCase();
7712       const Standard_Integer aPos = aCmd.Search (theKey);
7713       if (aPos == -1)
7714       {
7715         return;
7716       }
7717
7718       TCollection_AsciiString aPart1, aPart2;
7719       Standard_Integer aPart1To = aPos - 1;
7720       if (aPart1To >= 1
7721        && aPart1To <= theCmd.Length())
7722       {
7723         aPart1 = theCmd.SubString (1, aPart1To);
7724       }
7725
7726       Standard_Integer aPart2From = aPos + theKey.Length();
7727       if (aPart2From >= 1
7728        && aPart2From <= theCmd.Length())
7729       {
7730         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
7731       }
7732
7733       theCmd = aPart1 + theVal + aPart2;
7734     }
7735
7736   protected:
7737
7738     Draw_Interpretor*       myDrawInter;
7739     TCollection_AsciiString myCommand;
7740
7741   };
7742
7743   //! Replace the animation with the new one.
7744   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
7745                                 Handle(AIS_Animation)&       theAnimation,
7746                                 const Handle(AIS_Animation)& theAnimationNew)
7747   {
7748     theAnimationNew->CopyFrom (theAnimation);
7749     if (!theParentAnimation.IsNull())
7750     {
7751       theParentAnimation->Replace (theAnimation, theAnimationNew);
7752     }
7753     else
7754     {
7755       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
7756       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
7757     }
7758     theAnimation = theAnimationNew;
7759   }
7760
7761   //! Parse the point.
7762   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
7763   {
7764     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
7765     if (!anXYZ[0].IsRealValue()
7766      || !anXYZ[1].IsRealValue()
7767      || !anXYZ[2].IsRealValue())
7768     {
7769       return Standard_False;
7770     }
7771
7772     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
7773     return Standard_True;
7774   }
7775
7776   //! Parse the quaternion.
7777   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
7778   {
7779     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
7780     if (!anXYZW[0].IsRealValue()
7781      || !anXYZW[1].IsRealValue()
7782      || !anXYZW[2].IsRealValue()
7783      || !anXYZW[3].IsRealValue())
7784     {
7785       return Standard_False;
7786     }
7787
7788     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
7789     return Standard_True;
7790   }
7791
7792   //! Auxiliary class for flipping image upside-down.
7793   class ImageFlipper
7794   {
7795   public:
7796
7797     //! Empty constructor.
7798     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
7799
7800     //! Perform flipping.
7801     Standard_Boolean FlipY (Image_PixMap& theImage)
7802     {
7803       if (theImage.IsEmpty()
7804        || theImage.SizeX() == 0
7805        || theImage.SizeY() == 0)
7806       {
7807         return Standard_False;
7808       }
7809
7810       const Standard_Size aRowSize = theImage.SizeRowBytes();
7811       if (myTmp.Size() < aRowSize
7812       && !myTmp.Allocate (aRowSize))
7813       {
7814         return Standard_False;
7815       }
7816
7817       // for odd height middle row should be left as is
7818       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
7819       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
7820       {
7821         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
7822         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
7823         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
7824         memcpy (aTop,               aBot,         aRowSize);
7825         memcpy (aBot,               myTmp.Data(), aRowSize);
7826       }
7827       return Standard_True;
7828     }
7829
7830   private:
7831     NCollection_Buffer myTmp;
7832   };
7833
7834 }
7835
7836 //=================================================================================================
7837 //function : VViewParams
7838 //purpose  : Gets or sets AIS View characteristics
7839 //=================================================================================================
7840 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
7841 {
7842   Handle(V3d_View) aView = ViewerTest::CurrentView();
7843   if (aView.IsNull())
7844   {
7845     Message::SendFail ("Error: no active viewer");
7846     return 1;
7847   }
7848
7849   Standard_Boolean toSetProj     = Standard_False;
7850   Standard_Boolean toSetUp       = Standard_False;
7851   Standard_Boolean toSetAt       = Standard_False;
7852   Standard_Boolean toSetEye      = Standard_False;
7853   Standard_Boolean toSetScale    = Standard_False;
7854   Standard_Boolean toSetSize     = Standard_False;
7855   Standard_Boolean toSetCenter2d = Standard_False;
7856   Standard_Real    aViewScale = aView->Scale();
7857   Standard_Real    aViewSize  = 1.0;
7858   Graphic3d_Vec2i  aCenter2d;
7859   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
7860   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
7861   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
7862   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
7863   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
7864   if (theArgsNb == 1)
7865   {
7866     // print all of the available view parameters
7867     char aText[4096];
7868     Sprintf (aText,
7869              "Scale: %g\n"
7870              "Proj:  %12g %12g %12g\n"
7871              "Up:    %12g %12g %12g\n"
7872              "At:    %12g %12g %12g\n"
7873              "Eye:   %12g %12g %12g\n",
7874               aViewScale,
7875               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7876               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7877               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
7878               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z());
7879     theDi << aText;
7880     return 0;
7881   }
7882
7883   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
7884   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
7885   {
7886     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7887     anArg.LowerCase();
7888     if (anUpdateTool.parseRedrawMode (anArg))
7889     {
7890       continue;
7891     }
7892     else if (anArg == "-cmd"
7893           || anArg == "-command"
7894           || anArg == "-args")
7895     {
7896       char aText[4096];
7897       Sprintf (aText,
7898                "-scale %g "
7899                "-proj %g %g %g "
7900                "-up %g %g %g "
7901                "-at %g %g %g\n",
7902                 aViewScale,
7903                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7904                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7905                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
7906       theDi << aText;
7907     }
7908     else if (anArg == "-scale"
7909           || anArg == "-size")
7910     {
7911       if (anArgIter + 1 < theArgsNb
7912        && *theArgVec[anArgIter + 1] != '-')
7913       {
7914         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7915         if (aValueArg.IsRealValue())
7916         {
7917           ++anArgIter;
7918           if (anArg == "-scale")
7919           {
7920             toSetScale = Standard_True;
7921             aViewScale = aValueArg.RealValue();
7922           }
7923           else if (anArg == "-size")
7924           {
7925             toSetSize = Standard_True;
7926             aViewSize = aValueArg.RealValue();
7927           }
7928           continue;
7929         }
7930       }
7931       if (anArg == "-scale")
7932       {
7933         theDi << "Scale: " << aView->Scale() << "\n";
7934       }
7935       else if (anArg == "-size")
7936       {
7937         Graphic3d_Vec2d aSizeXY;
7938         aView->Size (aSizeXY.x(), aSizeXY.y());
7939         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
7940       }
7941     }
7942     else if (anArg == "-eye"
7943           || anArg == "-at"
7944           || anArg == "-up"
7945           || anArg == "-proj")
7946     {
7947       if (anArgIter + 3 < theArgsNb)
7948       {
7949         gp_XYZ anXYZ;
7950         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
7951         {
7952           anArgIter += 3;
7953           if (anArg == "-eye")
7954           {
7955             toSetEye = Standard_True;
7956             aViewEye = anXYZ;
7957           }
7958           else if (anArg == "-at")
7959           {
7960             toSetAt = Standard_True;
7961             aViewAt = anXYZ;
7962           }
7963           else if (anArg == "-up")
7964           {
7965             toSetUp = Standard_True;
7966             aViewUp = anXYZ;
7967           }
7968           else if (anArg == "-proj")
7969           {
7970             toSetProj = Standard_True;
7971             aViewProj = anXYZ;
7972           }
7973           continue;
7974         }
7975       }
7976
7977       if (anArg == "-eye")
7978       {
7979         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
7980       }
7981       else if (anArg == "-at")
7982       {
7983         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
7984       }
7985       else if (anArg == "-up")
7986       {
7987         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
7988       }
7989       else if (anArg == "-proj")
7990       {
7991         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
7992       }
7993     }
7994     else if (anArg == "-center")
7995     {
7996       if (anArgIter + 2 < theArgsNb)
7997       {
7998         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
7999         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
8000         if (anX.IsIntegerValue()
8001          && anY.IsIntegerValue())
8002         {
8003           toSetCenter2d = Standard_True;
8004           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
8005         }
8006       }
8007     }
8008     else
8009     {
8010       Message::SendFail() << "Syntax error at '" << anArg << "'";
8011       return 1;
8012     }
8013   }
8014
8015   // change view parameters in proper order
8016   if (toSetScale)
8017   {
8018     aView->SetScale (aViewScale);
8019   }
8020   if (toSetSize)
8021   {
8022     aView->SetSize (aViewSize);
8023   }
8024   if (toSetEye)
8025   {
8026     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
8027   }
8028   if (toSetAt)
8029   {
8030     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
8031   }
8032   if (toSetProj)
8033   {
8034     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
8035   }
8036   if (toSetUp)
8037   {
8038     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
8039   }
8040   if (toSetCenter2d)
8041   {
8042     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
8043   }
8044
8045   return 0;
8046 }
8047
8048 //==============================================================================
8049 //function : V2DMode
8050 //purpose  :
8051 //==============================================================================
8052 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
8053 {
8054   bool is2dMode = true;
8055   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
8056   if (aV3dView.IsNull())
8057   {
8058     Message::SendFail ("Error: no active viewer");
8059     return 1;
8060   }
8061   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
8062   {
8063     const TCollection_AsciiString anArg = theArgVec[anArgIt];
8064     TCollection_AsciiString anArgCase = anArg;
8065     anArgCase.LowerCase();
8066     if (anArgIt + 1 < theArgsNb
8067      && anArgCase == "-name")
8068     {
8069       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
8070       TCollection_AsciiString aViewName = aViewNames.GetViewName();
8071       if (!ViewerTest_myViews.IsBound1 (aViewName))
8072       {
8073         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
8074         return 1;
8075       }
8076       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
8077     }
8078     else if (anArgCase == "-mode")
8079     {
8080       if (anArgIt + 1 < theArgsNb
8081        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
8082       {
8083         ++anArgIt;
8084       }
8085     }
8086     else if (ViewerTest::ParseOnOff (theArgVec[anArgIt], is2dMode))
8087     {
8088       //
8089     }
8090     else
8091     {
8092       Message::SendFail() << "Syntax error: unknown argument " << anArg;
8093       return 1;
8094     }
8095   }
8096
8097   aV3dView->SetView2DMode (is2dMode);
8098   return 0;
8099 }
8100
8101 //==============================================================================
8102 //function : VAnimation
8103 //purpose  :
8104 //==============================================================================
8105 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
8106                                     Standard_Integer  theArgNb,
8107                                     const char**      theArgVec)
8108 {
8109   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
8110   if (theArgNb < 2)
8111   {
8112     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
8113          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
8114     {
8115       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
8116     }
8117     return 0;
8118   }
8119   if (aCtx.IsNull())
8120   {
8121     Message::SendFail ("Error: no active viewer");
8122     return 1;
8123   }
8124
8125   Standard_Integer anArgIter = 1;
8126   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
8127   if (aNameArg.IsEmpty())
8128   {
8129     Message::SendFail ("Syntax error: animation name is not defined");
8130     return 1;
8131   }
8132
8133   TCollection_AsciiString aNameArgLower = aNameArg;
8134   aNameArgLower.LowerCase();
8135   if (aNameArgLower == "-reset"
8136    || aNameArgLower == "-clear")
8137   {
8138     ViewerTest_AnimationTimelineMap.Clear();
8139     return 0;
8140   }
8141   else if (aNameArg.Value (1) == '-')
8142   {
8143     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
8144     return 1;
8145   }
8146
8147   const char* aNameSplitter = "/";
8148   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
8149   if (aSplitPos == -1)
8150   {
8151     aNameSplitter = ".";
8152     aSplitPos = aNameArg.Search (aNameSplitter);
8153   }
8154
8155   // find existing or create a new animation by specified name within syntax "parent.child".
8156   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
8157   for (; !aNameArg.IsEmpty();)
8158   {
8159     TCollection_AsciiString aNameParent;
8160     if (aSplitPos != -1)
8161     {
8162       if (aSplitPos == aNameArg.Length())
8163       {
8164         Message::SendFail ("Syntax error: animation name is not defined");
8165         return 1;
8166       }
8167
8168       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
8169       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
8170
8171       aSplitPos = aNameArg.Search (aNameSplitter);
8172     }
8173     else
8174     {
8175       aNameParent = aNameArg;
8176       aNameArg.Clear();
8177     }
8178
8179     if (anAnimation.IsNull())
8180     {
8181       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
8182       {
8183         anAnimation = new AIS_Animation (aNameParent);
8184         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
8185       }
8186       aRootAnimation = anAnimation;
8187     }
8188     else
8189     {
8190       aParentAnimation = anAnimation;
8191       anAnimation = aParentAnimation->Find (aNameParent);
8192       if (anAnimation.IsNull())
8193       {
8194         anAnimation = new AIS_Animation (aNameParent);
8195         aParentAnimation->Add (anAnimation);
8196       }
8197     }
8198   }
8199
8200   if (anArgIter >= theArgNb)
8201   {
8202     // just print the list of children
8203     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
8204     {
8205       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
8206     }
8207     return 0;
8208   }
8209
8210   // animation parameters
8211   Standard_Boolean toPlay = Standard_False;
8212   Standard_Real aPlaySpeed     = 1.0;
8213   Standard_Real aPlayStartTime = anAnimation->StartPts();
8214   Standard_Real aPlayDuration  = anAnimation->Duration();
8215   Standard_Boolean isFreeCamera = Standard_False;
8216   Standard_Boolean isLockLoop   = Standard_False;
8217
8218   // video recording parameters
8219   TCollection_AsciiString aRecFile;
8220   Image_VideoParams aRecParams;
8221
8222   Handle(V3d_View) aView = ViewerTest::CurrentView();
8223   for (; anArgIter < theArgNb; ++anArgIter)
8224   {
8225     TCollection_AsciiString anArg (theArgVec[anArgIter]);
8226     anArg.LowerCase();
8227     // general options
8228     if (anArg == "-reset"
8229      || anArg == "-clear")
8230     {
8231       anAnimation->Clear();
8232     }
8233     else if (anArg == "-remove"
8234           || anArg == "-del"
8235           || anArg == "-delete")
8236     {
8237       if (!aParentAnimation.IsNull())
8238       {
8239         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
8240       }
8241       else
8242       {
8243         aParentAnimation->Remove (anAnimation);
8244       }
8245     }
8246     // playback options
8247     else if (anArg == "-play")
8248     {
8249       toPlay = Standard_True;
8250       if (++anArgIter < theArgNb)
8251       {
8252         if (*theArgVec[anArgIter] == '-')
8253         {
8254           --anArgIter;
8255           continue;
8256         }
8257         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
8258
8259         if (++anArgIter < theArgNb)
8260         {
8261           if (*theArgVec[anArgIter] == '-')
8262           {
8263             --anArgIter;
8264             continue;
8265           }
8266           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8267         }
8268       }
8269     }
8270     else if (anArg == "-resume")
8271     {
8272       toPlay = Standard_True;
8273       aPlayStartTime = anAnimation->ElapsedTime();
8274       if (++anArgIter < theArgNb)
8275       {
8276         if (*theArgVec[anArgIter] == '-')
8277         {
8278           --anArgIter;
8279           continue;
8280         }
8281
8282         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8283       }
8284     }
8285     else if (anArg == "-playspeed"
8286           || anArg == "-speed")
8287     {
8288       if (++anArgIter >= theArgNb)
8289       {
8290         Message::SendFail() << "Syntax error at " << anArg << "";
8291         return 1;
8292       }
8293       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
8294     }
8295     else if (anArg == "-lock"
8296           || anArg == "-lockloop"
8297           || anArg == "-playlockloop")
8298     {
8299       isLockLoop = Standard_True;
8300     }
8301     else if (anArg == "-freecamera"
8302           || anArg == "-playfreecamera"
8303           || anArg == "-freelook")
8304     {
8305       isFreeCamera = Standard_True;
8306     }
8307     // video recodring options
8308     else if (anArg == "-rec"
8309           || anArg == "-record")
8310     {
8311       if (++anArgIter >= theArgNb)
8312       {
8313         Message::SendFail() << "Syntax error at " << anArg;
8314         return 1;
8315       }
8316
8317       aRecFile = theArgVec[anArgIter];
8318       if (aRecParams.FpsNum <= 0)
8319       {
8320         aRecParams.FpsNum = 24;
8321       }
8322
8323       if (anArgIter + 2 < theArgNb
8324       && *theArgVec[anArgIter + 1] != '-'
8325       && *theArgVec[anArgIter + 2] != '-')
8326       {
8327         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
8328         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
8329         if (aWidthArg .IsIntegerValue()
8330          && aHeightArg.IsIntegerValue())
8331         {
8332           aRecParams.Width  = aWidthArg .IntegerValue();
8333           aRecParams.Height = aHeightArg.IntegerValue();
8334           anArgIter += 2;
8335         }
8336       }
8337     }
8338     else if (anArg == "-fps")
8339     {
8340       if (++anArgIter >= theArgNb)
8341       {
8342         Message::SendFail() << "Syntax error at " << anArg;
8343         return 1;
8344       }
8345
8346       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
8347       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
8348       if (aSplitIndex == 0)
8349       {
8350         aRecParams.FpsNum = aFpsArg.IntegerValue();
8351       }
8352       else
8353       {
8354         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
8355         aFpsArg.Split (aFpsArg.Length() - 1);
8356         const TCollection_AsciiString aNumStr = aFpsArg;
8357         aRecParams.FpsNum = aNumStr.IntegerValue();
8358         aRecParams.FpsDen = aDenStr.IntegerValue();
8359         if (aRecParams.FpsDen < 1)
8360         {
8361           Message::SendFail() << "Syntax error at " << anArg;
8362           return 1;
8363         }
8364       }
8365     }
8366     else if (anArg == "-format")
8367     {
8368       if (++anArgIter >= theArgNb)
8369       {
8370         Message::SendFail() << "Syntax error at " << anArg;
8371         return 1;
8372       }
8373       aRecParams.Format = theArgVec[anArgIter];
8374     }
8375     else if (anArg == "-pix_fmt"
8376           || anArg == "-pixfmt"
8377           || anArg == "-pixelformat")
8378     {
8379       if (++anArgIter >= theArgNb)
8380       {
8381         Message::SendFail() << "Syntax error at " << anArg;
8382         return 1;
8383       }
8384       aRecParams.PixelFormat = theArgVec[anArgIter];
8385     }
8386     else if (anArg == "-codec"
8387           || anArg == "-vcodec"
8388           || anArg == "-videocodec")
8389     {
8390       if (++anArgIter >= theArgNb)
8391       {
8392         Message::SendFail() << "Syntax error at " << anArg;
8393         return 1;
8394       }
8395       aRecParams.VideoCodec = theArgVec[anArgIter];
8396     }
8397     else if (anArg == "-crf"
8398           || anArg == "-preset"
8399           || anArg == "-qp")
8400     {
8401       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
8402       if (++anArgIter >= theArgNb)
8403       {
8404         Message::SendFail() << "Syntax error at " << anArg;
8405         return 1;
8406       }
8407
8408       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
8409     }
8410     // animation definition options
8411     else if (anArg == "-start"
8412           || anArg == "-starttime"
8413           || anArg == "-startpts")
8414     {
8415       if (++anArgIter >= theArgNb)
8416       {
8417         Message::SendFail() << "Syntax error at " << anArg;
8418         return 1;
8419       }
8420
8421       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
8422       aRootAnimation->UpdateTotalDuration();
8423     }
8424     else if (anArg == "-end"
8425           || anArg == "-endtime"
8426           || anArg == "-endpts")
8427     {
8428       if (++anArgIter >= theArgNb)
8429       {
8430         Message::SendFail() << "Syntax error at " << anArg;
8431         return 1;
8432       }
8433
8434       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
8435       aRootAnimation->UpdateTotalDuration();
8436     }
8437     else if (anArg == "-dur"
8438           || anArg == "-duration")
8439     {
8440       if (++anArgIter >= theArgNb)
8441       {
8442         Message::SendFail() << "Syntax error at " << anArg;
8443         return 1;
8444       }
8445
8446       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
8447       aRootAnimation->UpdateTotalDuration();
8448     }
8449     else if (anArg == "-command"
8450           || anArg == "-cmd"
8451           || anArg == "-invoke"
8452           || anArg == "-eval"
8453           || anArg == "-proc")
8454     {
8455       if (++anArgIter >= theArgNb)
8456       {
8457         Message::SendFail() << "Syntax error at " << anArg;
8458         return 1;
8459       }
8460
8461       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
8462       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
8463     }
8464     else if (anArg == "-objecttrsf"
8465           || anArg == "-objectransformation"
8466           || anArg == "-objtransformation"
8467           || anArg == "-objtrsf"
8468           || anArg == "-object"
8469           || anArg == "-obj")
8470     {
8471       if (++anArgIter >= theArgNb)
8472       {
8473         Message::SendFail() << "Syntax error at " << anArg;
8474         return 1;
8475       }
8476
8477       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
8478       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
8479       Handle(AIS_InteractiveObject) anObject;
8480       if (!aMapOfAIS.Find2 (anObjName, anObject))
8481       {
8482         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
8483         return 1;
8484       }
8485
8486       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
8487       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
8488       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
8489       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
8490       Standard_Boolean isTrsfSet = Standard_False;
8491       Standard_Integer aTrsfArgIter = anArgIter + 1;
8492       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
8493       {
8494         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
8495         aTrsfArg.LowerCase();
8496         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
8497         if (aTrsfArg.StartsWith ("-rotation")
8498          || aTrsfArg.StartsWith ("-rot"))
8499         {
8500           isTrsfSet = Standard_True;
8501           if (aTrsfArgIter + 4 >= theArgNb
8502           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
8503           {
8504             Message::SendFail() << "Syntax error at " << aTrsfArg;
8505             return 1;
8506           }
8507           aTrsfArgIter += 4;
8508         }
8509         else if (aTrsfArg.StartsWith ("-location")
8510               || aTrsfArg.StartsWith ("-loc"))
8511         {
8512           isTrsfSet = Standard_True;
8513           if (aTrsfArgIter + 3 >= theArgNb
8514           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
8515           {
8516             Message::SendFail() << "Syntax error at " << aTrsfArg;
8517             return 1;
8518           }
8519           aTrsfArgIter += 3;
8520         }
8521         else if (aTrsfArg.StartsWith ("-scale"))
8522         {
8523           isTrsfSet = Standard_True;
8524           if (++aTrsfArgIter >= theArgNb)
8525           {
8526             Message::SendFail() << "Syntax error at " << aTrsfArg;
8527             return 1;
8528           }
8529
8530           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
8531           if (!aScaleStr.IsRealValue())
8532           {
8533             Message::SendFail() << "Syntax error at " << aTrsfArg;
8534             return 1;
8535           }
8536           aScales[anIndex] = aScaleStr.RealValue();
8537         }
8538         else
8539         {
8540           anArgIter = aTrsfArgIter - 1;
8541           break;
8542         }
8543       }
8544       if (!isTrsfSet)
8545       {
8546         Message::SendFail() << "Syntax error at " << anArg;
8547         return 1;
8548       }
8549       else if (aTrsfArgIter >= theArgNb)
8550       {
8551         anArgIter = theArgNb;
8552       }
8553
8554       aTrsfs[0].SetRotation        (aRotQuats[0]);
8555       aTrsfs[1].SetRotation        (aRotQuats[1]);
8556       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
8557       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
8558       aTrsfs[0].SetScaleFactor     (aScales[0]);
8559       aTrsfs[1].SetScaleFactor     (aScales[1]);
8560
8561       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
8562       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
8563     }
8564     else if (anArg == "-viewtrsf"
8565           || anArg == "-view")
8566     {
8567       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
8568       if (aCamAnimation.IsNull())
8569       {
8570         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
8571         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
8572       }
8573
8574       Handle(Graphic3d_Camera) aCams[2] =
8575       {
8576         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
8577         new Graphic3d_Camera (aCamAnimation->View()->Camera())
8578       };
8579
8580       Standard_Boolean isTrsfSet = Standard_False;
8581       Standard_Integer aViewArgIter = anArgIter + 1;
8582       for (; aViewArgIter < theArgNb; ++aViewArgIter)
8583       {
8584         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
8585         aViewArg.LowerCase();
8586         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
8587         if (aViewArg.StartsWith ("-scale"))
8588         {
8589           isTrsfSet = Standard_True;
8590           if (++aViewArgIter >= theArgNb)
8591           {
8592             Message::SendFail() << "Syntax error at " << anArg;
8593             return 1;
8594           }
8595
8596           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
8597           if (!aScaleStr.IsRealValue())
8598           {
8599             Message::SendFail() << "Syntax error at " << aViewArg;
8600             return 1;
8601           }
8602           Standard_Real aScale = aScaleStr.RealValue();
8603           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
8604           aCams[anIndex]->SetScale (aScale);
8605         }
8606         else if (aViewArg.StartsWith ("-eye")
8607               || aViewArg.StartsWith ("-center")
8608               || aViewArg.StartsWith ("-at")
8609               || aViewArg.StartsWith ("-up"))
8610         {
8611           isTrsfSet = Standard_True;
8612           gp_XYZ anXYZ;
8613           if (aViewArgIter + 3 >= theArgNb
8614           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
8615           {
8616             Message::SendFail() << "Syntax error at " << aViewArg;
8617             return 1;
8618           }
8619           aViewArgIter += 3;
8620
8621           if (aViewArg.StartsWith ("-eye"))
8622           {
8623             aCams[anIndex]->SetEye (anXYZ);
8624           }
8625           else if (aViewArg.StartsWith ("-center")
8626                 || aViewArg.StartsWith ("-at"))
8627           {
8628             aCams[anIndex]->SetCenter (anXYZ);
8629           }
8630           else if (aViewArg.StartsWith ("-up"))
8631           {
8632             aCams[anIndex]->SetUp (anXYZ);
8633           }
8634         }
8635         else
8636         {
8637           anArgIter = aViewArgIter - 1;
8638           break;
8639         }
8640       }
8641       if (!isTrsfSet)
8642       {
8643         Message::SendFail() << "Syntax error at " << anArg;
8644         return 1;
8645       }
8646       else if (aViewArgIter >= theArgNb)
8647       {
8648         anArgIter = theArgNb;
8649       }
8650
8651       aCamAnimation->SetCameraStart(aCams[0]);
8652       aCamAnimation->SetCameraEnd  (aCams[1]);
8653     }
8654     else
8655     {
8656       Message::SendFail() << "Syntax error at " << anArg;
8657       return 1;
8658     }
8659   }
8660
8661   if (!toPlay && aRecFile.IsEmpty())
8662   {
8663     return 0;
8664   }
8665
8666   // Start animation timeline and process frame updating.
8667   TheIsAnimating = Standard_True;
8668   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
8669   Handle(Graphic3d_Camera) aCameraBack = new Graphic3d_Camera (aView->Camera());
8670   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
8671   if (isFreeCamera)
8672   {
8673     aView->Camera()->Copy (aCameraBack);
8674   }
8675
8676   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
8677   if (aRecParams.FpsNum <= 0)
8678   {
8679     while (!anAnimation->IsStopped())
8680     {
8681       aCameraBack->Copy (aView->Camera());
8682       const Standard_Real aPts = anAnimation->UpdateTimer();
8683       if (isFreeCamera)
8684       {
8685         aView->Camera()->Copy (aCameraBack);
8686       }
8687
8688       if (aPts >= anUpperPts)
8689       {
8690         anAnimation->Pause();
8691         break;
8692       }
8693
8694       if (aView->IsInvalidated())
8695       {
8696         aView->Redraw();
8697       }
8698       else
8699       {
8700         aView->RedrawImmediate();
8701       }
8702
8703       if (!isLockLoop)
8704       {
8705         // handle user events
8706         theDI.Eval ("after 1 set waiter 1");
8707         theDI.Eval ("vwait waiter");
8708       }
8709       if (!TheIsAnimating)
8710       {
8711         anAnimation->Pause();
8712         theDI << aPts;
8713         break;
8714       }
8715     }
8716
8717     if (aView->IsInvalidated())
8718     {
8719       aView->Redraw();
8720     }
8721     else
8722     {
8723       aView->RedrawImmediate();
8724     }
8725   }
8726   else
8727   {
8728     OSD_Timer aPerfTimer;
8729     aPerfTimer.Start();
8730
8731     Handle(Image_VideoRecorder) aRecorder;
8732     ImageFlipper aFlipper;
8733     Handle(Draw_ProgressIndicator) aProgress;
8734     if (!aRecFile.IsEmpty())
8735     {
8736       if (aRecParams.Width  <= 0
8737        || aRecParams.Height <= 0)
8738       {
8739         aView->Window()->Size (aRecParams.Width, aRecParams.Height);
8740       }
8741
8742       aRecorder = new Image_VideoRecorder();
8743       if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
8744       {
8745         Message::SendFail ("Error: failed to open video file for recording");
8746         return 0;
8747       }
8748
8749       aProgress = new Draw_ProgressIndicator (theDI, 1);
8750     }
8751
8752     // Manage frame-rated animation here
8753     Standard_Real aPts = aPlayStartTime;
8754     int64_t aNbFrames = 0;
8755     Message_ProgressSentry aPSentry (aProgress, "Video recording, sec", 0, Max (1, Standard_Integer(aPlayDuration / aPlaySpeed)), 1);
8756     Standard_Integer aSecondsProgress = 0;
8757     for (; aPts <= anUpperPts && aPSentry.More();)
8758     {
8759       const Standard_Real aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
8760       aPts = aPlayStartTime + aRecPts;
8761       ++aNbFrames;
8762       if (!anAnimation->Update (aPts))
8763       {
8764         break;
8765       }
8766
8767       if (!aRecorder.IsNull())
8768       {
8769         V3d_ImageDumpOptions aDumpParams;
8770         aDumpParams.Width          = aRecParams.Width;
8771         aDumpParams.Height         = aRecParams.Height;
8772         aDumpParams.BufferType     = Graphic3d_BT_RGBA;
8773         aDumpParams.StereoOptions  = V3d_SDO_MONO;
8774         aDumpParams.ToAdjustAspect = Standard_True;
8775         if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
8776         {
8777           Message::SendFail ("Error: view dump is failed");
8778           return 0;
8779         }
8780         aFlipper.FlipY (aRecorder->ChangeFrame());
8781         if (!aRecorder->PushFrame())
8782         {
8783           return 0;
8784         }
8785       }
8786       else
8787       {
8788         aView->Redraw();
8789       }
8790
8791       while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
8792       {
8793         aPSentry.Next();
8794         ++aSecondsProgress;
8795       }
8796     }
8797
8798     aPerfTimer.Stop();
8799     anAnimation->Stop();
8800     const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
8801     theDI << "Average FPS: " << aRecFps << "\n"
8802           << "Nb. Frames: "  << Standard_Real(aNbFrames);
8803
8804     aView->Redraw();
8805   }
8806
8807   aView->SetImmediateUpdate (wasImmediateUpdate);
8808   TheIsAnimating = Standard_False;
8809   return 0;
8810 }
8811
8812
8813 //=======================================================================
8814 //function : VChangeSelected
8815 //purpose  : Adds the shape to selection or remove one from it
8816 //=======================================================================
8817 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
8818                                 Standard_Integer argc,
8819                                 const char ** argv)
8820 {
8821   if(argc != 2)
8822   {
8823     di<<"Usage : " << argv[0] << " shape \n";
8824     return 1;
8825   }
8826   //get AIS_Shape:
8827   TCollection_AsciiString aName(argv[1]);
8828   Handle(AIS_InteractiveObject) anAISObject;
8829   if (!GetMapOfAIS().Find2 (aName, anAISObject)
8830     || anAISObject.IsNull())
8831   {
8832     di<<"Use 'vdisplay' before";
8833     return 1;
8834   }
8835
8836   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
8837   return 0;
8838 }
8839
8840 //=======================================================================
8841 //function : VNbSelected
8842 //purpose  : Returns number of selected objects
8843 //=======================================================================
8844 static Standard_Integer VNbSelected (Draw_Interpretor& di,
8845                                 Standard_Integer argc,
8846                                 const char ** argv)
8847 {
8848   if(argc != 1)
8849   {
8850     di << "Usage : " << argv[0] << "\n";
8851     return 1;
8852   }
8853   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8854   if(aContext.IsNull())
8855   {
8856     di << "use 'vinit' command before " << argv[0] << "\n";
8857     return 1;
8858   }
8859   di << aContext->NbSelected() << "\n";
8860   return 0;
8861 }
8862
8863 //=======================================================================
8864 //function : VPurgeDisplay
8865 //purpose  : Switches altialiasing on or off
8866 //=======================================================================
8867 static Standard_Integer VPurgeDisplay (Draw_Interpretor& di,
8868                                 Standard_Integer argc,
8869                                 const char ** argv)
8870 {
8871   if (argc > 1)
8872   {
8873     di << "Usage : " << argv[0] << "\n";
8874     return 1;
8875   }
8876   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8877   if (aContext.IsNull())
8878   {
8879     di << "use 'vinit' command before " << argv[0] << "\n";
8880     return 1;
8881   }
8882
8883   di << aContext->PurgeDisplay() << "\n";
8884   return 0;
8885 }
8886
8887 //=======================================================================
8888 //function : VSetViewSize
8889 //purpose  :
8890 //=======================================================================
8891 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
8892                                 Standard_Integer argc,
8893                                 const char ** argv)
8894 {
8895   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8896   if(aContext.IsNull())
8897   {
8898     di << "use 'vinit' command before " << argv[0] << "\n";
8899     return 1;
8900   }
8901   if(argc != 2)
8902   {
8903     di<<"Usage : " << argv[0] << " Size\n";
8904     return 1;
8905   }
8906   Standard_Real aSize = Draw::Atof (argv[1]);
8907   if (aSize <= 0.)
8908   {
8909     di<<"Bad Size value  : " << aSize << "\n";
8910     return 1;
8911   }
8912
8913   Handle(V3d_View) aView = ViewerTest::CurrentView();
8914   aView->SetSize(aSize);
8915   return 0;
8916 }
8917
8918 //=======================================================================
8919 //function : VMoveView
8920 //purpose  :
8921 //=======================================================================
8922 static Standard_Integer VMoveView (Draw_Interpretor& di,
8923                                 Standard_Integer argc,
8924                                 const char ** argv)
8925 {
8926   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8927   if(aContext.IsNull())
8928   {
8929     di << "use 'vinit' command before " << argv[0] << "\n";
8930     return 1;
8931   }
8932   if(argc < 4 || argc > 5)
8933   {
8934     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8935     return 1;
8936   }
8937   Standard_Real Dx = Draw::Atof (argv[1]);
8938   Standard_Real Dy = Draw::Atof (argv[2]);
8939   Standard_Real Dz = Draw::Atof (argv[3]);
8940   Standard_Boolean aStart = Standard_True;
8941   if (argc == 5)
8942   {
8943       aStart = (Draw::Atoi (argv[4]) > 0);
8944   }
8945
8946   Handle(V3d_View) aView = ViewerTest::CurrentView();
8947   aView->Move(Dx,Dy,Dz,aStart);
8948   return 0;
8949 }
8950
8951 //=======================================================================
8952 //function : VTranslateView
8953 //purpose  :
8954 //=======================================================================
8955 static Standard_Integer VTranslateView (Draw_Interpretor& di,
8956                                 Standard_Integer argc,
8957                                 const char ** argv)
8958 {
8959   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8960   if(aContext.IsNull())
8961   {
8962     di << "use 'vinit' command before " << argv[0] << "\n";
8963     return 1;
8964   }
8965   if(argc < 4 || argc > 5)
8966   {
8967     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8968     return 1;
8969   }
8970   Standard_Real Dx = Draw::Atof (argv[1]);
8971   Standard_Real Dy = Draw::Atof (argv[2]);
8972   Standard_Real Dz = Draw::Atof (argv[3]);
8973   Standard_Boolean aStart = Standard_True;
8974   if (argc == 5)
8975   {
8976       aStart = (Draw::Atoi (argv[4]) > 0);
8977   }
8978
8979   Handle(V3d_View) aView = ViewerTest::CurrentView();
8980   aView->Translate(Dx,Dy,Dz,aStart);
8981   return 0;
8982 }
8983
8984 //=======================================================================
8985 //function : VTurnView
8986 //purpose  :
8987 //=======================================================================
8988 static Standard_Integer VTurnView (Draw_Interpretor& di,
8989                                 Standard_Integer argc,
8990                                 const char ** argv)
8991 {
8992   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8993   if(aContext.IsNull()) {
8994     di << "use 'vinit' command before " << argv[0] << "\n";
8995     return 1;
8996   }
8997   if(argc < 4 || argc > 5){
8998     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
8999     return 1;
9000   }
9001   Standard_Real Ax = Draw::Atof (argv[1]);
9002   Standard_Real Ay = Draw::Atof (argv[2]);
9003   Standard_Real Az = Draw::Atof (argv[3]);
9004   Standard_Boolean aStart = Standard_True;
9005   if (argc == 5)
9006   {
9007       aStart = (Draw::Atoi (argv[4]) > 0);
9008   }
9009
9010   Handle(V3d_View) aView = ViewerTest::CurrentView();
9011   aView->Turn(Ax,Ay,Az,aStart);
9012   return 0;
9013 }
9014
9015 //==============================================================================
9016 //function : VTextureEnv
9017 //purpose  : ENables or disables environment mapping
9018 //==============================================================================
9019 class OCC_TextureEnv : public Graphic3d_TextureEnv
9020 {
9021 public:
9022   OCC_TextureEnv(const Standard_CString FileName);
9023   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
9024   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
9025                             const Standard_Boolean theModulateFlag,
9026                             const Graphic3d_TypeOfTextureFilter theFilter,
9027                             const Standard_ShortReal theXScale,
9028                             const Standard_ShortReal theYScale,
9029                             const Standard_ShortReal theXShift,
9030                             const Standard_ShortReal theYShift,
9031                             const Standard_ShortReal theAngle);
9032   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
9033 };
9034 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
9035
9036 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
9037   : Graphic3d_TextureEnv(theFileName)
9038 {
9039 }
9040
9041 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
9042   : Graphic3d_TextureEnv(theTexId)
9043 {
9044 }
9045
9046 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
9047                                           const Standard_Boolean theModulateFlag,
9048                                           const Graphic3d_TypeOfTextureFilter theFilter,
9049                                           const Standard_ShortReal theXScale,
9050                                           const Standard_ShortReal theYScale,
9051                                           const Standard_ShortReal theXShift,
9052                                           const Standard_ShortReal theYShift,
9053                                           const Standard_ShortReal theAngle)
9054 {
9055   myParams->SetRepeat     (theRepeatFlag);
9056   myParams->SetModulate   (theModulateFlag);
9057   myParams->SetFilter     (theFilter);
9058   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
9059   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
9060   myParams->SetRotation   (theAngle);
9061 }
9062
9063 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
9064 {
9065   // get the active view
9066   Handle(V3d_View) aView = ViewerTest::CurrentView();
9067   if (aView.IsNull())
9068   {
9069     Message::SendFail ("Error: no active viewer");
9070     return 1;
9071   }
9072
9073   // Checking the input arguments
9074   Standard_Boolean anEnableFlag = Standard_False;
9075   Standard_Boolean isOk         = theArgNb >= 2;
9076   if (isOk)
9077   {
9078     TCollection_AsciiString anEnableOpt(theArgVec[1]);
9079     anEnableFlag = anEnableOpt.IsEqual("on");
9080     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
9081   }
9082   if (anEnableFlag)
9083   {
9084     isOk = (theArgNb == 3 || theArgNb == 11);
9085     if (isOk)
9086     {
9087       TCollection_AsciiString aTextureOpt(theArgVec[2]);
9088       isOk = (!aTextureOpt.IsIntegerValue() ||
9089              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
9090
9091       if (isOk && theArgNb == 11)
9092       {
9093         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
9094                                 aModulateOpt(theArgVec[4]),
9095                                 aFilterOpt  (theArgVec[5]),
9096                                 aSScaleOpt  (theArgVec[6]),
9097                                 aTScaleOpt  (theArgVec[7]),
9098                                 aSTransOpt  (theArgVec[8]),
9099                                 aTTransOpt  (theArgVec[9]),
9100                                 anAngleOpt  (theArgVec[10]);
9101         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
9102                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
9103                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
9104                 aSScaleOpt.IsRealValue() && aTScaleOpt.IsRealValue() &&
9105                 aSTransOpt.IsRealValue() && aTTransOpt.IsRealValue() &&
9106                 anAngleOpt.IsRealValue());
9107       }
9108     }
9109   }
9110
9111   if (!isOk)
9112   {
9113     Message::SendFail() << "Usage:\n"
9114                         << theArgVec[0] << " off\n"
9115                         << 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]";
9116     return 1;
9117   }
9118
9119   if (anEnableFlag)
9120   {
9121     TCollection_AsciiString aTextureOpt(theArgVec[2]);
9122     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
9123                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
9124                                      new OCC_TextureEnv(theArgVec[2]);
9125
9126     if (theArgNb == 11)
9127     {
9128       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
9129       aTexEnv->SetTextureParameters(
9130         aRepeatOpt.  IsEqual("repeat"),
9131         aModulateOpt.IsEqual("modulate"),
9132         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
9133                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
9134                                                                            Graphic3d_TOTF_TRILINEAR,
9135         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
9136         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
9137         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
9138         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
9139         (Standard_ShortReal)Draw::Atof(theArgVec[10])
9140         );
9141     }
9142     aView->SetTextureEnv(aTexEnv);
9143   }
9144   else // Disabling environment mapping
9145   {
9146     Handle(Graphic3d_TextureEnv) aTexture;
9147     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
9148   }
9149
9150   aView->Redraw();
9151   return 0;
9152 }
9153
9154 namespace
9155 {
9156   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
9157
9158   //! Remove registered clipping plane from all views and objects.
9159   static void removePlane (MapOfPlanes& theRegPlanes,
9160                            const TCollection_AsciiString& theName)
9161   {
9162     Handle(Graphic3d_ClipPlane) aClipPlane;
9163     if (!theRegPlanes.Find (theName, aClipPlane))
9164     {
9165       Message::SendWarning ("Warning: no such plane");
9166       return;
9167     }
9168
9169     theRegPlanes.UnBind (theName);
9170     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
9171          anIObjIt.More(); anIObjIt.Next())
9172     {
9173       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
9174       aPrs->RemoveClipPlane (aClipPlane);
9175     }
9176
9177     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
9178          aViewIt.More(); aViewIt.Next())
9179     {
9180       const Handle(V3d_View)& aView = aViewIt.Key2();
9181       aView->RemoveClipPlane(aClipPlane);
9182     }
9183
9184     ViewerTest::RedrawAllViews();
9185   }
9186 }
9187
9188 //===============================================================================================
9189 //function : VClipPlane
9190 //purpose  :
9191 //===============================================================================================
9192 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9193 {
9194   // use short-cut for created clip planes map of created (or "registered by name") clip planes
9195   static MapOfPlanes aRegPlanes;
9196
9197   if (theArgsNb < 2)
9198   {
9199     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
9200     {
9201       theDi << aPlaneIter.Key() << " ";
9202     }
9203     return 0;
9204   }
9205
9206   TCollection_AsciiString aCommand (theArgVec[1]);
9207   aCommand.LowerCase();
9208   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
9209   if (anActiveView.IsNull())
9210   {
9211     Message::SendFail ("Error: no active viewer");
9212     return 1;
9213   }
9214
9215   // print maximum number of planes for current viewer
9216   if (aCommand == "-maxplanes"
9217    || aCommand == "maxplanes")
9218   {
9219     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
9220           << " plane slots provided by driver.\n";
9221     return 0;
9222   }
9223
9224   // create / delete plane instance
9225   if (aCommand == "-create"
9226    || aCommand == "create"
9227    || aCommand == "-delete"
9228    || aCommand == "delete"
9229    || aCommand == "-clone"
9230    || aCommand == "clone")
9231   {
9232     if (theArgsNb < 3)
9233     {
9234       Message::SendFail ("Syntax error: plane name is required");
9235       return 1;
9236     }
9237
9238     Standard_Boolean toCreate = aCommand == "-create"
9239                              || aCommand == "create";
9240     Standard_Boolean toClone  = aCommand == "-clone"
9241                              || aCommand == "clone";
9242     Standard_Boolean toDelete = aCommand == "-delete"
9243                              || aCommand == "delete";
9244     TCollection_AsciiString aPlane (theArgVec[2]);
9245
9246     if (toCreate)
9247     {
9248       if (aRegPlanes.IsBound (aPlane))
9249       {
9250         std::cout << "Warning: existing plane has been overridden.\n";
9251         toDelete = true;
9252       }
9253       else
9254       {
9255         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9256         return 0;
9257       }
9258     }
9259     else if (toClone) // toClone
9260     {
9261       if (!aRegPlanes.IsBound (aPlane))
9262       {
9263         Message::SendFail ("Error: no such plane");
9264         return 1;
9265       }
9266       else if (theArgsNb < 4)
9267       {
9268         Message::SendFail ("Syntax error: enter name for new plane");
9269         return 1;
9270       }
9271
9272       TCollection_AsciiString aClone (theArgVec[3]);
9273       if (aRegPlanes.IsBound (aClone))
9274       {
9275         Message::SendFail ("Error: plane name is in use");
9276         return 1;
9277       }
9278
9279       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
9280
9281       aRegPlanes.Bind (aClone, aClipPlane->Clone());
9282       return 0;
9283     }
9284
9285     if (toDelete)
9286     {
9287       if (aPlane == "ALL"
9288        || aPlane == "all"
9289        || aPlane == "*")
9290       {
9291         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
9292         {
9293           aPlane = aPlaneIter.Key();
9294           removePlane (aRegPlanes, aPlane);
9295           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
9296         }
9297       }
9298       else
9299       {
9300         removePlane (aRegPlanes, aPlane);
9301       }
9302     }
9303
9304     if (toCreate)
9305     {
9306       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9307     }
9308     return 0;
9309   }
9310
9311   // set / unset plane command
9312   if (aCommand == "set"
9313    || aCommand == "unset")
9314   {
9315     if (theArgsNb < 5)
9316     {
9317       Message::SendFail ("Syntax error: need more arguments");
9318       return 1;
9319     }
9320
9321     // redirect to new syntax
9322     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
9323     anArgVec.SetValue (1, theArgVec[0]);
9324     anArgVec.SetValue (2, theArgVec[2]);
9325     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
9326     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
9327     {
9328       anArgVec.SetValue (anIt, theArgVec[anIt]);
9329     }
9330
9331     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
9332   }
9333
9334   // change plane command
9335   TCollection_AsciiString aPlaneName;
9336   Handle(Graphic3d_ClipPlane) aClipPlane;
9337   Standard_Integer anArgIter = 0;
9338   if (aCommand == "-change"
9339    || aCommand == "change")
9340   {
9341     // old syntax support
9342     if (theArgsNb < 3)
9343     {
9344       Message::SendFail ("Syntax error: need more arguments");
9345       return 1;
9346     }
9347
9348     anArgIter  = 3;
9349     aPlaneName = theArgVec[2];
9350     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
9351     {
9352       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
9353       return 1;
9354     }
9355   }
9356   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
9357   {
9358     anArgIter  = 2;
9359     aPlaneName = theArgVec[1];
9360   }
9361   else
9362   {
9363     anArgIter  = 2;
9364     aPlaneName = theArgVec[1];
9365     aClipPlane = new Graphic3d_ClipPlane();
9366     aRegPlanes.Bind (aPlaneName, aClipPlane);
9367     theDi << "Created new plane " << aPlaneName << ".\n";
9368   }
9369
9370   if (theArgsNb - anArgIter < 1)
9371   {
9372     Message::SendFail ("Syntax error: need more arguments");
9373     return 1;
9374   }
9375
9376   for (; anArgIter < theArgsNb; ++anArgIter)
9377   {
9378     const char**     aChangeArgs   = theArgVec + anArgIter;
9379     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
9380     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
9381     aChangeArg.LowerCase();
9382
9383     Standard_Boolean toEnable = Standard_True;
9384     if (ViewerTest::ParseOnOff (aChangeArgs[0], toEnable))
9385     {
9386       aClipPlane->SetOn (toEnable);
9387     }
9388     else if (aChangeArg.StartsWith ("-equation")
9389           || aChangeArg.StartsWith ("equation"))
9390     {
9391       if (aNbChangeArgs < 5)
9392       {
9393         Message::SendFail ("Syntax error: need more arguments");
9394         return 1;
9395       }
9396
9397       Standard_Integer aSubIndex = 1;
9398       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
9399       if (aPrefixLen < aChangeArg.Length())
9400       {
9401         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
9402         if (!aSubStr.IsIntegerValue()
9403           || aSubStr.IntegerValue() <= 0)
9404         {
9405           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9406           return 1;
9407         }
9408         aSubIndex = aSubStr.IntegerValue();
9409       }
9410
9411       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
9412       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
9413       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
9414       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
9415       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9416       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
9417       {
9418         if (aSubPln->ChainNextPlane().IsNull())
9419         {
9420           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9421         }
9422         aSubPln = aSubPln->ChainNextPlane();
9423       }
9424       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9425       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
9426       anArgIter += 4;
9427     }
9428     else if ((aChangeArg == "-boxinterior"
9429            || aChangeArg == "-boxint"
9430            || aChangeArg == "-box")
9431             && aNbChangeArgs >= 7)
9432     {
9433       Graphic3d_BndBox3d aBndBox;
9434       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
9435       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
9436       anArgIter += 6;
9437
9438       Standard_Integer aNbSubPlanes = 6;
9439       const Graphic3d_Vec3d aDirArray[6] =
9440       {
9441         Graphic3d_Vec3d (-1, 0, 0),
9442         Graphic3d_Vec3d ( 1, 0, 0),
9443         Graphic3d_Vec3d ( 0,-1, 0),
9444         Graphic3d_Vec3d ( 0, 1, 0),
9445         Graphic3d_Vec3d ( 0, 0,-1),
9446         Graphic3d_Vec3d ( 0, 0, 1),
9447       };
9448       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9449       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
9450       {
9451         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
9452         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
9453         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
9454         if (aSubPlaneIter + 1 == aNbSubPlanes)
9455         {
9456           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9457         }
9458         else
9459         {
9460           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9461         }
9462         aSubPln = aSubPln->ChainNextPlane();
9463       }
9464     }
9465     else if (aChangeArg == "-capping"
9466           || aChangeArg == "capping")
9467     {
9468       if (aNbChangeArgs < 2)
9469       {
9470         Message::SendFail ("Syntax error: need more arguments");
9471         return 1;
9472       }
9473
9474       if (ViewerTest::ParseOnOff (aChangeArgs[1], toEnable))
9475       {
9476         aClipPlane->SetCapping (toEnable);
9477         anArgIter += 1;
9478       }
9479       else
9480       {
9481         // just skip otherwise (old syntax)
9482       }
9483     }
9484     else if (aChangeArg == "-useobjectmaterial"
9485           || aChangeArg == "-useobjectmat"
9486           || aChangeArg == "-useobjmat"
9487           || aChangeArg == "-useobjmaterial")
9488     {
9489       if (aNbChangeArgs < 2)
9490       {
9491         Message::SendFail ("Syntax error: need more arguments");
9492         return 1;
9493       }
9494
9495       if (ViewerTest::ParseOnOff (aChangeArgs[1], toEnable))
9496       {
9497         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
9498         anArgIter += 1;
9499       }
9500     }
9501     else if (aChangeArg == "-useobjecttexture"
9502           || aChangeArg == "-useobjecttex"
9503           || aChangeArg == "-useobjtexture"
9504           || aChangeArg == "-useobjtex")
9505     {
9506       if (aNbChangeArgs < 2)
9507       {
9508         Message::SendFail ("Syntax error: need more arguments");
9509         return 1;
9510       }
9511
9512       if (ViewerTest::ParseOnOff (aChangeArgs[1], toEnable))
9513       {
9514         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
9515         anArgIter += 1;
9516       }
9517     }
9518     else if (aChangeArg == "-useobjectshader"
9519           || aChangeArg == "-useobjshader")
9520     {
9521       if (aNbChangeArgs < 2)
9522       {
9523         Message::SendFail ("Syntax error: need more arguments");
9524         return 1;
9525       }
9526
9527       if (ViewerTest::ParseOnOff (aChangeArgs[1], toEnable))
9528       {
9529         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
9530         anArgIter += 1;
9531       }
9532     }
9533     else if (aChangeArg == "-color"
9534           || aChangeArg == "color")
9535     {
9536       Quantity_Color aColor;
9537       Standard_Integer aNbParsed = ViewerTest::ParseColor (aNbChangeArgs - 1,
9538                                                            aChangeArgs + 1,
9539                                                            aColor);
9540       if (aNbParsed == 0)
9541       {
9542         Message::SendFail ("Syntax error: need more arguments");
9543         return 1;
9544       }
9545       aClipPlane->SetCappingColor (aColor);
9546       anArgIter += aNbParsed;
9547     }
9548     else if (aNbChangeArgs >= 1
9549           && (aChangeArg == "-material"
9550            || aChangeArg == "material"))
9551     {
9552       ++anArgIter;
9553       Graphic3d_NameOfMaterial aMatName;
9554       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
9555       {
9556         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
9557         return 1;
9558       }
9559       aClipPlane->SetCappingMaterial (aMatName);
9560     }
9561     else if ((aChangeArg == "-transparency"
9562            || aChangeArg == "-transp")
9563           && aNbChangeArgs >= 2)
9564     {
9565       TCollection_AsciiString aValStr (aChangeArgs[1]);
9566       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
9567       if (aValStr.IsRealValue())
9568       {
9569         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
9570         aMat.SetTransparency ((float )aValStr.RealValue());
9571         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
9572         aClipPlane->SetCappingMaterial (aMat);
9573       }
9574       else
9575       {
9576         aValStr.LowerCase();
9577         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
9578         if (aValStr == "opaque")
9579         {
9580           aMode = Graphic3d_AlphaMode_Opaque;
9581         }
9582         else if (aValStr == "mask")
9583         {
9584           aMode = Graphic3d_AlphaMode_Mask;
9585         }
9586         else if (aValStr == "blend")
9587         {
9588           aMode = Graphic3d_AlphaMode_Blend;
9589         }
9590         else if (aValStr == "blendauto")
9591         {
9592           aMode = Graphic3d_AlphaMode_BlendAuto;
9593         }
9594         else
9595         {
9596           Message::SendFail() << "Syntax error at '" << aValStr << "'";
9597           return 1;
9598         }
9599         anAspect->SetAlphaMode (aMode);
9600         aClipPlane->SetCappingAspect (anAspect);
9601       }
9602       anArgIter += 1;
9603     }
9604     else if (aChangeArg == "-texname"
9605           || aChangeArg == "texname")
9606     {
9607       if (aNbChangeArgs < 2)
9608       {
9609         Message::SendFail ("Syntax error: need more arguments");
9610         return 1;
9611       }
9612
9613       TCollection_AsciiString aTextureName (aChangeArgs[1]);
9614       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
9615       if (!aTexture->IsDone())
9616       {
9617         aClipPlane->SetCappingTexture (NULL);
9618       }
9619       else
9620       {
9621         aTexture->EnableModulate();
9622         aTexture->EnableRepeat();
9623         aClipPlane->SetCappingTexture (aTexture);
9624       }
9625       anArgIter += 1;
9626     }
9627     else if (aChangeArg == "-texscale"
9628           || aChangeArg == "texscale")
9629     {
9630       if (aClipPlane->CappingTexture().IsNull())
9631       {
9632         Message::SendFail ("Error: no texture is set");
9633         return 1;
9634       }
9635
9636       if (aNbChangeArgs < 3)
9637       {
9638         Message::SendFail ("Syntax error: need more arguments");
9639         return 1;
9640       }
9641
9642       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9643       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9644       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
9645       anArgIter += 2;
9646     }
9647     else if (aChangeArg == "-texorigin"
9648           || aChangeArg == "texorigin") // texture origin
9649     {
9650       if (aClipPlane->CappingTexture().IsNull())
9651       {
9652         Message::SendFail ("Error: no texture is set");
9653         return 1;
9654       }
9655
9656       if (aNbChangeArgs < 3)
9657       {
9658         Message::SendFail ("Syntax error: need more arguments");
9659         return 1;
9660       }
9661
9662       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9663       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9664
9665       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
9666       anArgIter += 2;
9667     }
9668     else if (aChangeArg == "-texrotate"
9669           || aChangeArg == "texrotate") // texture rotation
9670     {
9671       if (aClipPlane->CappingTexture().IsNull())
9672       {
9673         Message::SendFail ("Error: no texture is set");
9674         return 1;
9675       }
9676
9677       if (aNbChangeArgs < 2)
9678       {
9679         Message::SendFail ("Syntax error: need more arguments");
9680         return 1;
9681       }
9682
9683       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9684       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
9685       anArgIter += 1;
9686     }
9687     else if (aChangeArg == "-hatch"
9688           || aChangeArg == "hatch")
9689     {
9690       if (aNbChangeArgs < 2)
9691       {
9692         Message::SendFail ("Syntax error: need more arguments");
9693         return 1;
9694       }
9695
9696       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
9697       aHatchStr.LowerCase();
9698       if (aHatchStr == "on")
9699       {
9700         aClipPlane->SetCappingHatchOn();
9701       }
9702       else if (aHatchStr == "off")
9703       {
9704         aClipPlane->SetCappingHatchOff();
9705       }
9706       else
9707       {
9708         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
9709       }
9710       anArgIter += 1;
9711     }
9712     else if (aChangeArg == "-delete"
9713           || aChangeArg == "delete")
9714     {
9715       removePlane (aRegPlanes, aPlaneName);
9716       return 0;
9717     }
9718     else if (aChangeArg == "-set"
9719           || aChangeArg == "-unset"
9720           || aChangeArg == "-setoverrideglobal")
9721     {
9722       // set / unset plane command
9723       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
9724       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
9725       Standard_Integer anIt = 1;
9726       for (; anIt < aNbChangeArgs; ++anIt)
9727       {
9728         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
9729         if (anEntityName.IsEmpty()
9730          || anEntityName.Value (1) == '-')
9731         {
9732           break;
9733         }
9734         else if (!toOverrideGlobal
9735                && ViewerTest_myViews.IsBound1 (anEntityName))
9736         {
9737           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
9738           if (toSet)
9739           {
9740             aView->AddClipPlane (aClipPlane);
9741           }
9742           else
9743           {
9744             aView->RemoveClipPlane (aClipPlane);
9745           }
9746           continue;
9747         }
9748         else if (GetMapOfAIS().IsBound2 (anEntityName))
9749         {
9750           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
9751           if (toSet)
9752           {
9753             aIObj->AddClipPlane (aClipPlane);
9754           }
9755           else
9756           {
9757             aIObj->RemoveClipPlane (aClipPlane);
9758           }
9759           if (!aIObj->ClipPlanes().IsNull())
9760           {
9761             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
9762           }
9763         }
9764         else
9765         {
9766           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
9767           return 1;
9768         }
9769       }
9770
9771       if (anIt == 1)
9772       {
9773         // apply to active view
9774         if (toSet)
9775         {
9776           anActiveView->AddClipPlane (aClipPlane);
9777         }
9778         else
9779         {
9780           anActiveView->RemoveClipPlane (aClipPlane);
9781         }
9782       }
9783       else
9784       {
9785         anArgIter = anArgIter + anIt - 1;
9786       }
9787     }
9788     else
9789     {
9790       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9791       return 1;
9792     }
9793   }
9794
9795   ViewerTest::RedrawAllViews();
9796   return 0;
9797 }
9798
9799 //===============================================================================================
9800 //function : VZRange
9801 //purpose  :
9802 //===============================================================================================
9803 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9804 {
9805   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9806
9807   if (aCurrentView.IsNull())
9808   {
9809     Message::SendFail ("Error: no active viewer");
9810     return 1;
9811   }
9812
9813   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
9814
9815   if (theArgsNb < 2)
9816   {
9817     theDi << "ZNear: " << aCamera->ZNear() << "\n";
9818     theDi << "ZFar: " << aCamera->ZFar() << "\n";
9819     return 0;
9820   }
9821
9822   if (theArgsNb == 3)
9823   {
9824     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
9825     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
9826
9827     if (aNewZNear >= aNewZFar)
9828     {
9829       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
9830       return 1;
9831     }
9832
9833     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
9834     {
9835       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
9836       return 1;
9837     }
9838
9839     aCamera->SetZRange (aNewZNear, aNewZFar);
9840   }
9841   else
9842   {
9843     Message::SendFail ("Syntax error: wrong command arguments");
9844     return 1;
9845   }
9846
9847   aCurrentView->Redraw();
9848
9849   return 0;
9850 }
9851
9852 //===============================================================================================
9853 //function : VAutoZFit
9854 //purpose  :
9855 //===============================================================================================
9856 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9857 {
9858   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9859
9860   if (aCurrentView.IsNull())
9861   {
9862     Message::SendFail ("Error: no active viewer");
9863     return 1;
9864   }
9865
9866   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
9867
9868   if (theArgsNb > 3)
9869   {
9870     Message::SendFail ("Syntax error: wrong command arguments");
9871     return 1;
9872   }
9873
9874   if (theArgsNb < 2)
9875   {
9876     theDi << "Auto z-fit mode: \n"
9877           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
9878           << "Scale: " << aScale << "\n";
9879     return 0;
9880   }
9881
9882   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
9883
9884   if (theArgsNb >= 3)
9885   {
9886     aScale = Draw::Atoi (theArgVec[2]);
9887   }
9888
9889   aCurrentView->SetAutoZFitMode (isOn, aScale);
9890   aCurrentView->Redraw();
9891   return 0;
9892 }
9893
9894 //! Auxiliary function to print projection type
9895 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
9896 {
9897   switch (theProjType)
9898   {
9899     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
9900     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
9901     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
9902     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
9903     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
9904   }
9905   return "UNKNOWN";
9906 }
9907
9908 //===============================================================================================
9909 //function : VCamera
9910 //purpose  :
9911 //===============================================================================================
9912 static int VCamera (Draw_Interpretor& theDI,
9913                     Standard_Integer  theArgsNb,
9914                     const char**      theArgVec)
9915 {
9916   Handle(V3d_View) aView = ViewerTest::CurrentView();
9917   if (aView.IsNull())
9918   {
9919     Message::SendFail ("Error: no active viewer");
9920     return 1;
9921   }
9922
9923   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9924   if (theArgsNb < 2)
9925   {
9926     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
9927     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
9928     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
9929     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
9930     theDI << "Distance:   " << aCamera->Distance() << "\n";
9931     theDI << "IOD:        " << aCamera->IOD() << "\n";
9932     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
9933     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
9934     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
9935     return 0;
9936   }
9937
9938   TCollection_AsciiString aPrsName;
9939   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9940   {
9941     Standard_CString        anArg = theArgVec[anArgIter];
9942     TCollection_AsciiString anArgCase (anArg);
9943     anArgCase.LowerCase();
9944     if (anArgCase == "-proj"
9945      || anArgCase == "-projection"
9946      || anArgCase == "-projtype"
9947      || anArgCase == "-projectiontype")
9948     {
9949       theDI << projTypeName (aCamera->ProjectionType()) << " ";
9950     }
9951     else if (anArgCase == "-ortho"
9952           || anArgCase == "-orthographic")
9953     {
9954       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
9955     }
9956     else if (anArgCase == "-persp"
9957           || anArgCase == "-perspective"
9958           || anArgCase == "-perspmono"
9959           || anArgCase == "-perspectivemono"
9960           || anArgCase == "-mono")
9961     {
9962       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
9963     }
9964     else if (anArgCase == "-stereo"
9965           || anArgCase == "-stereoscopic"
9966           || anArgCase == "-perspstereo"
9967           || anArgCase == "-perspectivestereo")
9968     {
9969       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
9970     }
9971     else if (anArgCase == "-left"
9972           || anArgCase == "-lefteye"
9973           || anArgCase == "-monoleft"
9974           || anArgCase == "-monolefteye"
9975           || anArgCase == "-perpsleft"
9976           || anArgCase == "-perpslefteye")
9977     {
9978       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
9979     }
9980     else if (anArgCase == "-right"
9981           || anArgCase == "-righteye"
9982           || anArgCase == "-monoright"
9983           || anArgCase == "-monorighteye"
9984           || anArgCase == "-perpsright")
9985     {
9986       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
9987     }
9988     else if (anArgCase == "-dist"
9989           || anArgCase == "-distance")
9990     {
9991       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
9992       if (anArgValue != NULL
9993       && *anArgValue != '-')
9994       {
9995         ++anArgIter;
9996         aCamera->SetDistance (Draw::Atof (anArgValue));
9997         continue;
9998       }
9999       theDI << aCamera->Distance() << " ";
10000     }
10001     else if (anArgCase == "-iod")
10002     {
10003       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10004       if (anArgValue != NULL
10005       && *anArgValue != '-')
10006       {
10007         ++anArgIter;
10008         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
10009         continue;
10010       }
10011       theDI << aCamera->IOD() << " ";
10012     }
10013     else if (anArgCase == "-iodtype")
10014     {
10015       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10016       TCollection_AsciiString anValueCase (anArgValue);
10017       anValueCase.LowerCase();
10018       if (anValueCase == "abs"
10019        || anValueCase == "absolute")
10020       {
10021         ++anArgIter;
10022         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
10023         continue;
10024       }
10025       else if (anValueCase == "rel"
10026             || anValueCase == "relative")
10027       {
10028         ++anArgIter;
10029         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
10030         continue;
10031       }
10032       else if (*anArgValue != '-')
10033       {
10034         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
10035         return 1;
10036       }
10037       switch (aCamera->GetIODType())
10038       {
10039         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
10040         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
10041       }
10042     }
10043     else if (anArgCase == "-zfocus")
10044     {
10045       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10046       if (anArgValue != NULL
10047       && *anArgValue != '-')
10048       {
10049         ++anArgIter;
10050         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
10051         continue;
10052       }
10053       theDI << aCamera->ZFocus() << " ";
10054     }
10055     else if (anArgCase == "-zfocustype")
10056     {
10057       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10058       TCollection_AsciiString anValueCase (anArgValue);
10059       anValueCase.LowerCase();
10060       if (anValueCase == "abs"
10061        || anValueCase == "absolute")
10062       {
10063         ++anArgIter;
10064         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
10065         continue;
10066       }
10067       else if (anValueCase == "rel"
10068             || anValueCase == "relative")
10069       {
10070         ++anArgIter;
10071         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
10072         continue;
10073       }
10074       else if (*anArgValue != '-')
10075       {
10076         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
10077         return 1;
10078       }
10079       switch (aCamera->ZFocusType())
10080       {
10081         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
10082         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
10083       }
10084     }
10085     else if (anArgCase == "-lockzup"
10086           || anArgCase == "-turntable")
10087     {
10088       bool toLockUp = true;
10089       if (++anArgIter < theArgsNb
10090       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toLockUp))
10091       {
10092         --anArgIter;
10093       }
10094       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
10095     }
10096     else if (anArgCase == "-fov"
10097           || anArgCase == "-fovy"
10098           || anArgCase == "-fovx"
10099           || anArgCase == "-fov2d")
10100     {
10101       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10102       if (anArgValue != NULL
10103       && *anArgValue != '-')
10104       {
10105         ++anArgIter;
10106         if (anArgCase == "-fov2d")
10107         {
10108           aCamera->SetFOV2d (Draw::Atof (anArgValue));
10109         }
10110         else if (anArgCase == "-fovx")
10111         {
10112           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
10113         }
10114         else
10115         {
10116           aCamera->SetFOVy (Draw::Atof (anArgValue));
10117         }
10118         continue;
10119       }
10120       if (anArgCase == "-fov2d")
10121       {
10122         theDI << aCamera->FOV2d() << " ";
10123       }
10124       else if (anArgCase == "-fovx")
10125       {
10126         theDI << aCamera->FOVx() << " ";
10127       }
10128       else
10129       {
10130         theDI << aCamera->FOVy() << " ";
10131       }
10132     }
10133     else if (anArgIter + 1 < theArgsNb
10134           && anArgCase == "-xrpose")
10135     {
10136       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
10137       anXRArg.LowerCase();
10138       if (anXRArg == "base")
10139       {
10140         aCamera = aView->View()->BaseXRCamera();
10141       }
10142       else if (anXRArg == "head")
10143       {
10144         aCamera = aView->View()->PosedXRCamera();
10145       }
10146       else
10147       {
10148         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
10149         return 1;
10150       }
10151       if (aCamera.IsNull())
10152       {
10153         Message::SendFail() << "Error: undefined XR pose";
10154         return 0;
10155       }
10156       if (aView->AutoZFitMode())
10157       {
10158         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
10159         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
10160         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
10161       }
10162     }
10163     else if (aPrsName.IsEmpty()
10164          && !anArgCase.StartsWith ("-"))
10165     {
10166       aPrsName = anArg;
10167     }
10168     else
10169     {
10170       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
10171       return 1;
10172     }
10173   }
10174
10175   if (aPrsName.IsEmpty()
10176    || theArgsNb > 2)
10177   {
10178     aView->Redraw();
10179   }
10180
10181   if (!aPrsName.IsEmpty())
10182   {
10183     Handle(AIS_CameraFrustum) aCameraFrustum;
10184     if (GetMapOfAIS().IsBound2 (aPrsName))
10185     {
10186       // find existing object
10187       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
10188       if (aCameraFrustum.IsNull())
10189       {
10190         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
10191         return 1;
10192       }
10193     }
10194
10195     if (aCameraFrustum.IsNull())
10196     {
10197       aCameraFrustum = new AIS_CameraFrustum();
10198     }
10199     else
10200     {
10201       // not include displayed object of old camera frustum in the new one.
10202       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
10203       aView->ZFitAll();
10204     }
10205     aCameraFrustum->SetCameraFrustum (aCamera);
10206
10207     ViewerTest::Display (aPrsName, aCameraFrustum);
10208   }
10209
10210   return 0;
10211 }
10212
10213 //! Parse stereo output mode
10214 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
10215                                          Graphic3d_StereoMode& theMode)
10216 {
10217   TCollection_AsciiString aFlag (theArg);
10218   aFlag.LowerCase();
10219   if (aFlag == "quadbuffer")
10220   {
10221     theMode = Graphic3d_StereoMode_QuadBuffer;
10222   }
10223   else if (aFlag == "anaglyph")
10224   {
10225     theMode = Graphic3d_StereoMode_Anaglyph;
10226   }
10227   else if (aFlag == "row"
10228         || aFlag == "rowinterlaced")
10229   {
10230     theMode = Graphic3d_StereoMode_RowInterlaced;
10231   }
10232   else if (aFlag == "col"
10233         || aFlag == "colinterlaced"
10234         || aFlag == "columninterlaced")
10235   {
10236     theMode = Graphic3d_StereoMode_ColumnInterlaced;
10237   }
10238   else if (aFlag == "chess"
10239         || aFlag == "chessboard")
10240   {
10241     theMode = Graphic3d_StereoMode_ChessBoard;
10242   }
10243   else if (aFlag == "sbs"
10244         || aFlag == "sidebyside")
10245   {
10246     theMode = Graphic3d_StereoMode_SideBySide;
10247   }
10248   else if (aFlag == "ou"
10249         || aFlag == "overunder")
10250   {
10251     theMode = Graphic3d_StereoMode_OverUnder;
10252   }
10253   else if (aFlag == "pageflip"
10254         || aFlag == "softpageflip")
10255   {
10256     theMode = Graphic3d_StereoMode_SoftPageFlip;
10257   }
10258   else if (aFlag == "openvr"
10259         || aFlag == "vr")
10260   {
10261     theMode = Graphic3d_StereoMode_OpenVR;
10262   }
10263   else
10264   {
10265     return Standard_False;
10266   }
10267   return Standard_True;
10268 }
10269
10270 //! Parse anaglyph filter
10271 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
10272                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
10273 {
10274   TCollection_AsciiString aFlag (theArg);
10275   aFlag.LowerCase();
10276   if (aFlag == "redcyansimple")
10277   {
10278     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10279   }
10280   else if (aFlag == "redcyan"
10281         || aFlag == "redcyanoptimized")
10282   {
10283     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
10284   }
10285   else if (aFlag == "yellowbluesimple")
10286   {
10287     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
10288   }
10289   else if (aFlag == "yellowblue"
10290         || aFlag == "yellowblueoptimized")
10291   {
10292     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
10293   }
10294   else if (aFlag == "greenmagenta"
10295         || aFlag == "greenmagentasimple")
10296   {
10297     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
10298   }
10299   else
10300   {
10301     return Standard_False;
10302   }
10303   return Standard_True;
10304 }
10305
10306 //==============================================================================
10307 //function : VStereo
10308 //purpose  :
10309 //==============================================================================
10310
10311 static int VStereo (Draw_Interpretor& theDI,
10312                     Standard_Integer  theArgNb,
10313                     const char**      theArgVec)
10314 {
10315   Handle(V3d_View) aView = ViewerTest::CurrentView();
10316   if (theArgNb < 2)
10317   {
10318     if (aView.IsNull())
10319     {
10320       Message::SendFail ("Error: no active viewer");
10321       return 0;
10322     }
10323
10324     Standard_Boolean isActive = ViewerTest_myDefaultCaps.contextStereo;
10325     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
10326     if (isActive)
10327     {
10328       TCollection_AsciiString aMode;
10329       switch (aView->RenderingParams().StereoMode)
10330       {
10331         case Graphic3d_StereoMode_QuadBuffer       : aMode = "quadBuffer";       break;
10332         case Graphic3d_StereoMode_RowInterlaced    : aMode = "rowInterlaced";    break;
10333         case Graphic3d_StereoMode_ColumnInterlaced : aMode = "columnInterlaced"; break;
10334         case Graphic3d_StereoMode_ChessBoard       : aMode = "chessBoard";       break;
10335         case Graphic3d_StereoMode_SideBySide       : aMode = "sideBySide";       break;
10336         case Graphic3d_StereoMode_OverUnder        : aMode = "overUnder";        break;
10337         case Graphic3d_StereoMode_SoftPageFlip     : aMode = "softpageflip";     break;
10338         case Graphic3d_StereoMode_OpenVR           : aMode = "openVR";           break;
10339         case Graphic3d_StereoMode_Anaglyph  :
10340           aMode = "anaglyph";
10341           switch (aView->RenderingParams().AnaglyphFilter)
10342           {
10343             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
10344             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
10345             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
10346             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
10347             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
10348             default: break;
10349           }
10350         default: break;
10351       }
10352       theDI << "Mode " << aMode << "\n";
10353     }
10354     return 0;
10355   }
10356
10357   Handle(Graphic3d_Camera) aCamera;
10358   Graphic3d_RenderingParams*   aParams   = NULL;
10359   Graphic3d_StereoMode         aMode     = Graphic3d_StereoMode_QuadBuffer;
10360   if (!aView.IsNull())
10361   {
10362     aParams   = &aView->ChangeRenderingParams();
10363     aMode     = aParams->StereoMode;
10364     aCamera   = aView->Camera();
10365   }
10366
10367   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10368   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10369   {
10370     Standard_CString        anArg = theArgVec[anArgIter];
10371     TCollection_AsciiString aFlag (anArg);
10372     aFlag.LowerCase();
10373     if (anUpdateTool.parseRedrawMode (aFlag))
10374     {
10375       continue;
10376     }
10377     else if (aFlag == "0"
10378           || aFlag == "off")
10379     {
10380       if (++anArgIter < theArgNb)
10381       {
10382         Message::SendFail ("Error: wrong number of arguments");
10383         return 1;
10384       }
10385
10386       if (!aCamera.IsNull()
10387        &&  aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
10388       {
10389         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10390       }
10391       ViewerTest_myDefaultCaps.contextStereo = Standard_False;
10392       return 0;
10393     }
10394     else if (aFlag == "1"
10395           || aFlag == "on")
10396     {
10397       if (++anArgIter < theArgNb)
10398       {
10399         Message::SendFail ("Error: wrong number of arguments");
10400         return 1;
10401       }
10402
10403       if (!aCamera.IsNull())
10404       {
10405         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10406       }
10407       ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10408       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
10409       {
10410         return 0;
10411       }
10412     }
10413     else if (aFlag == "-reverse"
10414           || aFlag == "-reversed"
10415           || aFlag == "-swap")
10416     {
10417       Standard_Boolean toEnable = Standard_True;
10418       if (++anArgIter < theArgNb
10419       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
10420       {
10421         --anArgIter;
10422       }
10423       aParams->ToReverseStereo = toEnable;
10424     }
10425     else if (aFlag == "-noreverse"
10426           || aFlag == "-noswap")
10427     {
10428       Standard_Boolean toDisable = Standard_True;
10429       if (++anArgIter < theArgNb
10430       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toDisable))
10431       {
10432         --anArgIter;
10433       }
10434       aParams->ToReverseStereo = !toDisable;
10435     }
10436     else if (aFlag == "-mode"
10437           || aFlag == "-stereomode")
10438     {
10439       if (++anArgIter >= theArgNb
10440       || !parseStereoMode (theArgVec[anArgIter], aMode))
10441       {
10442         Message::SendFail() << "Syntax error at '" << anArg << "'";
10443         return 1;
10444       }
10445
10446       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10447       {
10448         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10449       }
10450     }
10451     else if (aFlag == "-anaglyph"
10452           || aFlag == "-anaglyphfilter")
10453     {
10454       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10455       if (++anArgIter >= theArgNb
10456       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
10457       {
10458         Message::SendFail() << "Syntax error at '" << anArg << "'";
10459         return 1;
10460       }
10461
10462       aMode = Graphic3d_StereoMode_Anaglyph;
10463       aParams->AnaglyphFilter = aFilter;
10464     }
10465     else if (parseStereoMode (anArg, aMode)) // short syntax
10466     {
10467       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10468       {
10469         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10470       }
10471     }
10472     else if (anArgIter + 1 < theArgNb
10473           && aFlag == "-hmdfov2d")
10474     {
10475       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
10476       if (aParams->HmdFov2d < 10.0f
10477        || aParams->HmdFov2d > 180.0f)
10478       {
10479         Message::SendFail() << "Error: FOV is out of range";
10480         return 1;
10481       }
10482     }
10483     else if (aFlag == "-mirror"
10484           || aFlag == "-mirrorcomposer")
10485     {
10486       Standard_Boolean toEnable = Standard_True;
10487       if (++anArgIter < theArgNb
10488       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
10489       {
10490         --anArgIter;
10491       }
10492       aParams->ToMirrorComposer = toEnable;
10493     }
10494     else if (anArgIter + 1 < theArgNb
10495           && (aFlag == "-unitfactor"
10496            || aFlag == "-unitscale"))
10497     {
10498       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
10499     }
10500     else
10501     {
10502       Message::SendFail() << "Syntax error at '" << anArg << "'";
10503       return 1;
10504     }
10505   }
10506
10507   if (!aView.IsNull())
10508   {
10509     aParams->StereoMode = aMode;
10510     aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10511     if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
10512     {
10513       // initiate implicit continuous rendering
10514       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
10515     }
10516   }
10517   return 0;
10518 }
10519
10520 //===============================================================================================
10521 //function : VDefaults
10522 //purpose  :
10523 //===============================================================================================
10524 static int VDefaults (Draw_Interpretor& theDi,
10525                       Standard_Integer  theArgsNb,
10526                       const char**      theArgVec)
10527 {
10528   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
10529   if (aCtx.IsNull())
10530   {
10531     Message::SendFail ("Error: no active viewer");
10532     return 1;
10533   }
10534
10535   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
10536   if (theArgsNb < 2)
10537   {
10538     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
10539     {
10540       theDi << "DeflType:           relative\n"
10541             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
10542     }
10543     else
10544     {
10545       theDi << "DeflType:           absolute\n"
10546             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
10547     }
10548     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
10549     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
10550     return 0;
10551   }
10552
10553   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
10554   {
10555     TCollection_AsciiString anArg (theArgVec[anArgIter]);
10556     anArg.UpperCase();
10557     if (anArg == "-ABSDEFL"
10558      || anArg == "-ABSOLUTEDEFLECTION"
10559      || anArg == "-DEFL"
10560      || anArg == "-DEFLECTION")
10561     {
10562       if (++anArgIter >= theArgsNb)
10563       {
10564         Message::SendFail() << "Syntax error at " << anArg;
10565         return 1;
10566       }
10567       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
10568       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
10569     }
10570     else if (anArg == "-RELDEFL"
10571           || anArg == "-RELATIVEDEFLECTION"
10572           || anArg == "-DEVCOEFF"
10573           || anArg == "-DEVIATIONCOEFF"
10574           || anArg == "-DEVIATIONCOEFFICIENT")
10575     {
10576       if (++anArgIter >= theArgsNb)
10577       {
10578         Message::SendFail() << "Syntax error at " << anArg;
10579         return 1;
10580       }
10581       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
10582       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
10583     }
10584     else if (anArg == "-ANGDEFL"
10585           || anArg == "-ANGULARDEFL"
10586           || anArg == "-ANGULARDEFLECTION")
10587     {
10588       if (++anArgIter >= theArgsNb)
10589       {
10590         Message::SendFail() << "Syntax error at " << anArg;
10591         return 1;
10592       }
10593       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
10594     }
10595     else if (anArg == "-AUTOTR"
10596           || anArg == "-AUTOTRIANG"
10597           || anArg == "-AUTOTRIANGULATION")
10598     {
10599       ++anArgIter;
10600       bool toTurnOn = true;
10601       if (anArgIter >= theArgsNb
10602       || !ViewerTest::ParseOnOff (theArgVec[anArgIter], toTurnOn))
10603       {
10604         Message::SendFail() << "Syntax error at '" << anArg << "'";
10605         return 1;
10606       }
10607       aDefParams->SetAutoTriangulation (toTurnOn);
10608     }
10609     else
10610     {
10611       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
10612       return 1;
10613     }
10614   }
10615
10616   return 0;
10617 }
10618
10619 //! Auxiliary method
10620 inline void addLight (const Handle(V3d_Light)& theLightNew,
10621                       const Graphic3d_ZLayerId theLayer,
10622                       const Standard_Boolean   theIsGlobal)
10623 {
10624   if (theLightNew.IsNull())
10625   {
10626     return;
10627   }
10628
10629   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10630   if (theLayer == Graphic3d_ZLayerId_UNKNOWN)
10631   {
10632     aViewer->AddLight (theLightNew);
10633     if (theIsGlobal)
10634     {
10635       aViewer->SetLightOn (theLightNew);
10636     }
10637     else
10638     {
10639       ViewerTest::CurrentView()->SetLightOn (theLightNew);
10640     }
10641   }
10642   else
10643   {
10644     Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (theLayer);
10645     if (aSettings.Lights().IsNull())
10646     {
10647       aSettings.SetLights (new Graphic3d_LightSet());
10648     }
10649     aSettings.Lights()->Add (theLightNew);
10650     aViewer->SetZLayerSettings (theLayer, aSettings);
10651   }
10652 }
10653
10654 //! Auxiliary method
10655 inline Standard_Integer getLightId (const TCollection_AsciiString& theArgNext)
10656 {
10657   TCollection_AsciiString anArgNextCase (theArgNext);
10658   anArgNextCase.UpperCase();
10659   if (anArgNextCase.Length() > 5
10660    && anArgNextCase.SubString (1, 5).IsEqual ("LIGHT"))
10661   {
10662     return theArgNext.SubString (6, theArgNext.Length()).IntegerValue();
10663   }
10664   else
10665   {
10666     return theArgNext.IntegerValue();
10667   }
10668 }
10669
10670 //===============================================================================================
10671 //function : VLight
10672 //purpose  :
10673 //===============================================================================================
10674 static int VLight (Draw_Interpretor& theDi,
10675                    Standard_Integer  theArgsNb,
10676                    const char**      theArgVec)
10677 {
10678   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
10679   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10680   if (aView.IsNull()
10681    || aViewer.IsNull())
10682   {
10683     Message::SendFail ("Error: no active viewer");
10684     return 1;
10685   }
10686
10687   Standard_Real anXYZ[3]   = {};
10688   Standard_Real anAtten[2] = {};
10689   if (theArgsNb < 2)
10690   {
10691     // print lights info
10692     Standard_Integer aLightId = 0;
10693     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
10694     {
10695       Handle(V3d_Light) aLight = aLightIter.Value();
10696       const Quantity_Color aColor = aLight->Color();
10697       theDi << "Light #" << aLightId
10698             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
10699             << " [" << aLight->GetId() << "]" << "\n";
10700       switch (aLight->Type())
10701       {
10702         case V3d_AMBIENT:
10703         {
10704           theDi << "  Type:       Ambient\n";
10705           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10706           break;
10707         }
10708         case V3d_DIRECTIONAL:
10709         {
10710           theDi << "  Type:       Directional\n";
10711           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10712           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10713           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10714           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10715           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10716           break;
10717         }
10718         case V3d_POSITIONAL:
10719         {
10720           theDi << "  Type:       Positional\n";
10721           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10722           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10723           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10724           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10725           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10726           aLight->Attenuation (anAtten[0], anAtten[1]);
10727           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10728           theDi << "  Range:      " << aLight->Range() << "\n";
10729           break;
10730         }
10731         case V3d_SPOT:
10732         {
10733           theDi << "  Type:       Spot\n";
10734           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10735           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10736           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10737           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10738           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10739           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10740           aLight->Attenuation (anAtten[0], anAtten[1]);
10741           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10742           theDi << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n";
10743           theDi << "  Exponent:   " << aLight->Concentration() << "\n";
10744           theDi << "  Range:      " << aLight->Range() << "\n";
10745           break;
10746         }
10747         default:
10748         {
10749           theDi << "  Type:       UNKNOWN\n";
10750           break;
10751         }
10752       }
10753       theDi << "  Color:      " << aColor.Red() << ", " << aColor.Green() << ", " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
10754     }
10755   }
10756
10757   Handle(V3d_Light) aLightNew;
10758   Handle(V3d_Light) aLightOld;
10759   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
10760   Standard_Boolean  isGlobal = Standard_True;
10761   Standard_Boolean  toCreate = Standard_False;
10762   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10763   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
10764   {
10765     Handle(V3d_Light) aLightCurr = aLightNew.IsNull() ? aLightOld : aLightNew;
10766
10767     TCollection_AsciiString aName, aValue;
10768     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
10769     TCollection_AsciiString anArgCase (anArg);
10770     anArgCase.UpperCase();
10771     if (anUpdateTool.parseRedrawMode (anArg))
10772     {
10773       continue;
10774     }
10775
10776     if (anArgCase.IsEqual ("NEW")
10777      || anArgCase.IsEqual ("ADD")
10778      || anArgCase.IsEqual ("CREATE")
10779      || anArgCase.IsEqual ("-NEW")
10780      || anArgCase.IsEqual ("-ADD")
10781      || anArgCase.IsEqual ("-CREATE"))
10782     {
10783       toCreate = Standard_True;
10784     }
10785     else if (anArgCase.IsEqual ("-LAYER")
10786           || anArgCase.IsEqual ("-ZLAYER"))
10787     {
10788       if (++anArgIt >= theArgsNb)
10789       {
10790         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10791         return 1;
10792       }
10793
10794       TCollection_AsciiString aValStr (theArgVec[anArgIt]);
10795       aValStr.LowerCase();
10796       if (aValStr == "default"
10797        || aValStr == "def")
10798       {
10799         aLayer = Graphic3d_ZLayerId_Default;
10800       }
10801       else if (aValStr == "top")
10802       {
10803         aLayer = Graphic3d_ZLayerId_Top;
10804       }
10805       else if (aValStr == "topmost")
10806       {
10807         aLayer = Graphic3d_ZLayerId_Topmost;
10808       }
10809       else if (aValStr == "toposd"
10810             || aValStr == "osd")
10811       {
10812         aLayer = Graphic3d_ZLayerId_TopOSD;
10813       }
10814       else if (aValStr == "botosd"
10815             || aValStr == "bottom")
10816       {
10817         aLayer = Graphic3d_ZLayerId_BotOSD;
10818       }
10819       else if (aValStr.IsIntegerValue())
10820       {
10821         aLayer = Draw::Atoi (theArgVec[anArgIt]);
10822       }
10823       else
10824       {
10825         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10826         return 1;
10827       }
10828     }
10829     else if (anArgCase.IsEqual ("GLOB")
10830           || anArgCase.IsEqual ("GLOBAL")
10831           || anArgCase.IsEqual ("-GLOB")
10832           || anArgCase.IsEqual ("-GLOBAL"))
10833     {
10834       isGlobal = Standard_True;
10835     }
10836     else if (anArgCase.IsEqual ("LOC")
10837           || anArgCase.IsEqual ("LOCAL")
10838           || anArgCase.IsEqual ("-LOC")
10839           || anArgCase.IsEqual ("-LOCAL"))
10840     {
10841       isGlobal = Standard_False;
10842     }
10843     else if (anArgCase.IsEqual ("DEF")
10844           || anArgCase.IsEqual ("DEFAULTS")
10845           || anArgCase.IsEqual ("-DEF")
10846           || anArgCase.IsEqual ("-DEFAULTS"))
10847     {
10848       toCreate = Standard_False;
10849       aViewer->SetDefaultLights();
10850     }
10851     else if (anArgCase.IsEqual ("CLR")
10852           || anArgCase.IsEqual ("CLEAR")
10853           || anArgCase.IsEqual ("-CLR")
10854           || anArgCase.IsEqual ("-CLEAR"))
10855     {
10856       toCreate = Standard_False;
10857
10858       TColStd_SequenceOfInteger aLayers;
10859       aViewer->GetAllZLayers (aLayers);
10860       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10861       {
10862         if (aLayeriter.Value() == aLayer
10863          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10864         {
10865           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10866           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10867           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10868           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10869           {
10870             break;
10871           }
10872         }
10873       }
10874
10875       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10876       {
10877         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10878         {
10879           Handle(V3d_Light) aLight = aLightIter.Value();
10880           aViewer->DelLight (aLight);
10881           aLightIter = aView->ActiveLightIterator();
10882         }
10883       }
10884     }
10885     else if (anArgCase.IsEqual ("AMB")
10886           || anArgCase.IsEqual ("AMBIENT")
10887           || anArgCase.IsEqual ("AMBLIGHT"))
10888     {
10889       if (!toCreate)
10890       {
10891         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10892         return 1;
10893       }
10894
10895       addLight (aLightNew, aLayer, isGlobal);
10896       toCreate  = Standard_False;
10897       aLightNew = new V3d_AmbientLight();
10898     }
10899     else if (anArgCase.IsEqual ("DIRECTIONAL")
10900           || anArgCase.IsEqual ("DIRLIGHT"))
10901     {
10902       if (!toCreate)
10903       {
10904         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10905         return 1;
10906       }
10907
10908       addLight (aLightNew, aLayer, isGlobal);
10909       toCreate  = Standard_False;
10910       aLightNew = new V3d_DirectionalLight();
10911     }
10912     else if (anArgCase.IsEqual ("SPOT")
10913           || anArgCase.IsEqual ("SPOTLIGHT"))
10914     {
10915       if (!toCreate)
10916       {
10917         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10918         return 1;
10919       }
10920
10921       addLight (aLightNew, aLayer, isGlobal);
10922       toCreate  = Standard_False;
10923       aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
10924     }
10925     else if (anArgCase.IsEqual ("POSLIGHT")
10926           || anArgCase.IsEqual ("POSITIONAL"))
10927     {
10928       if (!toCreate)
10929       {
10930         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10931         return 1;
10932       }
10933
10934       addLight (aLightNew, aLayer, isGlobal);
10935       toCreate  = Standard_False;
10936       aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
10937     }
10938     else if (anArgCase.IsEqual ("CHANGE")
10939           || anArgCase.IsEqual ("-CHANGE"))
10940     {
10941       if (++anArgIt >= theArgsNb)
10942       {
10943         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10944         return 1;
10945       }
10946
10947       addLight (aLightNew, aLayer, isGlobal);
10948       aLightNew.Nullify();
10949       const Standard_Integer aLightId = getLightId (theArgVec[anArgIt]);
10950       Standard_Integer aLightIt = 0;
10951       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
10952       {
10953         if (aLightIt == aLightId)
10954         {
10955           aLightOld = aLightIter.Value();
10956           break;
10957         }
10958       }
10959
10960       if (aLightOld.IsNull())
10961       {
10962         Message::SendFail() << "Error: Light " << theArgVec[anArgIt] << " is undefined";
10963         return 1;
10964       }
10965     }
10966     else if (anArgCase.IsEqual ("DEL")
10967           || anArgCase.IsEqual ("DELETE")
10968           || anArgCase.IsEqual ("-DEL")
10969           || anArgCase.IsEqual ("-DELETE"))
10970     {
10971       Handle(V3d_Light) aLightDel;
10972       if (++anArgIt >= theArgsNb)
10973       {
10974         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10975         return 1;
10976       }
10977
10978       const TCollection_AsciiString anArgNext (theArgVec[anArgIt]);
10979       const Standard_Integer aLightDelId = getLightId (theArgVec[anArgIt]);
10980       Standard_Integer aLightIt = 0;
10981       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
10982       {
10983         aLightDel = aLightIter.Value();
10984         if (aLightIt == aLightDelId)
10985         {
10986           break;
10987         }
10988       }
10989       if (aLightDel.IsNull())
10990       {
10991         continue;
10992       }
10993
10994       TColStd_SequenceOfInteger aLayers;
10995       aViewer->GetAllZLayers (aLayers);
10996       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10997       {
10998         if (aLayeriter.Value() == aLayer
10999          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
11000         {
11001           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
11002           if (!aSettings.Lights().IsNull())
11003           {
11004             aSettings.Lights()->Remove (aLightDel);
11005             if (aSettings.Lights()->IsEmpty())
11006             {
11007               aSettings.SetLights (Handle(Graphic3d_LightSet)());
11008             }
11009           }
11010           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
11011           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
11012           {
11013             break;
11014           }
11015         }
11016       }
11017
11018       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
11019       {
11020         aViewer->DelLight (aLightDel);
11021       }
11022     }
11023     else if (anArgCase.IsEqual ("COLOR")
11024           || anArgCase.IsEqual ("COLOUR")
11025           || anArgCase.IsEqual ("-COLOR")
11026           || anArgCase.IsEqual ("-COLOUR"))
11027     {
11028       if (++anArgIt >= theArgsNb
11029        || aLightCurr.IsNull())
11030       {
11031         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11032         return 1;
11033       }
11034
11035       TCollection_AsciiString anArgNext (theArgVec[anArgIt]);
11036       anArgNext.UpperCase();
11037       const Quantity_Color aColor = ViewerTest::GetColorFromName (anArgNext.ToCString());
11038       aLightCurr->SetColor (aColor);
11039     }
11040     else if (anArgCase.IsEqual ("POS")
11041           || anArgCase.IsEqual ("POSITION")
11042           || anArgCase.IsEqual ("-POS")
11043           || anArgCase.IsEqual ("-POSITION"))
11044     {
11045       if ((anArgIt + 3) >= theArgsNb
11046        || aLightCurr.IsNull()
11047        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11048         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11049       {
11050         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11051         return 1;
11052       }
11053
11054       anXYZ[0] = Atof (theArgVec[++anArgIt]);
11055       anXYZ[1] = Atof (theArgVec[++anArgIt]);
11056       anXYZ[2] = Atof (theArgVec[++anArgIt]);
11057       aLightCurr->SetPosition (anXYZ[0], anXYZ[1], anXYZ[2]);
11058     }
11059     else if (anArgCase.IsEqual ("DIR")
11060           || anArgCase.IsEqual ("DIRECTION")
11061           || anArgCase.IsEqual ("-DIR")
11062           || anArgCase.IsEqual ("-DIRECTION"))
11063     {
11064       if ((anArgIt + 3) >= theArgsNb
11065        || aLightCurr.IsNull()
11066        || (aLightCurr->Type() != Graphic3d_TOLS_DIRECTIONAL
11067         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11068       {
11069         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11070         return 1;
11071       }
11072
11073       anXYZ[0] = Atof (theArgVec[++anArgIt]);
11074       anXYZ[1] = Atof (theArgVec[++anArgIt]);
11075       anXYZ[2] = Atof (theArgVec[++anArgIt]);
11076       aLightCurr->SetDirection (anXYZ[0], anXYZ[1], anXYZ[2]);
11077     }
11078     else if (anArgCase.IsEqual ("SM")
11079           || anArgCase.IsEqual ("SMOOTHNESS")
11080           || anArgCase.IsEqual ("-SM")
11081           || anArgCase.IsEqual ("-SMOOTHNESS"))
11082     {
11083       if (++anArgIt >= theArgsNb
11084        || aLightCurr.IsNull())
11085       {
11086         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11087         return 1;
11088       }
11089
11090       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11091       if (Abs (aSmoothness) <= ShortRealEpsilon())
11092       {
11093         aLightCurr->SetIntensity (1.f);
11094       }
11095       else if (Abs (aLightCurr->Smoothness()) <= ShortRealEpsilon())
11096       {
11097         aLightCurr->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
11098       }
11099       else
11100       {
11101         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightCurr->Smoothness());
11102         aLightCurr->SetIntensity (aLightCurr->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
11103       }
11104
11105       if (aLightCurr->Type() == Graphic3d_TOLS_POSITIONAL)
11106       {
11107         aLightCurr->SetSmoothRadius (aSmoothness);
11108       }
11109       else if (aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11110       {
11111         aLightCurr->SetSmoothAngle (aSmoothness);
11112       }
11113     }
11114     else if (anArgCase.IsEqual ("INT")
11115           || anArgCase.IsEqual ("INTENSITY")
11116           || anArgCase.IsEqual ("-INT")
11117           || anArgCase.IsEqual ("-INTENSITY"))
11118     {
11119       if (++anArgIt >= theArgsNb
11120        || aLightCurr.IsNull())
11121       {
11122         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11123         return 1;
11124       }
11125
11126       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11127       aLightCurr->SetIntensity (aIntensity);
11128     }
11129     else if (anArgCase.IsEqual ("ANG")
11130           || anArgCase.IsEqual ("ANGLE")
11131           || anArgCase.IsEqual ("-ANG")
11132           || anArgCase.IsEqual ("-ANGLE"))
11133     {
11134       if (++anArgIt >= theArgsNb
11135        || aLightCurr.IsNull()
11136        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11137       {
11138         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11139         return 1;
11140       }
11141
11142       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11143       aLightCurr->SetAngle (Standard_ShortReal (anAngle / 180.0 * M_PI));
11144     }
11145     else if (anArgCase.IsEqual ("CONSTATTEN")
11146           || anArgCase.IsEqual ("CONSTATTENUATION")
11147           || anArgCase.IsEqual ("-CONSTATTEN")
11148           || anArgCase.IsEqual ("-CONSTATTENUATION"))
11149     {
11150       if (++anArgIt >= theArgsNb
11151        || aLightCurr.IsNull()
11152        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11153         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11154       {
11155         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11156         return 1;
11157       }
11158
11159       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11160       anAtten[0] = Atof (theArgVec[anArgIt]);
11161       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11162     }
11163     else if (anArgCase.IsEqual ("LINATTEN")
11164           || anArgCase.IsEqual ("LINEARATTEN")
11165           || anArgCase.IsEqual ("LINEARATTENUATION")
11166           || anArgCase.IsEqual ("-LINATTEN")
11167           || anArgCase.IsEqual ("-LINEARATTEN")
11168           || anArgCase.IsEqual ("-LINEARATTENUATION"))
11169     {
11170       if (++anArgIt >= theArgsNb
11171        || aLightCurr.IsNull()
11172        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11173         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11174       {
11175         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11176         return 1;
11177       }
11178
11179       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11180       anAtten[1] = Atof (theArgVec[anArgIt]);
11181       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11182     }
11183     else if (anArgCase.IsEqual ("EXP")
11184           || anArgCase.IsEqual ("EXPONENT")
11185           || anArgCase.IsEqual ("SPOTEXP")
11186           || anArgCase.IsEqual ("SPOTEXPONENT")
11187           || anArgCase.IsEqual ("-EXP")
11188           || anArgCase.IsEqual ("-EXPONENT")
11189           || anArgCase.IsEqual ("-SPOTEXP")
11190           || anArgCase.IsEqual ("-SPOTEXPONENT"))
11191     {
11192       if (++anArgIt >= theArgsNb
11193        || aLightCurr.IsNull()
11194        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11195       {
11196         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11197         return 1;
11198       }
11199
11200       aLightCurr->SetConcentration ((Standard_ShortReal )Atof (theArgVec[anArgIt]));
11201     }
11202     else if (anArgCase.IsEqual("RANGE")
11203           || anArgCase.IsEqual("-RANGE"))
11204     {
11205       if (++anArgIt >= theArgsNb
11206        || aLightCurr.IsNull()
11207        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT
11208        || aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11209       {
11210         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11211         return 1;
11212       }
11213
11214       aLightCurr->SetRange ((Standard_ShortReal)Atof (theArgVec[anArgIt]));
11215     }
11216     else if (anArgCase.IsEqual ("HEAD")
11217           || anArgCase.IsEqual ("HEADLIGHT")
11218           || anArgCase.IsEqual ("-HEAD")
11219           || anArgCase.IsEqual ("-HEADLIGHT"))
11220     {
11221       if (aLightCurr.IsNull()
11222        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
11223       {
11224         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11225         return 1;
11226       }
11227
11228       Standard_Boolean isHeadLight = Standard_True;
11229       if (anArgIt + 1 < theArgsNb
11230        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
11231       {
11232         ++anArgIt;
11233       }
11234       aLightCurr->SetHeadlight (isHeadLight);
11235     }
11236     else
11237     {
11238       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
11239     }
11240   }
11241
11242   addLight (aLightNew, aLayer, isGlobal);
11243   return 0;
11244 }
11245
11246 //===============================================================================================
11247 //function : VPBREnvironment
11248 //purpose  :
11249 //===============================================================================================
11250 static int VPBREnvironment (Draw_Interpretor&,
11251                             Standard_Integer theArgsNb,
11252                             const char**     theArgVec)
11253 {
11254   if (theArgsNb > 2)
11255   {
11256     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
11257     return 1;
11258   }
11259
11260   Handle(V3d_View) aView = ViewerTest::CurrentView();
11261   if (aView.IsNull())
11262   {
11263     Message::SendFail ("Error: no active viewer");
11264     return 1;
11265   }
11266
11267   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
11268   anArg.LowerCase();
11269
11270   if (anArg == "-generate"
11271    || anArg == "-gen")
11272   {
11273     aView->GeneratePBREnvironment (Standard_True);
11274   }
11275   else if (anArg == "-clear")
11276   {
11277     aView->ClearPBREnvironment (Standard_True);
11278   }
11279   else
11280   {
11281     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
11282     return 1;
11283   }
11284
11285   return 0;
11286 }
11287
11288 //! Read Graphic3d_RenderingParams::PerfCounters flag.
11289 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
11290                                             Standard_Boolean& theToReset,
11291                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
11292                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
11293 {
11294   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
11295   TCollection_AsciiString aVal = theValue;
11296   Standard_Boolean toReverse = Standard_False;
11297   if (aVal == "none")
11298   {
11299     theToReset = Standard_True;
11300     return Standard_True;
11301   }
11302   else if (aVal.StartsWith ("-"))
11303   {
11304     toReverse = Standard_True;
11305     aVal = aVal.SubString (2, aVal.Length());
11306   }
11307   else if (aVal.StartsWith ("no"))
11308   {
11309     toReverse = Standard_True;
11310     aVal = aVal.SubString (3, aVal.Length());
11311   }
11312   else if (aVal.StartsWith ("+"))
11313   {
11314     aVal = aVal.SubString (2, aVal.Length());
11315   }
11316   else
11317   {
11318     theToReset = Standard_True;
11319   }
11320
11321   if (     aVal == "fps"
11322         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11323   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
11324   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
11325   else if (aVal == "structs"
11326         || aVal == "structures"
11327         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
11328   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
11329   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
11330   else if (aVal == "tris"
11331         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
11332   else if (aVal == "pnts"
11333         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
11334   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
11335   else if (aVal == "mem"
11336         || aVal == "gpumem"
11337         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
11338   else if (aVal == "skipimmediate"
11339         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
11340   else if (aVal == "frametime"
11341         || aVal == "frametimers"
11342         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
11343   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
11344   else if (aVal == "extended"
11345         || aVal == "verbose"
11346         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
11347   else if (aVal == "full"
11348         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
11349   else
11350   {
11351     return Standard_False;
11352   }
11353
11354   if (toReverse)
11355   {
11356     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
11357   }
11358   else
11359   {
11360     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
11361   }
11362   return Standard_True;
11363 }
11364
11365 //! Read Graphic3d_RenderingParams::PerfCounters flags.
11366 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
11367                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
11368 {
11369   TCollection_AsciiString aValue = theValue;
11370   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
11371   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
11372   Standard_Boolean toReset = Standard_False;
11373   for (;;)
11374   {
11375     Standard_Integer aSplitPos = aValue.Search ("|");
11376     if (aSplitPos <= 0)
11377     {
11378       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
11379       {
11380         return Standard_False;
11381       }
11382       if (toReset)
11383       {
11384         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
11385       }
11386       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
11387       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
11388       return Standard_True;
11389     }
11390
11391     if (aSplitPos > 1)
11392     {
11393       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
11394       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
11395       {
11396         return Standard_False;
11397       }
11398     }
11399     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
11400   }
11401 }
11402
11403 //=======================================================================
11404 //function : VRenderParams
11405 //purpose  : Enables/disables rendering features
11406 //=======================================================================
11407
11408 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
11409                                        Standard_Integer  theArgNb,
11410                                        const char**      theArgVec)
11411 {
11412   Handle(V3d_View) aView = ViewerTest::CurrentView();
11413   if (aView.IsNull())
11414   {
11415     Message::SendFail ("Error: no active viewer");
11416     return 1;
11417   }
11418
11419   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
11420   TCollection_AsciiString aCmdName (theArgVec[0]);
11421   aCmdName.LowerCase();
11422   if (aCmdName == "vraytrace")
11423   {
11424     if (theArgNb == 1)
11425     {
11426       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
11427       return 0;
11428     }
11429     else if (theArgNb == 2)
11430     {
11431       TCollection_AsciiString aValue (theArgVec[1]);
11432       aValue.LowerCase();
11433       if (aValue == "on"
11434        || aValue == "1")
11435       {
11436         aParams.Method = Graphic3d_RM_RAYTRACING;
11437         aView->Redraw();
11438         return 0;
11439       }
11440       else if (aValue == "off"
11441             || aValue == "0")
11442       {
11443         aParams.Method = Graphic3d_RM_RASTERIZATION;
11444         aView->Redraw();
11445         return 0;
11446       }
11447       else
11448       {
11449         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
11450         return 1;
11451       }
11452     }
11453     else
11454     {
11455       Message::SendFail ("Syntax error: wrong number of arguments");
11456       return 1;
11457     }
11458   }
11459
11460   if (theArgNb < 2)
11461   {
11462     theDI << "renderMode:  ";
11463     switch (aParams.Method)
11464     {
11465       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11466       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
11467     }
11468     theDI << "\n";
11469     theDI << "transparency:  ";
11470     switch (aParams.TransparencyMethod)
11471     {
11472       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
11473       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
11474                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
11475     }
11476     theDI << "\n";
11477     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
11478     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
11479     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
11480     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
11481     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
11482     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
11483     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
11484     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
11485     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
11486     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
11487     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
11488     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
11489     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
11490     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
11491     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
11492     theDI << "shadingModel: ";
11493     switch (aView->ShadingModel())
11494     {
11495       case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
11496       case Graphic3d_TOSM_UNLIT:     theDI << "unlit";     break;
11497       case Graphic3d_TOSM_FACET:     theDI << "flat";      break;
11498       case Graphic3d_TOSM_VERTEX:    theDI << "gouraud";   break;
11499       case Graphic3d_TOSM_FRAGMENT:  theDI << "phong";     break;
11500       case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
11501       case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
11502     }
11503     {
11504       theDI << "perfCounters:";
11505       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
11506       {
11507         theDI << " fps";
11508       }
11509       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
11510       {
11511         theDI << " cpu";
11512       }
11513       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
11514       {
11515         theDI << " structs";
11516       }
11517       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
11518       {
11519         theDI << " groups";
11520       }
11521       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
11522       {
11523         theDI << " arrays";
11524       }
11525       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
11526       {
11527         theDI << " tris";
11528       }
11529       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
11530       {
11531         theDI << " lines";
11532       }
11533       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
11534       {
11535         theDI << " pnts";
11536       }
11537       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
11538       {
11539         theDI << " gpumem";
11540       }
11541       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
11542       {
11543         theDI << " frameTime";
11544       }
11545       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
11546       {
11547         theDI << " skipimmediate";
11548       }
11549       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
11550       {
11551         theDI << " none";
11552       }
11553       theDI << "\n";
11554     }
11555     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
11556     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
11557     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
11558                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
11559                                                                                                                     "noUpdate") << "\n";
11560     theDI << "\n";
11561     return 0;
11562   }
11563
11564   Standard_Boolean toPrint = Standard_False;
11565   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
11566   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11567   {
11568     Standard_CString        anArg (theArgVec[anArgIter]);
11569     TCollection_AsciiString aFlag (anArg);
11570     aFlag.LowerCase();
11571     if (anUpdateTool.parseRedrawMode (aFlag))
11572     {
11573       continue;
11574     }
11575     else if (aFlag == "-echo"
11576           || aFlag == "-print")
11577     {
11578       toPrint = Standard_True;
11579       anUpdateTool.Invalidate();
11580     }
11581     else if (aFlag == "-mode"
11582           || aFlag == "-rendermode"
11583           || aFlag == "-render_mode")
11584     {
11585       if (toPrint)
11586       {
11587         switch (aParams.Method)
11588         {
11589           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11590           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
11591         }
11592         continue;
11593       }
11594       else
11595       {
11596         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11597         return 1;
11598       }
11599     }
11600     else if (aFlag == "-ray"
11601           || aFlag == "-raytrace")
11602     {
11603       if (toPrint)
11604       {
11605         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
11606         continue;
11607       }
11608
11609       aParams.Method = Graphic3d_RM_RAYTRACING;
11610     }
11611     else if (aFlag == "-rast"
11612           || aFlag == "-raster"
11613           || aFlag == "-rasterization")
11614     {
11615       if (toPrint)
11616       {
11617         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
11618         continue;
11619       }
11620
11621       aParams.Method = Graphic3d_RM_RASTERIZATION;
11622     }
11623     else if (aFlag == "-msaa")
11624     {
11625       if (toPrint)
11626       {
11627         theDI << aParams.NbMsaaSamples << " ";
11628         continue;
11629       }
11630       else if (++anArgIter >= theArgNb)
11631       {
11632         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11633         return 1;
11634       }
11635
11636       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11637       if (aNbSamples < 0)
11638       {
11639         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11640         return 1;
11641       }
11642       else
11643       {
11644         aParams.NbMsaaSamples = aNbSamples;
11645       }
11646     }
11647     else if (aFlag == "-linefeather"
11648           || aFlag == "-edgefeather"
11649           || aFlag == "-feather")
11650     {
11651       if (toPrint)
11652       {
11653         theDI << " " << aParams.LineFeather << " ";
11654         continue;
11655       }
11656       else if (++anArgIter >= theArgNb)
11657       {
11658         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11659         return 1;
11660       }
11661
11662       TCollection_AsciiString aParam = theArgVec[anArgIter];
11663       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11664       if (aFeather <= 0.0f)
11665       {
11666         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
11667         return 1;
11668       }
11669       aParams.LineFeather = aFeather;
11670     }
11671     else if (aFlag == "-oit")
11672     {
11673       if (toPrint)
11674       {
11675         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
11676         {
11677           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
11678         }
11679         else
11680         {
11681           theDI << "off" << " ";
11682         }
11683         continue;
11684       }
11685       else if (++anArgIter >= theArgNb)
11686       {
11687         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11688         return 1;
11689       }
11690
11691       TCollection_AsciiString aParam = theArgVec[anArgIter];
11692       aParam.LowerCase();
11693       if (aParam.IsRealValue())
11694       {
11695         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11696         if (aWeight < 0.f || aWeight > 1.f)
11697         {
11698           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11699           return 1;
11700         }
11701
11702         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11703         aParams.OitDepthFactor     = aWeight;
11704       }
11705       else if (aParam == "off")
11706       {
11707         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
11708       }
11709       else
11710       {
11711         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11712         return 1;
11713       }
11714     }
11715     else if (aFlag == "-depthprepass")
11716     {
11717       if (toPrint)
11718       {
11719         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11720         continue;
11721       }
11722       aParams.ToEnableDepthPrepass = Standard_True;
11723       if (anArgIter + 1 < theArgNb
11724        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11725       {
11726         ++anArgIter;
11727       }
11728     }
11729     else if (aFlag == "-samplealphatocoverage"
11730           || aFlag == "-alphatocoverage")
11731     {
11732       if (toPrint)
11733       {
11734         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11735         continue;
11736       }
11737       aParams.ToEnableAlphaToCoverage = Standard_True;
11738       if (anArgIter + 1 < theArgNb
11739        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11740       {
11741         ++anArgIter;
11742       }
11743     }
11744     else if (aFlag == "-rendscale"
11745           || aFlag == "-renderscale"
11746           || aFlag == "-renderresolutionscale")
11747     {
11748       if (toPrint)
11749       {
11750         theDI << aParams.RenderResolutionScale << " ";
11751         continue;
11752       }
11753       else if (++anArgIter >= theArgNb)
11754       {
11755         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11756         return 1;
11757       }
11758
11759       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11760       if (aScale < 0.01)
11761       {
11762         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11763         return 1;
11764       }
11765       else
11766       {
11767         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11768       }
11769     }
11770     else if (aFlag == "-raydepth"
11771           || aFlag == "-ray_depth")
11772     {
11773       if (toPrint)
11774       {
11775         theDI << aParams.RaytracingDepth << " ";
11776         continue;
11777       }
11778       else if (++anArgIter >= theArgNb)
11779       {
11780         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11781         return 1;
11782       }
11783
11784       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11785
11786       // We allow RaytracingDepth be more than 10 in case of GI enabled
11787       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11788       {
11789         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11790         return 1;
11791       }
11792       else
11793       {
11794         aParams.RaytracingDepth = aDepth;
11795       }
11796     }
11797     else if (aFlag == "-shad"
11798           || aFlag == "-shadows")
11799     {
11800       if (toPrint)
11801       {
11802         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11803         continue;
11804       }
11805
11806       Standard_Boolean toEnable = Standard_True;
11807       if (++anArgIter < theArgNb
11808       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11809       {
11810         --anArgIter;
11811       }
11812       aParams.IsShadowEnabled = toEnable;
11813     }
11814     else if (aFlag == "-refl"
11815           || aFlag == "-reflections")
11816     {
11817       if (toPrint)
11818       {
11819         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11820         continue;
11821       }
11822
11823       Standard_Boolean toEnable = Standard_True;
11824       if (++anArgIter < theArgNb
11825       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11826       {
11827         --anArgIter;
11828       }
11829       aParams.IsReflectionEnabled = toEnable;
11830     }
11831     else if (aFlag == "-fsaa")
11832     {
11833       if (toPrint)
11834       {
11835         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11836         continue;
11837       }
11838
11839       Standard_Boolean toEnable = Standard_True;
11840       if (++anArgIter < theArgNb
11841       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11842       {
11843         --anArgIter;
11844       }
11845       aParams.IsAntialiasingEnabled = toEnable;
11846     }
11847     else if (aFlag == "-gleam")
11848     {
11849       if (toPrint)
11850       {
11851         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11852         continue;
11853       }
11854
11855       Standard_Boolean toEnable = Standard_True;
11856       if (++anArgIter < theArgNb
11857       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11858       {
11859         --anArgIter;
11860       }
11861       aParams.IsTransparentShadowEnabled = toEnable;
11862     }
11863     else if (aFlag == "-gi")
11864     {
11865       if (toPrint)
11866       {
11867         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11868         continue;
11869       }
11870
11871       Standard_Boolean toEnable = Standard_True;
11872       if (++anArgIter < theArgNb
11873       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11874       {
11875         --anArgIter;
11876       }
11877       aParams.IsGlobalIlluminationEnabled = toEnable;
11878       if (!toEnable)
11879       {
11880         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11881       }
11882     }
11883     else if (aFlag == "-blockedrng"
11884           || aFlag == "-brng")
11885     {
11886       if (toPrint)
11887       {
11888         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
11889         continue;
11890       }
11891
11892       Standard_Boolean toEnable = Standard_True;
11893       if (++anArgIter < theArgNb
11894         && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11895       {
11896         --anArgIter;
11897       }
11898       aParams.CoherentPathTracingMode = toEnable;
11899     }
11900     else if (aFlag == "-maxrad")
11901     {
11902       if (toPrint)
11903       {
11904         theDI << aParams.RadianceClampingValue << " ";
11905         continue;
11906       }
11907       else if (++anArgIter >= theArgNb)
11908       {
11909         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11910         return 1;
11911       }
11912
11913       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11914       if (!aMaxRadStr.IsRealValue())
11915       {
11916         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11917         return 1;
11918       }
11919
11920       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11921       if (aMaxRadiance <= 0.0)
11922       {
11923         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
11924         return 1;
11925       }
11926       else
11927       {
11928         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
11929       }
11930     }
11931     else if (aFlag == "-iss")
11932     {
11933       if (toPrint)
11934       {
11935         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
11936         continue;
11937       }
11938
11939       Standard_Boolean toEnable = Standard_True;
11940       if (++anArgIter < theArgNb
11941         && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11942       {
11943         --anArgIter;
11944       }
11945       aParams.AdaptiveScreenSampling = toEnable;
11946     }
11947     else if (aFlag == "-issatomic")
11948     {
11949       if (toPrint)
11950       {
11951         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
11952         continue;
11953       }
11954
11955       Standard_Boolean toEnable = Standard_True;
11956       if (++anArgIter < theArgNb
11957       && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11958       {
11959         --anArgIter;
11960       }
11961       aParams.AdaptiveScreenSamplingAtomic = toEnable;
11962     }
11963     else if (aFlag == "-issd")
11964     {
11965       if (toPrint)
11966       {
11967         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
11968         continue;
11969       }
11970
11971       Standard_Boolean toEnable = Standard_True;
11972       if (++anArgIter < theArgNb
11973         && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
11974       {
11975         --anArgIter;
11976       }
11977       aParams.ShowSamplingTiles = toEnable;
11978     }
11979     else if (aFlag == "-tilesize")
11980     {
11981       if (toPrint)
11982       {
11983         theDI << aParams.RayTracingTileSize << " ";
11984         continue;
11985       }
11986       else if (++anArgIter >= theArgNb)
11987       {
11988         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11989         return 1;
11990       }
11991
11992       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
11993       if (aTileSize < 1)
11994       {
11995         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
11996         return 1;
11997       }
11998       aParams.RayTracingTileSize = aTileSize;
11999     }
12000     else if (aFlag == "-nbtiles")
12001     {
12002       if (toPrint)
12003       {
12004         theDI << aParams.NbRayTracingTiles << " ";
12005         continue;
12006       }
12007       else if (++anArgIter >= theArgNb)
12008       {
12009         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12010         return 1;
12011       }
12012
12013       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
12014       if (aNbTiles < -1)
12015       {
12016         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
12017         return 1;
12018       }
12019       else if (aNbTiles > 0
12020             && (aNbTiles < 64
12021              || aNbTiles > 1024))
12022       {
12023         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
12024       }
12025       aParams.NbRayTracingTiles = aNbTiles;
12026     }
12027     else if (aFlag == "-env")
12028     {
12029       if (toPrint)
12030       {
12031         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
12032         continue;
12033       }
12034
12035       Standard_Boolean toEnable = Standard_True;
12036       if (++anArgIter < theArgNb
12037         && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
12038       {
12039         --anArgIter;
12040       }
12041       aParams.UseEnvironmentMapBackground = toEnable;
12042     }
12043     else if (aFlag == "-ignorenormalmap")
12044     {
12045       if (toPrint)
12046       {
12047         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
12048         continue;
12049       }
12050
12051       Standard_Boolean toEnable = Standard_True;
12052       if (++anArgIter < theArgNb
12053         && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
12054       {
12055         --anArgIter;
12056       }
12057       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
12058     }
12059     else if (aFlag == "-twoside")
12060     {
12061       if (toPrint)
12062       {
12063         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
12064         continue;
12065       }
12066
12067       Standard_Boolean toEnable = Standard_True;
12068       if (++anArgIter < theArgNb
12069         && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
12070       {
12071         --anArgIter;
12072       }
12073       aParams.TwoSidedBsdfModels = toEnable;
12074     }
12075     else if (aFlag == "-shademodel"
12076           || aFlag == "-shadingmodel"
12077           || aFlag == "-shading")
12078     {
12079       if (toPrint)
12080       {
12081         switch (aView->ShadingModel())
12082         {
12083           case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
12084           case Graphic3d_TOSM_UNLIT:     theDI << "unlit ";    break;
12085           case Graphic3d_TOSM_FACET:     theDI << "flat ";     break;
12086           case Graphic3d_TOSM_VERTEX:    theDI << "gouraud ";  break;
12087           case Graphic3d_TOSM_FRAGMENT:  theDI << "phong ";    break;
12088           case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
12089           case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
12090         }
12091         continue;
12092       }
12093
12094       if (++anArgIter >= theArgNb)
12095       {
12096         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12097       }
12098
12099       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TOSM_DEFAULT;
12100       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
12101        && aModel != Graphic3d_TOSM_DEFAULT)
12102       {
12103         aView->SetShadingModel (aModel);
12104       }
12105       else
12106       {
12107         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
12108         return 1;
12109       }
12110     }
12111     else if (aFlag == "-pbrenvpow2size"
12112           || aFlag == "-pbrenvp2s"
12113           || aFlag == "-pep2s")
12114     {
12115       if (++anArgIter >= theArgNb)
12116       {
12117         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12118         return 1;
12119       }
12120
12121       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
12122       if (aPbrEnvPow2Size < 1)
12123       {
12124         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
12125         return 1;
12126       }
12127       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
12128     }
12129     else if (aFlag == "-pbrenvspecmaplevelsnumber"
12130           || aFlag == "-pbrenvspecmapnblevels"
12131           || aFlag == "-pbrenvspecmaplevels"
12132           || aFlag == "-pbrenvsmln"
12133           || aFlag == "-pesmln")
12134     {
12135       if (++anArgIter >= theArgNb)
12136       {
12137         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12138         return 1;
12139       }
12140
12141       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
12142       if (aPbrEnvSpecMapNbLevels < 2)
12143       {
12144         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
12145         return 1;
12146       }
12147       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
12148     }
12149     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
12150           || aFlag == "-pbrenvbakingdiffsamples"
12151           || aFlag == "-pbrenvbdsn")
12152     {
12153       if (++anArgIter >= theArgNb)
12154       {
12155         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12156         return 1;
12157       }
12158
12159       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
12160       if (aPbrEnvBakingDiffNbSamples < 1)
12161       {
12162         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environtment has to be greater or equal 1");
12163         return 1;
12164       }
12165       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
12166     }
12167     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
12168           || aFlag == "-pbrenvbakingspecsamples"
12169           || aFlag == "-pbrenvbssn")
12170     {
12171     if (++anArgIter >= theArgNb)
12172     {
12173       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12174       return 1;
12175     }
12176
12177     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
12178     if (aPbrEnvBakingSpecNbSamples < 1)
12179     {
12180       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environtment has to be greater or equal 1");
12181       return 1;
12182     }
12183     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
12184     }
12185     else if (aFlag == "-pbrenvbakingprobability"
12186           || aFlag == "-pbrenvbp")
12187     {
12188       if (++anArgIter >= theArgNb)
12189       {
12190         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12191         return 1;
12192       }
12193       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
12194       if (aPbrEnvBakingProbability < 0.f
12195        || aPbrEnvBakingProbability > 1.f)
12196       {
12197         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environtment has to be in range of [0, 1]");
12198         return 1;
12199       }
12200       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
12201     }
12202     else if (aFlag == "-resolution")
12203     {
12204       if (++anArgIter >= theArgNb)
12205       {
12206         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12207         return 1;
12208       }
12209
12210       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
12211       if (aResolution.IsIntegerValue())
12212       {
12213         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
12214       }
12215       else
12216       {
12217         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
12218         return 1;
12219       }
12220     }
12221     else if (aFlag == "-rebuildglsl"
12222           || aFlag == "-rebuild")
12223     {
12224       if (toPrint)
12225       {
12226         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
12227         continue;
12228       }
12229
12230       Standard_Boolean toEnable = Standard_True;
12231       if (++anArgIter < theArgNb
12232           && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
12233       {
12234         --anArgIter;
12235       }
12236       aParams.RebuildRayTracingShaders = toEnable;
12237     }
12238     else if (aFlag == "-focal")
12239     {
12240       if (++anArgIter >= theArgNb)
12241       {
12242         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12243         return 1;
12244       }
12245
12246       TCollection_AsciiString aParam (theArgVec[anArgIter]);
12247       if (aParam.IsRealValue())
12248       {
12249         float aFocalDist = static_cast<float> (aParam.RealValue());
12250         if (aFocalDist < 0)
12251         {
12252           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12253           return 1;
12254         }
12255         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
12256       }
12257       else
12258       {
12259         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12260         return 1;
12261       }
12262     }
12263     else if (aFlag == "-aperture")
12264     {
12265       if (++anArgIter >= theArgNb)
12266       {
12267         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12268         return 1;
12269       }
12270
12271       TCollection_AsciiString aParam(theArgVec[anArgIter]);
12272       if (aParam.IsRealValue())
12273       {
12274         float aApertureSize = static_cast<float> (aParam.RealValue());
12275         if (aApertureSize < 0)
12276         {
12277           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12278           return 1;
12279         }
12280         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
12281       }
12282       else
12283       {
12284         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12285         return 1;
12286       }
12287     }
12288     else if (aFlag == "-exposure")
12289     {
12290       if (++anArgIter >= theArgNb)
12291       {
12292         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12293         return 1;
12294       }
12295
12296       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
12297       if (anExposure.IsRealValue())
12298       {
12299         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
12300       }
12301       else
12302       {
12303         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12304         return 1;
12305       }
12306     }
12307     else if (aFlag == "-whitepoint")
12308     {
12309       if (++anArgIter >= theArgNb)
12310       {
12311         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12312         return 1;
12313       }
12314
12315       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
12316       if (aWhitePoint.IsRealValue())
12317       {
12318         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
12319       }
12320       else
12321       {
12322         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12323         return 1;
12324       }
12325     }
12326     else if (aFlag == "-tonemapping")
12327     {
12328       if (++anArgIter >= theArgNb)
12329       {
12330         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12331         return 1;
12332       }
12333
12334       TCollection_AsciiString aMode (theArgVec[anArgIter]);
12335       aMode.LowerCase();
12336
12337       if (aMode == "disabled")
12338       {
12339         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
12340       }
12341       else if (aMode == "filmic")
12342       {
12343         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
12344       }
12345       else
12346       {
12347         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12348         return 1;
12349       }
12350     }
12351     else if (aFlag == "-performancestats"
12352           || aFlag == "-performancecounters"
12353           || aFlag == "-perfstats"
12354           || aFlag == "-perfcounters"
12355           || aFlag == "-stats")
12356     {
12357       if (++anArgIter >= theArgNb)
12358       {
12359         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12360         return 1;
12361       }
12362
12363       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
12364       aFlagsStr.LowerCase();
12365       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
12366       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
12367       {
12368         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12369         return 1;
12370       }
12371       aView->ChangeRenderingParams().CollectedStats = aFlags;
12372       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
12373     }
12374     else if (aFlag == "-perfupdateinterval"
12375           || aFlag == "-statsupdateinterval")
12376     {
12377       if (++anArgIter >= theArgNb)
12378       {
12379         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12380         return 1;
12381       }
12382       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12383     }
12384     else if (aFlag == "-perfchart"
12385           || aFlag == "-statschart")
12386     {
12387       if (++anArgIter >= theArgNb)
12388       {
12389         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12390         return 1;
12391       }
12392       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
12393     }
12394     else if (aFlag == "-perfchartmax"
12395           || aFlag == "-statschartmax")
12396     {
12397       if (++anArgIter >= theArgNb)
12398       {
12399         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12400         return 1;
12401       }
12402       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12403     }
12404     else if (aFlag == "-frustumculling"
12405           || aFlag == "-culling")
12406     {
12407       if (toPrint)
12408       {
12409         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
12410                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
12411                                                                                                    "noUpdate") << " ";
12412         continue;
12413       }
12414
12415       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
12416       if (++anArgIter < theArgNb)
12417       {
12418         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
12419         aStateStr.LowerCase();
12420         bool toEnable = true;
12421         if (ViewerTest::ParseOnOff (aStateStr.ToCString(), toEnable))
12422         {
12423           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
12424         }
12425         else if (aStateStr == "noupdate"
12426               || aStateStr == "freeze")
12427         {
12428           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
12429         }
12430         else
12431         {
12432           --anArgIter;
12433         }
12434       }
12435       aParams.FrustumCullingState = aState;
12436     }
12437     else
12438     {
12439       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
12440       return 1;
12441     }
12442   }
12443
12444   return 0;
12445 }
12446
12447 //=======================================================================
12448 //function : searchInfo
12449 //purpose  :
12450 //=======================================================================
12451 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12452                                            const TCollection_AsciiString&              theKey)
12453 {
12454   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12455   {
12456     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12457     {
12458       return anIter.Value();
12459     }
12460   }
12461   return TCollection_AsciiString();
12462 }
12463
12464 //=======================================================================
12465 //function : VStatProfiler
12466 //purpose  :
12467 //=======================================================================
12468 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12469                                        Standard_Integer  theArgNb,
12470                                        const char**      theArgVec)
12471 {
12472   Handle(V3d_View) aView = ViewerTest::CurrentView();
12473   if (aView.IsNull())
12474   {
12475     Message::SendFail ("Error: no active viewer");
12476     return 1;
12477   }
12478
12479   Standard_Boolean toRedraw = Standard_True;
12480   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12481   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12482   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12483   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12484   {
12485     Standard_CString        anArg (theArgVec[anArgIter]);
12486     TCollection_AsciiString aFlag (anArg);
12487     aFlag.LowerCase();
12488     if (aFlag == "-noredraw")
12489     {
12490       toRedraw = Standard_False;
12491     }
12492     else
12493     {
12494       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12495       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12496       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12497       else if (aFlag == "alllayers"
12498             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12499       else if (aFlag == "allstructs"
12500             || aFlag == "allstructures"
12501             || aFlag == "structs"
12502             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12503       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12504       else if (aFlag == "allarrays"
12505             || aFlag == "fillarrays"
12506             || aFlag == "linearrays"
12507             || aFlag == "pointarrays"
12508             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12509       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12510       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12511       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12512       else if (aFlag == "geommem"
12513             || aFlag == "texturemem"
12514             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12515       else if (aFlag == "elapsedframe"
12516             || aFlag == "cpuframeaverage"
12517             || aFlag == "cpupickingaverage"
12518             || aFlag == "cpucullingaverage"
12519             || aFlag == "cpudynaverage"
12520             || aFlag == "cpuframemax"
12521             || aFlag == "cpupickingmax"
12522             || aFlag == "cpucullingmax"
12523             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12524       else
12525       {
12526         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12527         continue;
12528       }
12529
12530       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12531     }
12532   }
12533
12534   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12535   {
12536     aView->ChangeRenderingParams().CollectedStats =
12537       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12538
12539     if (toRedraw)
12540     {
12541       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12542       aView->Redraw();
12543       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12544     }
12545
12546     TColStd_IndexedDataMapOfStringString aDict;
12547     aView->StatisticInformation (aDict);
12548
12549     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12550
12551     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12552     {
12553       Standard_CString        anArg(theArgVec[anArgIter]);
12554       TCollection_AsciiString aFlag(anArg);
12555       aFlag.LowerCase();
12556       if (aFlag == "fps")
12557       {
12558         theDI << searchInfo (aDict, "FPS") << " ";
12559       }
12560       else if (aFlag == "cpu")
12561       {
12562         theDI << searchInfo (aDict, "CPU FPS") << " ";
12563       }
12564       else if (aFlag == "alllayers")
12565       {
12566         theDI << searchInfo (aDict, "Layers") << " ";
12567       }
12568       else if (aFlag == "layers")
12569       {
12570         theDI << searchInfo (aDict, "Rendered layers") << " ";
12571       }
12572       else if (aFlag == "allstructs"
12573             || aFlag == "allstructures")
12574       {
12575         theDI << searchInfo (aDict, "Structs") << " ";
12576       }
12577       else if (aFlag == "structs"
12578             || aFlag == "structures")
12579       {
12580         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
12581         if (aRend.IsEmpty()) // all structures rendered
12582         {
12583           aRend = searchInfo (aDict, "Structs");
12584         }
12585         theDI << aRend << " ";
12586       }
12587       else if (aFlag == "groups")
12588       {
12589         theDI << searchInfo (aDict, "Rendered groups") << " ";
12590       }
12591       else if (aFlag == "allarrays")
12592       {
12593         theDI << searchInfo (aDict, "Rendered arrays") << " ";
12594       }
12595       else if (aFlag == "fillarrays")
12596       {
12597         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
12598       }
12599       else if (aFlag == "linearrays")
12600       {
12601         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
12602       }
12603       else if (aFlag == "pointarrays")
12604       {
12605         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
12606       }
12607       else if (aFlag == "textarrays")
12608       {
12609         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
12610       }
12611       else if (aFlag == "triangles")
12612       {
12613         theDI << searchInfo (aDict, "Rendered triangles") << " ";
12614       }
12615       else if (aFlag == "points")
12616       {
12617         theDI << searchInfo (aDict, "Rendered points") << " ";
12618       }
12619       else if (aFlag == "geommem")
12620       {
12621         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12622       }
12623       else if (aFlag == "texturemem")
12624       {
12625         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12626       }
12627       else if (aFlag == "framemem")
12628       {
12629         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12630       }
12631       else if (aFlag == "elapsedframe")
12632       {
12633         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12634       }
12635       else if (aFlag == "cpuframe_average")
12636       {
12637         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12638       }
12639       else if (aFlag == "cpupicking_average")
12640       {
12641         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12642       }
12643       else if (aFlag == "cpuculling_average")
12644       {
12645         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12646       }
12647       else if (aFlag == "cpudyn_average")
12648       {
12649         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12650       }
12651       else if (aFlag == "cpuframe_max")
12652       {
12653         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12654       }
12655       else if (aFlag == "cpupicking_max")
12656       {
12657         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12658       }
12659       else if (aFlag == "cpuculling_max")
12660       {
12661         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12662       }
12663       else if (aFlag == "cpudyn_max")
12664       {
12665         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12666       }
12667     }
12668   }
12669   else
12670   {
12671     if (toRedraw)
12672     {
12673       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12674       aView->Redraw();
12675       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12676     }
12677     theDI << "Statistic info:\n" << aView->StatisticInformation();
12678   }
12679   return 0;
12680 }
12681
12682 //=======================================================================
12683 //function : VXRotate
12684 //purpose  :
12685 //=======================================================================
12686 static Standard_Integer VXRotate (Draw_Interpretor& di,
12687                                    Standard_Integer argc,
12688                                    const char ** argv)
12689 {
12690   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12691   if (aContext.IsNull())
12692   {
12693     di << argv[0] << "ERROR : use 'vinit' command before \n";
12694     return 1;
12695   }
12696
12697   if (argc != 3)
12698   {
12699     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12700     return 1;
12701   }
12702
12703   TCollection_AsciiString aName (argv[1]);
12704   Standard_Real anAngle = Draw::Atof (argv[2]);
12705
12706   // find object
12707   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12708   Handle(AIS_InteractiveObject) anIObj;
12709   if (!aMap.Find2 (aName, anIObj))
12710   {
12711     di << "Use 'vdisplay' before\n";
12712     return 1;
12713   }
12714
12715   gp_Trsf aTransform;
12716   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12717   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12718
12719   aContext->SetLocation (anIObj, aTransform);
12720   aContext->UpdateCurrentViewer();
12721   return 0;
12722 }
12723
12724 //===============================================================================================
12725 //function : VManipulator
12726 //purpose  :
12727 //===============================================================================================
12728 static int VManipulator (Draw_Interpretor& theDi,
12729                          Standard_Integer  theArgsNb,
12730                          const char**      theArgVec)
12731 {
12732   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12733   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12734   ViewerTest::GetAISContext()->MainSelector()->SetPickClosest (Standard_False);
12735   if (aCurrentView.IsNull()
12736    || aViewer.IsNull())
12737   {
12738     Message::SendFail ("Error: no active viewer");
12739     return 1;
12740   }
12741
12742   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12743   Standard_Integer anArgIter = 1;
12744   for (; anArgIter < theArgsNb; ++anArgIter)
12745   {
12746     anUpdateTool.parseRedrawMode (theArgVec[anArgIter]);
12747   }
12748
12749   ViewerTest_CmdParser aCmd;
12750   aCmd.SetDescription ("Manages manipulator for interactive objects:");
12751   aCmd.AddOption ("attach",         "... object - attach manipulator to an object");
12752   aCmd.AddOption ("adjustPosition", "... {0|1} - adjust position when attaching");
12753   aCmd.AddOption ("adjustSize",     "... {0|1} - adjust size when attaching ");
12754   aCmd.AddOption ("enableModes",    "... {0|1} - enable modes when attaching ");
12755   aCmd.AddOption ("view",           "... {active | [view name]} - define view in which manipulator will be displayed, 'all' by default");
12756   aCmd.AddOption ("detach",         "...       - detach manipulator");
12757
12758   aCmd.AddOption ("startTransform",   "... mouse_x mouse_y - invoke start transformation");
12759   aCmd.AddOption ("transform",        "... mouse_x mouse_y - invoke transformation");
12760   aCmd.AddOption ("stopTransform",    "... [abort] - invoke stop transformation");
12761
12762   aCmd.AddOption ("move",   "... x y z - move object");
12763   aCmd.AddOption ("rotate", "... x y z dx dy dz angle - rotate object");
12764   aCmd.AddOption ("scale",  "... factor - scale object");
12765
12766   aCmd.AddOption ("autoActivate",      "... {0|1} - set activation on detection");
12767   aCmd.AddOption ("followTranslation", "... {0|1} - set following translation transform");
12768   aCmd.AddOption ("followRotation",    "... {0|1} - set following rotation transform");
12769   aCmd.AddOption ("followDragging",    "... {0|1} - set following dragging transform");
12770   aCmd.AddOption ("gap",               "... value - set gap between sub-parts");
12771   aCmd.AddOption ("part",              "... axis mode {0|1} - set visual part");
12772   aCmd.AddOption ("parts",             "... all axes mode {0|1} - set visual part");
12773   aCmd.AddOption ("pos",               "... x y z [nx ny nz [xx xy xz]] - set position of manipulator");
12774   aCmd.AddOption ("size",              "... size - set size of manipulator");
12775   aCmd.AddOption ("zoomable",          "... {0|1} - set zoom persistence");
12776
12777   aCmd.Parse (theArgsNb, theArgVec);
12778
12779   if (aCmd.HasOption ("help"))
12780   {
12781     theDi.PrintHelp (theArgVec[0]);
12782     return 0;
12783   }
12784
12785   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12786
12787   TCollection_AsciiString aName (aCmd.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0).c_str());
12788
12789   if (aName.IsEmpty())
12790   {
12791     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
12792     return 1;
12793   }
12794
12795   // ----------------------------------
12796   // detach existing manipulator object
12797   // ----------------------------------
12798
12799   if (aCmd.HasOption ("detach"))
12800   {
12801     if (!aMapAIS.IsBound2 (aName))
12802     {
12803       Message::SendFail() << "Syntax error: could not find \"" << aName << "\" AIS object";
12804       return 1;
12805     }
12806
12807     Handle(AIS_Manipulator) aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12808     if (aManipulator.IsNull())
12809     {
12810       Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12811       return 1;
12812     }
12813
12814     aManipulator->Detach();
12815     aMapAIS.UnBind2 (aName);
12816     ViewerTest::GetAISContext()->Remove (aManipulator, Standard_True);
12817
12818     return 0;
12819   }
12820
12821   // -----------------------------------------------
12822   // find or create manipulator if it does not exist
12823   // -----------------------------------------------
12824
12825   Handle(AIS_Manipulator) aManipulator;
12826   if (!aMapAIS.IsBound2 (aName))
12827   {
12828     std::cout << theArgVec[0] << ": AIS object \"" << aName << "\" has been created.\n";
12829
12830     aManipulator = new AIS_Manipulator();
12831     aManipulator->SetModeActivationOnDetection (true);
12832     aMapAIS.Bind (aManipulator, aName);
12833   }
12834   else
12835   {
12836     aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12837     if (aManipulator.IsNull())
12838     {
12839       Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12840       return 1;
12841     }
12842   }
12843
12844   // -----------------------------------------
12845   // change properties of manipulator instance
12846   // -----------------------------------------
12847
12848   if (aCmd.HasOption ("autoActivate", 1, Standard_True))
12849   {
12850     aManipulator->SetModeActivationOnDetection (aCmd.ArgBool ("autoActivate"));
12851   }
12852   if (aCmd.HasOption ("followTranslation", 1, Standard_True))
12853   {
12854     aManipulator->ChangeTransformBehavior().SetFollowTranslation (aCmd.ArgBool ("followTranslation"));
12855   }
12856   if (aCmd.HasOption ("followRotation", 1, Standard_True))
12857   {
12858     aManipulator->ChangeTransformBehavior().SetFollowRotation (aCmd.ArgBool ("followRotation"));
12859   }
12860   if (aCmd.HasOption("followDragging", 1, Standard_True))
12861   {
12862     aManipulator->ChangeTransformBehavior().SetFollowDragging(aCmd.ArgBool("followDragging"));
12863   }
12864   if (aCmd.HasOption ("gap", 1, Standard_True))
12865   {
12866     aManipulator->SetGap (aCmd.ArgFloat ("gap"));
12867   }
12868   if (aCmd.HasOption ("part", 3, Standard_True))
12869   {
12870     Standard_Integer anAxis = aCmd.ArgInt  ("part", 0);
12871     Standard_Integer aMode  = aCmd.ArgInt  ("part", 1);
12872     Standard_Boolean aOnOff = aCmd.ArgBool ("part", 2);
12873     if (aMode < 1 || aMode > 4)
12874     {
12875       Message::SendFail ("Syntax error: mode value should be in range [1, 4]");
12876       return 1;
12877     }
12878
12879     aManipulator->SetPart (anAxis, static_cast<AIS_ManipulatorMode> (aMode), aOnOff);
12880   }
12881   if (aCmd.HasOption("parts", 2, Standard_True))
12882   {
12883     Standard_Integer aMode = aCmd.ArgInt("parts", 0);
12884     Standard_Boolean aOnOff = aCmd.ArgBool("parts", 1);
12885     if (aMode < 1 || aMode > 4)
12886     {
12887       Message::SendFail ("Syntax error: mode value should be in range [1, 4]");
12888       return 1;
12889     }
12890
12891     aManipulator->SetPart(static_cast<AIS_ManipulatorMode>(aMode), aOnOff);
12892   }
12893   if (aCmd.HasOption ("pos", 3, Standard_True))
12894   {
12895     gp_Pnt aLocation = aCmd.ArgPnt ("pos", 0);
12896     gp_Dir aVDir     = aCmd.HasOption ("pos", 6) ? gp_Dir (aCmd.ArgVec ("pos", 3)) : aManipulator->Position().Direction();
12897     gp_Dir aXDir     = aCmd.HasOption ("pos", 9) ? gp_Dir (aCmd.ArgVec ("pos", 6)) : aManipulator->Position().XDirection();
12898
12899     aManipulator->SetPosition (gp_Ax2 (aLocation, aVDir, aXDir));
12900   }
12901   if (aCmd.HasOption ("size", 1, Standard_True))
12902   {
12903     aManipulator->SetSize (aCmd.ArgFloat ("size"));
12904   }
12905   if (aCmd.HasOption ("zoomable", 1, Standard_True))
12906   {
12907     aManipulator->SetZoomPersistence (!aCmd.ArgBool ("zoomable"));
12908
12909     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12910     {
12911       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
12912       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
12913     }
12914   }
12915
12916   // ---------------------------------------------------
12917   // attach, detach or access manipulator from an object
12918   // ---------------------------------------------------
12919
12920   if (aCmd.HasOption ("attach"))
12921   {
12922     // Find an object and attach manipulator to it
12923     if (!aCmd.HasOption ("attach", 1, Standard_True))
12924     {
12925       return 1;
12926     }
12927
12928     TCollection_AsciiString anObjName (aCmd.Arg ("attach", 0).c_str());
12929     Handle(AIS_InteractiveObject) anObject;
12930     if (!aMapAIS.Find2 (anObjName, anObject))
12931     {
12932       Message::SendFail() << "Syntax error: AIS object \"" << anObjName << "\" does not exist";
12933       return 1;
12934     }
12935
12936     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS);
12937          anIter.More(); anIter.Next())
12938     {
12939       Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
12940       if (!aManip.IsNull()
12941        && aManip->IsAttached()
12942        && aManip->Object() == anObject)
12943       {
12944         Message::SendFail() << "Syntax error: AIS object \"" << anObjName << "\" already has manipulator";
12945         return 1;
12946       }
12947     }
12948
12949     AIS_Manipulator::OptionsForAttach anOptions;
12950     if (aCmd.HasOption ("adjustPosition", 1, Standard_True))
12951     {
12952       anOptions.SetAdjustPosition (aCmd.ArgBool ("adjustPosition"));
12953     }
12954     if (aCmd.HasOption ("adjustSize", 1, Standard_True))
12955     {
12956       anOptions.SetAdjustSize (aCmd.ArgBool ("adjustSize"));
12957     }
12958     if (aCmd.HasOption ("enableModes", 1, Standard_True))
12959     {
12960       anOptions.SetEnableModes (aCmd.ArgBool ("enableModes"));
12961     }
12962
12963     aManipulator->Attach (anObject, anOptions);
12964
12965     // Check view option
12966     if (aCmd.HasOption ("view"))
12967     {
12968       if (!aCmd.HasOption ("view", 1, Standard_True))
12969       {
12970         return 1;
12971       }
12972       TCollection_AsciiString aViewString (aCmd.Arg ("view", 0).c_str());
12973       Handle(V3d_View) aView;
12974       if (aViewString.IsEqual ("active"))
12975       {
12976         aView = ViewerTest::CurrentView();
12977       }
12978       else // Check view name
12979       {
12980         ViewerTest_Names aViewNames (aViewString);
12981         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
12982         {
12983           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
12984           return 1;
12985         }
12986         aView = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
12987         if (aView.IsNull())
12988         {
12989           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
12990           return 1;
12991         }
12992       }
12993       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
12994         anIter (ViewerTest_myViews); anIter.More(); anIter.Next())
12995       {
12996         ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), Standard_False);
12997       }
12998       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aView, Standard_True);
12999     }
13000   }
13001
13002   // --------------------------------------
13003   // apply transformation using manipulator
13004   // --------------------------------------
13005
13006   if (aCmd.HasOption ("startTransform", 2, Standard_True))
13007   {
13008     aManipulator->StartTransform (aCmd.ArgInt ("startTransform", 0), aCmd.ArgInt ("startTransform", 1), ViewerTest::CurrentView());
13009   }
13010   if (aCmd.HasOption ("transform", 2, Standard_True))
13011   {
13012     aManipulator->Transform (aCmd.ArgInt ("transform", 0), aCmd.ArgInt ("transform", 1), ViewerTest::CurrentView());
13013   }
13014   if (aCmd.HasOption ("stopTransform"))
13015   {
13016     Standard_Boolean toApply = !aCmd.HasOption ("stopTransform", 1) || (aCmd.Arg ("stopTransform", 0) != "abort");
13017
13018     aManipulator->StopTransform (toApply);
13019   }
13020
13021   gp_Trsf aT;
13022   if (aCmd.HasOption ("move", 3, Standard_True))
13023   {
13024     aT.SetTranslationPart (aCmd.ArgVec ("move"));
13025   }
13026   if (aCmd.HasOption ("rotate", 7, Standard_True))
13027   {
13028     aT.SetRotation (gp_Ax1 (aCmd.ArgPnt ("rotate", 0), aCmd.ArgVec ("rotate", 3)), aCmd.ArgDouble ("rotate", 6));
13029   }
13030   if (aCmd.HasOption ("scale", 1))
13031   {
13032     aT.SetScale (gp_Pnt(), aCmd.ArgDouble("scale"));
13033   }
13034
13035   if (aT.Form() != gp_Identity)
13036   {
13037     aManipulator->Transform (aT);
13038   }
13039
13040   ViewerTest::GetAISContext()->Redisplay (aManipulator, Standard_True);
13041
13042   return 0;
13043 }
13044
13045 //===============================================================================================
13046 //function : VSelectionProperties
13047 //purpose  :
13048 //===============================================================================================
13049 static int VSelectionProperties (Draw_Interpretor& theDi,
13050                                  Standard_Integer  theArgsNb,
13051                                  const char**      theArgVec)
13052 {
13053   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
13054   if (aCtx.IsNull())
13055   {
13056     Message::SendFail ("Error: no active viewer");
13057     return 1;
13058   }
13059
13060   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
13061   {
13062     // handle obsolete alias
13063     bool toEnable = true;
13064     if (theArgsNb < 2)
13065     {
13066       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
13067       return 0;
13068     }
13069     else if (theArgsNb != 2
13070          || !ViewerTest::ParseOnOff (theArgVec[1], toEnable))
13071     {
13072       Message::SendFail ("Syntax error: wrong number of parameters");
13073       return 1;
13074     }
13075     if (toEnable != aCtx->ToHilightSelected())
13076     {
13077       aCtx->ClearDetected();
13078       aCtx->SetToHilightSelected (toEnable);
13079     }
13080     return 0;
13081   }
13082
13083   Standard_Boolean toPrint  = theArgsNb == 1;
13084   Standard_Boolean toRedraw = Standard_False;
13085   Standard_Integer anArgIter = 1;
13086   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
13087   if (anArgIter < theArgsNb)
13088   {
13089     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
13090     anArgFirst.LowerCase();
13091     ++anArgIter;
13092     if (anArgFirst == "dynhighlight"
13093      || anArgFirst == "dynhilight"
13094      || anArgFirst == "dynamichighlight"
13095      || anArgFirst == "dynamichilight")
13096     {
13097       aType = Prs3d_TypeOfHighlight_Dynamic;
13098     }
13099     else if (anArgFirst == "localdynhighlight"
13100           || anArgFirst == "localdynhilight"
13101           || anArgFirst == "localdynamichighlight"
13102           || anArgFirst == "localdynamichilight")
13103     {
13104       aType = Prs3d_TypeOfHighlight_LocalDynamic;
13105     }
13106     else if (anArgFirst == "selhighlight"
13107           || anArgFirst == "selhilight"
13108           || anArgFirst == "selectedhighlight"
13109           || anArgFirst == "selectedhilight")
13110     {
13111       aType = Prs3d_TypeOfHighlight_Selected;
13112     }
13113     else if (anArgFirst == "localselhighlight"
13114           || anArgFirst == "localselhilight"
13115           || anArgFirst == "localselectedhighlight"
13116           || anArgFirst == "localselectedhilight")
13117     {
13118       aType = Prs3d_TypeOfHighlight_LocalSelected;
13119     }
13120     else
13121     {
13122       --anArgIter;
13123     }
13124   }
13125   for (; anArgIter < theArgsNb; ++anArgIter)
13126   {
13127     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13128     anArg.LowerCase();
13129     if (anArg == "-help")
13130     {
13131       theDi.PrintHelp (theArgVec[0]);
13132       return 0;
13133     }
13134     else if (anArg == "-print")
13135     {
13136       toPrint = Standard_True;
13137     }
13138     else if (anArg == "-autoactivate")
13139     {
13140       Standard_Boolean toEnable = Standard_True;
13141       if (anArgIter + 1 < theArgsNb
13142        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13143       {
13144         ++anArgIter;
13145       }
13146       aCtx->SetAutoActivateSelection (toEnable);
13147     }
13148     else if (anArg == "-automatichighlight"
13149           || anArg == "-automatichilight"
13150           || anArg == "-autohighlight"
13151           || anArg == "-autohilight")
13152     {
13153       Standard_Boolean toEnable = Standard_True;
13154       if (anArgIter + 1 < theArgsNb
13155        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13156       {
13157         ++anArgIter;
13158       }
13159       aCtx->ClearSelected (false);
13160       aCtx->ClearDetected();
13161       aCtx->SetAutomaticHilight (toEnable);
13162       toRedraw = true;
13163     }
13164     else if (anArg == "-highlightselected"
13165           || anArg == "-hilightselected")
13166     {
13167       Standard_Boolean toEnable = Standard_True;
13168       if (anArgIter + 1 < theArgsNb
13169        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13170       {
13171         ++anArgIter;
13172       }
13173       aCtx->ClearDetected();
13174       aCtx->SetToHilightSelected (toEnable);
13175       toRedraw = true;
13176     }
13177     else if (anArg == "-pickstrategy"
13178           || anArg == "-pickingstrategy")
13179     {
13180       if (++anArgIter >= theArgsNb)
13181       {
13182         Message::SendFail ("Syntax error: type of highlighting is undefined");
13183         return 1;
13184       }
13185
13186       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13187       TCollection_AsciiString aVal (theArgVec[anArgIter]);
13188       aVal.LowerCase();
13189       if (aVal == "first"
13190        || aVal == "firstaccepted"
13191        || aVal == "firstacceptable")
13192       {
13193         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13194       }
13195       else if (aVal == "topmost"
13196             || aVal == "onlyTopmost")
13197       {
13198         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
13199       }
13200       else
13201       {
13202         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
13203         return 1;
13204       }
13205
13206       aCtx->SetPickingStrategy (aStrategy);
13207     }
13208     else if (anArg == "-pixtol"
13209           && anArgIter + 1 < theArgsNb)
13210     {
13211       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
13212     }
13213     else if ((anArg == "-mode"
13214            || anArg == "-dispmode")
13215           && anArgIter + 1 < theArgsNb)
13216     {
13217       if (aType == Prs3d_TypeOfHighlight_None)
13218       {
13219         Message::SendFail ("Syntax error: type of highlighting is undefined");
13220         return 1;
13221       }
13222
13223       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13224       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13225       aStyle->SetDisplayMode (aDispMode);
13226       toRedraw = Standard_True;
13227     }
13228     else if (anArg == "-layer"
13229           && anArgIter + 1 < theArgsNb)
13230     {
13231       if (aType == Prs3d_TypeOfHighlight_None)
13232       {
13233         Message::SendFail ("Syntax error: type of highlighting is undefined");
13234         return 1;
13235       }
13236
13237       ++anArgIter;
13238       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13239       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13240       {
13241         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13242         return 1;
13243       }
13244
13245       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13246       aStyle->SetZLayer (aNewLayer);
13247       toRedraw = Standard_True;
13248     }
13249     else if (anArg == "-hicolor"
13250           || anArg == "-selcolor"
13251           || anArg == "-color")
13252     {
13253       if (anArg.StartsWith ("-hi"))
13254       {
13255         aType = Prs3d_TypeOfHighlight_Dynamic;
13256       }
13257       else if (anArg.StartsWith ("-sel"))
13258       {
13259         aType = Prs3d_TypeOfHighlight_Selected;
13260       }
13261       else if (aType == Prs3d_TypeOfHighlight_None)
13262       {
13263         Message::SendFail ("Syntax error: type of highlighting is undefined");
13264         return 1;
13265       }
13266
13267       Quantity_Color aColor;
13268       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgsNb - anArgIter - 1,
13269                                                            theArgVec + anArgIter + 1,
13270                                                            aColor);
13271       if (aNbParsed == 0)
13272       {
13273         Message::SendFail ("Syntax error: need more arguments");
13274         return 1;
13275       }
13276       anArgIter += aNbParsed;
13277
13278       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13279       aStyle->SetColor (aColor);
13280       toRedraw = Standard_True;
13281     }
13282     else if ((anArg == "-transp"
13283            || anArg == "-transparency"
13284            || anArg == "-hitransp"
13285            || anArg == "-seltransp"
13286            || anArg == "-hitransplocal"
13287            || anArg == "-seltransplocal")
13288           && anArgIter + 1 < theArgsNb)
13289     {
13290       if (anArg.StartsWith ("-hi"))
13291       {
13292         aType = Prs3d_TypeOfHighlight_Dynamic;
13293       }
13294       else if (anArg.StartsWith ("-sel"))
13295       {
13296         aType = Prs3d_TypeOfHighlight_Selected;
13297       }
13298       else if (aType == Prs3d_TypeOfHighlight_None)
13299       {
13300         Message::SendFail ("Syntax error: type of highlighting is undefined");
13301         return 1;
13302       }
13303
13304       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13305       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13306       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13307       toRedraw = Standard_True;
13308     }
13309     else if ((anArg == "-mat"
13310            || anArg == "-material")
13311           && anArgIter + 1 < theArgsNb)
13312     {
13313       if (aType == Prs3d_TypeOfHighlight_None)
13314       {
13315         Message::SendFail ("Syntax error: type of highlighting is undefined");
13316         return 1;
13317       }
13318
13319       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13320       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13321       if (aMatName != Graphic3d_NOM_DEFAULT)
13322       {
13323         ++anArgIter;
13324         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13325         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13326         Graphic3d_MaterialAspect aMat (aMatName);
13327         aMat.SetColor (aStyle->Color());
13328         aMat.SetTransparency (aStyle->Transparency());
13329         anAspect->SetFrontMaterial (aMat);
13330         anAspect->SetInteriorColor (aStyle->Color());
13331         aStyle->SetBasicFillAreaAspect (anAspect);
13332       }
13333       else
13334       {
13335         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
13336       }
13337       toRedraw = Standard_True;
13338     }
13339     else
13340     {
13341       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
13342     }
13343   }
13344
13345   if (toPrint)
13346   {
13347     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
13348     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
13349     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
13350     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
13351     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
13352     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
13353     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
13354     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
13355     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
13356     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
13357     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
13358     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
13359     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
13360     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
13361   }
13362
13363   if (aCtx->NbSelected() != 0 && toRedraw)
13364   {
13365     aCtx->HilightSelected (Standard_True);
13366   }
13367
13368   return 0;
13369 }
13370
13371 //===============================================================================================
13372 //function : VDumpSelectionImage
13373 //purpose  :
13374 //===============================================================================================
13375 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13376                                 Standard_Integer  theArgsNb,
13377                                 const char**      theArgVec)
13378 {
13379   if (theArgsNb < 2)
13380   {
13381     Message::SendFail() << "Syntax error: wrong number arguments for '" << theArgVec[0] << "'";
13382     return 1;
13383   }
13384
13385   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13386   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13387   if (aContext.IsNull())
13388   {
13389     Message::SendFail ("Error: no active viewer");
13390     return 1;
13391   }
13392
13393   TCollection_AsciiString aFile;
13394   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13395   Handle(Graphic3d_Camera) aCustomCam;
13396   Image_Format anImgFormat = Image_Format_BGR;
13397   Standard_Integer aPickedIndex = 1;
13398   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13399   {
13400     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13401     aParam.LowerCase();
13402     if (aParam == "-type")
13403     {
13404       if (++anArgIter >= theArgsNb)
13405       {
13406         Message::SendFail ("Syntax error: wrong number parameters of flag '-depth'");
13407         return 1;
13408       }
13409
13410       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13411       aValue.LowerCase();
13412       if (aValue == "depth"
13413        || aValue == "normdepth"
13414        || aValue == "normalizeddepth")
13415       {
13416         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13417         anImgFormat = Image_Format_GrayF;
13418       }
13419       if (aValue == "depthinverted"
13420        || aValue == "normdepthinverted"
13421        || aValue == "normalizeddepthinverted"
13422        || aValue == "inverted")
13423       {
13424         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13425         anImgFormat = Image_Format_GrayF;
13426       }
13427       else if (aValue == "unnormdepth"
13428             || aValue == "unnormalizeddepth")
13429       {
13430         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13431         anImgFormat = Image_Format_GrayF;
13432       }
13433       else if (aValue == "objectcolor"
13434             || aValue == "object"
13435             || aValue == "color")
13436       {
13437         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13438       }
13439       else if (aValue == "entitycolor"
13440             || aValue == "entity")
13441       {
13442         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13443       }
13444       else if (aValue == "ownercolor"
13445             || aValue == "owner")
13446       {
13447         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13448       }
13449       else if (aValue == "selectionmodecolor"
13450             || aValue == "selectionmode"
13451             || aValue == "selmodecolor"
13452             || aValue == "selmode")
13453       {
13454         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13455       }
13456     }
13457     else if (aParam == "-picked"
13458           || aParam == "-pickeddepth"
13459           || aParam == "-pickedindex")
13460     {
13461       if (++anArgIter >= theArgsNb)
13462       {
13463         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13464         return 1;
13465       }
13466
13467       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13468     }
13469     else if (anArgIter + 1 < theArgsNb
13470           && aParam == "-xrpose")
13471     {
13472       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13473       anXRArg.LowerCase();
13474       if (anXRArg == "base")
13475       {
13476         aCustomCam = aView->View()->BaseXRCamera();
13477       }
13478       else if (anXRArg == "head")
13479       {
13480         aCustomCam = aView->View()->PosedXRCamera();
13481       }
13482       else
13483       {
13484         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13485         return 1;
13486       }
13487       if (aCustomCam.IsNull())
13488       {
13489         Message::SendFail() << "Error: undefined XR pose";
13490         return 0;
13491       }
13492     }
13493     else if (aFile.IsEmpty())
13494     {
13495       aFile = theArgVec[anArgIter];
13496     }
13497     else
13498     {
13499       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13500       return 1;
13501     }
13502   }
13503   if (aFile.IsEmpty())
13504   {
13505     Message::SendFail ("Syntax error: image file name is missing");
13506     return 1;
13507   }
13508
13509   Standard_Integer aWidth = 0, aHeight = 0;
13510   aView->Window()->Size (aWidth, aHeight);
13511
13512   Image_AlienPixMap aPixMap;
13513   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13514   {
13515     Message::SendFail ("Error: can't allocate image");
13516     return 1;
13517   }
13518
13519   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13520   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13521   if (!aCustomCam.IsNull())
13522   {
13523     aView->SetCamera (aCustomCam);
13524   }
13525   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13526   {
13527     Message::SendFail ("Error: can't generate selection image");
13528     return 1;
13529   }
13530   if (!aCustomCam.IsNull())
13531   {
13532     aView->SetCamera (aCamBack);
13533   }
13534   aView->SetImmediateUpdate (wasImmUpdate);
13535
13536   if (!aPixMap.Save (aFile))
13537   {
13538     Message::SendFail ("Error: can't save selection image");
13539     return 0;
13540   }
13541   return 0;
13542 }
13543
13544 //===============================================================================================
13545 //function : VViewCube
13546 //purpose  :
13547 //===============================================================================================
13548 static int VViewCube (Draw_Interpretor& ,
13549                       Standard_Integer  theNbArgs,
13550                       const char**      theArgVec)
13551 {
13552   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13553   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13554   if (aContext.IsNull() || aView.IsNull())
13555   {
13556     Message::SendFail ("Error: no active viewer");
13557     return 1;
13558   }
13559   else if (theNbArgs < 2)
13560   {
13561     Message::SendFail ("Syntax error: wrong number arguments");
13562     return 1;
13563   }
13564
13565   Handle(AIS_ViewCube) aViewCube;
13566   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13567   Quantity_Color aColorRgb;
13568   TCollection_AsciiString aName;
13569   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13570   {
13571     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13572     anArg.LowerCase();
13573     if (anUpdateTool.parseRedrawMode (anArg))
13574     {
13575       //
13576     }
13577     else if (aViewCube.IsNull())
13578     {
13579       aName = theArgVec[anArgIter];
13580       if (aName.StartsWith ("-"))
13581       {
13582         Message::SendFail ("Syntax error: object name should be specified");
13583         return 1;
13584       }
13585       Handle(AIS_InteractiveObject) aPrs;
13586       GetMapOfAIS().Find2 (aName, aPrs);
13587       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13588       if (aViewCube.IsNull())
13589       {
13590         aViewCube = new AIS_ViewCube();
13591         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13592         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13593         aViewCube->SetFixedAnimationLoop (false);
13594       }
13595     }
13596     else if (anArg == "-reset")
13597     {
13598       aViewCube->ResetStyles();
13599     }
13600     else if (anArg == "-color"
13601           || anArg == "-boxcolor"
13602           || anArg == "-boxsidecolor"
13603           || anArg == "-sidecolor"
13604           || anArg == "-boxedgecolor"
13605           || anArg == "-edgecolor"
13606           || anArg == "-boxcornercolor"
13607           || anArg == "-cornercolor"
13608           || anArg == "-innercolor"
13609           || anArg == "-textcolor")
13610     {
13611       Standard_Integer aNbParsed = ViewerTest::ParseColor (theNbArgs - anArgIter - 1,
13612                                                            theArgVec + anArgIter + 1,
13613                                                            aColorRgb);
13614       if (aNbParsed == 0)
13615       {
13616         Message::SendFail() << "Syntax error at '" << anArg << "'";
13617         return 1;
13618       }
13619       anArgIter += aNbParsed;
13620       if (anArg == "-boxcolor")
13621       {
13622         aViewCube->SetBoxColor (aColorRgb);
13623       }
13624       else if (anArg == "-boxsidecolor"
13625             || anArg == "-sidecolor")
13626       {
13627         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13628         aViewCube->SynchronizeAspects();
13629       }
13630       else if (anArg == "-boxedgecolor"
13631             || anArg == "-edgecolor")
13632       {
13633         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13634         aViewCube->SynchronizeAspects();
13635       }
13636       else if (anArg == "-boxcornercolor"
13637             || anArg == "-cornercolor")
13638       {
13639         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13640         aViewCube->SynchronizeAspects();
13641       }
13642       else if (anArg == "-innercolor")
13643       {
13644         aViewCube->SetInnerColor (aColorRgb);
13645       }
13646       else if (anArg == "-textcolor")
13647       {
13648         aViewCube->SetTextColor (aColorRgb);
13649       }
13650       else
13651       {
13652         aViewCube->SetColor (aColorRgb);
13653       }
13654     }
13655     else if (anArgIter + 1 < theNbArgs
13656           && (anArg == "-transparency"
13657            || anArg == "-boxtransparency"))
13658     {
13659       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13660       if (aValue < 0.0 || aValue > 1.0)
13661       {
13662         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13663         return 1;
13664       }
13665
13666       if (anArg == "-boxtransparency")
13667       {
13668         aViewCube->SetBoxTransparency (aValue);
13669       }
13670       else
13671       {
13672         aViewCube->SetTransparency (aValue);
13673       }
13674     }
13675     else if (anArg == "-axes"
13676           || anArg == "-edges"
13677           || anArg == "-vertices"
13678           || anArg == "-vertexes"
13679           || anArg == "-fixedanimation")
13680     {
13681       bool toShow = true;
13682       if (anArgIter + 1 < theNbArgs
13683        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toShow))
13684       {
13685         ++anArgIter;
13686       }
13687       if (anArg == "-fixedanimation")
13688       {
13689         aViewCube->SetFixedAnimationLoop (toShow);
13690       }
13691       else if (anArg == "-axes")
13692       {
13693         aViewCube->SetDrawAxes (toShow);
13694       }
13695       else if (anArg == "-edges")
13696       {
13697         aViewCube->SetDrawEdges (toShow);
13698       }
13699       else
13700       {
13701         aViewCube->SetDrawVertices (toShow);
13702       }
13703     }
13704     else if (anArg == "-yup"
13705           || anArg == "-zup")
13706     {
13707       bool isOn = true;
13708       if (anArgIter + 1 < theNbArgs
13709        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isOn))
13710       {
13711         ++anArgIter;
13712       }
13713       if (anArg == "-yup")
13714       {
13715         aViewCube->SetYup (isOn);
13716       }
13717       else
13718       {
13719         aViewCube->SetYup (!isOn);
13720       }
13721     }
13722     else if (anArgIter + 1 < theNbArgs
13723           && anArg == "-font")
13724     {
13725       aViewCube->SetFont (theArgVec[++anArgIter]);
13726     }
13727     else if (anArgIter + 1 < theNbArgs
13728           && anArg == "-fontheight")
13729     {
13730       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
13731     }
13732     else if (anArgIter + 1 < theNbArgs
13733           && (anArg == "-size"
13734            || anArg == "-boxsize"))
13735     {
13736       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
13737                           anArg != "-boxsize");
13738     }
13739     else if (anArgIter + 1 < theNbArgs
13740           && (anArg == "-boxfacet"
13741            || anArg == "-boxfacetextension"
13742            || anArg == "-facetextension"
13743            || anArg == "-extension"))
13744     {
13745       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
13746     }
13747     else if (anArgIter + 1 < theNbArgs
13748           && (anArg == "-boxedgegap"
13749            || anArg == "-edgegap"))
13750     {
13751       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
13752     }
13753     else if (anArgIter + 1 < theNbArgs
13754           && (anArg == "-boxedgeminsize"
13755            || anArg == "-edgeminsize"))
13756     {
13757       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
13758     }
13759     else if (anArgIter + 1 < theNbArgs
13760           && (anArg == "-boxcornerminsize"
13761            || anArg == "-cornerminsize"))
13762     {
13763       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
13764     }
13765     else if (anArgIter + 1 < theNbArgs
13766           && anArg == "-axespadding")
13767     {
13768       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
13769     }
13770     else if (anArgIter + 1 < theNbArgs
13771           && anArg == "-roundradius")
13772     {
13773       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
13774     }
13775     else if (anArgIter + 1 < theNbArgs
13776           && anArg == "-duration")
13777     {
13778       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
13779     }
13780     else if (anArgIter + 1 < theNbArgs
13781           && anArg == "-axesradius")
13782     {
13783       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
13784     }
13785     else if (anArgIter + 1 < theNbArgs
13786           && anArg == "-axesconeradius")
13787     {
13788       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
13789     }
13790     else if (anArgIter + 1 < theNbArgs
13791           && anArg == "-axessphereradius")
13792     {
13793       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
13794     }
13795     else
13796     {
13797       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13798       return 1;
13799     }
13800   }
13801   if (aViewCube.IsNull())
13802   {
13803     Message::SendFail ("Syntax error: wrong number of arguments");
13804     return 1;
13805   }
13806
13807   ViewerTest::Display (aName, aViewCube, false);
13808   return 0;
13809 }
13810
13811 //===============================================================================================
13812 //function : VColorConvert
13813 //purpose  :
13814 //===============================================================================================
13815 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13816 {
13817   if (theNbArgs != 6)
13818   {
13819     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13820     return 1;
13821   }
13822
13823   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
13824   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
13825   {
13826     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
13827     return 1;
13828   }
13829
13830   const char* aTypeStr = theArgVec[2];
13831   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
13832   if (! strcasecmp (aTypeStr, "srgb"))
13833   {
13834     aType = Quantity_TOC_sRGB;
13835   }
13836   else if (! strcasecmp (aTypeStr, "hls"))
13837   {
13838     aType = Quantity_TOC_HLS;
13839   }
13840   else if (! strcasecmp (aTypeStr, "lab"))
13841   {
13842     aType = Quantity_TOC_CIELab;
13843   }
13844   else if (! strcasecmp (aTypeStr, "lch"))
13845   {
13846     aType = Quantity_TOC_CIELch;
13847   }
13848   else
13849   {
13850     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
13851     return 1;
13852   }
13853
13854   double aC1 = Draw::Atof (theArgVec[3]);
13855   double aC2 = Draw::Atof (theArgVec[4]);
13856   double aC3 = Draw::Atof (theArgVec[5]);
13857
13858   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
13859   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
13860
13861   // print values with 6 decimal digits
13862   char buffer[1024];
13863   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
13864   theDI << buffer;
13865
13866   return 0;
13867 }
13868  
13869 //===============================================================================================
13870 //function : VColorDiff
13871 //purpose  :
13872 //===============================================================================================
13873 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13874 {
13875   if (theNbArgs != 7)
13876   {
13877     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13878     return 1;
13879   }
13880
13881   double aR1 = Draw::Atof (theArgVec[1]);
13882   double aG1 = Draw::Atof (theArgVec[2]);
13883   double aB1 = Draw::Atof (theArgVec[3]);
13884   double aR2 = Draw::Atof (theArgVec[4]);
13885   double aG2 = Draw::Atof (theArgVec[5]);
13886   double aB2 = Draw::Atof (theArgVec[6]);
13887
13888   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
13889   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
13890
13891   theDI << aColor1.DeltaE2000 (aColor2);
13892
13893   return 0;
13894 }
13895  
13896 //=======================================================================
13897 //function : ViewerCommands
13898 //purpose  :
13899 //=======================================================================
13900
13901 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
13902 {
13903
13904   const char *group = "ZeViewer";
13905   theCommands.Add("vinit",
13906           "vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]"
13907     "\n\t\t:     [-exitOnClose] [-closeOnEscape] [-cloneActive] [-2d_mode {on|off}=off]"
13908   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
13909     "\n\t\t:     [-display displayName]"
13910   #endif
13911     "\n\t\t: Creates new View window with specified name viewName."
13912     "\n\t\t: By default the new view is created in the viewer and in"
13913     "\n\t\t: graphic driver shared with active view."
13914     "\n\t\t:  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}"
13915     "\n\t\t: If driverName isn't specified the driver will be shared with active view."
13916     "\n\t\t: If viewerName isn't specified the viewer will be shared with active view."
13917 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
13918     "\n\t\t:  -display HostName.DisplayNumber[:ScreenNumber]"
13919     "\n\t\t: Display name will be used within creation of graphic driver, when specified."
13920 #endif
13921     "\n\t\t:  -left,  -top    pixel position of left top corner of the window."
13922     "\n\t\t:  -width, -height width and heigth of window respectively."
13923     "\n\t\t:  -cloneActive floag to copy camera and dimensions of active view."
13924     "\n\t\t:  -exitOnClose when specified, closing the view will exit application."
13925     "\n\t\t:  -closeOnEscape when specified, view will be closed on pressing Escape."
13926     "\n\t\t:  -2d_mode when on, view will not react on rotate scene events"
13927     "\n\t\t: Additional commands for operations with views: vclose, vactivate, vviewlist.",
13928     __FILE__,VInit,group);
13929   theCommands.Add("vclose" ,
13930     "[view_id [keep_context=0|1]]\n"
13931     "or vclose ALL - to remove all created views\n"
13932     " - removes view(viewer window) defined by its view_id.\n"
13933     " - keep_context: by default 0; if 1 and the last view is deleted"
13934     " the current context is not removed.",
13935     __FILE__,VClose,group);
13936   theCommands.Add("vactivate" ,
13937     "vactivate view_id [-noUpdate]"
13938     " - activates view(viewer window) defined by its view_id",
13939     __FILE__,VActivate,group);
13940   theCommands.Add("vviewlist",
13941     "vviewlist [format={tree, long}]"
13942     " - prints current list of views per viewer and graphic_driver ID shared between viewers"
13943     " - format: format of result output, if tree the output is a tree view;"
13944     "otherwise it's a list of full view names. By default format = tree",
13945     __FILE__,VViewList,group);
13946   theCommands.Add("vhelp" ,
13947     "vhelp            : display help on the viewer commands",
13948     __FILE__,VHelp,group);
13949   theCommands.Add("vviewproj",
13950           "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]"
13951     "\n\t\t:         [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]"
13952     "\n\t\t: Setup view direction"
13953     "\n\t\t:   -Yup      use Y-up convention instead of Zup (which is default)."
13954     "\n\t\t:   +-X+-Y+-Z define direction as combination of DX, DY and DZ;"
13955     "\n\t\t:             for example '+Z' will show front of the model,"
13956     "\n\t\t:             '-X-Y+Z' will define left axonometrical view."
13957     "\n\t\t:   -frame    define camera Up and Right directions (regardless Up convention);"
13958     "\n\t\t:             for example '+X+Z' will show front of the model with Z-up."
13959     __FILE__,VViewProj,group);
13960   theCommands.Add("vtop" ,
13961     "vtop or <T>      : Top view. Orientation +X+Y" ,
13962     __FILE__,VViewProj,group);
13963   theCommands.Add("vbottom" ,
13964     "vbottom          : Bottom view. Orientation +X-Y" ,
13965     __FILE__,VViewProj,group);
13966   theCommands.Add("vleft" ,
13967     "vleft            : Left view. Orientation -Y+Z" ,
13968     __FILE__,VViewProj,group);
13969   theCommands.Add("vright" ,
13970     "vright           : Right view. Orientation +Y+Z" ,
13971     __FILE__,VViewProj,group);
13972   theCommands.Add("vaxo" ,
13973     " vaxo or <A>     : Axonometric view. Orientation +X-Y+Z",
13974     __FILE__,VViewProj,group);
13975   theCommands.Add("vfront" ,
13976     "vfront           : Front view. Orientation +X+Z" ,
13977     __FILE__,VViewProj,group);
13978   theCommands.Add("vback" ,
13979     "vback            : Back view. Orientation -X+Z" ,
13980     __FILE__,VViewProj,group);
13981   theCommands.Add("vpick" ,
13982     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
13983     VPick,group);
13984   theCommands.Add("vfit",
13985     "vfit or <F> [-selected] [-noupdate]"
13986     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
13987     __FILE__,VFit,group);
13988   theCommands.Add ("vfitarea",
13989     "vfitarea x1 y1 x2 y2"
13990     "\n\t\t: vfitarea x1 y1 z1 x2 y2 z2"
13991     "\n\t\t: Fit view to show area located between two points"
13992     "\n\t\t: given in world 2D or 3D corrdinates.",
13993     __FILE__, VFitArea, group);
13994   theCommands.Add ("vzfit", "vzfit [scale]\n"
13995     "   Matches Z near, Z far view volume planes to the displayed objects.\n"
13996     "   \"scale\" - specifies factor to scale computed z range.\n",
13997     __FILE__, VZFit, group);
13998   theCommands.Add("vrepaint",
13999             "vrepaint [-immediate] [-continuous FPS]"
14000     "\n\t\t: force redraw of active View"
14001     "\n\t\t:   -immediate  flag performs redraw of immediate layers only;"
14002     "\n\t\t:   -continuous activates/deactivates continuous redraw of active View,"
14003     "\n\t\t:                0 means no continuous rendering,"
14004     "\n\t\t:               -1 means non-stop redraws,"
14005     "\n\t\t:               >0 specifies target framerate,",
14006     __FILE__,VRepaint,group);
14007   theCommands.Add("vclear",
14008     "vclear          : vclear"
14009     "\n\t\t: remove all the object from the viewer",
14010     __FILE__,VClear,group);
14011   theCommands.Add (
14012     "vbackground",
14013     "Changes background or some background settings.\n"
14014     "\n"
14015     "Usage:\n"
14016     "  vbackground -imageFile ImageFile [-imageMode FillType]\n"
14017     "  vbackground -imageMode FillType\n"
14018     "  vbackground -gradient Color1 Color2 [-gradientMode FillMethod]\n"
14019     "  vbackground -gradientMode FillMethod\n"
14020     "  vbackground -cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]\n"
14021     "  vbackground -color Color\n"
14022     "  vbackground -default -gradient Color1 Color2 [-gradientMode FillType]\n"
14023     "  vbackground -default -color Color\n"
14024     "  vbackground -help\n"
14025     "\n"
14026     "Options:\n"
14027     "  -imageFile    (-imgFile, -image, -img):             sets filename of image used as background\n"
14028     "  -imageMode    (-imgMode, -imageMd, -imgMd):         sets image fill type\n"
14029     "  -gradient     (-grad, -gr):                         sets background gradient starting and ending colors\n"
14030     "  -gradientMode (-gradMode, -gradMd, -grMode, -grMd): sets gradient fill method\n"
14031     "  -cubemap      (-cmap, -cm):                         sets environmet cubemap as background\n"
14032     "  -invertedz    (-invz, -iz):                         sets inversion of Z axis for background cubemap rendering\n"
14033     "  -order        (-o):                                 defines order of tiles in one image cubemap\n"
14034     "                                                      (has no effect in case of multi image cubemaps)\n"
14035     "  -color        (-col):                               sets background color\n"
14036     "  -default      (-def):                               sets background default gradient or color\n"
14037     "  -help         (-h):                                 outputs short help message\n"
14038     "\n"
14039     "Arguments:\n"
14040     "  Color:        Red Green Blue  - where Red, Green, Blue must be integers within the range [0, 255]\n"
14041     "                                  or reals within the range [0.0, 1.0]\n"
14042     "                ColorName       - one of WHITE, BLACK, RED, GREEN, BLUE, etc.\n"
14043     "                #HHH, [#]HHHHHH - where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F)\n"
14044     "  FillMethod:   one of NONE, HOR[IZONTAL], VER[TICAL], DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, "
14045     "CORNER4\n"
14046     "  FillType:     one of CENTERED, TILED, STRETCH, NONE\n"
14047     "  ImageFile:    a name of the file with the image used as a background\n"
14048     "  CubemapFilei: a name of the file with one image packed cubemap or names of separate files with every cubemap side\n"
14049     "  TileIndexi:   a cubemap side index in range [0, 5] for i tile of one image packed cubemap\n",
14050     __FILE__,
14051     vbackground,
14052     group);
14053   theCommands.Add ("vsetbg",
14054                    "Loads image as background."
14055                    "\n\t\t: vsetbg ImageFile [FillType]"
14056                    "\n\t\t: vsetbg -imageFile ImageFile [-imageMode FillType]"
14057                    "\n\t\t: Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.",
14058                    __FILE__,
14059                    vbackground,
14060                    group);
14061   theCommands.Add ("vsetbgmode",
14062                    "Changes background image fill type."
14063                    "\n\t\t: vsetbgmode [-imageMode] FillType"
14064                    "\n\t\t: Alias for 'vbackground -imageMode FillType'.",
14065                    __FILE__,
14066                    vbackground,
14067                    group);
14068   theCommands.Add ("vsetgradientbg",
14069                    "Mounts gradient background."
14070                    "\n\t\t: vsetgradientbg Color1 Color2 [FillMethod]"
14071                    "\n\t\t: vsetgradientbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14072                    "\n\t\t: Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.",
14073                    __FILE__,
14074                    vbackground,
14075                    group);
14076   theCommands.Add ("vsetgrbgmode",
14077                    "Changes gradient background fill method."
14078                    "\n\t\t: vsetgrbgmode [-gradientMode] FillMethod"
14079                    "\n\t\t: Alias for 'vbackground -gradientMode FillMethod'.",
14080                    __FILE__,
14081                    vbackground,
14082                    group);
14083   theCommands.Add ("vsetcolorbg",
14084                    "Sets background color."
14085                    "\n\t\t: vsetcolorbg [-color] Color."
14086                    "\n\t\t: Alias for 'vbackground -color Color'.",
14087                    __FILE__,
14088                    vbackground,
14089                    group);
14090   theCommands.Add ("vsetdefaultbg",
14091                    "Sets default viewer background fill color (flat/gradient)."
14092                    "\n\t\t: vsetdefaultbg Color1 Color2 [FillMethod]"
14093                    "\n\t\t: vsetdefaultbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14094                    "\n\t\t: Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'."
14095                    "\n\t\t: vsetdefaultbg [-color] Color"
14096                    "\n\t\t: Alias for 'vbackground -default -color Color'.",
14097                    __FILE__,
14098                    vbackground,
14099                    group);
14100   theCommands.Add("vscale",
14101     "vscale          : vscale X Y Z",
14102     __FILE__,VScale,group);
14103   theCommands.Add("vzbufftrihedron",
14104             "vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]"
14105     "\n\t\t:       [-position center|left_lower|left_upper|right_lower|right_upper]"
14106     "\n\t\t:       [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]"
14107     "\n\t\t:       [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]"
14108     "\n\t\t:       [-nbfacets value=12] [-colorLabels color=WHITE]"
14109     "\n\t\t: Displays a trihedron",
14110     __FILE__,VZBuffTrihedron,group);
14111   theCommands.Add("vrotate",
14112     "vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]"
14113     "\n                : Option -mouseStart starts rotation according to the mouse position"
14114     "\n                : Option -mouseMove continues rotation with angle computed"
14115     "\n                : from last and new mouse position."
14116     "\n                : vrotate AX AY AZ [X Y Z]",
14117     __FILE__,VRotate,group);
14118   theCommands.Add("vzoom",
14119     "vzoom           : vzoom coef",
14120     __FILE__,VZoom,group);
14121   theCommands.Add("vpan",
14122     "vpan            : vpan dx dy",
14123     __FILE__,VPan,group);
14124   theCommands.Add("vcolorscale",
14125     "vcolorscale name [-noupdate|-update] [-demo]"
14126     "\n\t\t:       [-range RangeMin=0 RangeMax=1 NbIntervals=10]"
14127     "\n\t\t:       [-font HeightFont=20]"
14128     "\n\t\t:       [-logarithmic {on|off}=off] [-reversed {on|off}=off]"
14129     "\n\t\t:       [-smoothTransition {on|off}=off]"
14130     "\n\t\t:       [-hueRange MinAngle=230 MaxAngle=0]"
14131     "\n\t\t:       [-colorRange MinColor=BLUE1 MaxColor=RED]"
14132     "\n\t\t:       [-textpos {left|right|center|none}=right]"
14133     "\n\t\t:       [-labelAtBorder {on|off}=on]"
14134     "\n\t\t:       [-colors Color1 Color2 ...] [-color Index Color]"
14135     "\n\t\t:       [-labels Label1 Label2 ...] [-label Index Label]"
14136     "\n\t\t:       [-freeLabels NbOfLabels Label1 Label2 ...]"
14137     "\n\t\t:       [-xy Left=0 Bottom=0]"
14138     "\n\t\t:       [-uniform lightness hue_from hue_to]"
14139     "\n\t\t:  -demo     - displays a color scale with demonstratio values"
14140     "\n\t\t:  -colors   - set colors for all intervals"
14141     "\n\t\t:  -color    - set color for specific interval"
14142     "\n\t\t:  -uniform  - generate colors with the same lightness"
14143     "\n\t\t:  -textpos  - horizontal label position relative to color scale bar"
14144     "\n\t\t:  -labelAtBorder - vertical label position relative to color interval;"
14145     "\n\t\t:              at border means the value inbetween neighbor intervals,"
14146     "\n\t\t:              at center means the center value within current interval"
14147     "\n\t\t:  -labels   - set labels for all intervals"
14148     "\n\t\t:  -freeLabels - same as -labels but does not require"
14149     "\n\t\t:              matching the number of intervals"
14150     "\n\t\t:  -label    - set label for specific interval"
14151     "\n\t\t:  -title    - set title"
14152     "\n\t\t:  -reversed - setup smooth color transition between intervals"
14153     "\n\t\t:  -smoothTransition - swap colorscale direction"
14154     "\n\t\t:  -hueRange - set hue angles corresponding to minimum and maximum values",
14155     __FILE__, VColorScale, group);
14156   theCommands.Add("vgraduatedtrihedron",
14157     "vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
14158     "\t[-namefont Name] [-valuesfont Name]\n"
14159     "\t[-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]\n"
14160     "\t[-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]"
14161     "\t[-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]\n"
14162     "\t[-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]\n"
14163     "\t[-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]"
14164     "\t[-xcolor Color] [-ycolor Color] [-zcolor Color]\n"
14165     "\t[-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]\n"
14166     "\t[-xticks Number] [-yticks Number] [-zticks Number]\n"
14167     "\t[-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]\n"
14168     "\t[-drawgrid on/off] [-drawaxes on/off]\n"
14169     " - Displays or erases graduated trihedron"
14170     " - xname, yname, zname - names of axes, default: X, Y, Z\n"
14171     " - namefont - font of axes names. Default: Arial\n"
14172     " - xnameoffset, ynameoffset, znameoffset - offset of name from values or tickmarks or axis. Default: 30\n"
14173     " - xnamecolor, ynamecolor, znamecolor - colors of axes names\n"
14174     " - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values from tickmarks or axis. Default: 10\n"
14175     " - valuesfont - font of axes values. Default: Arial\n"
14176     " - xcolor, ycolor, zcolor - color of axis and values\n"
14177     " - xticks, yticks, xzicks - number of tickmark on axes. Default: 5\n"
14178     " - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10\n",
14179     __FILE__,VGraduatedTrihedron,group);
14180   theCommands.Add("vtile" ,
14181             "vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]"
14182     "\n\t\t: Setup view to draw a tile (a part of virtual bigger viewport)."
14183     "\n\t\t:  -totalSize the size of virtual bigger viewport"
14184     "\n\t\t:  -tileSize  tile size (the view size will be used if omitted)"
14185     "\n\t\t:  -lowerLeft tile offset as lower left corner"
14186     "\n\t\t:  -upperLeft tile offset as upper left corner",
14187     __FILE__, VTile, group);
14188   theCommands.Add("vzlayer",
14189               "vzlayer [layerId]"
14190       "\n\t\t:         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]"
14191       "\n\t\t:         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]"
14192       "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
14193       "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]"
14194       "\n\t\t: ZLayer list management:"
14195       "\n\t\t:   -add      add new z layer to viewer and print its id"
14196       "\n\t\t:   -insertBefore add new z layer and insert it before existing one"
14197       "\n\t\t:   -insertAfter  add new z layer and insert it after  existing one"
14198       "\n\t\t:   -delete   delete z layer"
14199       "\n\t\t:   -get      print sequence of z layers"
14200       "\n\t\t:   -settings print status of z layer settings"
14201       "\n\t\t:   -disable  disables given setting"
14202       "\n\t\t:   -enable   enables  given setting",
14203     __FILE__,VZLayer,group);
14204   theCommands.Add("vlayerline",
14205     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
14206     __FILE__,VLayerLine,group);
14207   theCommands.Add("vgrid",
14208               "vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]"
14209       "\n\t\t:       [-step X Y] [-size DX DY]"
14210       "\n\t\t:       [-step StepRadius NbDivisions] [-radius Radius]",
14211     __FILE__, VGrid, group);
14212   theCommands.Add ("vpriviledgedplane",
14213     "vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]"
14214     "\n\t\t:   Ox, Oy, Oz - plane origin"
14215     "\n\t\t:   Nx, Ny, Nz - plane normal direction"
14216     "\n\t\t:   Xx, Xy, Xz - plane x-reference axis direction"
14217     "\n\t\t: Sets or prints viewer's priviledged plane geometry.",
14218     __FILE__, VPriviledgedPlane, group);
14219   theCommands.Add ("vconvert",
14220     "vconvert v [Mode={window|view}]"
14221     "\n\t\t: vconvert x y [Mode={window|view|grid|ray}]"
14222     "\n\t\t: vconvert x y z [Mode={window|grid}]"
14223     "\n\t\t:   window - convert to window coordinates, pixels"
14224     "\n\t\t:   view   - convert to view projection plane"
14225     "\n\t\t:   grid   - convert to model coordinates, given on grid"
14226     "\n\t\t:   ray    - convert projection ray to model coordiantes"
14227     "\n\t\t: - vconvert v window : convert view to window;"
14228     "\n\t\t: - vconvert v view   : convert window to view;"
14229     "\n\t\t: - vconvert x y window : convert view to window;"
14230     "\n\t\t: - vconvert x y view : convert window to view;"
14231     "\n\t\t: - vconvert x y : convert window to model;"
14232     "\n\t\t: - vconvert x y grid : convert window to model using grid;"
14233     "\n\t\t: - vconvert x y ray : convert window projection line to model;"
14234     "\n\t\t: - vconvert x y z window : convert model to window;"
14235     "\n\t\t: - vconvert x y z grid : convert view to model using grid;"
14236     "\n\t\t: Converts the given coordinates to window/view/model space.",
14237     __FILE__, VConvert, group);
14238   theCommands.Add ("vfps",
14239     "vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view",
14240     __FILE__, VFps, group);
14241   theCommands.Add ("vgldebug",
14242             "vgldebug [-sync {0|1}] [-debug {0|1}] [-glslWarn {0|1}]"
14243     "\n\t\t:          [-glslCode {off|short|full}] [-extraMsg {0|1}] [{0|1}]"
14244     "\n\t\t: Request debug GL context. Should be called BEFORE vinit."
14245     "\n\t\t: Debug context can be requested only on Windows"
14246     "\n\t\t: with GL_ARB_debug_output extension implemented by GL driver!"
14247     "\n\t\t:  -sync     - request synchronized debug GL context"
14248     "\n\t\t:  -glslWarn - log GLSL compiler/linker warnings,"
14249     "\n\t\t:              which are suppressed by default,"
14250     "\n\t\t:  -glslCode - log GLSL program source code,"
14251     "\n\t\t:              which are suppressed by default,"
14252     "\n\t\t:  -extraMsg - log extra diagnostic messages from GL context,"
14253     "\n\t\t:              which are suppressed by default",
14254     __FILE__, VGlDebug, group);
14255   theCommands.Add ("vvbo",
14256     "vvbo [{0|1}] : turn VBO usage On/Off; affects only newly displayed objects",
14257     __FILE__, VVbo, group);
14258   theCommands.Add ("vstereo",
14259             "vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
14260     "\n\t\t:         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]"
14261     "\n\t\t:         [-anaglyph Filter]"
14262     "\n\t\t: Control stereo output mode."
14263     "\n\t\t: When -mirrorComposer is specified, VR rendered frame will be mirrored in window (debug)."
14264     "\n\t\t: Parameter -unitFactor specifies meters scale factor for mapping VR input."
14265     "\n\t\t: Available modes for -mode:"
14266     "\n\t\t:  quadBuffer        - OpenGL QuadBuffer stereo,"
14267     "\n\t\t:                     requires driver support."
14268     "\n\t\t:                     Should be called BEFORE vinit!"
14269     "\n\t\t:  anaglyph         - Anaglyph glasses"
14270     "\n\t\t:  rowInterlaced    - row-interlaced display"
14271     "\n\t\t:  columnInterlaced - column-interlaced display"
14272     "\n\t\t:  chessBoard       - chess-board output"
14273     "\n\t\t:  sideBySide       - horizontal pair"
14274     "\n\t\t:  overUnder        - vertical   pair"
14275     "\n\t\t:  openVR           - OpenVR (HMD)"
14276     "\n\t\t: Available Anaglyph filters for -anaglyph:"
14277     "\n\t\t:  redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
14278     "\n\t\t:  greenMagentaSimple",
14279     __FILE__, VStereo, group);
14280   theCommands.Add ("vcaps",
14281             "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
14282     "\n\t\t:       [-compatibleProfile {0|1}] [-compressedTextures {0|1}]"
14283     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}]"
14284     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
14285     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
14286     "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
14287     "\n\t\t: Modify particular graphic driver options:"
14288     "\n\t\t:  sRGB     - enable/disable sRGB rendering"
14289     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
14290     "\n\t\t:             built-in GLSL programs"
14291     "\n\t\t:            (requires compatible profile)"
14292     "\n\t\t:  polygonMode - use Polygon Mode instead of built-in GLSL programs"
14293     "\n\t\t:  compressedTexture - allow uploading of GPU-supported compressed texture formats"
14294     "\n\t\t:  VBO      - use Vertex Buffer Object (copy vertex"
14295     "\n\t\t:             arrays to GPU memory)"
14296     "\n\t\t:  sprite   - use textured sprites instead of bitmaps"
14297     "\n\t\t:  vsync    - switch VSync on or off"
14298     "\n\t\t:  winBuffer - allow using window buffer for rendering"
14299     "\n\t\t: Context creation options:"
14300     "\n\t\t:  softMode          - software OpenGL implementation"
14301     "\n\t\t:  compatibleProfile - backward-compatible profile"
14302     "\n\t\t:  quadbuffer        - QuadBuffer"
14303     "\n\t\t:  noExtensions      - disallow usage of extensions"
14304     "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
14305     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
14306     "\n\t\t: rendering paths producing the same visual result when"
14307     "\n\t\t: possible."
14308     "\n\t\t: Command is intended for testing old hardware compatibility.",
14309     __FILE__, VCaps, group);
14310   theCommands.Add ("vmemgpu",
14311     "vmemgpu [f]: print system-dependent GPU memory information if available;"
14312     " with f option returns free memory in bytes",
14313     __FILE__, VMemGpu, group);
14314   theCommands.Add ("vreadpixel",
14315     "vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]"
14316     " : Read pixel value for active view",
14317     __FILE__, VReadPixel, group);
14318   theCommands.Add("diffimage",
14319             "diffimage imageFile1 imageFile2 [diffImageFile]"
14320     "\n\t\t:           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]"
14321     "\n\t\t:           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]"
14322     "\n\t\t: Compare two images by content and generate difference image."
14323     "\n\t\t: When -exitOnClose is specified, closing the view will exit application."
14324     "\n\t\t: When -closeOnEscape is specified, view will be closed on pressing Escape.",
14325     __FILE__, VDiffImage, group);
14326   theCommands.Add ("vselect",
14327     "vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1] [shift_selection = 0|1]\n"
14328     "- emulates different types of selection:\n"
14329     "- 1) single click selection\n"
14330     "- 2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)\n"
14331     "- 3) selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn)\n"
14332     "- 4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.\n"
14333     "     If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined \n"
14334     "     rectangle or polygon will be detected, otherwise algorithm will chose only fully included sensitives.\n"
14335     "     Default behavior is to detect only full inclusion. (partial inclusion - overlap - is not allowed by default)\n"
14336     "- 5) any of these selections with shift button pressed",
14337     __FILE__, VSelect, group);
14338   theCommands.Add ("vmoveto",
14339     "vmoveto [x y] [-reset]"
14340     "\n\t\t: Emulates cursor movement to pixel position (x,y)."
14341     "\n\t\t:   -reset resets current highlighting",
14342     __FILE__, VMoveTo, group);
14343   theCommands.Add ("vviewparams",
14344               "vviewparams [-args] [-scale [s]]"
14345       "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
14346       "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
14347       "\n\t\t: Manage current view parameters or prints all"
14348       "\n\t\t: current values when called without argument."
14349       "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
14350       "\n\t\t:   -eye  [x y z] prints or sets eye location"
14351       "\n\t\t:   -at   [x y z] prints or sets center of look"
14352       "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
14353       "\n\t\t:   -proj [x y z] prints or sets direction of look"
14354       "\n\t\t:   -center x y   sets location of center of the screen in pixels"
14355       "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
14356       "\n\t\t:                 or changes the size of its maximum dimension"
14357       "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
14358     __FILE__, VViewParams, group);
14359
14360   theCommands.Add("v2dmode",
14361     "v2dmode [-name viewName] [-mode {-on|-off}=-on]"
14362     "\n\t\t:   name   - name of existing view, if not defined, the active view is changed"
14363     "\n\t\t:   mode   - switches On/Off rotation mode"
14364     "\n\t\t: Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:"
14365     "\n\t\t:   - rotation of the view by 3rd mouse button with Ctrl active"
14366     "\n\t\t:   - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right"
14367     "\n\t\t: View camera position might be changed only by commands.",
14368     __FILE__, V2DMode, group);
14369
14370   theCommands.Add("vanimation", "Alias for vanim",
14371     __FILE__, VAnimation, group);
14372
14373   theCommands.Add("vanim",
14374             "List existing animations:"
14375     "\n\t\t:  vanim"
14376     "\n\t\t: Animation playback:"
14377     "\n\t\t:  vanim name -play|-resume [playFrom [playDuration]]"
14378     "\n\t\t:            [-speed Coeff] [-freeLook] [-lockLoop]"
14379     "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
14380     "\n\t\t:   -freeLook skip camera animations"
14381     "\n\t\t:   -lockLoop disable any interactions"
14382     "\n\t\t:"
14383     "\n\t\t: Animation definition:"
14384     "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
14385     "\n\t\t:        [start TimeSec] [duration TimeSec]"
14386     "\n\t\t:"
14387     "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
14388     "\n\t\t: specifies nested animations."
14389     "\n\t\t: There is no syntax to explicitly add new animation,"
14390     "\n\t\t: and all non-existing animations within the name will be"
14391     "\n\t\t: implicitly created on first use (including parents)."
14392     "\n\t\t:"
14393     "\n\t\t: Each animation might define the SINGLE action (see below),"
14394     "\n\t\t: like camera transition, object transformation or custom callback."
14395     "\n\t\t: Child animations can be used for defining concurrent actions."
14396     "\n\t\t:"
14397     "\n\t\t: Camera animation:"
14398     "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
14399     "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
14400     "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
14401     "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
14402     "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
14403     "\n\t\t:   -atX    camera Center positions pair"
14404     "\n\t\t:   -upX    camera Up directions pair"
14405     "\n\t\t:   -scaleX camera Scale factors pair"
14406     "\n\t\t: Object animation:"
14407     "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
14408     "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
14409     "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
14410     "\n\t\t:   -locX   object Location points pair (translation)"
14411     "\n\t\t:   -rotX   object Orientations pair (quaternions)"
14412     "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
14413     "\n\t\t: Custom callback:"
14414     "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
14415     "\n\t\t:   %Pts        overall animation presentation timestamp"
14416     "\n\t\t:   %LocalPts   local animation timestamp"
14417     "\n\t\t:   %Normalized local animation normalized value in range 0..1"
14418     "\n\t\t:"
14419     "\n\t\t: Video recording:"
14420     "\n\t\t:  vanim name -record FileName [Width Height] [-fps FrameRate=24]"
14421     "\n\t\t:             [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]"
14422     "\n\t\t:             [-crf Value] [-preset Preset]"
14423     "\n\t\t:   -fps     video framerate"
14424     "\n\t\t:   -format  file format, container (matroska, etc.)"
14425     "\n\t\t:   -vcodec  video codec identifier (ffv1, mjpeg, etc.)"
14426     "\n\t\t:   -pix_fmt image pixel format (yuv420p, rgb24, etc.)"
14427     "\n\t\t:   -crf     constant rate factor (specific to codec)"
14428     "\n\t\t:   -preset  codec parameters preset (specific to codec)"
14429     __FILE__, VAnimation, group);
14430
14431   theCommands.Add("vchangeselected",
14432     "vchangeselected shape"
14433     "- adds to shape to selection or remove one from it",
14434                 __FILE__, VChangeSelected, group);
14435   theCommands.Add ("vnbselected",
14436     "vnbselected"
14437     "\n\t\t: Returns number of selected objects", __FILE__, VNbSelected, group);
14438   theCommands.Add ("vcamera",
14439               "vcamera [PrsName] [-ortho] [-projtype]"
14440       "\n\t\t:         [-persp]"
14441       "\n\t\t:         [-fovy   [Angle]] [-distance [Distance]]"
14442       "\n\t\t:         [-stereo] [-leftEye] [-rightEye]"
14443       "\n\t\t:         [-iod [Distance]] [-iodType    [absolute|relative]]"
14444       "\n\t\t:         [-zfocus [Value]] [-zfocusType [absolute|relative]]"
14445       "\n\t\t:         [-fov2d  [Angle]] [-lockZup {0|1}]"
14446       "\n\t\t:         [-xrPose base|head=base]"
14447       "\n\t\t: Manages camera parameters."
14448       "\n\t\t: Displays frustum when presntation name PrsName is specified."
14449       "\n\t\t: Prints current value when option called without argument."
14450       "\n\t\t: Orthographic camera:"
14451       "\n\t\t:   -ortho      activate orthographic projection"
14452       "\n\t\t: Perspective camera:"
14453       "\n\t\t:   -persp      activate perspective  projection (mono)"
14454       "\n\t\t:   -fovy       field of view in y axis, in degrees"
14455       "\n\t\t:   -fov2d      field of view limit for 2d on-screen elements"
14456       "\n\t\t:   -distance   distance of eye from camera center"
14457       "\n\t\t:   -lockZup    lock Z up (tunrtable mode)"
14458       "\n\t\t: Stereoscopic camera:"
14459       "\n\t\t:   -stereo     perspective  projection (stereo)"
14460       "\n\t\t:   -leftEye    perspective  projection (left  eye)"
14461       "\n\t\t:   -rightEye   perspective  projection (right eye)"
14462       "\n\t\t:   -iod        intraocular distance value"
14463       "\n\t\t:   -iodType    distance type, absolute or relative"
14464       "\n\t\t:   -zfocus     stereographic focus value"
14465       "\n\t\t:   -zfocusType focus type, absolute or relative",
14466     __FILE__, VCamera, group);
14467   theCommands.Add ("vautozfit", "command to enable or disable automatic z-range adjusting\n"
14468     "- vautozfit [on={1|0}] [scale]\n"
14469     "    Prints or changes parameters of automatic z-fit mode:\n"
14470     "   \"on\" - turns automatic z-fit on or off\n"
14471     "   \"scale\" - specifies factor to scale computed z range.\n",
14472     __FILE__, VAutoZFit, group);
14473   theCommands.Add ("vzrange", "command to manually access znear and zfar values\n"
14474     "   vzrange                - without parameters shows current values\n"
14475     "   vzrange [znear] [zfar] - applies provided values to view",
14476     __FILE__,VZRange, group);
14477   theCommands.Add ("vpurgedisplay",
14478     "vpurgedisplay"
14479     "- removes structures which don't belong to objects displayed in neutral point",
14480     __FILE__, VPurgeDisplay, group);
14481   theCommands.Add("vsetviewsize",
14482     "vsetviewsize size",
14483     __FILE__,VSetViewSize,group);
14484   theCommands.Add("vmoveview",
14485     "vmoveview Dx Dy Dz [Start = 1|0]",
14486     __FILE__,VMoveView,group);
14487   theCommands.Add("vtranslateview",
14488     "vtranslateview Dx Dy Dz [Start = 1|0)]",
14489     __FILE__,VTranslateView,group);
14490   theCommands.Add("vturnview",
14491     "vturnview Ax Ay Az [Start = 1|0]",
14492     __FILE__,VTurnView,group);
14493   theCommands.Add("vtextureenv",
14494     "Enables or disables environment mapping in the 3D view, loading the texture from the given standard "
14495     "or user-defined file and optionally applying texture mapping parameters\n"
14496     "                  Usage:\n"
14497     "                  vtextureenv off - disables environment mapping\n"
14498     "                  vtextureenv on {std_texture|texture_file_name} [rep mod flt ss st ts tt rot] - enables environment mapping\n"
14499     "                              std_texture = (0..7)\n"
14500     "                              rep         = {clamp|repeat}\n"
14501     "                              mod         = {decal|modulate}\n"
14502     "                              flt         = {nearest|bilinear|trilinear}\n"
14503     "                              ss, st      - scale factors for s and t texture coordinates\n"
14504     "                              ts, tt      - translation for s and t texture coordinates\n"
14505     "                              rot         - texture rotation angle in degrees",
14506     __FILE__, VTextureEnv, group);
14507   theCommands.Add("vhlr",
14508             "vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]"
14509       "\n\t\t: Hidden Line Removal algorithm."
14510       "\n\t\t:   -showHidden if set ON, hidden lines are drawn as dotted ones"
14511       "\n\t\t:   -algoType   type of HLR algorithm.\n",
14512     __FILE__,VHLR,group);
14513   theCommands.Add("vhlrtype",
14514               "vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]"
14515       "\n\t\t: Changes the type of HLR algorithm using for shapes:"
14516       "\n\t\t:   'algo' - exact HLR algorithm is applied"
14517       "\n\t\t:   'polyAlgo' - polygonal HLR algorithm is applied"
14518       "\n\t\t: If shapes are not given - option is applied to all shapes in the view",
14519     __FILE__,VHLRType,group);
14520   theCommands.Add("vclipplane",
14521               "vclipplane planeName [{0|1}]"
14522       "\n\t\t:   [-equation1 A B C D]"
14523       "\n\t\t:   [-equation2 A B C D]"
14524       "\n\t\t:   [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]"
14525       "\n\t\t:   [-set|-unset|-setOverrideGlobal [objects|views]]"
14526       "\n\t\t:   [-maxPlanes]"
14527       "\n\t\t:   [-capping {0|1}]"
14528       "\n\t\t:     [-color R G B] [-transparency Value] [-hatch {on|off|ID}]"
14529       "\n\t\t:     [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]"
14530       "\n\t\t:       [-texRotate Angle]"
14531       "\n\t\t:     [-useObjMaterial {0|1}] [-useObjTexture {0|1}]"
14532       "\n\t\t:       [-useObjShader {0|1}]"
14533       "\n\t\t: Clipping planes management:"
14534       "\n\t\t:   -maxPlanes   print plane limit for view"
14535       "\n\t\t:   -delete      delete plane with given name"
14536       "\n\t\t:   {off|on|0|1} turn clipping on/off"
14537       "\n\t\t:   -set|-unset  set/unset plane for Object or View list;"
14538       "\n\t\t:                applied to active View when list is omitted"
14539       "\n\t\t:   -equation A B C D change plane equation"
14540       "\n\t\t:   -clone SourcePlane NewPlane clone the plane definition."
14541       "\n\t\t: Capping options:"
14542       "\n\t\t:   -capping {off|on|0|1} turn capping on/off"
14543       "\n\t\t:   -color R G B          set capping color"
14544       "\n\t\t:   -transparency Value   set capping transparency 0..1"
14545       "\n\t\t:   -texName Texture      set capping texture"
14546       "\n\t\t:   -texScale SX SY       set capping tex scale"
14547       "\n\t\t:   -texOrigin TX TY      set capping tex origin"
14548       "\n\t\t:   -texRotate Angle      set capping tex rotation"
14549       "\n\t\t:   -hatch {on|off|ID}    set capping hatching mask"
14550       "\n\t\t:   -useObjMaterial {off|on|0|1} use material of clipped object"
14551       "\n\t\t:   -useObjTexture  {off|on|0|1} use texture of clipped object"
14552       "\n\t\t:   -useObjShader   {off|on|0|1} use shader program of object",
14553       __FILE__, VClipPlane, group);
14554   theCommands.Add("vdefaults",
14555                "vdefaults [-absDefl value]"
14556        "\n\t\t:           [-devCoeff value]"
14557        "\n\t\t:           [-angDefl value]"
14558        "\n\t\t:           [-autoTriang {off/on | 0/1}]"
14559     , __FILE__, VDefaults, group);
14560   theCommands.Add("vlight",
14561     "tool to manage light sources, without arguments shows list of lights."
14562     "\n    Main commands: "
14563     "\n      '-clear' to clear lights"
14564     "\n      '-{def}aults' to load deafault lights"
14565     "\n      '-add' <type> to add any light source"
14566     "\n          where <type> is one of {amb}ient|directional|{spot}light|positional"
14567     "\n      'change' <lightId> to edit light source with specified lightId"
14568     "\n\n      In addition to 'add' and 'change' commands you can use light parameters:"
14569     "\n        -layer Id"
14570     "\n        -{pos}ition X Y Z"
14571     "\n        -{dir}ection X Y Z (for directional light or for spotlight)"
14572     "\n        -color colorName"
14573     "\n        -{head}light 0|1"
14574     "\n        -{sm}oothness value"
14575     "\n        -{int}ensity value"
14576     "\n        -{constAtten}uation value"
14577     "\n        -{linearAtten}uation value"
14578     "\n        -angle angleDeg"
14579     "\n        -{spotexp}onent value"
14580     "\n        -range value"
14581     "\n        -local|-global"
14582     "\n\n        example: vlight -add positional -head 1 -pos 0 1 1 -color red"
14583     "\n        example: vlight -change 0 -direction 0 -1 0 -linearAttenuation 0.2",
14584     __FILE__, VLight, group);
14585   theCommands.Add("vpbrenv",
14586     "vpbrenv -clear|-generate"
14587     "\n\t\t: Clears or generates PBR environment map of active view."
14588     "\n\t\t:  -clear clears PBR environment (fills by white color)"
14589     "\n\t\t:  -generate generates PBR environment from current background cubemap",
14590     __FILE__, VPBREnvironment, group);
14591   theCommands.Add("vraytrace",
14592             "vraytrace [0|1]"
14593     "\n\t\t: Turns on/off ray-tracing renderer."
14594     "\n\t\t:   'vraytrace 0' alias for 'vrenderparams -raster'."
14595     "\n\t\t:   'vraytrace 1' alias for 'vrenderparams -rayTrace'.",
14596     __FILE__, VRenderParams, group);
14597   theCommands.Add("vrenderparams",
14598     "\n    Manages rendering parameters: "
14599     "\n      '-raster'                   Disables GPU ray-tracing"
14600     "\n      '-msaa         0..4'        Specifies number of samples for MSAA"
14601     "\n      '-lineFeather  > 0'         Sets line feather factor"
14602     "\n      '-oit          off|0.0-1.0' Enables/disables OIT and sets depth weight factor"
14603     "\n      '-depthPrePass on|off'      Enables/disables depth pre-pass"
14604     "\n      '-alphatocoverage on|off'   Enables/disables alpha to coverage (needs MSAA)"
14605     "\n      '-rendScale    value        Rendering resolution scale factor"
14606     "\n      '-rayTrace'                 Enables  GPU ray-tracing"
14607     "\n      '-rayDepth     0..10'       Defines maximum ray-tracing depth"
14608     "\n      '-shadows      on|off'      Enables/disables shadows rendering"
14609     "\n      '-reflections  on|off'      Enables/disables specular reflections"
14610     "\n      '-fsaa         on|off'      Enables/disables adaptive anti-aliasing"
14611     "\n      '-gleam        on|off'      Enables/disables transparency shadow effects"
14612     "\n      '-gi           on|off'      Enables/disables global illumination effects"
14613     "\n      '-brng         on|off'      Enables/disables blocked RNG (fast coherent PT)"
14614     "\n      '-env          on|off'      Enables/disables environment map background"
14615     "\n      '-ignoreNormalMap on|off'   Enables/disables normal map ignoring during path tracing"
14616     "\n      '-twoside      on|off'      Enables/disables two-sided BSDF models (PT mode)"
14617     "\n      '-iss          on|off'      Enables/disables adaptive screen sampling (PT mode)"
14618     "\n      '-issd         on|off'      Shows screen sampling distribution in ISS mode"
14619     "\n      '-maxrad       > 0.0'       Value used for clamping radiance estimation (PT mode)"
14620     "\n      '-tileSize     1..4096'     Specifies   size of screen tiles in ISS mode (32 by default)"
14621     "\n      '-nbtiles      64..1024'    Specifies number of screen tiles per Redraw in ISS mode (256 by default)"
14622     "\n      '-rebuildGlsl  on|off'      Rebuild Ray-Tracing GLSL programs (for debugging)"
14623     "\n      '-shadingModel model'       Controls shading model from enumeration"
14624     "\n                                  unlit, flat, gouraud, phong"
14625     "\n      '-pbrEnvPow2size > 0'       Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size)"
14626     "\n      '-pbrEnvSMLN > 1'           Controls number of mipmap levels used in specular IBL map"
14627     "\n      '-pbrEnvBDSN > 0'           Controls number of samples in Monte-Carlo integration during diffuse IBL map's sherical harmonics calculation"
14628     "\n      '-pbrEnvBSSN > 0'           Controls maximum number of samples per mipmap level in Monte-Carlo integration during specular IBL maps generation"
14629     "\n      '-pbrEnvBP [0, 1]'          Controls strength of samples number reducing during specular IBL maps generation (1 disables reducing)"
14630     "\n      '-resolution   value'       Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
14631     "\n      '-aperture     >= 0.0'      Aperture size  of perspective camera for depth-of-field effect (0 disables DOF)"
14632     "\n      '-focal        >= 0.0'      Focal distance of perspective camera for depth-of-field effect"
14633     "\n      '-exposure     value'       Exposure value for tone mapping (0.0 value disables the effect)"
14634     "\n      '-whitepoint   value'       White point value for filmic tone mapping"
14635     "\n      '-tonemapping  mode'        Tone mapping mode (disabled, filmic)"
14636     "\n      '-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points"
14637     "\n      '              |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate'"
14638     "\n                                  Show/hide performance counters (flags can be combined)"
14639     "\n      '-perfUpdateInterval nbSeconds' Performance counters update interval"
14640     "\n      '-perfChart    nbFrames'    Show frame timers chart limited by specified number of frames"
14641     "\n      '-perfChartMax seconds'     Maximum time in seconds with the chart"
14642     "\n      '-frustumCulling on|off|noupdate' Enable/disable objects frustum clipping or"
14643     "\n                                        set state to check structures culled previously."
14644     "\n    Unlike vcaps, these parameters dramatically change visual properties."
14645     "\n    Command is intended to control presentation quality depending on"
14646     "\n    hardware capabilities and performance.",
14647     __FILE__, VRenderParams, group);
14648   theCommands.Add("vstatprofiler",
14649     "\n vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups"
14650     "\n                |allArrays|fillArrays|lineArrays|pointArrays|textArrays"
14651     "\n                |triangles|points|geomMem|textureMem|frameMem"
14652     "\n                |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage"
14653     "\n                |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]"
14654     "\n                [-noredraw]"
14655     "\n\t\t: Prints rendering statistics."
14656     "\n\t\t:   If there are some parameters - print corresponding statistic counters values,"
14657     "\n\t\t:   else - print all performance counters set previously."
14658     "\n\t\t:   '-noredraw' Flag to avoid additional redraw call and use already collected values.\n",
14659     __FILE__, VStatProfiler, group);
14660   theCommands.Add ("vplace",
14661             "vplace dx dy"
14662     "\n\t\t: Places the point (in pixels) at the center of the window",
14663     __FILE__, VPlace, group);
14664   theCommands.Add("vxrotate",
14665     "vxrotate",
14666     __FILE__,VXRotate,group);
14667
14668     theCommands.Add("vmanipulator",
14669       "\n    vmanipulator Name [-attach AISObject | -detach | ...]"
14670       "\n    tool to create and manage AIS manipulators."
14671       "\n    Options: "
14672       "\n      '-attach AISObject'                 attach manipulator to AISObject"
14673       "\n      '-adjustPosition {0|1}'             adjust position when attaching"
14674       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
14675       "\n      '-enableModes    {0|1}'             enable modes when attaching"
14676       "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
14677       "\n                                          by default it is displayed in all views of the current viewer"
14678       "\n      '-detach'                           detach manipulator"
14679       "\n      '-startTransform mouse_x mouse_y' - invoke start of transformation"
14680       "\n      '-transform      mouse_x mouse_y' - invoke transformation"
14681       "\n      '-stopTransform  [abort]'         - invoke stop of transformation"
14682       "\n      '-move x y z'                     - move attached object"
14683       "\n      '-rotate x y z dx dy dz angle'    - rotate attached object"
14684       "\n      '-scale factor'                   - scale attached object"
14685       "\n      '-autoActivate      {0|1}'        - set activation on detection"
14686       "\n      '-followTranslation {0|1}'        - set following translation transform"
14687       "\n      '-followRotation    {0|1}'        - set following rotation transform"
14688       "\n      '-followDragging    {0|1}'        - set following dragging transform"
14689       "\n      '-gap value'                      - set gap between sub-parts"
14690       "\n      '-part axis mode    {0|1}'        - set visual part"
14691       "\n      '-parts axis mode   {0|1}'        - set visual part"
14692       "\n      '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator"
14693       "\n      '-size value'                     - set size of manipulator"
14694       "\n      '-zoomable {0|1}'                 - set zoom persistence",
14695     __FILE__, VManipulator, group);
14696
14697   theCommands.Add("vselprops",
14698     "\n    vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]"
14699     "\n    Customizes selection and dynamic highlight parameters for the whole interactive context:"
14700     "\n    -autoActivate {0|1}     : disables|enables default computation and activation of global selection mode"
14701     "\n    -autoHighlight {0|1}    : disables|enables automatic highlighting in 3D Viewer"
14702     "\n    -highlightSelected {0|1}: disables|enables highlighting of detected object in selected state"
14703     "\n    -pickStrategy {first|topmost} : defines picking strategy"
14704     "\n                            'first'   to pick first acceptable (default)"
14705     "\n                            'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)"
14706     "\n    -pixTol    value        : sets up pixel tolerance"
14707     "\n    -dispMode  dispMode     : sets display mode for highlighting"
14708     "\n    -layer     ZLayer       : sets ZLayer for highlighting"
14709     "\n    -color     {name|r g b} : sets highlight color"
14710     "\n    -transp    value        : sets transparency coefficient for highlight"
14711     "\n    -material  material     : sets highlight material"
14712     "\n    -print                  : prints current state of all mentioned parameters",
14713     __FILE__, VSelectionProperties, group);
14714   theCommands.Add ("vhighlightselected",
14715                    "vhighlightselected [0|1]: alias for vselprops -highlightSelected.\n",
14716                    __FILE__, VSelectionProperties, group);
14717
14718   theCommands.Add ("vseldump",
14719                    "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
14720                    "\n\t\t:       [-xrPose base|head=base]"
14721                    "\n\t\t: Generate an image based on detection results:"
14722                    "\n\t\t:   depth       normalized depth values"
14723                    "\n\t\t:   unnormDepth unnormalized depth values"
14724                    "\n\t\t:   object      color of detected object"
14725                    "\n\t\t:   owner       color of detected owner"
14726                    "\n\t\t:   selMode     color of selection mode"
14727                    "\n\t\t:   entity      color of etected entity",
14728                    __FILE__, VDumpSelectionImage, group);
14729
14730   theCommands.Add ("vviewcube",
14731                    "vviewcube name"
14732                    "\n\t\t: Displays interactive view manipualtion object."
14733                    "\n\t\t: Options: "
14734                    "\n\t\t:   -reset                   reset geomertical and visual attributes'"
14735                    "\n\t\t:   -size Size               adapted size of View Cube"
14736                    "\n\t\t:   -boxSize Size            box size"
14737                    "\n\t\t:   -axes {0|1 }             show/hide axes (trihedron)"
14738                    "\n\t\t:   -edges {0|1}             show/hide edges of View Cube"
14739                    "\n\t\t:   -vertices {0|1}          show/hide vertices of View Cube"
14740                    "\n\t\t:   -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation"
14741                    "\n\t\t:   -color Color             color of View Cube"
14742                    "\n\t\t:   -boxColor Color          box color"
14743                    "\n\t\t:   -boxSideColor Color      box sides color"
14744                    "\n\t\t:   -boxEdgeColor Color      box edges color"
14745                    "\n\t\t:   -boxCornerColor Color    box corner color"
14746                    "\n\t\t:   -textColor Color         color of side text of view cube"
14747                    "\n\t\t:   -innerColor Color        inner box color"
14748                    "\n\t\t:   -transparency Value      transparency of object within [0, 1] range"
14749                    "\n\t\t:   -boxTransparency Value   transparency of box    within [0, 1] range"
14750                    "\n\t\t:   -font Name               font name"
14751                    "\n\t\t:   -fontHeight Value        font height"
14752                    "\n\t\t:   -boxFacetExtension Value box facet extension"
14753                    "\n\t\t:   -boxEdgeGap Value        gap between box edges and box sides"
14754                    "\n\t\t:   -boxEdgeMinSize Value    minimal box edge size"
14755                    "\n\t\t:   -boxCornerMinSize Value  minimal box corner size"
14756                    "\n\t\t:   -axesPadding Value       padding between box and arrows"
14757                    "\n\t\t:   -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range"
14758                    "\n\t\t:   -axesRadius Value        radius of axes of the trihedron"
14759                    "\n\t\t:   -axesConeRadius Value    radius of the cone (arrow) of the trihedron"
14760                    "\n\t\t:   -axesSphereRadius Value  radius of the sphere (central point) of trihedron"
14761                    "\n\t\t:   -fixedanimation {0|1}    uninterruptible animation loop"
14762                    "\n\t\t:   -duration Seconds        animation duration in seconds",
14763     __FILE__, VViewCube, group);
14764
14765   theCommands.Add("vcolorconvert" ,
14766                   "vcolorconvert {from|to} type C1 C2 C2"
14767                   "\n\t\t: vcolorconvert from type C1 C2 C2: Converts color from specified color space to linear RGB"
14768                   "\n\t\t: vcolorconvert to type R G B: Converts linear RGB color to specified color space"
14769                   "\n\t\t: type can be sRGB, HLS, Lab, or Lch",
14770                   __FILE__,VColorConvert,group);
14771   theCommands.Add("vcolordiff" ,
14772                   "vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
14773                   __FILE__,VColorDiff,group);
14774 }