0031709: Draw Harness - move methods ViewerTest::ParseOnOff()/ParseColor() to package...
[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_LocalArray.hxx>
59 #include <NCollection_Vector.hxx>
60 #include <OSD.hxx>
61 #include <OSD_Timer.hxx>
62 #include <OpenGl_GraphicDriver.hxx>
63 #include <Prs3d_ShadingAspect.hxx>
64 #include <Prs3d_Drawer.hxx>
65 #include <Prs3d_LineAspect.hxx>
66 #include <Prs3d_Root.hxx>
67 #include <Prs3d_Text.hxx>
68 #include <Select3D_SensitivePrimitiveArray.hxx>
69 #include <TColStd_HSequenceOfAsciiString.hxx>
70 #include <TColStd_SequenceOfInteger.hxx>
71 #include <TColStd_HSequenceOfReal.hxx>
72 #include <TColgp_Array1OfPnt2d.hxx>
73 #include <TColStd_MapOfAsciiString.hxx>
74 #include <ViewerTest_AutoUpdater.hxx>
75 #include <ViewerTest_ContinuousRedrawer.hxx>
76 #include <ViewerTest_EventManager.hxx>
77 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
78 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
79 #include <ViewerTest_CmdParser.hxx>
80 #include <ViewerTest_V3dView.hxx>
81 #include <V3d_AmbientLight.hxx>
82 #include <V3d_DirectionalLight.hxx>
83 #include <V3d_PositionalLight.hxx>
84 #include <V3d_SpotLight.hxx>
85
86 #include <tcl.h>
87
88 #include <cstdlib>
89
90 #if defined(_WIN32)
91   #include <WNT_WClass.hxx>
92   #include <WNT_Window.hxx>
93   #include <WNT_HIDSpaceMouse.hxx>
94 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
95   #include <Cocoa_Window.hxx>
96 #else
97   #include <Xw_Window.hxx>
98   #include <X11/Xlib.h> /* contains some dangerous #defines such as Status, True etc. */
99   #include <X11/Xutil.h>
100   #include <tk.h>
101 #endif
102
103 //==============================================================================
104 //  VIEWER GLOBAL VARIABLES
105 //==============================================================================
106
107 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
108 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
109
110 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
111 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
112
113 #if defined(_WIN32)
114 static Handle(WNT_Window)& VT_GetWindow() {
115   static Handle(WNT_Window) WNTWin;
116   return WNTWin;
117 }
118 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
119 static Handle(Cocoa_Window)& VT_GetWindow()
120 {
121   static Handle(Cocoa_Window) aWindow;
122   return aWindow;
123 }
124 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
125 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
126
127 #else
128 static Handle(Xw_Window)& VT_GetWindow(){
129   static Handle(Xw_Window) XWWin;
130   return XWWin;
131 }
132
133 static void VProcessEvents(ClientData,int);
134 #endif
135
136 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
137 {
138   static Handle(Aspect_DisplayConnection) aDisplayConnection;
139   return aDisplayConnection;
140 }
141
142 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
143 {
144   GetDisplayConnection() = theDisplayConnection;
145 }
146
147 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
148 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
149 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
150 static OpenGl_Caps ViewerTest_myDefaultCaps;
151
152 static void OSWindowSetup();
153
154 static struct
155 {
156   Quantity_Color FlatColor;
157   Quantity_Color GradientColor1;
158   Quantity_Color GradientColor2;
159   Aspect_GradientFillMethod FillMethod;
160 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
161
162 //==============================================================================
163 //  EVENT GLOBAL VARIABLES
164 //==============================================================================
165
166 Standard_Boolean TheIsAnimating = Standard_False;
167
168 namespace
169 {
170
171   //! Checks if some set is a subset of other set
172   //! @tparam TheSuperSet the type of the superset
173   //! @tparam TheSubSet the type of the subset
174   //! @param theSuperSet the superset
175   //! @param theSubSet the subset to be checked
176   //! @return true if the superset includes subset, or false otherwise
177   template <typename TheSuperSet, typename TheSubSet>
178   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
179   {
180     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
181   }
182
183   //! A variable set of keys for command-line options.
184   //! It includes a set of mandatory keys and a set of all possible keys.
185   class CommandOptionKeyVariableSet
186   {
187   public:
188     //! Default constructor
189     CommandOptionKeyVariableSet()
190     {
191     }
192
193     //! Constructor
194     //! @param theMandatoryKeySet the set of the mandatory option keys
195     //! @param theAdditionalKeySet the set of additional options that could be omitted
196     CommandOptionKeyVariableSet (
197       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
198       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
199     : myMandatoryKeySet (theMandatoryKeySet)
200     {
201       std::set_union (theMandatoryKeySet.begin(),
202                       theMandatoryKeySet.end(),
203                       theAdditionalKeySet.begin(),
204                       theAdditionalKeySet.end(),
205                       std::inserter (myFullKeySet, myFullKeySet.begin()));
206     }
207
208     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
209     //! and be contained in the full key set)
210     //! @param theCheckedKeySet the set of option keys to be checked
211     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
212     {
213       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
214     }
215
216   private:
217     //! A set of mandatory command-line option keys
218     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
219
220     //! A full set of command-line option keys (includes mandatory and additional option keys)
221     ViewerTest_CommandOptionKeySet myFullKeySet;
222   };
223
224   //! Gets some code by its name
225   //! @tparam TheCode the type of a code to be found
226   //! @param theCodeNameMap the map from code names to codes
227   //! @param theCodeName the name of a code to be found
228   //! @param theCode the code to be found
229   //! @return true if a code is found, or false otherwise
230   template <typename TheCode>
231   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
232                                  TCollection_AsciiString                           theCodeName,
233                                  TheCode&                                          theCode)
234   {
235     theCodeName.LowerCase();
236     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
237       theCodeName);
238     if (aCodeIterator == theCodeNameMap.end())
239     {
240       return false;
241     }
242     theCode = aCodeIterator->second;
243     return true;
244   }
245
246   // Defines possible commands related to background changing
247   enum BackgroundCommand
248   {
249     BackgroundCommand_Main,              //!< The main command that manages other commands through options
250     BackgroundCommand_Image,             //!< Sets an image as a background
251     BackgroundCommand_ImageMode,         //!< Changes a background image mode
252     BackgroundCommand_Gradient,          //!< Sets a gradient as a background
253     BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
254     BackgroundCommand_Color,             //!< Fills background with a specified color
255     BackgroundCommand_Default            //!< Sets the background default color or gradient
256   };
257
258   //! Map from background command names to its codes
259   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
260
261   //! Creates a map from background command names to its codes
262   //! @return a map from background command names to its codes
263   static BackgroundCommandNameMap createBackgroundCommandNameMap()
264   {
265     BackgroundCommandNameMap aBackgroundCommandNameMap;
266     aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
267     aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
268     aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
269     aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
270     aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
271     aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
272     aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
273     return aBackgroundCommandNameMap;
274   }
275
276   //! Gets a background command by its name
277   //! @param theBackgroundCommandName the name of the background command
278   //! @param theBackgroundCommand the background command to be found
279   //! @return true if a background command is found, or false otherwise
280   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
281                                           BackgroundCommand&             theBackgroundCommand)
282   {
283     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
284     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
285   }
286
287   //! Map from background image fill method names to its codes
288   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
289
290   //! Creates a map from background image fill method names to its codes
291   //! @return a map from background image fill method names to its codes
292   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
293   {
294     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
295     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
296     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
297     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
298     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
299     return aBackgroundImageFillMethodNameMap;
300   }
301
302   //! Gets a background image fill method by its name
303   //! @param theBackgroundImageFillMethodName the name of the background image fill method
304   //! @param theBackgroundImageFillMethod the background image fill method to be found
305   //! @return true if a background image fill method is found, or false otherwise
306   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
307                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
308   {
309     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
310       createBackgroundImageFillMethodNameMap();
311     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
312                               theBackgroundImageFillMethodName,
313                               theBackgroundImageFillMethod);
314   }
315
316   //! Map from background gradient fill method names to its codes
317   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
318
319   //! Creates a map from background gradient fill method names to its codes
320   //! @return a map from background gradient fill method names to its codes
321   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
322   {
323     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
324     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
325     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
326     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
327     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
328     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
329     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
330     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
331     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
332     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
333     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
334     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
335     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
336     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
337     return aBackgroundGradientFillMethodNameMap;
338   }
339
340   //! Gets a gradient fill method by its name
341   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
342   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
343   //! @return true if a gradient fill method is found, or false otherwise
344   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
345                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
346   {
347     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
348       createBackgroundGradientFillMethodNameMap();
349     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
350                               theBackgroundGradientFillMethodName,
351                               theBackgroundGradientFillMethod);
352   }
353
354   //! Changes the background in accordance with passed command line options
355   class BackgroundChanger
356   {
357   public:
358     //! Constructor. Prepares the command parser
359     BackgroundChanger()
360     {
361       prepareCommandParser();
362     }
363
364     //! Processes the command line and changes the background
365     //! @param theDrawInterpretor the interpreter of the Draw Harness application
366     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
367     //! @param theCommandLineArguments the array of command line arguments
368     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
369                              const Standard_Integer   theNumberOfCommandLineArguments,
370                              const char* const* const theCommandLineArguments)
371     {
372       const char* const aBackgroundCommandName = theCommandLineArguments[0];
373       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
374       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
375       {
376         return false;
377       }
378       addCommandDescription (aBackgroundCommand);
379       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
380       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
381     }
382
383   private:
384     //! The type of functions that are able to set gradient background filling
385     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
386                                       const Quantity_Color& /* theColor2 */,
387                                       const Aspect_GradientFillMethod /* theGradientMode */);
388
389     //! The type of functions that are able to fill a background with a specific color
390     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
391
392     //! the command parser used to parse command line options and its arguments
393     ViewerTest_CmdParser myCommandParser;
394
395     //! the option key for the command that sets an image as a background
396     ViewerTest_CommandOptionKey myImageOptionKey;
397
398     //! the option key for the command that sets a background image fill type
399     ViewerTest_CommandOptionKey myImageModeOptionKey;
400
401     //! the option key for the command that sets a gradient filling for the background
402     ViewerTest_CommandOptionKey myGradientOptionKey;
403
404     //! the option key for the command that sets a background gradient filling method
405     ViewerTest_CommandOptionKey myGradientModeOptionKey;
406
407     //! the option key for the command that fills background with a specific color
408     ViewerTest_CommandOptionKey myColorOptionKey;
409
410     //! the option key for the command that sets default background gradient or color
411     ViewerTest_CommandOptionKey myDefaultOptionKey;
412
413     //! the option key for the command that sets an environment cubemap as a background
414     ViewerTest_CommandOptionKey myCubeMapOptionKey;
415
416     //! the option key for the command that defines order of tiles in one image packed cubemap
417     ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
418
419     //! the option key for the command that sets inversion of Z axis for background cubemap
420     ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
421
422     //! the option key for the command that allows skip IBL map generation
423     ViewerTest_CommandOptionKey myCubeMapDoNotGenPBREnvOptionKey;
424
425     //! the variable set of options that are allowed for the old scenario (without any option passed)
426     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
427
428     //! the variable set of options that are allowed for setting an environment cubemap as background
429     CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
430
431     //! the variable set of options that are allowed for setting an image as a background
432     CommandOptionKeyVariableSet myImageOptionVariableSet;
433
434     //! the variable set of options that are allowed for setting a background image fill type
435     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
436
437     //! the variable set of options that are allowed for setting a gradient filling for the background
438     CommandOptionKeyVariableSet myGradientOptionVariableSet;
439
440     //! the variable set of options that are allowed for setting a background gradient filling method
441     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
442
443     //! the variable set of options that are allowed for filling a background with a specific color
444     CommandOptionKeyVariableSet myColorOptionVariableSet;
445
446     //! the variable set of options that are allowed for setting a default background gradient
447     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
448
449     //! the variable set of options that are allowed for setting a default background color
450     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
451
452     //! the variable set of options that are allowed for printing help
453     CommandOptionKeyVariableSet myHelpOptionVariableSet;
454
455     //! Adds options to command parser
456     void addOptionsToCommandParser()
457     {
458       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
459                                                     "filename of image used as background");
460       myImageModeOptionKey = myCommandParser.AddOption (
461         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
462       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
463                                                        "sets background gradient starting and ending colors");
464       myGradientModeOptionKey =
465         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
466                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
467                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
468       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
469       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
470
471       myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
472       myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
473       myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
474         "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
475       myCubeMapDoNotGenPBREnvOptionKey = myCommandParser.AddOption ("nopbrenv", "whether IBL map generation should be skipped");
476     }
477
478     //! Creates option sets used to determine if a passed option set is valid or not
479     void createOptionSets()
480     {
481       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
482       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
483       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
484
485       ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
486       aCubeMapOptionSet.insert (myCubeMapOptionKey);
487       ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
488       aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
489       aCubeMapAdditionalOptionKeySet.insert (myCubeMapDoNotGenPBREnvOptionKey);
490       aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
491       myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
492
493       ViewerTest_CommandOptionKeySet anImageOptionSet;
494       anImageOptionSet.insert (myImageOptionKey);
495       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
496       anImageModeOptionSet.insert (myImageModeOptionKey);
497       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
498       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
499
500       ViewerTest_CommandOptionKeySet aGradientOptionSet;
501       aGradientOptionSet.insert (myGradientOptionKey);
502       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
503       aGradientModeOptionSet.insert (myGradientModeOptionKey);
504       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
505       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
506
507       ViewerTest_CommandOptionKeySet aColorOptionSet;
508       aColorOptionSet.insert (myColorOptionKey);
509       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
510
511       aGradientOptionSet.insert (myDefaultOptionKey);
512       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
513       aColorOptionSet.insert (myDefaultOptionKey);
514       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
515
516       ViewerTest_CommandOptionKeySet aHelpOptionSet;
517       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
518       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
519     }
520
521     //! Prepares the command parser. Adds options and creates option sets used to determine
522     //! if a passed option set is valid or not
523     void prepareCommandParser()
524     {
525       addOptionsToCommandParser();
526       createOptionSets();
527     }
528
529     //! Adds a command description to the command parser
530     //! @param theBackgroundCommand the key of the command which description is added to the command parser
531     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
532     {
533       std::string aDescription;
534       bool        isMainCommand = false;
535       switch (theBackgroundCommand)
536       {
537         case BackgroundCommand_Main:
538           aDescription  = "Command: vbackground (changes background or some background settings)";
539           isMainCommand = true;
540           break;
541         case BackgroundCommand_Image:
542           aDescription = "Command: vsetbg (loads image as a background)";
543           break;
544         case BackgroundCommand_ImageMode:
545           aDescription = "Command: vsetbgmode (changes background fill type)";
546           break;
547         case BackgroundCommand_Gradient:
548           aDescription = "Command: vsetgradientbg (mounts gradient background)";
549           break;
550         case BackgroundCommand_GradientMode:
551           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
552           break;
553         case BackgroundCommand_Color:
554           aDescription = "Command: vsetcolorbg (sets color background)";
555           break;
556         case BackgroundCommand_Default:
557           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
558           break;
559         default:
560           return;
561       }
562       if (!isMainCommand)
563       {
564         aDescription += "\nThis command is obsolete. Use vbackground instead.";
565       }
566       myCommandParser.SetDescription (aDescription);
567     }
568
569     //! Check if a viewer is needed to be initialized
570     //! @param theBackgroundCommand the key of the command that changes the background
571     //! @return true if processing was successful, or false otherwise
572     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
573     {
574       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
575       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
576       const bool                           aViewerIsNotNeeded =
577         (theBackgroundCommand == BackgroundCommand_Default)
578         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
579         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
580         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
581       return !aViewerIsNotNeeded;
582     }
583
584     //! Check if a viewer is initialized
585     //! @param theBackgroundCommandName the name of the command that changes the background
586     //! @param theDrawInterpretor the interpreter of the Draw Harness application
587     //! @return true if a viewer is initialized, or false otherwise
588     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
589                                           Draw_Interpretor& theDrawInterpretor)
590     {
591       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
592       if (anAISContext.IsNull())
593       {
594         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
595         return false;
596       }
597       return true;
598     }
599
600     //! Processes command options
601     //! @param theBackgroundCommandName the name of the command that changes the background
602     //! @param theBackgroundCommand the key of the command that changes the background
603     //! @param theDrawInterpretor the interpreter of the Draw Harness application
604     //! @return true if processing was successful, or false otherwise
605     bool processCommandOptions (const char* const       theBackgroundCommandName,
606                                 const BackgroundCommand theBackgroundCommand,
607                                 Draw_Interpretor&       theDrawInterpretor) const
608     {
609       if (myCommandParser.HasNoOption())
610       {
611         return printHelp (theBackgroundCommandName, theDrawInterpretor);
612       }
613       if (checkViewerIsNeeded (theBackgroundCommand)
614           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
615       {
616         return false;
617       }
618       if (myCommandParser.HasOnlyUnnamedOption())
619       {
620         return processUnnamedOption (theBackgroundCommand);
621       }
622       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
623     }
624
625     //! Processes the unnamed option
626     //! @param theBackgroundCommand the key of the command that changes the background
627     //! @return true if processing was successful, or false otherwise
628     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
629     {
630       switch (theBackgroundCommand)
631       {
632         case BackgroundCommand_Main:
633           return false;
634         case BackgroundCommand_Image:
635           return processImageUnnamedOption();
636         case BackgroundCommand_ImageMode:
637           return processImageModeUnnamedOption();
638         case BackgroundCommand_Gradient:
639           return processGradientUnnamedOption();
640         case BackgroundCommand_GradientMode:
641           return processGradientModeUnnamedOption();
642         case BackgroundCommand_Color:
643           return processColorUnnamedOption();
644         case BackgroundCommand_Default:
645           return processDefaultUnnamedOption();
646         default:
647           return false;
648       }
649     }
650
651     //! Processes the image unnamed option
652     //! @return true if processing was successful, or false otherwise
653     bool processImageUnnamedOption() const
654     {
655       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
656         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
657       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
658       {
659         return false;
660       }
661       std::string anImageFileName;
662       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
663       {
664         return false;
665       }
666       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
667       if (aNumberOfImageUnnamedOptionArguments == 2)
668       {
669         std::string anImageModeString;
670         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
671         {
672           return false;
673         }
674         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
675         {
676           return false;
677         }
678       }
679       setImage (anImageFileName.c_str(), anImageMode);
680       return true;
681     }
682
683     //! Processes the image mode unnamed option
684     //! @return true if processing was successful, or false otherwise
685     bool processImageModeUnnamedOption() const
686     {
687       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
688     }
689
690     //! Processes the gradient unnamed option
691     //! @param theSetGradient the function used to set a background gradient filling
692     //! @return true if processing was successful, or false otherwise
693     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
694     {
695       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
696         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
697       if (aNumberOfGradientUnnamedOptionArguments < 2)
698       {
699         return false;
700       }
701
702       Standard_Integer anArgumentIndex = 0;
703       Quantity_Color   aColor1;
704       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
705       {
706         return false;
707       }
708       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
709       {
710         return false;
711       }
712
713       Quantity_Color aColor2;
714       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
715       {
716         return false;
717       }
718       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
719       {
720         return false;
721       }
722
723       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
724       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
725       {
726         std::string anGradientModeString;
727
728         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
729                                   anArgumentIndex,
730                                   anGradientModeString))
731         {
732           return false;
733         }
734         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
735         {
736           return false;
737         }
738         ++anArgumentIndex;
739       }
740       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
741       {
742         return false;
743       }
744       theSetGradient (aColor1, aColor2, aGradientMode);
745       return true;
746     }
747
748     //! Processes the gradient mode unnamed option
749     //! @return true if processing was successful, or false otherwise
750     bool processGradientModeUnnamedOption() const
751     {
752       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
753     }
754
755     //! Processes the color unnamed option
756     //! @param theSetColor the function used to set a background color
757     //! @return true if processing was successful, or false otherwise
758     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
759     {
760       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
761     }
762
763     //! Processes the default back unnamed option
764     //! @return true if processing was successful, or false otherwise
765     bool processDefaultUnnamedOption() const
766     {
767       if (processGradientUnnamedOption (setDefaultGradient))
768       {
769         return true;
770       }
771       return processColorUnnamedOption (setDefaultColor);
772     }
773
774     //! Processes named options
775     //! @param theBackgroundCommandName the name of the command that changes the background
776     //! @param theBackgroundCommand the key of the command that changes the background
777     //! @param theDrawInterpretor the interpreter of the Draw Harness application
778     //! @return true if processing was successful, or false otherwise
779     bool processNamedOptions (const char* const       theBackgroundCommandName,
780                               const BackgroundCommand theBackgroundCommand,
781                               Draw_Interpretor&       theDrawInterpretor) const
782     {
783       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
784       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
785       if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
786       {
787         return processCubeMapOptionSet();
788       }
789       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
790           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
791       {
792         return processImageOptionSet();
793       }
794       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
795           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
796       {
797         return processImageModeOptionSet();
798       }
799       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
800           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
801       {
802         return processGradientOptionSet();
803       }
804       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
805           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
806       {
807         return processGradientModeOptionSet();
808       }
809       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
810           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
811       {
812         return processColorOptionSet();
813       }
814       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
815           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
816               && (theBackgroundCommand == BackgroundCommand_Default)))
817       {
818         return processDefaultGradientOptionSet();
819       }
820       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
821           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
822       {
823         return processDefaultColorOptionSet();
824       }
825       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
826       {
827         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
828       }
829       return false;
830     }
831
832     //! Process the cubemap option set in named and unnamed case.
833     //! @return true if processing was successful, or false otherwise
834     bool processCubeMapOptionSet() const
835     {
836       NCollection_Array1<TCollection_AsciiString> aFilePaths;
837
838       if (!processCubeMapOptions (aFilePaths))
839       {
840         return false;
841       }
842
843       Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
844
845       if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
846       {
847         if (!processCubeMapOrderOptions (anOrder))
848         {
849           return false;
850         }
851       }
852
853       bool aZIsInverted = false;
854       if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
855       {
856         if (!processCubeMapInvertedZOptionSet())
857         {
858           return false;
859         }
860         aZIsInverted = true;
861       }
862
863       bool aToGenPBREnv = true;
864       if (myCommandParser.HasOption (myCubeMapDoNotGenPBREnvOptionKey))
865       {
866         if (!processCubeMapDoNotGenPBREnvOptionSet())
867         {
868           return false;
869         }
870         aToGenPBREnv = false;
871       }
872
873       setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted, aToGenPBREnv);
874       return true;
875     }
876
877     //! Processes the image option set
878     //! @return true if processing was successful, or false otherwise
879     bool processImageOptionSet() const
880     {
881       std::string anImageFileName;
882       if (!processImageOption (anImageFileName))
883       {
884         return false;
885       }
886       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
887       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
888       {
889         return false;
890       }
891       setImage (anImageFileName.c_str(), anImageMode);
892       return true;
893     }
894
895     //! Processes the image mode option set
896     //! @return true if processing was successful, or false otherwise
897     bool processImageModeOptionSet() const
898     {
899       return processImageModeOptionSet (myImageModeOptionKey);
900     }
901
902     //! Processes the image mode option set
903     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
904     //! @return true if processing was successful, or false otherwise
905     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
906     {
907       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
908       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
909       {
910         return false;
911       }
912       setImageMode (anImageMode);
913       return true;
914     }
915
916     //! Processes the gradient option set
917     //! @param theSetGradient the function used to set a background gradient filling
918     //! @return true if processing was successful, or false otherwise
919     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
920     {
921       Quantity_Color aColor1;
922       Quantity_Color aColor2;
923       if (!processGradientOption (aColor1, aColor2))
924       {
925         return false;
926       }
927       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
928       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
929       {
930         return false;
931       }
932       theSetGradient (aColor1, aColor2, aGradientMode);
933       return true;
934     }
935
936     //! Processes the gradient mode option set
937     //! @return true if processing was successful, or false otherwise
938     bool processGradientModeOptionSet() const
939     {
940       return processGradientModeOptionSet (myGradientModeOptionKey);
941     }
942
943     //! Processes the gradient mode option set
944     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
945     //! @return true if processing was successful, or false otherwise
946     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
947     {
948       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
949       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
950       {
951         return false;
952       }
953       setGradientMode (aGradientMode);
954       return true;
955     }
956
957     //! Processes the color option set
958     //! @param theSetColor the function used to set a background color
959     //! @return true if processing was successful, or false otherwise
960     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
961     {
962       return processColorOptionSet (myColorOptionKey, theSetColor);
963     }
964
965     //! Processes the default color option set
966     //! @return true if processing was successful, or false otherwise
967     bool processDefaultGradientOptionSet() const
968     {
969       return processGradientOptionSet (setDefaultGradient);
970     }
971
972     //! Processes the default gradient option set
973     //! @return true if processing was successful, or false otherwise
974     bool processDefaultColorOptionSet() const
975     {
976       return processColorOptionSet (setDefaultColor);
977     }
978
979     //! Processes the color option set
980     //! @param theColorOptionKey the key of the option that is interpreted as a color option
981     //! @param theSetColor the function used to set a background color
982     //! @return true if processing was successful, or false otherwise
983     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
984                                 SetColorFunction* const           theSetColor = setColor) const
985     {
986       Quantity_Color aColor;
987       if (!processColorOption (theColorOptionKey, aColor))
988       {
989         return false;
990       }
991       theSetColor (aColor);
992       return true;
993     }
994
995     //! Processes the help option set
996     //! @param theBackgroundCommandName the name of the command that changes the background
997     //! @param theDrawInterpretor the interpreter of the Draw Harness application
998     //! @return true if processing was successful, or false otherwise
999     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
1000     {
1001       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1002         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
1003       if (aNumberOfHelpOptionArguments != 0)
1004       {
1005         return false;
1006       }
1007       return printHelp (theBackgroundCommandName, theDrawInterpretor);
1008     }
1009
1010     //! Processes the cubemap option
1011     //! @param theFilePaths the array of filenames of cubemap sides
1012     //! @return true if processing was successful, or false otherwise
1013     bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
1014     {
1015       const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
1016
1017       if (aNumberOfCubeMapOptionArguments != 1
1018        && aNumberOfCubeMapOptionArguments != 6)
1019       {
1020         return false;
1021       }
1022
1023       theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
1024
1025       for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
1026       {
1027         std::string aCubeMapFileName;
1028         if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
1029         {
1030           return false;
1031         }
1032         theFilePaths[i] = aCubeMapFileName.c_str();
1033       }
1034
1035       return true;
1036     }
1037
1038     //! Processes the inverted z cubemap option
1039     //! @return true if processing was successful, or false otherwise
1040     bool processCubeMapInvertedZOptionSet () const
1041     {
1042       const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
1043         myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
1044
1045       if (aNumberOfCubeMapZInversionOptionArguments != 0)
1046       {
1047         return false;
1048       }
1049
1050       return true;
1051     }
1052
1053     //! Processes the option allowing to skip IBM maps generation
1054     //! @return true if processing was successful, or false otherwise
1055     bool processCubeMapDoNotGenPBREnvOptionSet() const
1056     {
1057       const Standard_Integer aNumberOfCubeMapDoNotGenPBREnvOptionArguments =
1058         myCommandParser.GetNumberOfOptionArguments(myCubeMapDoNotGenPBREnvOptionKey);
1059
1060       if (aNumberOfCubeMapDoNotGenPBREnvOptionArguments != 0)
1061       {
1062         return false;
1063       }
1064
1065       return true;
1066     }
1067
1068     //! Processes the tiles order option
1069     //! @param theOrder the array of indexes if cubemap sides in tile grid
1070     //! @return true if processing was successful, or false otherwise
1071     bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
1072     {
1073       const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
1074         myCubeMapOrderOptionKey);
1075
1076       if (aNumberOfCubeMapOrderOptionArguments != 6)
1077       {
1078         return false;
1079       }
1080
1081
1082       for (unsigned int i = 0; i < 6; ++i)
1083       {
1084         std::string anOrderItem;
1085         if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
1086         {
1087           return false;
1088         }
1089
1090         theOrder.Set (Graphic3d_CubeMapSide (i),
1091                       static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
1092       }
1093
1094       return theOrder.IsValid();
1095     }
1096
1097     //! Processes the image option
1098     //! @param theImageFileName the filename of the image to be used as a background
1099     //! @return true if processing was successful, or false otherwise
1100     bool processImageOption (std::string& theImageFileName) const
1101     {
1102       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1103         myImageOptionKey);
1104       if (aNumberOfImageOptionArguments != 1)
1105       {
1106         return false;
1107       }
1108       std::string anImageFileName;
1109       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
1110       {
1111         return false;
1112       }
1113       theImageFileName = anImageFileName;
1114       return true;
1115     }
1116
1117     //! Processes the image mode option
1118     //! @param theImageMode the fill type used for a background image
1119     //! @return true if processing was successful, or false otherwise
1120     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
1121     {
1122       return processImageModeOption (myImageModeOptionKey, theImageMode);
1123     }
1124
1125     //! Processes the image mode option
1126     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
1127     //! @param theImageMode the fill type used for a background image
1128     //! @return true if processing was successful, or false otherwise
1129     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
1130                                  Aspect_FillMethod&                theImageMode) const
1131     {
1132       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
1133     }
1134
1135     //! Processes the gradient option
1136     //! @param theColor1 the gradient starting color
1137     //! @param theColor2 the gradient ending color
1138     //! @return true if processing was successful, or false otherwise
1139     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
1140     {
1141       Standard_Integer anArgumentIndex = 0;
1142       Quantity_Color   aColor1;
1143       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
1144       {
1145         return false;
1146       }
1147       Quantity_Color aColor2;
1148       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
1149       {
1150         return false;
1151       }
1152       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1153         myGradientOptionKey);
1154       if (anArgumentIndex != aNumberOfGradientOptionArguments)
1155       {
1156         return false;
1157       }
1158       theColor1 = aColor1;
1159       theColor2 = aColor2;
1160       return true;
1161     }
1162
1163     //! Processes the gradient mode option
1164     //! @param theGradientMode the fill method used for a background gradient filling
1165     //! @return true if processing was successful, or false otherwise
1166     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
1167     {
1168       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
1169     }
1170
1171     //! Processes the gradient mode option
1172     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1173     //! @param theGradientMode the fill method used for a background gradient filling
1174     //! @return true if processing was successful, or false otherwise
1175     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1176                                     Aspect_GradientFillMethod&        theGradientMode) const
1177     {
1178       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1179     }
1180
1181     //! Processes some mode option
1182     //! @tparam TheMode the type of a mode to be processed
1183     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1184     //! @param theMode a mode to be processed
1185     //! @return true if processing was successful, or false otherwise
1186     template <typename TheMode>
1187     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1188                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1189                                                             TheMode& /* theMode */),
1190                             TheMode& theMode) const
1191     {
1192       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1193         theModeOptionKey);
1194       if (aNumberOfModeOptionArguments != 1)
1195       {
1196         return false;
1197       }
1198       std::string aModeString;
1199       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1200       {
1201         return false;
1202       }
1203       TheMode aMode = TheMode();
1204       if (!theGetModeByName (aModeString.c_str(), aMode))
1205       {
1206         return false;
1207       }
1208       theMode = aMode;
1209       return true;
1210     }
1211
1212     //! Processes the color option
1213     //! @param theColor a color used for filling a background
1214     //! @return true if processing was successful, or false otherwise
1215     bool processColorOption (Quantity_Color& theColor) const
1216     {
1217       return processColorOption (myColorOptionKey, theColor);
1218     }
1219
1220     //! Processes the color option
1221     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1222     //! @param theColor a color used for filling a background
1223     //! @return true if processing was successful, or false otherwise
1224     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1225     {
1226       Standard_Integer anArgumentIndex = 0;
1227       Quantity_Color   aColor;
1228       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1229       {
1230         return false;
1231       }
1232       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1233         theColorOptionKey);
1234       if (anArgumentIndex != aNumberOfColorOptionArguments)
1235       {
1236         return false;
1237       }
1238       theColor = aColor;
1239       return true;
1240     }
1241
1242     //! Prints helping message
1243     //! @param theBackgroundCommandName the name of the command that changes the background
1244     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1245     //! @return true if printing was successful, or false otherwise
1246     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1247     {
1248       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1249     }
1250
1251     //! Sets the cubemap as a background
1252     //! @param theFileNames the array of filenames of packed or multifile cubemap
1253     //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
1254     static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
1255                             const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
1256                             bool                                               theZIsInverted = false,
1257                             bool                                               theToGenPBREnv = true)
1258     {
1259       const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
1260       Handle(Graphic3d_CubeMap) aCubeMap;
1261
1262       if (theFileNames.Size() == 1)
1263         aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
1264       else
1265         aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
1266
1267       aCubeMap->SetZInversion (theZIsInverted);
1268
1269       aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
1270       aCubeMap->GetParams()->SetRepeat(Standard_False);
1271       aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
1272
1273       aCurrentView->SetBackgroundCubeMap (aCubeMap, theToGenPBREnv, Standard_True);
1274     }
1275
1276     //! Sets the image as a background
1277     //! @param theImageFileName the filename of the image to be used as a background
1278     //! @param theImageMode the fill type used for a background image
1279     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1280     {
1281       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1282       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1283     }
1284
1285     //! Sets the fill type used for a background image
1286     //! @param theImageMode the fill type used for a background image
1287     static void setImageMode (const Aspect_FillMethod theImageMode)
1288     {
1289       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1290       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1291     }
1292
1293     //! Sets the gradient filling for a background
1294     //! @param theColor1 the gradient starting color
1295     //! @param theColor2 the gradient ending color
1296     //! @param theGradientMode the fill method used for a background gradient filling
1297     static void setGradient (const Quantity_Color&           theColor1,
1298                              const Quantity_Color&           theColor2,
1299                              const Aspect_GradientFillMethod theGradientMode)
1300     {
1301       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1302       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1303     }
1304
1305     //! Sets the fill method used for a background gradient filling
1306     //! @param theGradientMode the fill method used for a background gradient filling
1307     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1308     {
1309       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1310       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1311     }
1312
1313     //! Sets the color used for filling a background
1314     //! @param theColor the color used for filling a background
1315     static void setColor (const Quantity_Color& theColor)
1316     {
1317       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1318       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1319       aCurrentView->SetBackgroundColor (theColor);
1320       aCurrentView->Update();
1321     }
1322
1323     //! Sets the gradient filling for a background in a default viewer
1324     //! @param theColor1 the gradient starting color
1325     //! @param theColor2 the gradient ending color
1326     //! @param theGradientMode the fill method used for a background gradient filling
1327     static void setDefaultGradient (const Quantity_Color&           theColor1,
1328                                     const Quantity_Color&           theColor2,
1329                                     const Aspect_GradientFillMethod theGradientMode)
1330     {
1331       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1332       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1333       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1334       setDefaultGradient();
1335     }
1336
1337     //! Sets the color used for filling a background in a default viewer
1338     //! @param theColor the color used for filling a background
1339     static void setDefaultColor (const Quantity_Color& theColor)
1340     {
1341       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1342       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1343       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1344       ViewerTest_DefaultBackground.FlatColor      = theColor;
1345       setDefaultGradient();
1346       setDefaultColor();
1347     }
1348
1349     //! Sets the gradient filling for a background in a default viewer.
1350     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1351     static void setDefaultGradient()
1352     {
1353       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1354              anInteractiveContextIterator (ViewerTest_myContexts);
1355            anInteractiveContextIterator.More();
1356            anInteractiveContextIterator.Next())
1357       {
1358         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1359         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1360                                              ViewerTest_DefaultBackground.GradientColor2,
1361                                              ViewerTest_DefaultBackground.FillMethod);
1362       }
1363     }
1364
1365     //! Sets the color used for filling a background in a default viewer.
1366     //! The color value is taken from ViewerTest_DefaultBackground structure
1367     static void setDefaultColor()
1368     {
1369       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1370              anInteractiveContextIterator (ViewerTest_myContexts);
1371            anInteractiveContextIterator.More();
1372            anInteractiveContextIterator.Next())
1373       {
1374         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1375         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1376       }
1377     }
1378   };
1379
1380 } // namespace
1381
1382 //==============================================================================
1383
1384 #ifdef _WIN32
1385 static LRESULT WINAPI ViewerWindowProc(
1386                                        HWND hwnd,
1387                                        UINT uMsg,
1388                                        WPARAM wParam,
1389                                        LPARAM lParam );
1390 static LRESULT WINAPI AdvViewerWindowProc(
1391   HWND hwnd,
1392   UINT uMsg,
1393   WPARAM wParam,
1394   LPARAM lParam );
1395 #endif
1396
1397
1398 //==============================================================================
1399 //function : WClass
1400 //purpose  :
1401 //==============================================================================
1402
1403 const Handle(WNT_WClass)& ViewerTest::WClass()
1404 {
1405   static Handle(WNT_WClass) theWClass;
1406 #if defined(_WIN32)
1407   if (theWClass.IsNull())
1408   {
1409     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1410                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1411                                 ::LoadCursor (NULL, IDC_ARROW));
1412   }
1413 #endif
1414   return theWClass;
1415 }
1416
1417 //==============================================================================
1418 //function : CreateName
1419 //purpose  : Create numerical name for new object in theMap
1420 //==============================================================================
1421 template <typename ObjectType>
1422 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1423                                     const TCollection_AsciiString& theDefaultString)
1424 {
1425   if (theObjectMap.IsEmpty())
1426     return theDefaultString + TCollection_AsciiString(1);
1427
1428   Standard_Integer aNextKey = 1;
1429   Standard_Boolean isFound = Standard_False;
1430   while (!isFound)
1431   {
1432     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1433     // Look for objects with default names
1434     if (theObjectMap.IsBound1(aStringKey))
1435     {
1436       aNextKey++;
1437     }
1438     else
1439       isFound = Standard_True;
1440   }
1441
1442   return theDefaultString + TCollection_AsciiString(aNextKey);
1443 }
1444
1445 //==============================================================================
1446 //structure : ViewerTest_Names
1447 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1448 //==============================================================================
1449 struct ViewerTest_Names
1450 {
1451 private:
1452   TCollection_AsciiString myDriverName;
1453   TCollection_AsciiString myViewerName;
1454   TCollection_AsciiString myViewName;
1455
1456 public:
1457
1458   const TCollection_AsciiString& GetDriverName () const
1459   {
1460     return myDriverName;
1461   }
1462   void SetDriverName (const TCollection_AsciiString& theDriverName)
1463   {
1464     myDriverName = theDriverName;
1465   }
1466   const TCollection_AsciiString& GetViewerName () const
1467   {
1468     return myViewerName;
1469   }
1470   void SetViewerName (const TCollection_AsciiString& theViewerName)
1471   {
1472     myViewerName = theViewerName;
1473   }
1474   const TCollection_AsciiString& GetViewName () const
1475   {
1476     return myViewName;
1477   }
1478   void SetViewName (const TCollection_AsciiString& theViewName)
1479   {
1480     myViewName = theViewName;
1481   }
1482
1483   //===========================================================================
1484   //function : Constructor for ViewerTest_Names
1485   //purpose  : Get view, viewer, driver names from custom string
1486   //===========================================================================
1487
1488   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1489   {
1490     TCollection_AsciiString aName(theInputString);
1491     if (theInputString.IsEmpty())
1492     {
1493       // Get current configuration
1494       if (ViewerTest_myDrivers.IsEmpty())
1495         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1496           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1497       else
1498         myDriverName = ViewerTest_myDrivers.Find2
1499         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1500
1501       if(ViewerTest_myContexts.IsEmpty())
1502       {
1503         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1504           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1505       }
1506       else
1507       {
1508         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1509       }
1510
1511       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1512     }
1513     else
1514     {
1515       // There is at least view name
1516       Standard_Integer aParserNumber = 0;
1517       for (Standard_Integer i = 0; i < 3; ++i)
1518       {
1519         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1520         if(aParserPos != -1)
1521         {
1522           aParserNumber++;
1523           aName.Split(aParserPos-1);
1524         }
1525         else
1526           break;
1527       }
1528       if (aParserNumber == 0)
1529       {
1530         // Only view name
1531         if (!ViewerTest::GetAISContext().IsNull())
1532         {
1533           myDriverName = ViewerTest_myDrivers.Find2
1534           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1535           myViewerName = ViewerTest_myContexts.Find2
1536           (ViewerTest::GetAISContext());
1537         }
1538         else
1539         {
1540           // There is no opened contexts here, need to create names for viewer and driver
1541           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1542             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1543
1544           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1545             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1546         }
1547         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1548       }
1549       else if (aParserNumber == 1)
1550       {
1551         // Here is viewerName/viewName
1552         if (!ViewerTest::GetAISContext().IsNull())
1553           myDriverName = ViewerTest_myDrivers.Find2
1554           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1555         else
1556         {
1557           // There is no opened contexts here, need to create name for driver
1558           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1559             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1560         }
1561         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1562
1563         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1564       }
1565       else
1566       {
1567         //Here is driverName/viewerName/viewName
1568         myDriverName = TCollection_AsciiString(aName);
1569
1570         TCollection_AsciiString aViewerName(theInputString);
1571         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1572         myViewerName = TCollection_AsciiString(aViewerName);
1573
1574         myViewName = TCollection_AsciiString(theInputString);
1575       }
1576     }
1577   }
1578 };
1579
1580 //==============================================================================
1581 //function : FindContextByView
1582 //purpose  : Find AIS_InteractiveContext by View
1583 //==============================================================================
1584
1585 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1586 {
1587   Handle(AIS_InteractiveContext) anAISContext;
1588
1589   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1590        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1591   {
1592     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1593        return anIter.Key2();
1594   }
1595   return anAISContext;
1596 }
1597
1598 //==============================================================================
1599 //function : IsWindowOverlapped
1600 //purpose  : Check if theWindow overlapp another view
1601 //==============================================================================
1602
1603 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1604                                      const Standard_Integer thePxTop,
1605                                      const Standard_Integer thePxRight,
1606                                      const Standard_Integer thePxBottom,
1607                                      TCollection_AsciiString& theViewId)
1608 {
1609   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1610       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1611   {
1612     Standard_Integer aTop = 0,
1613       aLeft = 0,
1614       aRight = 0,
1615       aBottom = 0;
1616     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1617     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1618         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1619         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1620         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1621     {
1622       theViewId = anIter.Key1();
1623       return Standard_True;
1624     }
1625   }
1626   return Standard_False;
1627 }
1628
1629 // Workaround: to create and delete non-orthographic views outside ViewerTest
1630 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1631 {
1632   ViewerTest_myViews.UnBind1 (theName);
1633 }
1634
1635 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1636                                const Handle(V3d_View)& theView)
1637 {
1638   ViewerTest_myViews.Bind (theName, theView);
1639 }
1640
1641 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1642 {
1643   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1644 }
1645
1646 //==============================================================================
1647 //function : ViewerInit
1648 //purpose  : Create the window viewer and initialize all the global variable
1649 //==============================================================================
1650
1651 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1652                                                 const Standard_Integer thePxTop,
1653                                                 const Standard_Integer thePxWidth,
1654                                                 const Standard_Integer thePxHeight,
1655                                                 const TCollection_AsciiString& theViewName,
1656                                                 const TCollection_AsciiString& theDisplayName,
1657                                                 const Handle(V3d_View)& theViewToClone)
1658 {
1659   // Default position and dimension of the viewer window.
1660   // Note that left top corner is set to be sufficiently small to have
1661   // window fit in the small screens (actual for remote desktops, see #23003).
1662   // The position corresponds to the window's client area, thus some
1663   // gap is added for window frame to be visible.
1664   Standard_Integer aPxLeft   = 20;
1665   Standard_Integer aPxTop    = 40;
1666   Standard_Integer aPxWidth  = 409;
1667   Standard_Integer aPxHeight = 409;
1668   Standard_Boolean toCreateViewer = Standard_False;
1669   if (!theViewToClone.IsNull())
1670   {
1671     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1672   }
1673
1674   Handle(OpenGl_GraphicDriver) aGraphicDriver;
1675   ViewerTest_Names aViewNames(theViewName);
1676   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1677     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1678
1679   if (thePxLeft != 0)
1680     aPxLeft = thePxLeft;
1681   if (thePxTop != 0)
1682     aPxTop = thePxTop;
1683   if (thePxWidth != 0)
1684     aPxWidth = thePxWidth;
1685   if (thePxHeight != 0)
1686     aPxHeight = thePxHeight;
1687
1688   // Get graphic driver (create it or get from another view)
1689   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1690   if (isNewDriver)
1691   {
1692     // Get connection string
1693   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1694     if (!theDisplayName.IsEmpty())
1695     {
1696       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1697     }
1698     else
1699     {
1700       ::Display* aDispX = NULL;
1701       // create dedicated display connection instead of reusing Tk connection
1702       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
1703       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1704       Tcl_Interp* aTclInterp = aCommands.Interp();
1705       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1706       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1707       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1708     }
1709   #else
1710     (void)theDisplayName; // avoid warning on unused argument
1711     SetDisplayConnection (new Aspect_DisplayConnection ());
1712   #endif
1713
1714     if (Draw_VirtualWindows)
1715     {
1716       // don't waste the time waiting for VSync when window is not displayed on the screen
1717       ViewerTest_myDefaultCaps.swapInterval = 0;
1718       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
1719       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
1720     }
1721     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
1722     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
1723     aGraphicDriver->InitContext();
1724
1725     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1726     toCreateViewer = Standard_True;
1727   }
1728   else
1729   {
1730     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
1731   }
1732
1733   //Dispose the window if input parameters are default
1734   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1735   {
1736     Standard_Integer aTop = 0,
1737                      aLeft = 0,
1738                      aRight = 0,
1739                      aBottom = 0,
1740                      aScreenWidth = 0,
1741                      aScreenHeight = 0;
1742
1743     // Get screen resolution
1744 #if defined(_WIN32) || defined(__WIN32__)
1745     RECT aWindowSize;
1746     GetClientRect(GetDesktopWindow(), &aWindowSize);
1747     aScreenHeight = aWindowSize.bottom;
1748     aScreenWidth = aWindowSize.right;
1749 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1750     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1751 #else
1752     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
1753     aScreenWidth = WidthOfScreen(aScreen);
1754     aScreenHeight = HeightOfScreen(aScreen);
1755 #endif
1756
1757     TCollection_AsciiString anOverlappedViewId("");
1758
1759     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1760     {
1761       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1762
1763       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1764         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1765       {
1766         if (aBottom + aPxHeight + 40 > aScreenHeight)
1767         {
1768           aPxLeft = 20;
1769           aPxTop = 40;
1770           break;
1771         }
1772         aPxLeft = 20;
1773         aPxTop = aBottom + 40;
1774       }
1775       else
1776         aPxLeft = aRight + 20;
1777     }
1778   }
1779
1780   // Get viewer name
1781   TCollection_AsciiString aTitle("3D View - ");
1782   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1783
1784   // Change name of current active window
1785   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1786   {
1787     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1788   }
1789
1790   // Create viewer
1791   Handle(V3d_Viewer) a3DViewer;
1792   // If it's the single view, we first look for empty context
1793   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1794   {
1795     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1796       anIter(ViewerTest_myContexts);
1797     if (anIter.More())
1798       ViewerTest::SetAISContext (anIter.Value());
1799     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1800   }
1801   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1802   {
1803     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1804     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1805   }
1806   else if (a3DViewer.IsNull())
1807   {
1808     toCreateViewer = Standard_True;
1809     a3DViewer = new V3d_Viewer(aGraphicDriver);
1810     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1811     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1812                                            ViewerTest_DefaultBackground.GradientColor2,
1813                                            ViewerTest_DefaultBackground.FillMethod);
1814   }
1815
1816   // AIS context setup
1817   if (ViewerTest::GetAISContext().IsNull() ||
1818       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1819   {
1820     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1821     ViewerTest::SetAISContext (aContext);
1822     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1823   }
1824   else
1825   {
1826     ViewerTest::ResetEventManager();
1827   }
1828
1829   // Create window
1830 #if defined(_WIN32)
1831   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
1832                                     Draw_VirtualWindows ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1833                                     aPxLeft, aPxTop,
1834                                     aPxWidth, aPxHeight,
1835                                     Quantity_NOC_BLACK);
1836   VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
1837 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1838   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1839                                      aPxLeft, aPxTop,
1840                                      aPxWidth, aPxHeight);
1841   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1842 #else
1843   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1844                                   aTitle.ToCString(),
1845                                   aPxLeft, aPxTop,
1846                                   aPxWidth, aPxHeight);
1847 #endif
1848   VT_GetWindow()->SetVirtual (Draw_VirtualWindows);
1849
1850   // View setup
1851   Handle(V3d_View) aView;
1852   if (!theViewToClone.IsNull())
1853   {
1854     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1855   }
1856   else
1857   {
1858     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1859   }
1860
1861   aView->SetWindow (VT_GetWindow());
1862   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1863
1864   ViewerTest::CurrentView(aView);
1865   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1866
1867   // Setup for X11 or NT
1868   OSWindowSetup();
1869
1870   // Set parameters for V3d_View and V3d_Viewer
1871   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1872   aV3dView->SetComputedMode(Standard_False);
1873
1874   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1875   if (toCreateViewer)
1876   {
1877     a3DViewer->SetDefaultLights();
1878     a3DViewer->SetLightOn();
1879   }
1880
1881 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1882   if (isNewDriver)
1883   {
1884     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
1885     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1886   }
1887 #endif
1888
1889   VT_GetWindow()->Map();
1890
1891   // Set the handle of created view in the event manager
1892   ViewerTest::ResetEventManager();
1893
1894   ViewerTest::CurrentView()->Redraw();
1895
1896   aView.Nullify();
1897   a3DViewer.Nullify();
1898
1899   return aViewNames.GetViewName();
1900 }
1901
1902 //==============================================================================
1903 //function : RedrawAllViews
1904 //purpose  : Redraw all created views
1905 //==============================================================================
1906 void ViewerTest::RedrawAllViews()
1907 {
1908   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1909   for (; aViewIt.More(); aViewIt.Next())
1910   {
1911     const Handle(V3d_View)& aView = aViewIt.Key2();
1912     aView->Redraw();
1913   }
1914 }
1915
1916 //==============================================================================
1917 //function : Vinit
1918 //purpose  : Create the window viewer and initialize all the global variable
1919 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
1920 //==============================================================================
1921
1922 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1923 {
1924   TCollection_AsciiString aViewName, aDisplayName;
1925   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
1926   Handle(V3d_View) aCopyFrom;
1927   TCollection_AsciiString aName, aValue;
1928   int is2dMode = -1;
1929   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
1930   {
1931     const TCollection_AsciiString anArg = theArgVec[anArgIt];
1932     TCollection_AsciiString anArgCase = anArg;
1933     anArgCase.LowerCase();
1934     if (anArgIt + 1 < theArgsNb
1935      && anArgCase == "-name")
1936     {
1937       aViewName = theArgVec[++anArgIt];
1938     }
1939     else if (anArgIt + 1 < theArgsNb
1940           && (anArgCase == "-left"
1941            || anArgCase == "-l"))
1942     {
1943       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
1944     }
1945     else if (anArgIt + 1 < theArgsNb
1946           && (anArgCase == "-top"
1947            || anArgCase == "-t"))
1948     {
1949       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
1950     }
1951     else if (anArgIt + 1 < theArgsNb
1952           && (anArgCase == "-width"
1953            || anArgCase == "-w"))
1954     {
1955       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
1956     }
1957     else if (anArgIt + 1 < theArgsNb
1958           && (anArgCase == "-height"
1959            || anArgCase == "-h"))
1960     {
1961       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
1962     }
1963     else if (anArgCase == "-exitonclose")
1964     {
1965       ViewerTest_EventManager::ToExitOnCloseView() = true;
1966       if (anArgIt + 1 < theArgsNb
1967        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
1968       {
1969         ++anArgIt;
1970       }
1971     }
1972     else if (anArgCase == "-closeonescape"
1973           || anArgCase == "-closeonesc")
1974     {
1975       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
1976       if (anArgIt + 1 < theArgsNb
1977        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
1978       {
1979         ++anArgIt;
1980       }
1981     }
1982     else if (anArgCase == "-2d_mode"
1983           || anArgCase == "-2dmode"
1984           || anArgCase == "-2d")
1985     {
1986       bool toEnable = true;
1987       if (anArgIt + 1 < theArgsNb
1988        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
1989       {
1990         ++anArgIt;
1991       }
1992       is2dMode = toEnable ? 1 : 0;
1993     }
1994     else if (anArgIt + 1 < theArgsNb
1995           && (anArgCase == "-disp"
1996            || anArgCase == "-display"))
1997     {
1998       aDisplayName = theArgVec[++anArgIt];
1999     }
2000     else if (!ViewerTest::CurrentView().IsNull()
2001           &&  aCopyFrom.IsNull()
2002           && (anArgCase == "-copy"
2003            || anArgCase == "-clone"
2004            || anArgCase == "-cloneactive"
2005            || anArgCase == "-cloneactiveview"))
2006     {
2007       aCopyFrom = ViewerTest::CurrentView();
2008     }
2009     // old syntax
2010     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2011     {
2012       aName.LowerCase();
2013       if (aName == "name")
2014       {
2015         aViewName = aValue;
2016       }
2017       else if (aName == "l"
2018             || aName == "left")
2019       {
2020         aPxLeft = aValue.IntegerValue();
2021       }
2022       else if (aName == "t"
2023             || aName == "top")
2024       {
2025         aPxTop = aValue.IntegerValue();
2026       }
2027       else if (aName == "disp"
2028             || aName == "display")
2029       {
2030         aDisplayName = aValue;
2031       }
2032       else if (aName == "w"
2033             || aName == "width")
2034       {
2035         aPxWidth = aValue.IntegerValue();
2036       }
2037       else if (aName == "h"
2038             || aName == "height")
2039       {
2040         aPxHeight = aValue.IntegerValue();
2041       }
2042       else
2043       {
2044         Message::SendFail() << "Syntax error: unknown argument " << anArg;
2045         return 1;
2046       }
2047     }
2048     else if (aViewName.IsEmpty())
2049     {
2050       aViewName = anArg;
2051     }
2052     else
2053     {
2054       Message::SendFail() << "Syntax error: unknown argument " << anArg;
2055       return 1;
2056     }
2057   }
2058
2059 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
2060   if (!aDisplayName.IsEmpty())
2061   {
2062     aDisplayName.Clear();
2063     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
2064   }
2065 #endif
2066
2067   ViewerTest_Names aViewNames (aViewName);
2068   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2069   {
2070     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2071     theDi.Eval (aCommand.ToCString());
2072     if (is2dMode != -1)
2073     {
2074       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2075     }
2076     return 0;
2077   }
2078
2079   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2080                                                             aViewName, aDisplayName, aCopyFrom);
2081   if (is2dMode != -1)
2082   {
2083     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2084   }
2085   theDi << aViewId;
2086   return 0;
2087 }
2088
2089 //! Parse HLR algo type.
2090 static Standard_Boolean parseHlrAlgoType (const char* theName,
2091                                           Prs3d_TypeOfHLR& theType)
2092 {
2093   TCollection_AsciiString aName (theName);
2094   aName.LowerCase();
2095   if (aName == "polyalgo")
2096   {
2097     theType = Prs3d_TOH_PolyAlgo;
2098   }
2099   else if (aName == "algo")
2100   {
2101     theType = Prs3d_TOH_Algo;
2102   }
2103   else
2104   {
2105     return Standard_False;
2106   }
2107   return Standard_True;
2108 }
2109
2110 //==============================================================================
2111 //function : VHLR
2112 //purpose  : hidden lines removal algorithm
2113 //==============================================================================
2114
2115 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2116 {
2117   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2118   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2119   if (aView.IsNull())
2120   {
2121     Message::SendFail ("Error: no active viewer");
2122     return 1;
2123   }
2124
2125   Standard_Boolean hasHlrOnArg = Standard_False;
2126   Standard_Boolean hasShowHiddenArg = Standard_False;
2127   Standard_Boolean isHLROn = Standard_False;
2128   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2129   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2130   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2131   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2132   {
2133     TCollection_AsciiString anArg (argv[anArgIter]);
2134     anArg.LowerCase();
2135     if (anUpdateTool.parseRedrawMode (anArg))
2136     {
2137       continue;
2138     }
2139     else if (anArg == "-showhidden"
2140           && anArgIter + 1 < argc
2141           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2142     {
2143       ++anArgIter;
2144       hasShowHiddenArg = Standard_True;
2145       continue;
2146     }
2147     else if ((anArg == "-type"
2148            || anArg == "-algo"
2149            || anArg == "-algotype")
2150           && anArgIter + 1 < argc
2151           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2152     {
2153       ++anArgIter;
2154       continue;
2155     }
2156     else if (!hasHlrOnArg
2157           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
2158     {
2159       hasHlrOnArg = Standard_True;
2160       continue;
2161     }
2162     // old syntax
2163     else if (!hasShowHiddenArg
2164           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
2165     {
2166       hasShowHiddenArg = Standard_True;
2167       continue;
2168     }
2169     else
2170     {
2171       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
2172       return 1;
2173     }
2174   }
2175   if (!hasHlrOnArg)
2176   {
2177     di << "HLR:        " << aView->ComputedMode() << "\n";
2178     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2179     di << "HlrAlgo:    ";
2180     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2181     {
2182       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2183       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2184       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2185     }
2186     anUpdateTool.Invalidate();
2187     return 0;
2188   }
2189
2190   Standard_Boolean toRecompute = Standard_False;
2191   if (aTypeOfHLR != Prs3d_TOH_NotSet
2192    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2193   {
2194     toRecompute = Standard_True;
2195     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2196   }
2197   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2198   {
2199     toRecompute = Standard_True;
2200     if (toShowHidden)
2201     {
2202       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2203     }
2204     else
2205     {
2206       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2207     }
2208   }
2209
2210   // redisplay shapes
2211   if (aView->ComputedMode() && isHLROn && toRecompute)
2212   {
2213     AIS_ListOfInteractive aListOfShapes;
2214     aCtx->DisplayedObjects (aListOfShapes);
2215     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2216     {
2217       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2218       {
2219         aCtx->Redisplay (aShape, Standard_False);
2220       }
2221     }
2222   }
2223
2224   aView->SetComputedMode (isHLROn);
2225   return 0;
2226 }
2227
2228 //==============================================================================
2229 //function : VHLRType
2230 //purpose  : change type of using HLR algorithm
2231 //==============================================================================
2232
2233 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2234 {
2235   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2236   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2237   if (aView.IsNull())
2238   {
2239     Message::SendFail ("Error: no active viewer");
2240     return 1;
2241   }
2242
2243   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2244   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2245   AIS_ListOfInteractive aListOfShapes;
2246   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2247   {
2248     TCollection_AsciiString anArg (argv[anArgIter]);
2249     anArg.LowerCase();
2250     if (anUpdateTool.parseRedrawMode (anArg))
2251     {
2252       continue;
2253     }
2254     else if ((anArg == "-type"
2255            || anArg == "-algo"
2256            || anArg == "-algotype")
2257           && anArgIter + 1 < argc
2258           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2259     {
2260       ++anArgIter;
2261       continue;
2262     }
2263     // old syntax
2264     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2265           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2266     {
2267       continue;
2268     }
2269     else
2270     {
2271       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2272       TCollection_AsciiString aName (argv[anArgIter]);
2273       if (!aMap.IsBound2 (aName))
2274       {
2275         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
2276         return 1;
2277       }
2278
2279       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2280       if (aShape.IsNull())
2281       {
2282         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
2283         return 1;
2284       }
2285       aListOfShapes.Append (aShape);
2286       continue;
2287     }
2288   }
2289   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2290   {
2291     Message::SendFail ("Syntax error: wrong number of arguments");
2292     return 1;
2293   }
2294
2295   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2296   if (isGlobal)
2297   {
2298     aCtx->DisplayedObjects (aListOfShapes);
2299     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2300   }
2301
2302   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2303   {
2304     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2305     if (aShape.IsNull())
2306     {
2307       continue;
2308     }
2309
2310     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2311                             && aView->ComputedMode();
2312     if (!isGlobal
2313      || aShape->TypeOfHLR() != aTypeOfHLR)
2314     {
2315       aShape->SetTypeOfHLR (aTypeOfHLR);
2316     }
2317     if (toUpdateShape)
2318     {
2319       aCtx->Redisplay (aShape, Standard_False);
2320     }
2321   }
2322   return 0;
2323 }
2324
2325 //==============================================================================
2326 //function : FindViewIdByWindowHandle
2327 //purpose  : Find theView Id in the map of views by window handle
2328 //==============================================================================
2329 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2330 TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2331 {
2332   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2333        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2334   {
2335     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2336     if (aWindowHandle == theWindowHandle)
2337       return anIter.Key1();
2338   }
2339   return TCollection_AsciiString("");
2340 }
2341 #endif
2342
2343 //! Make the view active
2344 void ActivateView (const TCollection_AsciiString& theViewName,
2345                    Standard_Boolean theToUpdate = Standard_True)
2346 {
2347   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2348   if (aView.IsNull())
2349   {
2350     return;
2351   }
2352
2353   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2354   if (!anAISContext.IsNull())
2355   {
2356     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2357     {
2358       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2359     }
2360
2361     ViewerTest::CurrentView (aView);
2362     ViewerTest::SetAISContext (anAISContext);
2363     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2364 #if defined(_WIN32)
2365     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2366 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
2367     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2368 #else
2369     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2370 #endif
2371     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2372     if (theToUpdate)
2373     {
2374       ViewerTest::CurrentView()->Redraw();
2375     }
2376   }
2377 }
2378
2379 //==============================================================================
2380 //function : RemoveView
2381 //purpose  :
2382 //==============================================================================
2383 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2384                              const Standard_Boolean  theToRemoveContext)
2385 {
2386   if (!ViewerTest_myViews.IsBound2 (theView))
2387   {
2388     return;
2389   }
2390
2391   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2392   RemoveView (aViewName, theToRemoveContext);
2393 }
2394
2395 //==============================================================================
2396 //function : RemoveView
2397 //purpose  : Close and remove view from display, clear maps if neccessary
2398 //==============================================================================
2399 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2400 {
2401   if (!ViewerTest_myViews.IsBound1(theViewName))
2402   {
2403     Message::SendFail() << "Wrong view name";
2404     return;
2405   }
2406
2407   // Activate another view if it's active now
2408   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2409   {
2410     if (ViewerTest_myViews.Extent() > 1)
2411     {
2412       TCollection_AsciiString aNewViewName;
2413       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2414            anIter.More(); anIter.Next())
2415       {
2416         if (anIter.Key1() != theViewName)
2417         {
2418           aNewViewName = anIter.Key1();
2419           break;
2420         }
2421       }
2422       ActivateView (aNewViewName);
2423     }
2424     else
2425     {
2426       VT_GetWindow().Nullify();
2427       ViewerTest::CurrentView (Handle(V3d_View)());
2428       if (isContextRemoved)
2429       {
2430         Handle(AIS_InteractiveContext) anEmptyContext;
2431         ViewerTest::SetAISContext(anEmptyContext);
2432       }
2433     }
2434   }
2435
2436   // Delete view
2437   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2438   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2439   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2440   aRedrawer.Stop (aView->Window());
2441
2442   // Remove view resources
2443   ViewerTest_myViews.UnBind1(theViewName);
2444   aView->Window()->Unmap();
2445   aView->Remove();
2446
2447 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2448   XFlush (GetDisplayConnection()->GetDisplay());
2449 #endif
2450
2451   // Keep context opened only if the closed view is last to avoid
2452   // unused empty contexts
2453   if (!aCurrentContext.IsNull())
2454   {
2455     // Check if there are more difined views in the viewer
2456     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
2457      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
2458     {
2459       // Remove driver if there is no viewers that use it
2460       Standard_Boolean isRemoveDriver = Standard_True;
2461       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2462           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2463       {
2464         if (aCurrentContext != anIter.Key2() &&
2465           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2466         {
2467           isRemoveDriver = Standard_False;
2468           break;
2469         }
2470       }
2471
2472       aCurrentContext->RemoveAll (Standard_False);
2473       if(isRemoveDriver)
2474       {
2475         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2476       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2477         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
2478       #endif
2479       }
2480
2481       ViewerTest_myContexts.UnBind2(aCurrentContext);
2482     }
2483   }
2484   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
2485   if (ViewerTest_EventManager::ToExitOnCloseView())
2486   {
2487     Draw_Interprete ("exit");
2488   }
2489 }
2490
2491 //==============================================================================
2492 //function : VClose
2493 //purpose  : Remove the view defined by its name
2494 //==============================================================================
2495
2496 static int VClose (Draw_Interpretor& /*theDi*/,
2497                    Standard_Integer  theArgsNb,
2498                    const char**      theArgVec)
2499 {
2500   NCollection_List<TCollection_AsciiString> aViewList;
2501   if (theArgsNb > 1)
2502   {
2503     TCollection_AsciiString anArg (theArgVec[1]);
2504     anArg.UpperCase();
2505     if (anArg.IsEqual ("ALL")
2506      || anArg.IsEqual ("*"))
2507     {
2508       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2509            anIter.More(); anIter.Next())
2510       {
2511         aViewList.Append (anIter.Key1());
2512       }
2513       if (aViewList.IsEmpty())
2514       {
2515         std::cout << "No view to close\n";
2516         return 0;
2517       }
2518     }
2519     else
2520     {
2521       ViewerTest_Names aViewName (theArgVec[1]);
2522       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2523       {
2524         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
2525         return 1;
2526       }
2527       aViewList.Append (aViewName.GetViewName());
2528     }
2529   }
2530   else
2531   {
2532     // close active view
2533     if (ViewerTest::CurrentView().IsNull())
2534     {
2535       Message::SendFail ("Error: no active view");
2536       return 1;
2537     }
2538     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2539   }
2540
2541   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2542   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2543        anIter.More(); anIter.Next())
2544   {
2545     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2546   }
2547
2548   return 0;
2549 }
2550
2551 //==============================================================================
2552 //function : VActivate
2553 //purpose  : Activate the view defined by its ID
2554 //==============================================================================
2555
2556 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2557 {
2558   if (theArgsNb == 1)
2559   {
2560     theDi.Eval("vviewlist");
2561     return 0;
2562   }
2563
2564   TCollection_AsciiString aNameString;
2565   Standard_Boolean toUpdate = Standard_True;
2566   Standard_Boolean toActivate = Standard_True;
2567   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2568   {
2569     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2570     anArg.LowerCase();
2571     if (toUpdate
2572      && anArg == "-noupdate")
2573     {
2574       toUpdate = Standard_False;
2575     }
2576     else if (toActivate
2577           && aNameString.IsEmpty()
2578           && anArg == "none")
2579     {
2580       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2581       VT_GetWindow().Nullify();
2582       ViewerTest::CurrentView (Handle(V3d_View)());
2583       ViewerTest::ResetEventManager();
2584       theDi << theArgVec[0] << ": all views are inactive\n";
2585       toActivate = Standard_False;
2586     }
2587     else if (toActivate
2588           && aNameString.IsEmpty())
2589     {
2590       aNameString = theArgVec[anArgIter];
2591     }
2592     else
2593     {
2594       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2595       return 1;
2596     }
2597   }
2598
2599   if (!toActivate)
2600   {
2601     return 0;
2602   }
2603   else if (aNameString.IsEmpty())
2604   {
2605     Message::SendFail ("Syntax error: wrong number of arguments");
2606     return 1;
2607   }
2608
2609   // Check if this view exists in the viewer with the driver
2610   ViewerTest_Names aViewNames (aNameString);
2611   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2612   {
2613     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2614     return 1;
2615   }
2616
2617   // Check if it is active already
2618   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2619   {
2620     theDi << theArgVec[0] << ": the view is active already\n";
2621     return 0;
2622   }
2623
2624   ActivateView (aViewNames.GetViewName(), toUpdate);
2625   return 0;
2626 }
2627
2628 //==============================================================================
2629 //function : VViewList
2630 //purpose  : Print current list of views per viewer and graphic driver ID
2631 //           shared between viewers
2632 //==============================================================================
2633
2634 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2635 {
2636   if (theArgsNb > 2)
2637   {
2638     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2639           << "Usage: " << theArgVec[0] << " name";
2640     return 1;
2641   }
2642   if (ViewerTest_myContexts.Size() < 1)
2643     return 0;
2644
2645   Standard_Boolean isTreeView =
2646     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2647
2648   if (isTreeView)
2649   {
2650     theDi << theArgVec[0] <<":\n";
2651   }
2652
2653   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2654        aDriverIter.More(); aDriverIter.Next())
2655   {
2656     if (isTreeView)
2657       theDi << aDriverIter.Key1() << ":\n";
2658
2659     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2660       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2661     {
2662       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2663       {
2664         if (isTreeView)
2665         {
2666           TCollection_AsciiString aContextName(aContextIter.Key1());
2667           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2668         }
2669
2670         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2671              aViewIter.More(); aViewIter.Next())
2672         {
2673           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2674           {
2675             TCollection_AsciiString aViewName(aViewIter.Key1());
2676             if (isTreeView)
2677             {
2678               if (aViewIter.Value() == ViewerTest::CurrentView())
2679                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2680               else
2681                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2682             }
2683             else
2684             {
2685               theDi << aViewName << " ";
2686             }
2687           }
2688         }
2689       }
2690     }
2691   }
2692   return 0;
2693 }
2694
2695 //==============================================================================
2696 //function : GetMousePosition
2697 //purpose  :
2698 //==============================================================================
2699 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2700                                    Standard_Integer& theY)
2701 {
2702   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2703   {
2704     theX = aViewCtrl->LastMousePosition().x();
2705     theY = aViewCtrl->LastMousePosition().y();
2706   }
2707 }
2708
2709 //==============================================================================
2710 //function : VViewProj
2711 //purpose  : Switch view projection
2712 //==============================================================================
2713 static int VViewProj (Draw_Interpretor& ,
2714                       Standard_Integer theNbArgs,
2715                       const char** theArgVec)
2716 {
2717   static Standard_Boolean isYup = Standard_False;
2718   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2719   if (aView.IsNull())
2720   {
2721     Message::SendFail ("Error: no active viewer");
2722     return 1;
2723   }
2724
2725   TCollection_AsciiString aCmdName (theArgVec[0]);
2726   Standard_Boolean isGeneralCmd = Standard_False;
2727   if (aCmdName == "vfront")
2728   {
2729     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2730   }
2731   else if (aCmdName == "vback")
2732   {
2733     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2734   }
2735   else if (aCmdName == "vtop")
2736   {
2737     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2738   }
2739   else if (aCmdName == "vbottom")
2740   {
2741     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2742   }
2743   else if (aCmdName == "vleft")
2744   {
2745     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2746   }
2747   else if (aCmdName == "vright")
2748   {
2749     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2750   }
2751   else if (aCmdName == "vaxo")
2752   {
2753     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2754   }
2755   else
2756   {
2757     isGeneralCmd = Standard_True;
2758     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2759     {
2760       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2761       anArgCase.LowerCase();
2762       if (anArgCase == "-zup")
2763       {
2764         isYup = Standard_False;
2765       }
2766       else if (anArgCase == "-yup")
2767       {
2768         isYup = Standard_True;
2769       }
2770       else if (anArgCase == "-front"
2771             || anArgCase == "front"
2772             || anArgCase == "-f"
2773             || anArgCase == "f")
2774       {
2775         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2776       }
2777       else if (anArgCase == "-back"
2778             || anArgCase == "back"
2779             || anArgCase == "-b"
2780             || anArgCase == "b")
2781       {
2782         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2783       }
2784       else if (anArgCase == "-top"
2785             || anArgCase == "top"
2786             || anArgCase == "-t"
2787             || anArgCase == "t")
2788       {
2789         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2790       }
2791       else if (anArgCase == "-bottom"
2792             || anArgCase == "bottom"
2793             || anArgCase == "-bot"
2794             || anArgCase == "bot"
2795             || anArgCase == "-b"
2796             || anArgCase == "b")
2797       {
2798         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2799       }
2800       else if (anArgCase == "-left"
2801             || anArgCase == "left"
2802             || anArgCase == "-l"
2803             || anArgCase == "l")
2804       {
2805         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2806       }
2807       else if (anArgCase == "-right"
2808             || anArgCase == "right"
2809             || anArgCase == "-r"
2810             || anArgCase == "r")
2811       {
2812         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2813       }
2814       else if (anArgCase == "-axoleft"
2815             || anArgCase == "-leftaxo"
2816             || anArgCase == "axoleft"
2817             || anArgCase == "leftaxo")
2818       {
2819         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
2820       }
2821       else if (anArgCase == "-axo"
2822             || anArgCase == "axo"
2823             || anArgCase == "-a"
2824             || anArgCase == "a"
2825             || anArgCase == "-axoright"
2826             || anArgCase == "-rightaxo"
2827             || anArgCase == "axoright"
2828             || anArgCase == "rightaxo")
2829       {
2830         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2831       }
2832       else if (anArgCase == "+x")
2833       {
2834         aView->SetProj (V3d_Xpos, isYup);
2835       }
2836       else if (anArgCase == "-x")
2837       {
2838         aView->SetProj (V3d_Xneg, isYup);
2839       }
2840       else if (anArgCase == "+y")
2841       {
2842         aView->SetProj (V3d_Ypos, isYup);
2843       }
2844       else if (anArgCase == "-y")
2845       {
2846         aView->SetProj (V3d_Yneg, isYup);
2847       }
2848       else if (anArgCase == "+z")
2849       {
2850         aView->SetProj (V3d_Zpos, isYup);
2851       }
2852       else if (anArgCase == "-z")
2853       {
2854         aView->SetProj (V3d_Zneg, isYup);
2855       }
2856       else if (anArgCase == "+x+y+z")
2857       {
2858         aView->SetProj (V3d_XposYposZpos, isYup);
2859       }
2860       else if (anArgCase == "+x+y-z")
2861       {
2862         aView->SetProj (V3d_XposYposZneg, isYup);
2863       }
2864       else if (anArgCase == "+x-y+z")
2865       {
2866         aView->SetProj (V3d_XposYnegZpos, isYup);
2867       }
2868       else if (anArgCase == "+x-y-z")
2869       {
2870         aView->SetProj (V3d_XposYnegZneg, isYup);
2871       }
2872       else if (anArgCase == "-x+y+z")
2873       {
2874         aView->SetProj (V3d_XnegYposZpos, isYup);
2875       }
2876       else if (anArgCase == "-x+y-z")
2877       {
2878         aView->SetProj (V3d_XnegYposZneg, isYup);
2879       }
2880       else if (anArgCase == "-x-y+z")
2881       {
2882         aView->SetProj (V3d_XnegYnegZpos, isYup);
2883       }
2884       else if (anArgCase == "-x-y-z")
2885       {
2886         aView->SetProj (V3d_XnegYnegZneg, isYup);
2887       }
2888       else if (anArgCase == "+x+y")
2889       {
2890         aView->SetProj (V3d_XposYpos, isYup);
2891       }
2892       else if (anArgCase == "+x-y")
2893       {
2894         aView->SetProj (V3d_XposYneg, isYup);
2895       }
2896       else if (anArgCase == "-x+y")
2897       {
2898         aView->SetProj (V3d_XnegYpos, isYup);
2899       }
2900       else if (anArgCase == "-x-y")
2901       {
2902         aView->SetProj (V3d_XnegYneg, isYup);
2903       }
2904       else if (anArgCase == "+x+z")
2905       {
2906         aView->SetProj (V3d_XposZpos, isYup);
2907       }
2908       else if (anArgCase == "+x-z")
2909       {
2910         aView->SetProj (V3d_XposZneg, isYup);
2911       }
2912       else if (anArgCase == "-x+z")
2913       {
2914         aView->SetProj (V3d_XnegZpos, isYup);
2915       }
2916       else if (anArgCase == "-x-z")
2917       {
2918         aView->SetProj (V3d_XnegZneg, isYup);
2919       }
2920       else if (anArgCase == "+y+z")
2921       {
2922         aView->SetProj (V3d_YposZpos, isYup);
2923       }
2924       else if (anArgCase == "+y-z")
2925       {
2926         aView->SetProj (V3d_YposZneg, isYup);
2927       }
2928       else if (anArgCase == "-y+z")
2929       {
2930         aView->SetProj (V3d_YnegZpos, isYup);
2931       }
2932       else if (anArgCase == "-y-z")
2933       {
2934         aView->SetProj (V3d_YnegZneg, isYup);
2935       }
2936       else if (anArgIter + 1 < theNbArgs
2937             && anArgCase == "-frame"
2938             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2939       {
2940         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2941         aFrameDef.LowerCase();
2942         gp_Dir aRight, anUp;
2943         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2944         {
2945           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2946           return 1;
2947         }
2948
2949         if (aFrameDef.Value (2) == 'x')
2950         {
2951           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2952         }
2953         else if (aFrameDef.Value (2) == 'y')
2954         {
2955           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2956         }
2957         else if (aFrameDef.Value (2) == 'z')
2958         {
2959           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2960         }
2961         else
2962         {
2963           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2964           return 1;
2965         }
2966
2967         if (aFrameDef.Value (4) == 'x')
2968         {
2969           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2970         }
2971         else if (aFrameDef.Value (4) == 'y')
2972         {
2973           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2974         }
2975         else if (aFrameDef.Value (4) == 'z')
2976         {
2977           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2978         }
2979         else
2980         {
2981           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2982           return 1;
2983         }
2984
2985         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2986         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2987         const gp_Dir aDir = anUp.Crossed (aRight);
2988         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2989         aCamera->SetDirection (aDir);
2990         aCamera->SetUp (anUp);
2991         aCamera->OrthogonalizeUp();
2992
2993         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2994         aView->Update();
2995       }
2996       else
2997       {
2998         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2999         return 1;
3000       }
3001     }
3002   }
3003
3004   if (!isGeneralCmd
3005     && theNbArgs != 1)
3006   {
3007     Message::SendFail ("Syntax error: wrong number of arguments");
3008     return 1;
3009   }
3010   return 0;
3011 }
3012
3013 //==============================================================================
3014 //function : VHelp
3015 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3016 //Draw arg : No args
3017 //==============================================================================
3018
3019 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3020 {
3021   di << "=========================\n";
3022   di << "F : FitAll\n";
3023   di << "T : TopView\n";
3024   di << "B : BottomView\n";
3025   di << "R : RightView\n";
3026   di << "L : LeftView\n";
3027   di << "Backspace : AxonometricView\n";
3028
3029   di << "=========================\n";
3030   di << "W, S : Fly   forward/backward\n";
3031   di << "A, D : Slide left/right\n";
3032   di << "Q, E : Bank  left/right\n";
3033   di << "-, + : Change flying speed\n";
3034   di << "Arrows : look left/right/up/down\n";
3035   di << "Arrows+Shift : slide left/right/up/down\n";
3036
3037   di << "=========================\n";
3038   di << "S + Ctrl : Shading\n";
3039   di << "W + Ctrl : Wireframe\n";
3040   di << "H : HiddenLineRemoval\n";
3041   di << "U : Unset display mode\n";
3042   di << "Delete : Remove selection from viewer\n";
3043
3044   di << "=========================\n";
3045   di << "Selection mode \n";
3046   di << "0 : Shape\n";
3047   di << "1 : Vertex\n";
3048   di << "2 : Edge\n";
3049   di << "3 : Wire\n";
3050   di << "4 : Face\n";
3051   di << "5 : Shell\n";
3052   di << "6 : Solid\n";
3053   di << "7 : Compound\n";
3054
3055   di << "=========================\n";
3056   di << "< : Hilight next detected\n";
3057   di << "> : Hilight previous detected\n";
3058
3059   return 0;
3060 }
3061
3062 #ifdef _WIN32
3063
3064 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3065                                            UINT theMsg,
3066                                            WPARAM wParam,
3067                                            LPARAM lParam )
3068 {
3069   if (ViewerTest_myViews.IsEmpty())
3070   {
3071     return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3072   }
3073
3074   switch (theMsg)
3075   {
3076     case WM_CLOSE:
3077     {
3078       // Delete view from map of views
3079       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3080       return 0;
3081     }
3082     case WM_ACTIVATE:
3083     {
3084       if (LOWORD(wParam) == WA_CLICKACTIVE
3085        || LOWORD(wParam) == WA_ACTIVE
3086        || ViewerTest::CurrentView().IsNull())
3087       {
3088         // Activate inactive window
3089         if (VT_GetWindow().IsNull()
3090          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3091         {
3092           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3093         }
3094       }
3095       break;
3096     }
3097     default:
3098     {
3099       return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3100     }
3101   }
3102   return 0;
3103 }
3104
3105 static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
3106                                         UINT theMsg,
3107                                         WPARAM wParam,
3108                                         LPARAM lParam)
3109 {
3110   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3111   if (aView.IsNull())
3112   {
3113     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3114   }
3115
3116   switch (theMsg)
3117   {
3118     case WM_PAINT:
3119     {
3120       PAINTSTRUCT aPaint;
3121       BeginPaint(theWinHandle, &aPaint);
3122       EndPaint  (theWinHandle, &aPaint);
3123       ViewerTest::CurrentEventManager()->ProcessExpose();
3124       break;
3125     }
3126     case WM_SIZE:
3127     {
3128       ViewerTest::CurrentEventManager()->ProcessConfigure();
3129       break;
3130     }
3131     case WM_MOVE:
3132     case WM_MOVING:
3133     case WM_SIZING:
3134     {
3135       switch (aView->RenderingParams().StereoMode)
3136       {
3137         case Graphic3d_StereoMode_RowInterlaced:
3138         case Graphic3d_StereoMode_ColumnInterlaced:
3139         case Graphic3d_StereoMode_ChessBoard:
3140         {
3141           // track window moves to reverse stereo pair
3142           aView->MustBeResized();
3143           aView->Update();
3144           break;
3145         }
3146         default:
3147           break;
3148       }
3149       break;
3150     }
3151     case WM_KEYUP:
3152     case WM_KEYDOWN:
3153     {
3154       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
3155       if (aVKey != Aspect_VKey_UNKNOWN)
3156       {
3157         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3158         if (theMsg == WM_KEYDOWN)
3159         {
3160           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3161         }
3162         else
3163         {
3164           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3165         }
3166         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3167       }
3168       break;
3169     }
3170     case WM_LBUTTONUP:
3171     case WM_MBUTTONUP:
3172     case WM_RBUTTONUP:
3173     case WM_LBUTTONDOWN:
3174     case WM_MBUTTONDOWN:
3175     case WM_RBUTTONDOWN:
3176     {
3177       const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3178       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3179       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3180       switch (theMsg)
3181       {
3182         case WM_LBUTTONUP:
3183         case WM_LBUTTONDOWN:
3184           aButton = Aspect_VKeyMouse_LeftButton;
3185           break;
3186         case WM_MBUTTONUP:
3187         case WM_MBUTTONDOWN:
3188           aButton = Aspect_VKeyMouse_MiddleButton;
3189           break;
3190         case WM_RBUTTONUP:
3191         case WM_RBUTTONDOWN:
3192           aButton = Aspect_VKeyMouse_RightButton;
3193           break;
3194       }
3195       if (theMsg == WM_LBUTTONDOWN
3196        || theMsg == WM_MBUTTONDOWN
3197        || theMsg == WM_RBUTTONDOWN)
3198       {
3199         if (aButton == Aspect_VKeyMouse_LeftButton)
3200         {
3201           TheIsAnimating = Standard_False;
3202         }
3203
3204         SetFocus  (theWinHandle);
3205         SetCapture(theWinHandle);
3206         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3207       }
3208       else
3209       {
3210         ReleaseCapture();
3211         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3212       }
3213       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3214       break;
3215     }
3216     case WM_MOUSEWHEEL:
3217     {
3218       const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
3219       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
3220       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3221       Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
3222       POINT aCursorPnt = { aPos.x(), aPos.y() };
3223       if (ScreenToClient (theWinHandle, &aCursorPnt))
3224       {
3225         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3226       }
3227
3228       ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3229       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3230       break;
3231     }
3232     case WM_MOUSEMOVE:
3233     {
3234       Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3235       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
3236       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
3237
3238       // don't make a slide-show from input events - fetch the actual mouse cursor position
3239       CURSORINFO aCursor;
3240       aCursor.cbSize = sizeof(aCursor);
3241       if (::GetCursorInfo (&aCursor) != FALSE)
3242       {
3243         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
3244         if (ScreenToClient (theWinHandle, &aCursorPnt))
3245         {
3246           // as we override mouse position, we need overriding also mouse state
3247           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3248           aButtons = WNT_Window::MouseButtonsAsync();
3249           aFlags   = WNT_Window::MouseKeyFlagsAsync();
3250         }
3251       }
3252
3253       if (VT_GetWindow().IsNull()
3254       || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3255       {
3256         // mouse move events come also for inactive windows
3257         break;
3258       }
3259
3260       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3261       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
3262       break;
3263     }
3264     case WM_INPUT:
3265     {
3266       UINT aSize = 0;
3267       ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER));
3268       NCollection_LocalArray<BYTE> aRawData (aSize);
3269       if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize)
3270       {
3271         break;
3272       }
3273
3274       const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData;
3275       if (aRawInput->header.dwType != RIM_TYPEHID)
3276       {
3277         break;
3278       }
3279
3280       RID_DEVICE_INFO aDevInfo;
3281       aDevInfo.cbSize = sizeof(RID_DEVICE_INFO);
3282       UINT aDevInfoSize = sizeof(RID_DEVICE_INFO);
3283       if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO)
3284         || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH
3285          && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION))
3286       {
3287         break;
3288       }
3289
3290       WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid);
3291       if (ViewerTest::CurrentEventManager()->Update3dMouse (aSpaceData)
3292       && !VT_GetWindow().IsNull())
3293       {
3294         VT_GetWindow()->InvalidateContent();
3295       }
3296       break;
3297     }
3298     default:
3299     {
3300       return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3301     }
3302   }
3303   return 0L;
3304 }
3305
3306 //==============================================================================
3307 //function : ViewerMainLoop
3308 //purpose  : Get a Event on the view and dispatch it
3309 //==============================================================================
3310
3311 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3312 {
3313   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3314   if (aViewCtrl.IsNull()
3315    || theNbArgs < 4)
3316   {
3317     return 0;
3318   }
3319
3320   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3321
3322   std::cout << "Start picking\n";
3323
3324   MSG aMsg;
3325   aMsg.wParam = 1;
3326   while (aViewCtrl->ToPickPoint())
3327   {
3328     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3329     if (GetMessageW (&aMsg, NULL, 0, 0))
3330     {
3331       TranslateMessage (&aMsg);
3332       DispatchMessageW (&aMsg);
3333     }
3334   }
3335
3336   std::cout << "Picking done\n";
3337   return 0;
3338 }
3339
3340 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
3341
3342 int min( int a, int b )
3343 {
3344   if( a<b )
3345     return a;
3346   else
3347     return b;
3348 }
3349
3350 int max( int a, int b )
3351 {
3352   if( a>b )
3353     return a;
3354   else
3355     return b;
3356 }
3357
3358 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3359 {
3360   static XEvent aReport;
3361   const Standard_Boolean toPick = theNbArgs > 0;
3362   if (theNbArgs > 0)
3363   {
3364     if (ViewerTest::CurrentEventManager().IsNull())
3365     {
3366       return 0;
3367     }
3368     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3369   }
3370
3371   Display* aDisplay = GetDisplayConnection()->GetDisplay();
3372   XNextEvent (aDisplay, &aReport);
3373
3374   // Handle event for the chosen display connection
3375   switch (aReport.type)
3376   {
3377     case ClientMessage:
3378     {
3379       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3380       {
3381         // Close the window
3382         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3383         return toPick ? 0 : 1;
3384       }
3385       break;
3386     }
3387     case FocusIn:
3388     {
3389       // Activate inactive view
3390       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3391       if (aWindow != aReport.xfocus.window)
3392       {
3393         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3394       }
3395       break;
3396     }
3397     case Expose:
3398     {
3399       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3400       if (anXWindow == aReport.xexpose.window)
3401       {
3402         ViewerTest::CurrentEventManager()->ProcessExpose();
3403       }
3404
3405       // remove all the ExposureMask and process them at once
3406       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3407       {
3408         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
3409         {
3410           break;
3411         }
3412       }
3413
3414       break;
3415     }
3416     case ConfigureNotify:
3417     {
3418       // remove all the StructureNotifyMask and process them at once
3419       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3420       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3421       {
3422         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
3423         {
3424           break;
3425         }
3426       }
3427
3428       if (anXWindow == aReport.xconfigure.window)
3429       {
3430         ViewerTest::CurrentEventManager()->ProcessConfigure();
3431       }
3432       break;
3433     }
3434     case KeyPress:
3435     case KeyRelease:
3436     {
3437       XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
3438       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
3439       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
3440       if (aVKey != Aspect_VKey_UNKNOWN)
3441       {
3442         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3443         if (aReport.type == KeyPress)
3444         {
3445           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3446         }
3447         else
3448         {
3449           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3450         }
3451         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3452       }
3453       break;
3454     }
3455     case ButtonPress:
3456     case ButtonRelease:
3457     {
3458       const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
3459       Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
3460       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3461       if (aReport.xbutton.button == Button1)
3462       {
3463         aButton = Aspect_VKeyMouse_LeftButton;
3464       }
3465       if (aReport.xbutton.button == Button2)
3466       {
3467         aButton = Aspect_VKeyMouse_MiddleButton;
3468       }
3469       if (aReport.xbutton.button == Button3)
3470       {
3471         aButton = Aspect_VKeyMouse_RightButton;
3472       }
3473
3474       if (aReport.xbutton.state & ControlMask)
3475       {
3476         aFlags |= Aspect_VKeyFlags_CTRL;
3477       }
3478       if (aReport.xbutton.state & ShiftMask)
3479       {
3480         aFlags |= Aspect_VKeyFlags_SHIFT;
3481       }
3482       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3483       {
3484         aFlags |= Aspect_VKeyFlags_ALT;
3485       }
3486
3487       if (aReport.xbutton.button == Button4
3488        || aReport.xbutton.button == Button5)
3489       {
3490         if (aReport.type != ButtonPress)
3491         {
3492           break;
3493         }
3494
3495         const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0);
3496         ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3497       }
3498       else if (aReport.type == ButtonPress)
3499       {
3500         if (aButton == Aspect_VKeyMouse_LeftButton)
3501         {
3502           TheIsAnimating = Standard_False;
3503         }
3504         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3505       }
3506       else
3507       {
3508         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3509       }
3510       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3511       break;
3512     }
3513     case MotionNotify:
3514     {
3515       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3516       if (anXWindow != aReport.xmotion.window)
3517       {
3518         break;
3519       }
3520
3521       // remove all the ButtonMotionMask and process them at once
3522       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3523       {
3524         if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
3525         {
3526           break;
3527         }
3528       }
3529
3530       Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y);
3531       Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
3532       Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
3533       if ((aReport.xmotion.state & Button1Mask) != 0)
3534       {
3535         aButtons |= Aspect_VKeyMouse_LeftButton;
3536       }
3537       else if ((aReport.xmotion.state & Button2Mask) != 0)
3538       {
3539         aButtons |= Aspect_VKeyMouse_MiddleButton;
3540       }
3541       else if ((aReport.xmotion.state & Button3Mask) != 0)
3542       {
3543         aButtons |= Aspect_VKeyMouse_RightButton;
3544       }
3545
3546       if (aReport.xmotion.state & ControlMask)
3547       {
3548         aFlags |= Aspect_VKeyFlags_CTRL;
3549       }
3550       if (aReport.xmotion.state & ShiftMask)
3551       {
3552         aFlags |= Aspect_VKeyFlags_SHIFT;
3553       }
3554       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3555       {
3556         aFlags |= Aspect_VKeyFlags_ALT;
3557       }
3558
3559       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3560       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3561       break;
3562     }
3563   }
3564   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
3565 }
3566
3567 //==============================================================================
3568 //function : VProcessEvents
3569 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
3570 //==============================================================================
3571 static void VProcessEvents (ClientData theDispX, int)
3572 {
3573   Display* aDispX = (Display* )theDispX;
3574   Handle(Aspect_DisplayConnection) aDispConn;
3575   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
3576        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
3577   {
3578     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
3579     if (aDispConnTmp->GetDisplay() == aDispX)
3580     {
3581       aDispConn = aDispConnTmp;
3582       break;
3583     }
3584   }
3585   if (aDispConn.IsNull())
3586   {
3587     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
3588     return;
3589   }
3590
3591   // process new events in queue
3592   SetDisplayConnection (aDispConn);
3593   int aNbRemain = 0;
3594   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
3595   {
3596     const int anEventResult = ViewerMainLoop (0, NULL);
3597     if (anEventResult == 0)
3598     {
3599       return;
3600     }
3601
3602     aNbRemain = XPending (aDispX);
3603     if (++anEventIter >= aNbEventsMax
3604      || aNbRemain <= 0)
3605     {
3606       break;
3607     }
3608   }
3609
3610   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
3611   // it is possible that new events will arrive to queue before the end of this callback
3612   // so that either this callback should go into an infinite loop (blocking processing of other events)
3613   // or to keep unprocessed events till the next queue update (which can arrive not soon).
3614   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
3615   if (aNbRemain != 0)
3616   {
3617     XEvent aDummyEvent;
3618     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
3619     aDummyEvent.type = ClientMessage;
3620     aDummyEvent.xclient.format = 32;
3621     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
3622     XFlush (aDispX);
3623   }
3624
3625   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
3626   {
3627     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
3628   }
3629 }
3630 #endif
3631
3632 //==============================================================================
3633 //function : OSWindowSetup
3634 //purpose  : Setup for the X11 window to be able to cath the event
3635 //==============================================================================
3636
3637
3638 static void OSWindowSetup()
3639 {
3640 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
3641   // X11
3642
3643   Window  window   = VT_GetWindow()->XWindow();
3644   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
3645   Display *aDisplay = GetDisplayConnection()->GetDisplay();
3646   XSynchronize(aDisplay, 1);
3647
3648   // X11 : For keyboard on SUN
3649   XWMHints wmhints;
3650   wmhints.flags = InputHint;
3651   wmhints.input = 1;
3652
3653   XSetWMHints( aDisplay, window, &wmhints);
3654
3655   XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask | KeyReleaseMask |
3656     ButtonPressMask | ButtonReleaseMask |
3657     StructureNotifyMask |
3658     PointerMotionMask |
3659     Button1MotionMask | Button2MotionMask |
3660     Button3MotionMask | FocusChangeMask
3661     );
3662   Atom aDeleteWindowAtom = GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW);
3663   XSetWMProtocols(aDisplay, window, &aDeleteWindowAtom, 1);
3664
3665   XSynchronize(aDisplay, 0);
3666
3667 #else
3668   // _WIN32
3669 #endif
3670
3671 }
3672
3673 //==============================================================================
3674 //function : VFit
3675 //purpose  :
3676 //==============================================================================
3677
3678 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3679 {
3680   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3681   if (aView.IsNull())
3682   {
3683     Message::SendFail ("Error: no active viewer");
3684     return 1;
3685   }
3686
3687   Standard_Boolean toFit = Standard_True;
3688   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3689   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3690   {
3691     TCollection_AsciiString anArg (theArgv[anArgIter]);
3692     anArg.LowerCase();
3693     if (anUpdateTool.parseRedrawMode (anArg))
3694     {
3695       continue;
3696     }
3697     else if (anArg == "-selected")
3698     {
3699       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3700       toFit = Standard_False;
3701     }
3702     else
3703     {
3704       Message::SendFail() << "Syntax error at '" << anArg << "'";
3705     }
3706   }
3707
3708   if (toFit)
3709   {
3710     aView->FitAll (0.01, Standard_False);
3711   }
3712   return 0;
3713 }
3714
3715 //=======================================================================
3716 //function : VFitArea
3717 //purpose  : Fit view to show area located between two points
3718 //         : given in world 2D or 3D coordinates.
3719 //=======================================================================
3720 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3721 {
3722   Handle(V3d_View) aView = ViewerTest::CurrentView();
3723   if (aView.IsNull())
3724   {
3725     Message::SendFail ("Error: No active viewer");
3726     return 1;
3727   }
3728
3729   // Parse arguments.
3730   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3731   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3732
3733   if (theArgNb == 5)
3734   {
3735     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3736     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3737     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3738     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3739   }
3740   else if (theArgNb == 7)
3741   {
3742     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3743     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3744     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3745     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3746     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3747     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3748   }
3749   else
3750   {
3751     Message::SendFail ("Syntax error: Invalid number of arguments");
3752     theDI.PrintHelp(theArgVec[0]);
3753     return 1;
3754   }
3755
3756   // Convert model coordinates to view space
3757   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3758   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3759   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3760
3761   // Determine fit area
3762   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3763   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3764
3765   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3766
3767   if (aDiagonal < Precision::Confusion())
3768   {
3769     Message::SendFail ("Error: view area is too small");
3770     return 1;
3771   }
3772
3773   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3774   return 0;
3775 }
3776
3777 //==============================================================================
3778 //function : VZFit
3779 //purpose  : ZFitall, no DRAW arguments
3780 //Draw arg : No args
3781 //==============================================================================
3782 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3783 {
3784   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3785
3786   if (aCurrentView.IsNull())
3787   {
3788     Message::SendFail ("Error: no active viewer");
3789     return 1;
3790   }
3791
3792   if (theArgsNb == 1)
3793   {
3794     aCurrentView->ZFitAll();
3795     aCurrentView->Redraw();
3796     return 0;
3797   }
3798
3799   Standard_Real aScale = 1.0;
3800
3801   if (theArgsNb >= 2)
3802   {
3803     aScale = Draw::Atoi (theArgVec[1]);
3804   }
3805
3806   aCurrentView->ZFitAll (aScale);
3807   aCurrentView->Redraw();
3808
3809   return 0;
3810 }
3811
3812 //==============================================================================
3813 //function : VRepaint
3814 //purpose  :
3815 //==============================================================================
3816 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3817 {
3818   Handle(V3d_View) aView = ViewerTest::CurrentView();
3819   if (aView.IsNull())
3820   {
3821     Message::SendFail ("Error: no active viewer");
3822     return 1;
3823   }
3824
3825   Standard_Boolean isImmediateUpdate = Standard_False;
3826   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3827   {
3828     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3829     anArg.LowerCase();
3830     if (anArg == "-immediate"
3831      || anArg == "-imm")
3832     {
3833       isImmediateUpdate = Standard_True;
3834       if (anArgIter + 1 < theArgNb
3835        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3836       {
3837         ++anArgIter;
3838       }
3839     }
3840     else if (anArg == "-continuous"
3841           || anArg == "-cont"
3842           || anArg == "-fps"
3843           || anArg == "-framerate")
3844     {
3845       Standard_Real aFps = -1.0;
3846       if (anArgIter + 1 < theArgNb
3847        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
3848       {
3849         aFps = Draw::Atof (theArgVec[++anArgIter]);
3850       }
3851
3852       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3853       if (Abs (aFps) >= 1.0)
3854       {
3855         aRedrawer.Start (aView->Window(), aFps);
3856       }
3857       else
3858       {
3859         aRedrawer.Stop();
3860       }
3861     }
3862     else
3863     {
3864       Message::SendFail() << "Syntax error at '" << anArg << "'";
3865       return 1;
3866     }
3867   }
3868
3869   if (isImmediateUpdate)
3870   {
3871     aView->RedrawImmediate();
3872   }
3873   else
3874   {
3875     aView->Redraw();
3876   }
3877   return 0;
3878 }
3879
3880 //==============================================================================
3881 //function : VClear
3882 //purpose  : Remove all the object from the viewer
3883 //Draw arg : No args
3884 //==============================================================================
3885
3886 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3887 {
3888   Handle(V3d_View) V = ViewerTest::CurrentView();
3889   if(!V.IsNull())
3890     ViewerTest::Clear();
3891   return 0;
3892 }
3893
3894 //==============================================================================
3895 //function : VPick
3896 //purpose  :
3897 //==============================================================================
3898
3899 static int VPick (Draw_Interpretor& ,
3900                   Standard_Integer theNbArgs,
3901                   const char** theArgVec)
3902 {
3903   if (ViewerTest::CurrentView().IsNull())
3904   {
3905     return 1;
3906   }
3907
3908   if (theNbArgs < 4)
3909   {
3910     Message::SendFail ("Syntax error: wrong number of arguments");
3911     return 1;
3912   }
3913
3914   while (ViewerMainLoop (theNbArgs, theArgVec))
3915   {
3916     //
3917   }
3918
3919   return 0;
3920 }
3921
3922 namespace
3923 {
3924
3925   //! Changes the background
3926   //! @param theDrawInterpretor the interpreter of the Draw Harness application
3927   //! @param theNumberOfCommandLineArguments the number of passed command line arguments
3928   //! @param theCommandLineArguments the array of command line arguments
3929   //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
3930   static int vbackground (Draw_Interpretor&      theDrawInterpretor,
3931                           const Standard_Integer theNumberOfCommandLineArguments,
3932                           const char** const     theCommandLineArguments)
3933   {
3934     if (theNumberOfCommandLineArguments < 1)
3935     {
3936       return TCL_ERROR;
3937     }
3938     BackgroundChanger aBackgroundChanger;
3939     if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
3940                                                 theNumberOfCommandLineArguments,
3941                                                 theCommandLineArguments))
3942     {
3943       theDrawInterpretor << "Wrong command arguments.\n"
3944                             "Type 'help "
3945                          << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
3946       return TCL_ERROR;
3947     }
3948     return TCL_OK;
3949   }
3950
3951 } // namespace
3952
3953 //==============================================================================
3954 //function : VScale
3955 //purpose  : View Scaling
3956 //==============================================================================
3957
3958 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3959 {
3960   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3961   if ( V3dView.IsNull() ) return 1;
3962
3963   if ( argc != 4 ) {
3964     di << argv[0] << "Invalid number of arguments\n";
3965     return 1;
3966   }
3967   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3968   return 0;
3969 }
3970 //==============================================================================
3971 //function : VZBuffTrihedron
3972 //purpose  :
3973 //==============================================================================
3974
3975 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3976                             Standard_Integer  theArgNb,
3977                             const char**      theArgVec)
3978 {
3979   Handle(V3d_View) aView = ViewerTest::CurrentView();
3980   if (aView.IsNull())
3981   {
3982     Message::SendFail ("Error: no active viewer");
3983     return 1;
3984   }
3985
3986   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3987
3988   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3989   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3990   Quantity_Color                aLabelsColor  = Quantity_NOC_WHITE;
3991   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3992   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3993   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
3994   Standard_Real                 aScale        = 0.1;
3995   Standard_Real                 aSizeRatio    = 0.8;
3996   Standard_Real                 anArrowDiam   = 0.05;
3997   Standard_Integer              aNbFacets     = 12;
3998   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3999   {
4000     Standard_CString        anArg = theArgVec[anArgIter];
4001     TCollection_AsciiString aFlag (anArg);
4002     aFlag.LowerCase();
4003     if (anUpdateTool.parseRedrawMode (aFlag))
4004     {
4005       continue;
4006     }
4007     else if (aFlag == "-on")
4008     {
4009       continue;
4010     }
4011     else if (aFlag == "-off")
4012     {
4013       aView->TriedronErase();
4014       return 0;
4015     }
4016     else if (aFlag == "-pos"
4017           || aFlag == "-position"
4018           || aFlag == "-corner")
4019     {
4020       if (++anArgIter >= theArgNb)
4021       {
4022         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4023         return 1;
4024       }
4025
4026       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
4027       aPosName.LowerCase();
4028       if (aPosName == "center")
4029       {
4030         aPosition = Aspect_TOTP_CENTER;
4031       }
4032       else if (aPosName == "left_lower"
4033             || aPosName == "lower_left"
4034             || aPosName == "leftlower"
4035             || aPosName == "lowerleft")
4036       {
4037         aPosition = Aspect_TOTP_LEFT_LOWER;
4038       }
4039       else if (aPosName == "left_upper"
4040             || aPosName == "upper_left"
4041             || aPosName == "leftupper"
4042             || aPosName == "upperleft")
4043       {
4044         aPosition = Aspect_TOTP_LEFT_UPPER;
4045       }
4046       else if (aPosName == "right_lower"
4047             || aPosName == "lower_right"
4048             || aPosName == "rightlower"
4049             || aPosName == "lowerright")
4050       {
4051         aPosition = Aspect_TOTP_RIGHT_LOWER;
4052       }
4053       else if (aPosName == "right_upper"
4054             || aPosName == "upper_right"
4055             || aPosName == "rightupper"
4056             || aPosName == "upperright")
4057       {
4058         aPosition = Aspect_TOTP_RIGHT_UPPER;
4059       }
4060       else
4061       {
4062         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
4063         return 1;
4064       }
4065     }
4066     else if (aFlag == "-type")
4067     {
4068       if (++anArgIter >= theArgNb)
4069       {
4070         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4071         return 1;
4072       }
4073
4074       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
4075       aTypeName.LowerCase();
4076       if (aTypeName == "wireframe"
4077        || aTypeName == "wire")
4078       {
4079         aVisType = V3d_WIREFRAME;
4080       }
4081       else if (aTypeName == "zbuffer"
4082             || aTypeName == "shaded")
4083       {
4084         aVisType = V3d_ZBUFFER;
4085       }
4086       else
4087       {
4088         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
4089       }
4090     }
4091     else if (aFlag == "-scale")
4092     {
4093       if (++anArgIter >= theArgNb)
4094       {
4095         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4096         return 1;
4097       }
4098
4099       aScale = Draw::Atof (theArgVec[anArgIter]);
4100     }
4101     else if (aFlag == "-size"
4102           || aFlag == "-sizeratio")
4103     {
4104       if (++anArgIter >= theArgNb)
4105       {
4106         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4107         return 1;
4108       }
4109
4110       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
4111     }
4112     else if (aFlag == "-arrowdiam"
4113           || aFlag == "-arrowdiameter")
4114     {
4115       if (++anArgIter >= theArgNb)
4116       {
4117         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4118         return 1;
4119       }
4120
4121       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
4122     }
4123     else if (aFlag == "-nbfacets")
4124     {
4125       if (++anArgIter >= theArgNb)
4126       {
4127         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4128         return 1;
4129       }
4130
4131       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
4132     }
4133     else if (aFlag == "-colorlabel"
4134           || aFlag == "-colorlabels")
4135     {
4136       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
4137                                                      theArgVec + anArgIter + 1,
4138                                                      aLabelsColor);
4139       if (aNbParsed == 0)
4140       {
4141         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4142         return 1;
4143       }
4144       anArgIter += aNbParsed;
4145     }
4146     else if (aFlag == "-colorarrowx")
4147     {
4148       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
4149                                                      theArgVec + anArgIter + 1,
4150                                                      anArrowColorX);
4151       if (aNbParsed == 0)
4152       {
4153         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4154         return 1;
4155       }
4156       anArgIter += aNbParsed;
4157     }
4158     else if (aFlag == "-colorarrowy")
4159     {
4160       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
4161                                                      theArgVec + anArgIter + 1,
4162                                                      anArrowColorY);
4163       if (aNbParsed == 0)
4164       {
4165         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4166         return 1;
4167       }
4168       anArgIter += aNbParsed;
4169     }
4170     else if (aFlag == "-colorarrowz")
4171     {
4172       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
4173                                                      theArgVec + anArgIter + 1,
4174                                                      anArrowColorZ);
4175       if (aNbParsed == 0)
4176       {
4177         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4178         return 1;
4179       }
4180       anArgIter += aNbParsed;
4181     }
4182     else
4183     {
4184       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4185       return 1;
4186     }
4187   }
4188
4189   aView->ZBufferTriedronSetup (anArrowColorX.Name(), anArrowColorY.Name(), anArrowColorZ.Name(),
4190                                aSizeRatio, anArrowDiam, aNbFacets);
4191   aView->TriedronDisplay (aPosition, aLabelsColor.Name(), aScale, aVisType);
4192   aView->ZFitAll();
4193   return 0;
4194 }
4195
4196 //==============================================================================
4197 //function : VRotate
4198 //purpose  : Camera Rotating
4199 //==============================================================================
4200
4201 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
4202 {
4203   Handle(V3d_View) aView = ViewerTest::CurrentView();
4204   if (aView.IsNull())
4205   {
4206     Message::SendFail ("Error: no active viewer");
4207     return 1;
4208   }
4209
4210   Standard_Boolean hasFlags = Standard_False;
4211   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4212   {
4213     Standard_CString        anArg (theArgVec[anArgIter]);
4214     TCollection_AsciiString aFlag (anArg);
4215     aFlag.LowerCase();
4216     if (aFlag == "-mousestart"
4217      || aFlag == "-mousefrom")
4218     {
4219       hasFlags = Standard_True;
4220       if (anArgIter + 2 >= theArgNb)
4221       {
4222         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4223         return 1;
4224       }
4225
4226       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4227       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4228       aView->StartRotation (anX, anY);
4229     }
4230     else if (aFlag == "-mousemove")
4231     {
4232       hasFlags = Standard_True;
4233       if (anArgIter + 2 >= theArgNb)
4234       {
4235         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4236         return 1;
4237       }
4238
4239       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4240       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4241       aView->Rotation (anX, anY);
4242     }
4243     else if (theArgNb != 4
4244           && theArgNb != 7)
4245     {
4246       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4247       return 1;
4248     }
4249   }
4250
4251   if (hasFlags)
4252   {
4253     return 0;
4254   }
4255   else if (theArgNb == 4)
4256   {
4257     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4258     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4259     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4260     aView->Rotate (anAX, anAY, anAZ);
4261     return 0;
4262   }
4263   else if (theArgNb == 7)
4264   {
4265     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4266     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4267     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4268
4269     Standard_Real anX = Draw::Atof (theArgVec[4]);
4270     Standard_Real anY = Draw::Atof (theArgVec[5]);
4271     Standard_Real anZ = Draw::Atof (theArgVec[6]);
4272
4273     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
4274     return 0;
4275   }
4276
4277   Message::SendFail ("Error: Invalid number of arguments");
4278   return 1;
4279 }
4280
4281 //==============================================================================
4282 //function : VZoom
4283 //purpose  : View zoom in / out (relative to current zoom)
4284 //==============================================================================
4285
4286 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4287   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4288   if ( V3dView.IsNull() ) {
4289     return 1;
4290   }
4291
4292   if ( argc == 2 ) {
4293     Standard_Real coef = Draw::Atof(argv[1]);
4294     if ( coef <= 0.0 ) {
4295       di << argv[1] << "Invalid value\n";
4296       return 1;
4297     }
4298     V3dView->SetZoom( Draw::Atof(argv[1]) );
4299     return 0;
4300   } else {
4301     di << argv[0] << " Invalid number of arguments\n";
4302     return 1;
4303   }
4304 }
4305
4306 //==============================================================================
4307 //function : VPan
4308 //purpose  : View panning (in pixels)
4309 //==============================================================================
4310
4311 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4312   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4313   if ( V3dView.IsNull() ) return 1;
4314
4315   if ( argc == 3 ) {
4316     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
4317     return 0;
4318   } else {
4319     di << argv[0] << " Invalid number of arguments\n";
4320     return 1;
4321   }
4322 }
4323
4324 //==============================================================================
4325 //function : VPlace
4326 //purpose  : Place the point (in pixels) at the center of the window
4327 //==============================================================================
4328 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
4329 {
4330   Handle(V3d_View) aView = ViewerTest::CurrentView();
4331   if (aView.IsNull())
4332   {
4333     Message::SendFail ("Error: no active viewer");
4334     return 1;
4335   }
4336
4337   if (theArgNb != 3)
4338   {
4339     Message::SendFail ("Syntax error: wrong number of arguments");
4340     return 1;
4341   }
4342
4343   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
4344
4345   return 0;
4346 }
4347
4348 static int VColorScale (Draw_Interpretor& theDI,
4349                         Standard_Integer  theArgNb,
4350                         const char**      theArgVec)
4351 {
4352   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4353   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
4354   if (aContext.IsNull())
4355   {
4356     Message::SendFail ("Error: no active viewer");
4357     return 1;
4358   }
4359   if (theArgNb <= 1)
4360   {
4361     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
4362     return 1;
4363   }
4364
4365   Handle(AIS_ColorScale) aColorScale;
4366   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
4367   {
4368     // find existing object
4369     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
4370     if (aColorScale.IsNull())
4371     {
4372       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
4373       return 1;
4374     }
4375   }
4376
4377   if (theArgNb <= 2)
4378   {
4379     if (aColorScale.IsNull())
4380     {
4381       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
4382       return 1;
4383     }
4384
4385     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
4386           << "Min range: "            << aColorScale->GetMin() << "\n"
4387           << "Max range: "            << aColorScale->GetMax() << "\n"
4388           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
4389           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
4390           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
4391           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
4392           << "Label position: ";
4393     switch (aColorScale->GetLabelPosition())
4394     {
4395       case Aspect_TOCSP_NONE:
4396         theDI << "None\n";
4397         break;
4398       case Aspect_TOCSP_LEFT:
4399         theDI << "Left\n";
4400         break;
4401       case Aspect_TOCSP_RIGHT:
4402         theDI << "Right\n";
4403         break;
4404       case Aspect_TOCSP_CENTER:
4405         theDI << "Center\n";
4406         break;
4407     }
4408     return 0;
4409   }
4410
4411   if (aColorScale.IsNull())
4412   {
4413     aColorScale = new AIS_ColorScale();
4414     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4415     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4416   }
4417
4418   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
4419   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
4420   {
4421     Standard_CString        anArg = theArgVec[anArgIter];
4422     TCollection_AsciiString aFlag (anArg);
4423     aFlag.LowerCase();
4424     if (anUpdateTool.parseRedrawMode (aFlag))
4425     {
4426       continue;
4427     }
4428     else if (aFlag == "-range")
4429     {
4430       if (anArgIter + 3 >= theArgNb)
4431       {
4432         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
4433         return 1;
4434       }
4435
4436       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
4437       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
4438       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
4439       if (!aRangeMin.IsRealValue()
4440        || !aRangeMax.IsRealValue())
4441       {
4442         Message::SendFail ("Syntax error: the range values should be real");
4443         return 1;
4444       }
4445       else if (!aNbIntervals.IsIntegerValue())
4446       {
4447         Message::SendFail ("Syntax error: the number of intervals should be integer");
4448         return 1;
4449       }
4450
4451       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
4452       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
4453     }
4454     else if (aFlag == "-font")
4455     {
4456       if (anArgIter + 1 >= theArgNb)
4457       {
4458         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4459         return 1;
4460       }
4461       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
4462       if (!aFontArg.IsIntegerValue())
4463       {
4464         Message::SendFail ("Syntax error: HeightFont value should be integer");
4465         return 1;
4466       }
4467
4468       aColorScale->SetTextHeight (aFontArg.IntegerValue());
4469       anArgIter += 1;
4470     }
4471     else if (aFlag == "-textpos")
4472     {
4473       if (anArgIter + 1 >= theArgNb)
4474       {
4475         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4476         return 1;
4477       }
4478
4479       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
4480       aTextPosArg.LowerCase();
4481       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
4482       if (aTextPosArg == "none")
4483       {
4484         aLabPosition = Aspect_TOCSP_NONE;
4485       }
4486       else if (aTextPosArg == "left")
4487       {
4488         aLabPosition = Aspect_TOCSP_LEFT;
4489       }
4490       else if (aTextPosArg == "right")
4491       {
4492         aLabPosition = Aspect_TOCSP_RIGHT;
4493       }
4494       else if (aTextPosArg == "center")
4495       {
4496         aLabPosition = Aspect_TOCSP_CENTER;
4497       }
4498       else
4499       {
4500         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
4501         return 1;
4502       }
4503       aColorScale->SetLabelPosition (aLabPosition);
4504     }
4505     else if (aFlag == "-logarithmic"
4506           || aFlag == "-log")
4507     {
4508       if (anArgIter + 1 >= theArgNb)
4509       {
4510         Message::SendFail() << "Synta error at argument '" << anArg << "'";
4511         return 1;
4512       }
4513
4514       Standard_Boolean IsLog;
4515       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
4516       {
4517         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4518         return 1;
4519       }
4520       aColorScale->SetLogarithmic (IsLog);
4521     }
4522     else if (aFlag == "-huerange"
4523           || aFlag == "-hue")
4524     {
4525       if (anArgIter + 2 >= theArgNb)
4526       {
4527         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4528         return 1;
4529       }
4530
4531       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
4532       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
4533       aColorScale->SetHueRange (aHueMin, aHueMax);
4534     }
4535     else if (aFlag == "-colorrange")
4536     {
4537       Quantity_Color aColorMin, aColorMax;
4538       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4539                                                       theArgVec + (anArgIter + 1),
4540                                                       aColorMin);
4541       anArgIter += aNbParsed1;
4542       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4543                                                       theArgVec + (anArgIter + 1),
4544                                                       aColorMax);
4545       anArgIter += aNbParsed2;
4546       if (aNbParsed1 == 0
4547        || aNbParsed2 == 0)
4548       {
4549         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4550         return 1;
4551       }
4552
4553       aColorScale->SetColorRange (aColorMin, aColorMax);
4554     }
4555     else if (aFlag == "-reversed"
4556           || aFlag == "-inverted"
4557           || aFlag == "-topdown"
4558           || aFlag == "-bottomup")
4559     {
4560       Standard_Boolean toEnable = Standard_True;
4561       if (anArgIter + 1 < theArgNb
4562        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
4563       {
4564         ++anArgIter;
4565       }
4566       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
4567     }
4568     else if (aFlag == "-smooth"
4569           || aFlag == "-smoothtransition")
4570     {
4571       Standard_Boolean toEnable = Standard_True;
4572       if (anArgIter + 1 < theArgNb
4573        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4574       {
4575         ++anArgIter;
4576       }
4577       aColorScale->SetSmoothTransition (toEnable);
4578     }
4579     else if (aFlag == "-xy")
4580     {
4581       if (anArgIter + 2 >= theArgNb)
4582       {
4583         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4584         return 1;
4585       }
4586
4587       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
4588       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
4589       if (!anX.IsIntegerValue()
4590        || !anY.IsIntegerValue())
4591       {
4592         Message::SendFail ("Syntax error: coordinates should be integer values");
4593         return 1;
4594       }
4595
4596       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
4597     }
4598     else if (aFlag == "-width"
4599           || aFlag == "-w"
4600           || aFlag == "-breadth")
4601     {
4602       if (anArgIter + 1 >= theArgNb)
4603       {
4604         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4605         return 1;
4606       }
4607
4608       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
4609       if (!aBreadth.IsIntegerValue())
4610       {
4611         Message::SendFail ("Syntax error: a width should be an integer value");
4612         return 1;
4613       }
4614       aColorScale->SetBreadth (aBreadth.IntegerValue());
4615     }
4616     else if (aFlag == "-height"
4617           || aFlag == "-h")
4618     {
4619       if (anArgIter + 1 >= theArgNb)
4620       {
4621         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4622         return 1;
4623       }
4624
4625       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
4626       if (!aHeight.IsIntegerValue())
4627       {
4628         Message::SendFail ("Syntax error: a width should be an integer value");
4629         return 1;
4630       }
4631       aColorScale->SetHeight (aHeight.IntegerValue());
4632     }
4633     else if (aFlag == "-color")
4634     {
4635       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4636       {
4637         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
4638         return 1;
4639       }
4640       else if (anArgIter + 2 >= theArgNb)
4641       {
4642         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4643         return 1;
4644       }
4645
4646       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
4647       if (!anInd.IsIntegerValue())
4648       {
4649         Message::SendFail ("Syntax error: Index value should be integer");
4650         return 1;
4651       }
4652       const Standard_Integer anIndex = anInd.IntegerValue();
4653       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
4654       {
4655         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
4656         return 1;
4657       }
4658
4659       Quantity_Color aColor;
4660       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4661                                                      theArgVec + (anArgIter + 1),
4662                                                      aColor);
4663       if (aNbParsed == 0)
4664       {
4665         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4666         return 1;
4667       }
4668       aColorScale->SetIntervalColor (aColor, anIndex);
4669       aColorScale->SetColorType (Aspect_TOCSD_USER);
4670       anArgIter += aNbParsed;
4671     }
4672     else if (aFlag == "-label")
4673     {
4674       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4675       {
4676         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
4677         return 1;
4678       }
4679       else if (anArgIter + 2 >= theArgNb)
4680       {
4681         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4682         return 1;
4683       }
4684
4685       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
4686       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
4687       {
4688         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
4689         return 1;
4690       }
4691
4692       TCollection_ExtendedString aText (theArgVec[anArgIter + 2]);
4693       aColorScale->SetLabel     (aText, anIndex);
4694       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4695       anArgIter += 2;
4696     }
4697     else if (aFlag == "-labelat"
4698           || aFlag == "-labat"
4699           || aFlag == "-labelatborder"
4700           || aFlag == "-labatborder"
4701           || aFlag == "-labelatcenter"
4702           || aFlag == "-labatcenter")
4703     {
4704       Standard_Boolean toEnable = Standard_True;
4705       if (aFlag == "-labelat"
4706        || aFlag == "-labat")
4707       {
4708         Standard_Integer aLabAtBorder = -1;
4709         if (++anArgIter >= theArgNb)
4710         {
4711           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
4712           anAtBorder.LowerCase();
4713           if (anAtBorder == "border")
4714           {
4715             aLabAtBorder = 1;
4716           }
4717           else if (anAtBorder == "center")
4718           {
4719             aLabAtBorder = 0;
4720           }
4721         }
4722         if (aLabAtBorder == -1)
4723         {
4724           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4725           return 1;
4726         }
4727         toEnable = (aLabAtBorder == 1);
4728       }
4729       else if (anArgIter + 1 < theArgNb
4730             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4731       {
4732         ++anArgIter;
4733       }
4734       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
4735                                   || aFlag == "-labatcenter"
4736                                    ? !toEnable
4737                                    :  toEnable);
4738     }
4739     else if (aFlag == "-colors")
4740     {
4741       Aspect_SequenceOfColor aSeq;
4742       for (;;)
4743       {
4744         Quantity_Color aColor;
4745         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4746                                                        theArgVec + (anArgIter + 1),
4747                                                        aColor);
4748         if (aNbParsed == 0)
4749         {
4750           break;
4751         }
4752         anArgIter += aNbParsed;
4753         aSeq.Append (aColor);
4754       }
4755       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4756       {
4757         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4758                             << aColorScale->GetNumberOfIntervals() << " intervals";
4759         return 1;
4760       }
4761
4762       aColorScale->SetColors    (aSeq);
4763       aColorScale->SetColorType (Aspect_TOCSD_USER);
4764     }
4765     else if (aFlag == "-uniform")
4766     {
4767       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4768       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4769       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4770       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4771       aColorScale->SetColorType (Aspect_TOCSD_USER);
4772     }
4773     else if (aFlag == "-labels"
4774           || aFlag == "-freelabels")
4775     {
4776       if (anArgIter + 1 >= theArgNb)
4777       {
4778         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4779         return 1;
4780       }
4781
4782       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4783                                  ? aColorScale->GetNumberOfIntervals() + 1
4784                                  : aColorScale->GetNumberOfIntervals();
4785       if (aFlag == "-freelabels")
4786       {
4787         ++anArgIter;
4788         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4789       }
4790       if (anArgIter + aNbLabels >= theArgNb)
4791       {
4792         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4793         return 1;
4794       }
4795
4796       TColStd_SequenceOfExtendedString aSeq;
4797       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4798       {
4799         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter]));
4800       }
4801       aColorScale->SetLabels (aSeq);
4802       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4803     }
4804     else if (aFlag == "-title")
4805     {
4806       if (anArgIter + 1 >= theArgNb)
4807       {
4808         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4809         return 1;
4810       }
4811
4812       Standard_Boolean isTwoArgs = Standard_False;
4813       if (anArgIter + 2 < theArgNb)
4814       {
4815         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4816         aSecondArg.LowerCase();
4817       Standard_DISABLE_DEPRECATION_WARNINGS
4818         if (aSecondArg == "none")
4819         {
4820           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4821           isTwoArgs = Standard_True;
4822         }
4823         else if (aSecondArg == "left")
4824         {
4825           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4826           isTwoArgs = Standard_True;
4827         }
4828         else if (aSecondArg == "right")
4829         {
4830           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4831           isTwoArgs = Standard_True;
4832         }
4833         else if (aSecondArg == "center")
4834         {
4835           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4836           isTwoArgs = Standard_True;
4837         }
4838       Standard_ENABLE_DEPRECATION_WARNINGS
4839       }
4840
4841       aColorScale->SetTitle (theArgVec[anArgIter + 1]);
4842       if (isTwoArgs)
4843       {
4844         anArgIter += 1;
4845       }
4846       anArgIter += 1;
4847     }
4848     else if (aFlag == "-demoversion"
4849           || aFlag == "-demo")
4850     {
4851       aColorScale->SetPosition (0, 0);
4852       aColorScale->SetTextHeight (16);
4853       aColorScale->SetRange (0.0, 100.0);
4854       aColorScale->SetNumberOfIntervals (10);
4855       aColorScale->SetBreadth (0);
4856       aColorScale->SetHeight  (0);
4857       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4858       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4859       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4860     }
4861     else if (aFlag == "-findcolor")
4862     {
4863       if (anArgIter + 1 >= theArgNb)
4864       {
4865         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4866         return 1;
4867       }
4868
4869       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4870
4871       if (!anArg1.IsRealValue())
4872       {
4873         Message::SendFail ("Syntax error: the value should be real");
4874         return 1;
4875       }
4876
4877       Quantity_Color aColor;
4878       aColorScale->FindColor (anArg1.RealValue(), aColor);
4879       theDI << Quantity_Color::StringName (aColor.Name());
4880       return 0;
4881     }
4882     else
4883     {
4884       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4885       return 1;
4886     }
4887   }
4888
4889   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4890   aView->Window()->Size (aWinWidth, aWinHeight);
4891   if (aColorScale->GetBreadth() == 0)
4892   {
4893     aColorScale->SetBreadth (aWinWidth);
4894   }
4895   if (aColorScale->GetHeight() == 0)
4896   {
4897     aColorScale->SetHeight (aWinHeight);
4898   }
4899   aColorScale->SetToUpdate();
4900   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4901   return 0;
4902 }
4903
4904 //==============================================================================
4905 //function : VGraduatedTrihedron
4906 //purpose  : Displays or hides a graduated trihedron
4907 //==============================================================================
4908 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4909                                   Quantity_Color& theColor)
4910 {
4911   Quantity_NameOfColor aColorName;
4912   TCollection_AsciiString aVal = theValue;
4913   aVal.UpperCase();
4914   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4915   {
4916     return Standard_False;
4917   }
4918   theColor = Quantity_Color (aColorName);
4919   return Standard_True;
4920 }
4921
4922 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4923 {
4924   if (theArgNum < 2)
4925   {
4926     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4927                         << theArgs[0] <<"' for more information";
4928     return 1;
4929   }
4930
4931   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4932   TCollection_AsciiString aParseKey;
4933   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4934   {
4935     TCollection_AsciiString anArg (theArgs [anArgIt]);
4936
4937     if (anArg.Value (1) == '-' && !anArg.IsRealValue())
4938     {
4939       aParseKey = anArg;
4940       aParseKey.Remove (1);
4941       aParseKey.LowerCase();
4942       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4943       continue;
4944     }
4945
4946     if (aParseKey.IsEmpty())
4947     {
4948       continue;
4949     }
4950
4951     aMapOfArgs(aParseKey)->Append (anArg);
4952   }
4953
4954   // Check parameters
4955   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4956        aMapIt.More(); aMapIt.Next())
4957   {
4958     const TCollection_AsciiString& aKey = aMapIt.Key();
4959     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4960
4961     // Bool key, without arguments
4962     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4963         && anArgs->IsEmpty())
4964     {
4965       continue;
4966     }
4967
4968     // One argument
4969     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4970           && anArgs->Length() == 1)
4971     {
4972       continue;
4973     }
4974
4975     // On/off arguments
4976     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4977         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4978         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4979         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4980         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4981     {
4982       continue;
4983     }
4984
4985     // One string argument
4986     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
4987           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
4988           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue())
4989     {
4990       continue;
4991     }
4992
4993     // One integer argument
4994     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
4995           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
4996           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
4997           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
4998          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
4999     {
5000       continue;
5001     }
5002
5003     // One real argument
5004     if ( aKey.IsEqual ("arrowlength")
5005          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue()))
5006     {
5007       continue;
5008     }
5009
5010     // Two string arguments
5011     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
5012          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue())
5013     {
5014       continue;
5015     }
5016
5017     TCollection_AsciiString aLowerKey;
5018     aLowerKey  = "-";
5019     aLowerKey += aKey;
5020     aLowerKey.LowerCase();
5021     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
5022                         << "Type help for more information";
5023     return 1;
5024   }
5025
5026   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
5027   if (anAISContext.IsNull())
5028   {
5029     Message::SendFail ("Error: no active viewer");
5030     return 1;
5031   }
5032
5033   Standard_Boolean toDisplay = Standard_True;
5034   Quantity_Color aColor;
5035   Graphic3d_GraduatedTrihedron aTrihedronData;
5036   // Process parameters
5037   Handle(TColStd_HSequenceOfAsciiString) aValues;
5038   if (aMapOfArgs.Find ("off", aValues))
5039   {
5040     toDisplay = Standard_False;
5041   }
5042
5043   // AXES NAMES
5044   if (aMapOfArgs.Find ("xname", aValues))
5045   {
5046     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
5047   }
5048   if (aMapOfArgs.Find ("yname", aValues))
5049   {
5050     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
5051   }
5052   if (aMapOfArgs.Find ("zname", aValues))
5053   {
5054     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
5055   }
5056   if (aMapOfArgs.Find ("xdrawname", aValues))
5057   {
5058     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5059   }
5060   if (aMapOfArgs.Find ("ydrawname", aValues))
5061   {
5062     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5063   }
5064   if (aMapOfArgs.Find ("zdrawname", aValues))
5065   {
5066     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5067   }
5068   if (aMapOfArgs.Find ("xnameoffset", aValues))
5069   {
5070     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5071   }
5072   if (aMapOfArgs.Find ("ynameoffset", aValues))
5073   {
5074     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5075   }
5076   if (aMapOfArgs.Find ("znameoffset", aValues))
5077   {
5078     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5079   }
5080
5081   // COLORS
5082   if (aMapOfArgs.Find ("xnamecolor", aValues))
5083   {
5084     if (!GetColor (aValues->Value(1), aColor))
5085     {
5086       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
5087       return 1;
5088     }
5089     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
5090   }
5091   if (aMapOfArgs.Find ("ynamecolor", aValues))
5092   {
5093     if (!GetColor (aValues->Value(1), aColor))
5094     {
5095       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
5096       return 1;
5097     }
5098     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
5099   }
5100   if (aMapOfArgs.Find ("znamecolor", aValues))
5101   {
5102     if (!GetColor (aValues->Value(1), aColor))
5103     {
5104       Message::SendFail ("Syntax error: -znamecolor wrong color name");
5105       return 1;
5106     }
5107     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
5108   }
5109   if (aMapOfArgs.Find ("xcolor", aValues))
5110   {
5111     if (!GetColor (aValues->Value(1), aColor))
5112     {
5113       Message::SendFail ("Syntax error: -xcolor wrong color name");
5114       return 1;
5115     }
5116     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
5117   }
5118   if (aMapOfArgs.Find ("ycolor", aValues))
5119   {
5120     if (!GetColor (aValues->Value(1), aColor))
5121     {
5122       Message::SendFail ("Syntax error: -ycolor wrong color name");
5123       return 1;
5124     }
5125     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
5126   }
5127   if (aMapOfArgs.Find ("zcolor", aValues))
5128   {
5129     if (!GetColor (aValues->Value(1), aColor))
5130     {
5131       Message::SendFail ("Syntax error: -zcolor wrong color name");
5132       return 1;
5133     }
5134     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
5135   }
5136
5137   // TICKMARKS
5138   if (aMapOfArgs.Find ("xticks", aValues))
5139   {
5140     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5141   }
5142   if (aMapOfArgs.Find ("yticks", aValues))
5143   {
5144     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5145   }
5146   if (aMapOfArgs.Find ("zticks", aValues))
5147   {
5148     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5149   }
5150   if (aMapOfArgs.Find ("xticklength", aValues))
5151   {
5152     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5153   }
5154   if (aMapOfArgs.Find ("yticklength", aValues))
5155   {
5156     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5157   }
5158   if (aMapOfArgs.Find ("zticklength", aValues))
5159   {
5160     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5161   }
5162   if (aMapOfArgs.Find ("xdrawticks", aValues))
5163   {
5164     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5165   }
5166   if (aMapOfArgs.Find ("ydrawticks", aValues))
5167   {
5168     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5169   }
5170   if (aMapOfArgs.Find ("zdrawticks", aValues))
5171   {
5172     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5173   }
5174
5175   // VALUES
5176   if (aMapOfArgs.Find ("xdrawvalues", aValues))
5177   {
5178     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5179   }
5180   if (aMapOfArgs.Find ("ydrawvalues", aValues))
5181   {
5182     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5183   }
5184   if (aMapOfArgs.Find ("zdrawvalues", aValues))
5185   {
5186     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5187   }
5188   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
5189   {
5190     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5191   }
5192   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
5193   {
5194     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5195   }
5196   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
5197   {
5198     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5199   }
5200
5201   // ARROWS
5202   if (aMapOfArgs.Find ("arrowlength", aValues))
5203   {
5204     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
5205   }
5206
5207   // FONTS
5208   if (aMapOfArgs.Find ("namefont", aValues))
5209   {
5210     aTrihedronData.SetNamesFont (aValues->Value(1));
5211   }
5212   if (aMapOfArgs.Find ("valuesfont", aValues))
5213   {
5214     aTrihedronData.SetValuesFont (aValues->Value(1));
5215   }
5216
5217   if (aMapOfArgs.Find ("drawgrid", aValues))
5218   {
5219     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
5220   }
5221   if (aMapOfArgs.Find ("drawaxes", aValues))
5222   {
5223     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
5224   }
5225
5226   // The final step: display of erase trihedron
5227   if (toDisplay)
5228   {
5229     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
5230   }
5231   else
5232   {
5233     ViewerTest::CurrentView()->GraduatedTrihedronErase();
5234   }
5235
5236   ViewerTest::GetAISContext()->UpdateCurrentViewer();
5237   ViewerTest::CurrentView()->Redraw();
5238
5239   return 0;
5240 }
5241
5242 //==============================================================================
5243 //function : VTile
5244 //purpose  :
5245 //==============================================================================
5246 static int VTile (Draw_Interpretor& theDI,
5247                   Standard_Integer  theArgNb,
5248                   const char**      theArgVec)
5249 {
5250   Handle(V3d_View) aView = ViewerTest::CurrentView();
5251   if (aView.IsNull())
5252   {
5253     Message::SendFail ("Error: no active viewer");
5254     return 1;
5255   }
5256
5257   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
5258   if (theArgNb < 2)
5259   {
5260     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
5261           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
5262           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
5263     return 0;
5264   }
5265
5266   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
5267   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5268   {
5269     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5270     anArg.LowerCase();
5271     if (anArg == "-lowerleft"
5272      || anArg == "-upperleft")
5273     {
5274       if (anArgIter + 3 < theArgNb)
5275       {
5276         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5277         return 1;
5278       }
5279       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
5280       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5281       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5282     }
5283     else if (anArg == "-total"
5284           || anArg == "-totalsize"
5285           || anArg == "-viewsize")
5286     {
5287       if (anArgIter + 3 < theArgNb)
5288       {
5289         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5290         return 1;
5291       }
5292       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5293       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5294       if (aTile.TotalSize.x() < 1
5295        || aTile.TotalSize.y() < 1)
5296       {
5297         Message::SendFail ("Error: total size is incorrect");
5298         return 1;
5299       }
5300     }
5301     else if (anArg == "-tilesize")
5302     {
5303       if (anArgIter + 3 < theArgNb)
5304       {
5305         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5306         return 1;
5307       }
5308
5309       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5310       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5311       if (aTile.TileSize.x() < 1
5312        || aTile.TileSize.y() < 1)
5313       {
5314         Message::SendFail ("Error: tile size is incorrect");
5315         return 1;
5316       }
5317     }
5318     else if (anArg == "-unset")
5319     {
5320       aView->Camera()->SetTile (Graphic3d_CameraTile());
5321       aView->Redraw();
5322       return 0;
5323     }
5324   }
5325
5326   if (aTile.TileSize.x() < 1
5327    || aTile.TileSize.y() < 1)
5328   {
5329     Message::SendFail ("Error: tile size is undefined");
5330     return 1;
5331   }
5332   else if (aTile.TotalSize.x() < 1
5333         || aTile.TotalSize.y() < 1)
5334   {
5335     Message::SendFail ("Error: total size is undefined");
5336     return 1;
5337   }
5338
5339   aView->Camera()->SetTile (aTile);
5340   aView->Redraw();
5341   return 0;
5342 }
5343
5344 //! Format ZLayer ID.
5345 inline const char* formZLayerId (const Standard_Integer theLayerId)
5346 {
5347   switch (theLayerId)
5348   {
5349     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
5350     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
5351     case Graphic3d_ZLayerId_Top:     return "[TOP]";
5352     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
5353     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
5354     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
5355   }
5356   return "";
5357 }
5358
5359 //! Print the ZLayer information.
5360 inline void printZLayerInfo (Draw_Interpretor& theDI,
5361                              const Graphic3d_ZLayerSettings& theLayer)
5362 {
5363   if (!theLayer.Name().IsEmpty())
5364   {
5365     theDI << "  Name: " << theLayer.Name() << "\n";
5366   }
5367   if (theLayer.IsImmediate())
5368   {
5369     theDI << "  Immediate: TRUE\n";
5370   }
5371   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
5372   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
5373   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
5374   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
5375   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
5376   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
5377   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
5378   {
5379     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
5380   }
5381 }
5382
5383 //==============================================================================
5384 //function : VZLayer
5385 //purpose  : Test z layer operations for v3d viewer
5386 //==============================================================================
5387 static int VZLayer (Draw_Interpretor& theDI,
5388                     Standard_Integer  theArgNb,
5389                     const char**      theArgVec)
5390 {
5391   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5392   if (aContextAIS.IsNull())
5393   {
5394     Message::SendFail ("Error: no active viewer");
5395     return 1;
5396   }
5397
5398   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
5399   if (theArgNb < 2)
5400   {
5401     TColStd_SequenceOfInteger aLayers;
5402     aViewer->GetAllZLayers (aLayers);
5403     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5404     {
5405       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
5406       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
5407       printZLayerInfo (theDI, aSettings);
5408     }
5409     return 1;
5410   }
5411
5412   Standard_Integer anArgIter = 1;
5413   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5414   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
5415   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5416   {
5417     ++anArgIter;
5418   }
5419
5420   {
5421     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
5422     if (aFirstArg.IsIntegerValue())
5423     {
5424       ++anArgIter;
5425       aLayerId = aFirstArg.IntegerValue();
5426     }
5427     else
5428     {
5429       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
5430       {
5431         ++anArgIter;
5432       }
5433     }
5434   }
5435
5436   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
5437   for (; anArgIter < theArgNb; ++anArgIter)
5438   {
5439     // perform operation
5440     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5441     anArg.LowerCase();
5442     if (anUpdateTool.parseRedrawMode (anArg))
5443     {
5444       //
5445     }
5446     else if (anArg == "-add"
5447           || anArg == "add")
5448     {
5449       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5450       if (!aViewer->AddZLayer (aLayerId))
5451       {
5452         Message::SendFail ("Error: can not add a new z layer");
5453         return 0;
5454       }
5455
5456       theDI << aLayerId;
5457     }
5458     else if (anArg == "-insertbefore"
5459           && anArgIter + 1 < theArgNb
5460           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5461     {
5462       ++anArgIter;
5463       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5464       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5465       {
5466         Message::SendFail ("Error: can not add a new z layer");
5467         return 0;
5468       }
5469
5470       theDI << aLayerId;
5471     }
5472     else if (anArg == "-insertafter"
5473           && anArgIter + 1 < theArgNb
5474           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5475     {
5476       ++anArgIter;
5477       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5478       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5479       {
5480         Message::SendFail ("Error: can not add a new z layer");
5481         return 0;
5482       }
5483
5484       theDI << aLayerId;
5485     }
5486     else if (anArg == "-del"
5487           || anArg == "-delete"
5488           || anArg == "del")
5489     {
5490       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5491       {
5492         if (++anArgIter >= theArgNb)
5493         {
5494           Message::SendFail ("Syntax error: id of z layer to remove is missing");
5495           return 1;
5496         }
5497
5498         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5499       }
5500
5501       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
5502        || aLayerId == Graphic3d_ZLayerId_Default
5503        || aLayerId == Graphic3d_ZLayerId_Top
5504        || aLayerId == Graphic3d_ZLayerId_Topmost
5505        || aLayerId == Graphic3d_ZLayerId_TopOSD
5506        || aLayerId == Graphic3d_ZLayerId_BotOSD)
5507       {
5508         Message::SendFail ("Syntax error: standard Z layer can not be removed");
5509         return 1;
5510       }
5511
5512       // move all object displayed in removing layer to default layer
5513       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
5514            anObjIter.More(); anObjIter.Next())
5515       {
5516         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
5517         if (aPrs.IsNull()
5518          || aPrs->ZLayer() != aLayerId)
5519         {
5520           continue;
5521         }
5522         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
5523       }
5524
5525       if (!aViewer->RemoveZLayer (aLayerId))
5526       {
5527         Message::SendFail ("Z layer can not be removed");
5528       }
5529       else
5530       {
5531         theDI << aLayerId << " ";
5532       }
5533     }
5534     else if (anArg == "-get"
5535           || anArg == "get")
5536     {
5537       TColStd_SequenceOfInteger aLayers;
5538       aViewer->GetAllZLayers (aLayers);
5539       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5540       {
5541         theDI << aLayeriter.Value() << " ";
5542       }
5543
5544       theDI << "\n";
5545     }
5546     else if (anArg == "-name")
5547     {
5548       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5549       {
5550         Message::SendFail ("Syntax error: id of Z layer is missing");
5551         return 1;
5552       }
5553
5554       if (++anArgIter >= theArgNb)
5555       {
5556         Message::SendFail ("Syntax error: name is missing");
5557         return 1;
5558       }
5559
5560       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5561       aSettings.SetName (theArgVec[anArgIter]);
5562       aViewer->SetZLayerSettings (aLayerId, aSettings);
5563     }
5564     else if (anArg == "-origin")
5565     {
5566       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5567       {
5568         Message::SendFail ("Syntax error: id of Z layer is missing");
5569         return 1;
5570       }
5571
5572       if (anArgIter + 2 >= theArgNb)
5573       {
5574         Message::SendFail ("Syntax error: origin coordinates are missing");
5575         return 1;
5576       }
5577
5578       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5579       gp_XYZ anOrigin;
5580       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
5581       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
5582       anOrigin.SetZ (0.0);
5583       if (anArgIter + 3 < theArgNb)
5584       {
5585         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
5586         anArgIter += 3;
5587       }
5588       else
5589       {
5590         anArgIter += 2;
5591       }
5592       aSettings.SetOrigin (anOrigin);
5593       aViewer->SetZLayerSettings (aLayerId, aSettings);
5594     }
5595     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5596           && anArgIter + 1 < theArgNb
5597           && (anArg == "-cullingdistance"
5598            || anArg == "-cullingdist"
5599            || anArg == "-culldistance"
5600            || anArg == "-culldist"
5601            || anArg == "-distcull"
5602            || anArg == "-distculling"
5603            || anArg == "-distanceculling"))
5604     {
5605       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5606       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
5607       aSettings.SetCullingDistance (aDist);
5608       aViewer->SetZLayerSettings (aLayerId, aSettings);
5609     }
5610     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5611           && anArgIter + 1 < theArgNb
5612           && (anArg == "-cullingsize"
5613            || anArg == "-cullsize"
5614            || anArg == "-sizecull"
5615            || anArg == "-sizeculling"))
5616     {
5617       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5618       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
5619       aSettings.SetCullingSize (aSize);
5620       aViewer->SetZLayerSettings (aLayerId, aSettings);
5621     }
5622     else if (anArg == "-settings"
5623           || anArg == "settings")
5624     {
5625       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5626       {
5627         if (++anArgIter >= theArgNb)
5628         {
5629           Message::SendFail ("Syntax error: id of Z layer is missing");
5630           return 1;
5631         }
5632
5633         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5634       }
5635
5636       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5637       printZLayerInfo (theDI, aSettings);
5638     }
5639     else if (anArg == "-enable"
5640           || anArg == "enable"
5641           || anArg == "-disable"
5642           || anArg == "disable")
5643     {
5644       const Standard_Boolean toEnable = anArg == "-enable"
5645                                      || anArg == "enable";
5646       if (++anArgIter >= theArgNb)
5647       {
5648         Message::SendFail ("Syntax error: option name is missing");
5649         return 1;
5650       }
5651
5652       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
5653       aSubOp.LowerCase();
5654       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5655       {
5656         if (++anArgIter >= theArgNb)
5657         {
5658           Message::SendFail ("Syntax error: id of Z layer is missing");
5659           return 1;
5660         }
5661
5662         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5663       }
5664
5665       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5666       if (aSubOp == "depthtest"
5667        || aSubOp == "test")
5668       {
5669         aSettings.SetEnableDepthTest (toEnable);
5670       }
5671       else if (aSubOp == "depthwrite"
5672             || aSubOp == "write")
5673       {
5674         aSettings.SetEnableDepthWrite (toEnable);
5675       }
5676       else if (aSubOp == "depthclear"
5677             || aSubOp == "clear")
5678       {
5679         aSettings.SetClearDepth (toEnable);
5680       }
5681       else if (aSubOp == "depthoffset"
5682             || aSubOp == "offset")
5683       {
5684         Graphic3d_PolygonOffset aParams;
5685         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
5686         if (toEnable)
5687         {
5688           if (anArgIter + 2 >= theArgNb)
5689           {
5690             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
5691             return 1;
5692           }
5693
5694           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5695           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5696         }
5697         aSettings.SetPolygonOffset (aParams);
5698       }
5699       else if (aSubOp == "positiveoffset"
5700             || aSubOp == "poffset")
5701       {
5702         if (toEnable)
5703         {
5704           aSettings.SetDepthOffsetPositive();
5705         }
5706         else
5707         {
5708           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
5709         }
5710       }
5711       else if (aSubOp == "negativeoffset"
5712             || aSubOp == "noffset")
5713       {
5714         if (toEnable)
5715         {
5716           aSettings.SetDepthOffsetNegative();
5717         }
5718         else
5719         {
5720           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
5721         }
5722       }
5723       else if (aSubOp == "textureenv")
5724       {
5725         aSettings.SetEnvironmentTexture (toEnable);
5726       }
5727       else if (aSubOp == "raytracing")
5728       {
5729         aSettings.SetRaytracable (toEnable);
5730       }
5731
5732       aViewer->SetZLayerSettings (aLayerId, aSettings);
5733     }
5734     else
5735     {
5736       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
5737       return 1;
5738     }
5739   }
5740
5741   return 0;
5742 }
5743
5744 // The interactive presentation of 2d layer item
5745 // for "vlayerline" command it provides a presentation of
5746 // line with user-defined linewidth, linetype and transparency.
5747 class V3d_LineItem : public AIS_InteractiveObject
5748 {
5749 public:
5750   // CASCADE RTTI
5751   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
5752
5753   // constructor
5754   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5755                                Standard_Real X2, Standard_Real Y2,
5756                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5757                                Standard_Real theWidth    = 0.5,
5758                                Standard_Real theTransp   = 1.0);
5759
5760   private:
5761
5762   void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
5763                 const Handle(Prs3d_Presentation)& thePresentation,
5764                 const Standard_Integer theMode) Standard_OVERRIDE;
5765
5766   void ComputeSelection (const Handle(SelectMgr_Selection)& /*aSelection*/,
5767                          const Standard_Integer /*aMode*/) Standard_OVERRIDE
5768   {}
5769
5770 private:
5771
5772   Standard_Real       myX1, myY1, myX2, myY2;
5773   Aspect_TypeOfLine   myType;
5774   Standard_Real       myWidth;
5775 };
5776
5777 // default constructor for line item
5778 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5779                            Standard_Real X2, Standard_Real Y2,
5780                            Aspect_TypeOfLine theType,
5781                            Standard_Real theWidth,
5782                            Standard_Real theTransp) :
5783   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5784   myType(theType), myWidth(theWidth)
5785 {
5786   SetTransparency (1-theTransp);
5787 }
5788
5789 // render line
5790 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePresentationManager*/,
5791                             const Handle(Prs3d_Presentation)& thePresentation,
5792                             const Standard_Integer /*theMode*/)
5793 {
5794   thePresentation->Clear();
5795   Quantity_Color aColor (Quantity_NOC_RED);
5796   Standard_Integer aWidth, aHeight;
5797   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5798   Handle (Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup (thePresentation);
5799   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5800   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5801   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5802   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5803   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5804   aGroup->AddPrimitiveArray (aPrim);
5805 }
5806
5807 //=============================================================================
5808 //function : VLayerLine
5809 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5810 //         : linewidth, transparency coefficient
5811 //============================================================================
5812 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5813 {
5814   // get the active view
5815   Handle(V3d_View) aView = ViewerTest::CurrentView();
5816   if (aView.IsNull())
5817   {
5818     di << "Call vinit before!\n";
5819     return 1;
5820   }
5821   else if (argc < 5)
5822   {
5823     di << "Use: " << argv[0];
5824     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5825     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5826     di << "              0 - solid  \n";
5827     di << "              1 - dashed \n";
5828     di << "              2 - dot    \n";
5829     di << "              3 - dashdot\n";
5830     di << " transparency : { 0.0 - 1.0 } \n";
5831     di << "                  0.0 - transparent\n";
5832     di << "                  1.0 - visible    \n";
5833     return 1;
5834   }
5835
5836   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5837   // get the input params
5838   Standard_Real X1 = Draw::Atof(argv[1]);
5839   Standard_Real Y1 = Draw::Atof(argv[2]);
5840   Standard_Real X2 = Draw::Atof(argv[3]);
5841   Standard_Real Y2 = Draw::Atof(argv[4]);
5842
5843   Standard_Real aWidth = 0.5;
5844   Standard_Real aTransparency = 1.0;
5845
5846   // has width
5847   if (argc > 5)
5848     aWidth = Draw::Atof(argv[5]);
5849
5850   // select appropriate line type
5851   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5852   if (argc > 6
5853   && !ViewerTest::ParseLineType (argv[6], aLineType))
5854   {
5855     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5856     return 1;
5857   }
5858
5859   // has transparency
5860   if (argc > 7)
5861   {
5862     aTransparency = Draw::Atof(argv[7]);
5863     if (aTransparency < 0 || aTransparency > 1.0)
5864       aTransparency = 1.0;
5865   }
5866
5867   static Handle (V3d_LineItem) aLine;
5868   if (!aLine.IsNull())
5869   {
5870     aContext->Erase (aLine, Standard_False);
5871   }
5872   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5873                             aLineType, aWidth,
5874                             aTransparency);
5875
5876   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5877   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5878   aLine->SetToUpdate();
5879   aContext->Display (aLine, Standard_True);
5880
5881   return 0;
5882 }
5883
5884
5885 //==============================================================================
5886 //function : VGrid
5887 //purpose  :
5888 //==============================================================================
5889
5890 static int VGrid (Draw_Interpretor& /*theDI*/,
5891                   Standard_Integer  theArgNb,
5892                   const char**      theArgVec)
5893 {
5894   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5895   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5896   if (aView.IsNull() || aViewer.IsNull())
5897   {
5898     Message::SendFail ("Error: no active viewer");
5899     return 1;
5900   }
5901
5902   Aspect_GridType     aType = aViewer->GridType();
5903   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5904   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5905   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5906   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5907   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5908   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5909   {
5910     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5911     anArg.LowerCase();
5912     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5913     {
5914       continue;
5915     }
5916     else if (anArgIter + 1 < theArgNb
5917           && anArg == "-type")
5918     {
5919       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5920       anArgNext.LowerCase();
5921       if (anArgNext == "r"
5922        || anArgNext == "rect"
5923        || anArgNext == "rectangular")
5924       {
5925         aType = Aspect_GT_Rectangular;
5926       }
5927       else if (anArgNext == "c"
5928             || anArgNext == "circ"
5929             || anArgNext == "circular")
5930       {
5931         aType = Aspect_GT_Circular;
5932       }
5933       else
5934       {
5935         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5936         return 1;
5937       }
5938     }
5939     else if (anArgIter + 1 < theArgNb
5940           && anArg == "-mode")
5941     {
5942       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5943       anArgNext.LowerCase();
5944       if (anArgNext == "l"
5945        || anArgNext == "line"
5946        || anArgNext == "lines")
5947       {
5948         aMode = Aspect_GDM_Lines;
5949       }
5950       else if (anArgNext == "p"
5951             || anArgNext == "point"
5952             || anArgNext == "points")
5953       {
5954         aMode = Aspect_GDM_Points;
5955       }
5956       else
5957       {
5958         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5959         return 1;
5960       }
5961     }
5962     else if (anArgIter + 2 < theArgNb
5963           && (anArg == "-origin"
5964            || anArg == "-orig"))
5965     {
5966       hasOrigin = true;
5967       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5968                               Draw::Atof (theArgVec[anArgIter + 2]));
5969       anArgIter += 2;
5970     }
5971     else if (anArgIter + 2 < theArgNb
5972           && anArg == "-step")
5973     {
5974       hasStep = true;
5975       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5976                             Draw::Atof (theArgVec[anArgIter + 2]));
5977       if (aNewStepXY.x() <= 0.0
5978        || aNewStepXY.y() <= 0.0)
5979       {
5980         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5981         return 1;
5982       }
5983       anArgIter += 2;
5984     }
5985     else if (anArgIter + 1 < theArgNb
5986           && (anArg == "-angle"
5987            || anArg == "-rotangle"
5988            || anArg == "-rotationangle"))
5989     {
5990       hasRotAngle = true;
5991       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
5992     }
5993     else if (anArgIter + 1 < theArgNb
5994           && (anArg == "-zoffset"
5995            || anArg == "-dz"))
5996     {
5997       hasZOffset = true;
5998       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
5999     }
6000     else if (anArgIter + 1 < theArgNb
6001           && anArg == "-radius")
6002     {
6003       hasSize = true;
6004       ++anArgIter;
6005       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
6006       if (aNewStepXY.x() <= 0.0)
6007       {
6008         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
6009         return 1;
6010       }
6011     }
6012     else if (anArgIter + 2 < theArgNb
6013           && anArg == "-size")
6014     {
6015       hasSize = true;
6016       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
6017                             Draw::Atof (theArgVec[anArgIter + 2]));
6018       if (aNewStepXY.x() <= 0.0
6019        || aNewStepXY.y() <= 0.0)
6020       {
6021         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
6022         return 1;
6023       }
6024       anArgIter += 2;
6025     }
6026     else if (anArg == "r"
6027           || anArg == "rect"
6028           || anArg == "rectangular")
6029     {
6030       aType = Aspect_GT_Rectangular;
6031     }
6032     else if (anArg == "c"
6033           || anArg == "circ"
6034           || anArg == "circular")
6035     {
6036       aType = Aspect_GT_Circular;
6037     }
6038     else if (anArg == "l"
6039           || anArg == "line"
6040           || anArg == "lines")
6041     {
6042       aMode = Aspect_GDM_Lines;
6043     }
6044     else if (anArg == "p"
6045           || anArg == "point"
6046           || anArg == "points")
6047     {
6048       aMode = Aspect_GDM_Points;
6049     }
6050     else if (anArgIter + 1 >= theArgNb
6051           && anArg == "off")
6052     {
6053       aViewer->DeactivateGrid();
6054       return 0;
6055     }
6056     else
6057     {
6058       Message::SendFail() << "Syntax error at '" << anArg << "'";
6059       return 1;
6060     }
6061   }
6062
6063   if (aType == Aspect_GT_Rectangular)
6064   {
6065     Graphic3d_Vec2d anOrigXY, aStepXY;
6066     Standard_Real aRotAngle = 0.0;
6067     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6068     if (hasOrigin)
6069     {
6070       anOrigXY = aNewOriginXY;
6071     }
6072     if (hasStep)
6073     {
6074       aStepXY = aNewStepXY;
6075     }
6076     if (hasRotAngle)
6077     {
6078       aRotAngle = aNewRotAngle;
6079     }
6080     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6081     if (hasSize || hasZOffset)
6082     {
6083       Graphic3d_Vec3d aSize;
6084       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6085       if (hasSize)
6086       {
6087         aSize.x() = aNewSizeXY.x();
6088         aSize.y() = aNewSizeXY.y();
6089       }
6090       if (hasZOffset)
6091       {
6092         aSize.z() = aNewZOffset;
6093       }
6094       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6095     }
6096   }
6097   else if (aType == Aspect_GT_Circular)
6098   {
6099     Graphic3d_Vec2d anOrigXY;
6100     Standard_Real aRadiusStep;
6101     Standard_Integer aDivisionNumber;
6102     Standard_Real aRotAngle = 0.0;
6103     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6104     if (hasOrigin)
6105     {
6106       anOrigXY = aNewOriginXY;
6107     }
6108     if (hasStep)
6109     {
6110       aRadiusStep     = aNewStepXY[0];
6111       aDivisionNumber = (int )aNewStepXY[1];
6112       if (aDivisionNumber < 1)
6113       {
6114         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
6115         return 1;
6116       }
6117     }
6118     if (hasRotAngle)
6119     {
6120       aRotAngle = aNewRotAngle;
6121     }
6122
6123     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6124     if (hasSize || hasZOffset)
6125     {
6126       Standard_Real aRadius = 0.0, aZOffset = 0.0;
6127       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
6128       if (hasSize)
6129       {
6130         aRadius = aNewSizeXY.x();
6131         if (aNewSizeXY.y() != 0.0)
6132         {
6133           Message::SendFail ("Syntax error: circular size should be specified as radius");
6134           return 1;
6135         }
6136       }
6137       if (hasZOffset)
6138       {
6139         aZOffset = aNewZOffset;
6140       }
6141       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
6142     }
6143   }
6144   aViewer->ActivateGrid (aType, aMode);
6145   return 0;
6146 }
6147
6148 //==============================================================================
6149 //function : VPriviledgedPlane
6150 //purpose  :
6151 //==============================================================================
6152
6153 static int VPriviledgedPlane (Draw_Interpretor& theDI,
6154                               Standard_Integer  theArgNb,
6155                               const char**      theArgVec)
6156 {
6157   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
6158   {
6159     Message::SendFail ("Error: wrong number of arguments! See usage:");
6160     theDI.PrintHelp (theArgVec[0]);
6161     return 1;
6162   }
6163
6164   // get the active viewer
6165   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
6166   if (aViewer.IsNull())
6167   {
6168     Message::SendFail ("Error: no active viewer");
6169     return 1;
6170   }
6171
6172   if (theArgNb == 1)
6173   {
6174     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
6175     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
6176     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
6177     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
6178     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
6179           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
6180           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
6181     return 0;
6182   }
6183
6184   Standard_Integer anArgIdx = 1;
6185   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
6186   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
6187   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
6188   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
6189   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
6190   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
6191
6192   gp_Ax3 aPriviledgedPlane;
6193   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
6194   gp_Dir aNorm (aNormX, aNormY, aNormZ);
6195   if (theArgNb > 7)
6196   {
6197     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
6198     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
6199     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
6200     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
6201     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
6202   }
6203   else
6204   {
6205     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
6206   }
6207
6208   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
6209
6210   return 0;
6211 }
6212
6213 //==============================================================================
6214 //function : VConvert
6215 //purpose  :
6216 //==============================================================================
6217
6218 static int VConvert (Draw_Interpretor& theDI,
6219                      Standard_Integer  theArgNb,
6220                      const char**      theArgVec)
6221 {
6222   // get the active view
6223   Handle(V3d_View) aView = ViewerTest::CurrentView();
6224   if (aView.IsNull())
6225   {
6226     Message::SendFail ("Error: no active viewer");
6227     return 1;
6228   }
6229
6230   enum { Model, Ray, View, Window, Grid } aMode = Model;
6231
6232   // access coordinate arguments
6233   TColStd_SequenceOfReal aCoord;
6234   Standard_Integer anArgIdx = 1;
6235   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
6236   {
6237     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6238     if (!anArg.IsRealValue())
6239     {
6240       break;
6241     }
6242     aCoord.Append (anArg.RealValue());
6243   }
6244
6245   // non-numeric argument too early
6246   if (aCoord.IsEmpty())
6247   {
6248     Message::SendFail ("Error: wrong number of arguments! See usage:");
6249     theDI.PrintHelp (theArgVec[0]);
6250     return 1;
6251   }
6252
6253   // collect all other arguments and options
6254   for (; anArgIdx < theArgNb; ++anArgIdx)
6255   {
6256     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6257     anArg.LowerCase();
6258     if      (anArg == "window") aMode = Window;
6259     else if (anArg == "view")   aMode = View;
6260     else if (anArg == "grid")   aMode = Grid;
6261     else if (anArg == "ray")    aMode = Ray;
6262     else
6263     {
6264       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
6265       theDI.PrintHelp (theArgVec[0]);
6266       return 1;
6267     }
6268   }
6269
6270   // complete input checks
6271   if ((aCoord.Length() == 1 && theArgNb > 3) ||
6272       (aCoord.Length() == 2 && theArgNb > 4) ||
6273       (aCoord.Length() == 3 && theArgNb > 5))
6274   {
6275     Message::SendFail ("Error: wrong number of arguments! See usage:");
6276     theDI.PrintHelp (theArgVec[0]);
6277     return 1;
6278   }
6279
6280   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
6281   Standard_Integer aXYp[2] = {0, 0};
6282
6283   // convert one-dimensional coordinate
6284   if (aCoord.Length() == 1)
6285   {
6286     switch (aMode)
6287     {
6288       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
6289       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
6290       default:
6291         Message::SendFail ("Error: wrong arguments! See usage:");
6292         theDI.PrintHelp (theArgVec[0]);
6293         return 1;
6294     }
6295   }
6296
6297   // convert 2D coordinates from projection or view reference space
6298   if (aCoord.Length() == 2)
6299   {
6300     switch (aMode)
6301     {
6302       case Model :
6303         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6304         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6305         return 0;
6306
6307       case View :
6308         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
6309         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
6310         return 0;
6311
6312       case Window :
6313         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
6314         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6315         return 0;
6316
6317       case Grid :
6318         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6319         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
6320         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6321         return 0;
6322
6323       case Ray :
6324         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
6325                                 (Standard_Integer) aCoord (2),
6326                                 aXYZ[0], aXYZ[1], aXYZ[2],
6327                                 aXYZ[3], aXYZ[4], aXYZ[5]);
6328         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6329         return 0;
6330
6331       default:
6332         Message::SendFail ("Error: wrong arguments! See usage:");
6333         theDI.PrintHelp (theArgVec[0]);
6334         return 1;
6335     }
6336   }
6337
6338   // convert 3D coordinates from view reference space
6339   else if (aCoord.Length() == 3)
6340   {
6341     switch (aMode)
6342     {
6343       case Window :
6344         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
6345         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6346         return 0;
6347
6348       case Grid :
6349         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
6350         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6351         return 0;
6352
6353       default:
6354         Message::SendFail ("Error: wrong arguments! See usage:");
6355         theDI.PrintHelp (theArgVec[0]);
6356         return 1;
6357     }
6358   }
6359
6360   return 0;
6361 }
6362
6363 //==============================================================================
6364 //function : VFps
6365 //purpose  :
6366 //==============================================================================
6367
6368 static int VFps (Draw_Interpretor& theDI,
6369                  Standard_Integer  theArgNb,
6370                  const char**      theArgVec)
6371 {
6372   // get the active view
6373   Handle(V3d_View) aView = ViewerTest::CurrentView();
6374   if (aView.IsNull())
6375   {
6376     Message::SendFail ("Error: no active viewer");
6377     return 1;
6378   }
6379
6380   Standard_Integer aFramesNb = -1;
6381   Standard_Real aDuration = -1.0;
6382   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6383   {
6384     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6385     anArg.LowerCase();
6386     if (aDuration < 0.0
6387      && anArgIter + 1 < theArgNb
6388      && (anArg == "-duration"
6389       || anArg == "-dur"
6390       || anArg == "-time"))
6391     {
6392       aDuration = Draw::Atof (theArgVec[++anArgIter]);
6393     }
6394     else if (aFramesNb < 0
6395           && anArg.IsIntegerValue())
6396     {
6397       aFramesNb = anArg.IntegerValue();
6398       if (aFramesNb <= 0)
6399       {
6400         Message::SendFail() << "Syntax error at '" << anArg << "'";
6401         return 1;
6402       }
6403     }
6404     else
6405     {
6406       Message::SendFail() << "Syntax error at '" << anArg << "'";
6407       return 1;
6408     }
6409   }
6410   if (aFramesNb < 0 && aDuration < 0.0)
6411   {
6412     aFramesNb = 100;
6413   }
6414
6415   // the time is meaningless for first call
6416   // due to async OpenGl rendering
6417   aView->Redraw();
6418
6419   // redraw view in loop to estimate average values
6420   OSD_Timer aTimer;
6421   aTimer.Start();
6422   Standard_Integer aFrameIter = 1;
6423   for (;; ++aFrameIter)
6424   {
6425     aView->Redraw();
6426     if ((aFramesNb > 0
6427       && aFrameIter >= aFramesNb)
6428      || (aDuration > 0.0
6429       && aTimer.ElapsedTime() >= aDuration))
6430     {
6431       break;
6432     }
6433   }
6434   aTimer.Stop();
6435   Standard_Real aCpu;
6436   const Standard_Real aTime = aTimer.ElapsedTime();
6437   aTimer.OSD_Chronometer::Show (aCpu);
6438
6439   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
6440   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
6441
6442   // return statistics
6443   theDI << "FPS: " << aFpsAver << "\n"
6444         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
6445
6446   // compute additional statistics in ray-tracing mode
6447   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
6448   if (aParams.Method == Graphic3d_RM_RAYTRACING)
6449   {
6450     Graphic3d_Vec2i aWinSize (0, 0);
6451     aView->Window()->Size (aWinSize.x(), aWinSize.y());
6452
6453     // 1 shadow ray and 1 secondary ray pew each bounce
6454     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
6455     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
6456   }
6457
6458   return 0;
6459 }
6460
6461 //! Auxiliary function for parsing glsl dump level argument.
6462 static Standard_Boolean parseGlslSourceFlag (Standard_CString               theArg,
6463                                              OpenGl_ShaderProgramDumpLevel& theGlslDumpLevel)
6464 {
6465   TCollection_AsciiString aTypeStr (theArg);
6466   aTypeStr.LowerCase();
6467   if (aTypeStr == "off"
6468    || aTypeStr == "0")
6469   {
6470     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6471   }
6472   else if (aTypeStr == "short")
6473   {
6474     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Short;
6475   }
6476   else if (aTypeStr == "full"
6477         || aTypeStr == "1")
6478   {
6479     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6480   }
6481   else
6482   {
6483     return Standard_False;
6484   }
6485   return Standard_True;
6486 }
6487
6488 //==============================================================================
6489 //function : VGlDebug
6490 //purpose  :
6491 //==============================================================================
6492
6493 static int VGlDebug (Draw_Interpretor& theDI,
6494                      Standard_Integer  theArgNb,
6495                      const char**      theArgVec)
6496 {
6497   Handle(OpenGl_GraphicDriver) aDriver;
6498   Handle(V3d_View) aView = ViewerTest::CurrentView();
6499   if (!aView.IsNull())
6500   {
6501     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aView->Viewer()->Driver());
6502   }
6503   OpenGl_Caps* aDefCaps = &ViewerTest_myDefaultCaps;
6504   OpenGl_Caps* aCaps    = !aDriver.IsNull() ? &aDriver->ChangeOptions() : NULL;
6505
6506   if (theArgNb < 2)
6507   {
6508     TCollection_AsciiString aDebActive, aSyncActive;
6509     if (aCaps == NULL)
6510     {
6511       aCaps = aDefCaps;
6512     }
6513     else
6514     {
6515       Standard_Boolean isActive = OpenGl_Context::CheckExtension ((const char* )::glGetString (GL_EXTENSIONS),
6516                                                                   "GL_ARB_debug_output");
6517       aDebActive = isActive ? " (active)" : " (inactive)";
6518       if (isActive)
6519       {
6520         // GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
6521         aSyncActive = ::glIsEnabled (0x8242) == GL_TRUE ? " (active)" : " (inactive)";
6522       }
6523     }
6524
6525     TCollection_AsciiString aGlslCodeDebugStatus = TCollection_AsciiString()
6526       + "glslSourceCode: "
6527       + (aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Off
6528          ? "Off"
6529          : aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short
6530           ? "Short"
6531           : "Full")
6532       + "\n";
6533     theDI << "debug:          " << (aCaps->contextDebug      ? "1" : "0") << aDebActive  << "\n"
6534           << "sync:           " << (aCaps->contextSyncDebug  ? "1" : "0") << aSyncActive << "\n"
6535           << "glslWarn:       " << (aCaps->glslWarnings      ? "1" : "0") << "\n"
6536           << aGlslCodeDebugStatus
6537           << "extraMsg:       " << (aCaps->suppressExtraMsg  ? "0" : "1") << "\n";
6538     return 0;
6539   }
6540
6541   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6542   {
6543     Standard_CString        anArg     = theArgVec[anArgIter];
6544     TCollection_AsciiString anArgCase (anArg);
6545     anArgCase.LowerCase();
6546     Standard_Boolean toEnableDebug = Standard_True;
6547     if (anArgCase == "-glsl"
6548      || anArgCase == "-glslwarn"
6549      || anArgCase == "-glslwarns"
6550      || anArgCase == "-glslwarnings")
6551     {
6552       Standard_Boolean toShowWarns = Standard_True;
6553       if (++anArgIter < theArgNb
6554       && !Draw::ParseOnOff (theArgVec[anArgIter], toShowWarns))
6555       {
6556         --anArgIter;
6557       }
6558       aDefCaps->glslWarnings = toShowWarns;
6559       if (aCaps != NULL)
6560       {
6561         aCaps->glslWarnings = toShowWarns;
6562       }
6563     }
6564     else if (anArgCase == "-extra"
6565           || anArgCase == "-extramsg"
6566           || anArgCase == "-extramessages")
6567     {
6568       Standard_Boolean toShow = Standard_True;
6569       if (++anArgIter < theArgNb
6570       && !Draw::ParseOnOff (theArgVec[anArgIter], toShow))
6571       {
6572         --anArgIter;
6573       }
6574       aDefCaps->suppressExtraMsg = !toShow;
6575       if (aCaps != NULL)
6576       {
6577         aCaps->suppressExtraMsg = !toShow;
6578       }
6579     }
6580     else if (anArgCase == "-noextra"
6581           || anArgCase == "-noextramsg"
6582           || anArgCase == "-noextramessages")
6583     {
6584       Standard_Boolean toSuppress = Standard_True;
6585       if (++anArgIter < theArgNb
6586       && !Draw::ParseOnOff (theArgVec[anArgIter], toSuppress))
6587       {
6588         --anArgIter;
6589       }
6590       aDefCaps->suppressExtraMsg = toSuppress;
6591       if (aCaps != NULL)
6592       {
6593         aCaps->suppressExtraMsg = toSuppress;
6594       }
6595     }
6596     else if (anArgCase == "-sync")
6597     {
6598       Standard_Boolean toSync = Standard_True;
6599       if (++anArgIter < theArgNb
6600       && !Draw::ParseOnOff (theArgVec[anArgIter], toSync))
6601       {
6602         --anArgIter;
6603       }
6604       aDefCaps->contextSyncDebug = toSync;
6605       if (toSync)
6606       {
6607         aDefCaps->contextDebug = Standard_True;
6608       }
6609     }
6610     else if (anArgCase == "-glslsourcecode"
6611           || anArgCase == "-glslcode")
6612     {
6613       OpenGl_ShaderProgramDumpLevel aGslsDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6614       if (++anArgIter < theArgNb
6615       && !parseGlslSourceFlag (theArgVec[anArgIter], aGslsDumpLevel))
6616       {
6617         --anArgIter;
6618       }
6619       aDefCaps->glslDumpLevel = aGslsDumpLevel;
6620       if (aCaps != NULL)
6621       {
6622         aCaps->glslDumpLevel = aGslsDumpLevel;
6623       }
6624     }
6625     else if (anArgCase == "-debug")
6626     {
6627       if (++anArgIter < theArgNb
6628       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnableDebug))
6629       {
6630         --anArgIter;
6631       }
6632       aDefCaps->contextDebug = toEnableDebug;
6633     }
6634     else if (Draw::ParseOnOff (anArg, toEnableDebug)
6635           && (anArgIter + 1 == theArgNb))
6636     {
6637       // simple alias to turn on almost everything
6638       aDefCaps->contextDebug     = toEnableDebug;
6639       aDefCaps->contextSyncDebug = toEnableDebug;
6640       aDefCaps->glslWarnings     = toEnableDebug;
6641       if (!toEnableDebug)
6642       {
6643         aDefCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6644       }
6645       aDefCaps->suppressExtraMsg = !toEnableDebug;
6646       if (aCaps != NULL)
6647       {
6648         aCaps->contextDebug     = toEnableDebug;
6649         aCaps->contextSyncDebug = toEnableDebug;
6650         aCaps->glslWarnings     = toEnableDebug;
6651         if (!toEnableDebug)
6652         {
6653           aCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6654         }
6655         aCaps->suppressExtraMsg = !toEnableDebug;
6656       }
6657     }
6658     else
6659     {
6660       Message::SendFail() << "Syntax error at '" << anArg << "'";
6661       return 1;
6662     }
6663   }
6664
6665   return 0;
6666 }
6667
6668 //==============================================================================
6669 //function : VVbo
6670 //purpose  :
6671 //==============================================================================
6672
6673 static int VVbo (Draw_Interpretor& theDI,
6674                  Standard_Integer  theArgNb,
6675                  const char**      theArgVec)
6676 {
6677   const Standard_Boolean toSet    = (theArgNb > 1);
6678   const Standard_Boolean toUseVbo = toSet ? (Draw::Atoi (theArgVec[1]) == 0) : 1;
6679   if (toSet)
6680   {
6681     ViewerTest_myDefaultCaps.vboDisable = toUseVbo;
6682   }
6683
6684   // get the context
6685   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6686   if (aContextAIS.IsNull())
6687   {
6688     if (!toSet)
6689     {
6690       Message::SendFail ("Error: no active viewer");
6691     }
6692     return 1;
6693   }
6694   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContextAIS->CurrentViewer()->Driver());
6695   if (!aDriver.IsNull())
6696   {
6697     if (!toSet)
6698     {
6699       theDI << (aDriver->Options().vboDisable ? "0" : "1") << "\n";
6700     }
6701     else
6702     {
6703       aDriver->ChangeOptions().vboDisable = toUseVbo;
6704     }
6705   }
6706
6707   return 0;
6708 }
6709
6710 //==============================================================================
6711 //function : VCaps
6712 //purpose  :
6713 //==============================================================================
6714
6715 static int VCaps (Draw_Interpretor& theDI,
6716                   Standard_Integer  theArgNb,
6717                   const char**      theArgVec)
6718 {
6719   OpenGl_Caps* aCaps = &ViewerTest_myDefaultCaps;
6720   Handle(OpenGl_GraphicDriver)   aDriver;
6721   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
6722   if (!aContext.IsNull())
6723   {
6724     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
6725     aCaps   = &aDriver->ChangeOptions();
6726   }
6727
6728   if (theArgNb < 2)
6729   {
6730     theDI << "sRGB:    " << (aCaps->sRGBDisable       ? "0" : "1") << "\n";
6731     theDI << "VBO:     " << (aCaps->vboDisable        ? "0" : "1") << "\n";
6732     theDI << "Sprites: " << (aCaps->pntSpritesDisable ? "0" : "1") << "\n";
6733     theDI << "SoftMode:" << (aCaps->contextNoAccel    ? "1" : "0") << "\n";
6734     theDI << "FFP:     " << (aCaps->ffpEnable         ? "1" : "0") << "\n";
6735     theDI << "PolygonMode: " << (aCaps->usePolygonMode ? "1" : "0") << "\n";
6736     theDI << "VSync:   " <<  aCaps->swapInterval                   << "\n";
6737     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
6738     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
6739     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
6740     theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
6741     theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
6742     theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n";
6743     return 0;
6744   }
6745
6746   ViewerTest_AutoUpdater anUpdateTool (aContext, ViewerTest::CurrentView());
6747   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6748   {
6749     Standard_CString        anArg     = theArgVec[anArgIter];
6750     TCollection_AsciiString anArgCase (anArg);
6751     anArgCase.LowerCase();
6752     if (anUpdateTool.parseRedrawMode (anArg))
6753     {
6754       continue;
6755     }
6756     else if (anArgCase == "-vsync"
6757           || anArgCase == "-swapinterval")
6758     {
6759       Standard_Boolean toEnable = Standard_True;
6760       if (++anArgIter < theArgNb
6761       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6762       {
6763         --anArgIter;
6764       }
6765       aCaps->swapInterval = toEnable;
6766     }
6767     else if (anArgCase == "-ffp")
6768     {
6769       Standard_Boolean toEnable = Standard_True;
6770       if (++anArgIter < theArgNb
6771       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6772       {
6773         --anArgIter;
6774       }
6775       aCaps->ffpEnable = toEnable;
6776     }
6777     else if (anArgCase == "-polygonmode")
6778     {
6779       Standard_Boolean toEnable = Standard_True;
6780       if (++anArgIter < theArgNb
6781       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6782       {
6783         --anArgIter;
6784       }
6785       aCaps->usePolygonMode = toEnable;
6786     }
6787     else if (anArgCase == "-srgb")
6788     {
6789       Standard_Boolean toEnable = Standard_True;
6790       if (++anArgIter < theArgNb
6791       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6792       {
6793         --anArgIter;
6794       }
6795       aCaps->sRGBDisable = !toEnable;
6796     }
6797     else if (anArgCase == "-compressedtextures")
6798     {
6799       Standard_Boolean toEnable = Standard_True;
6800       if (++anArgIter < theArgNb
6801       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6802       {
6803         --anArgIter;
6804       }
6805       aCaps->compressedTexturesDisable = !toEnable;
6806     }
6807     else if (anArgCase == "-vbo")
6808     {
6809       Standard_Boolean toEnable = Standard_True;
6810       if (++anArgIter < theArgNb
6811       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6812       {
6813         --anArgIter;
6814       }
6815       aCaps->vboDisable = !toEnable;
6816     }
6817     else if (anArgCase == "-sprite"
6818           || anArgCase == "-sprites")
6819     {
6820       Standard_Boolean toEnable = Standard_True;
6821       if (++anArgIter < theArgNb
6822       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6823       {
6824         --anArgIter;
6825       }
6826       aCaps->pntSpritesDisable = !toEnable;
6827     }
6828     else if (anArgCase == "-softmode")
6829     {
6830       Standard_Boolean toEnable = Standard_True;
6831       if (++anArgIter < theArgNb
6832       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6833       {
6834         --anArgIter;
6835       }
6836       aCaps->contextNoAccel = toEnable;
6837     }
6838     else if (anArgCase == "-winbuffer"
6839           || anArgCase == "-windowbuffer"
6840           || anArgCase == "-usewinbuffer"
6841           || anArgCase == "-usewindowbuffer"
6842           || anArgCase == "-usesystembuffer")
6843     {
6844       Standard_Boolean toEnable = Standard_True;
6845       if (++anArgIter < theArgNb
6846       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6847       {
6848         --anArgIter;
6849       }
6850       aCaps->useSystemBuffer = toEnable;
6851     }
6852     else if (anArgCase == "-accel"
6853           || anArgCase == "-acceleration")
6854     {
6855       Standard_Boolean toEnable = Standard_True;
6856       if (++anArgIter < theArgNb
6857       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6858       {
6859         --anArgIter;
6860       }
6861       aCaps->contextNoAccel = !toEnable;
6862     }
6863     else if (anArgCase == "-compat"
6864           || anArgCase == "-compatprofile"
6865           || anArgCase == "-compatible"
6866           || anArgCase == "-compatibleprofile")
6867     {
6868       Standard_Boolean toEnable = Standard_True;
6869       if (++anArgIter < theArgNb
6870       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6871       {
6872         --anArgIter;
6873       }
6874       aCaps->contextCompatible = toEnable;
6875       if (!aCaps->contextCompatible)
6876       {
6877         aCaps->ffpEnable = Standard_False;
6878       }
6879     }
6880     else if (anArgCase == "-core"
6881           || anArgCase == "-coreprofile")
6882     {
6883       Standard_Boolean toEnable = Standard_True;
6884       if (++anArgIter < theArgNb
6885       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6886       {
6887         --anArgIter;
6888       }
6889       aCaps->contextCompatible = !toEnable;
6890       if (!aCaps->contextCompatible)
6891       {
6892         aCaps->ffpEnable = Standard_False;
6893       }
6894     }
6895     else if (anArgCase == "-stereo"
6896           || anArgCase == "-quadbuffer")
6897     {
6898       Standard_Boolean toEnable = Standard_True;
6899       if (++anArgIter < theArgNb
6900       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6901       {
6902         --anArgIter;
6903       }
6904       aCaps->contextStereo = toEnable;
6905     }
6906     else if (anArgCase == "-noext"
6907           || anArgCase == "-noextensions"
6908           || anArgCase == "-noextension")
6909     {
6910       Standard_Boolean toDisable = Standard_True;
6911       if (++anArgIter < theArgNb
6912       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
6913       {
6914         --anArgIter;
6915       }
6916       aCaps->contextNoExtensions = toDisable;
6917     }
6918     else if (anArgCase == "-maxversion"
6919           || anArgCase == "-upperversion"
6920           || anArgCase == "-limitversion")
6921     {
6922       Standard_Integer aVer[2] = { -2, -1 };
6923       for (Standard_Integer aValIter = 0; aValIter < 2; ++aValIter)
6924       {
6925         if (anArgIter + 1 < theArgNb)
6926         {
6927           const TCollection_AsciiString aStr (theArgVec[anArgIter + 1]);
6928           if (aStr.IsIntegerValue())
6929           {
6930             aVer[aValIter] = aStr.IntegerValue();
6931             ++anArgIter;
6932           }
6933         }
6934       }
6935       if (aVer[0] < -1
6936        || aVer[1] < -1)
6937       {
6938         Message::SendFail() << "Syntax error at '" << anArgCase << "'";
6939         return 1;
6940       }
6941       aCaps->contextMajorVersionUpper = aVer[0];
6942       aCaps->contextMinorVersionUpper = aVer[1];
6943     }
6944     else
6945     {
6946       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
6947       return 1;
6948     }
6949   }
6950   if (aCaps != &ViewerTest_myDefaultCaps)
6951   {
6952     ViewerTest_myDefaultCaps = *aCaps;
6953   }
6954   return 0;
6955 }
6956
6957 //==============================================================================
6958 //function : VMemGpu
6959 //purpose  :
6960 //==============================================================================
6961
6962 static int VMemGpu (Draw_Interpretor& theDI,
6963                     Standard_Integer  theArgNb,
6964                     const char**      theArgVec)
6965 {
6966   // get the context
6967   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6968   if (aContextAIS.IsNull())
6969   {
6970     Message::SendFail ("Error: no active viewer");
6971     return 1;
6972   }
6973
6974   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
6975   if (aDriver.IsNull())
6976   {
6977     Message::SendFail ("Error: graphic driver not available");
6978     return 1;
6979   }
6980
6981   Standard_Size aFreeBytes = 0;
6982   TCollection_AsciiString anInfo;
6983   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
6984   {
6985     Message::SendFail ("Error: information not available");
6986     return 1;
6987   }
6988
6989   if (theArgNb > 1 && *theArgVec[1] == 'f')
6990   {
6991     theDI << Standard_Real (aFreeBytes);
6992   }
6993   else
6994   {
6995     theDI << anInfo;
6996   }
6997
6998   return 0;
6999 }
7000
7001 // ==============================================================================
7002 // function : VReadPixel
7003 // purpose  :
7004 // ==============================================================================
7005 static int VReadPixel (Draw_Interpretor& theDI,
7006                        Standard_Integer  theArgNb,
7007                        const char**      theArgVec)
7008 {
7009   // get the active view
7010   Handle(V3d_View) aView = ViewerTest::CurrentView();
7011   if (aView.IsNull())
7012   {
7013     Message::SendFail ("Error: no active viewer");
7014     return 1;
7015   }
7016   else if (theArgNb < 3)
7017   {
7018     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
7019                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
7020     return 1;
7021   }
7022
7023   Image_Format         aFormat     = Image_Format_RGBA;
7024   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
7025
7026   Standard_Integer aWidth, aHeight;
7027   aView->Window()->Size (aWidth, aHeight);
7028   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
7029   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
7030   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
7031   {
7032     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
7033     return 1;
7034   }
7035
7036   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
7037   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
7038   {
7039     TCollection_AsciiString aParam (theArgVec[anIter]);
7040     aParam.LowerCase();
7041     if (aParam == "-rgb"
7042      || aParam == "rgb"
7043      || aParam == "-srgb"
7044      || aParam == "srgb")
7045     {
7046       aFormat     = Image_Format_RGB;
7047       aBufferType = Graphic3d_BT_RGB;
7048       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
7049     }
7050     else if (aParam == "-hls"
7051           || aParam == "hls")
7052     {
7053       aFormat     = Image_Format_RGB;
7054       aBufferType = Graphic3d_BT_RGB;
7055       toShowHls   = Standard_True;
7056     }
7057     else if (aParam == "-rgbf"
7058           || aParam == "rgbf")
7059     {
7060       aFormat     = Image_Format_RGBF;
7061       aBufferType = Graphic3d_BT_RGB;
7062     }
7063     else if (aParam == "-rgba"
7064           || aParam == "rgba"
7065           || aParam == "-srgba"
7066           || aParam == "srgba")
7067     {
7068       aFormat     = Image_Format_RGBA;
7069       aBufferType = Graphic3d_BT_RGBA;
7070       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
7071     }
7072     else if (aParam == "-rgbaf"
7073           || aParam == "rgbaf")
7074     {
7075       aFormat     = Image_Format_RGBAF;
7076       aBufferType = Graphic3d_BT_RGBA;
7077     }
7078     else if (aParam == "-depth"
7079           || aParam == "depth")
7080     {
7081       aFormat     = Image_Format_GrayF;
7082       aBufferType = Graphic3d_BT_Depth;
7083     }
7084     else if (aParam == "-name"
7085           || aParam == "name")
7086     {
7087       toShowName = Standard_True;
7088     }
7089     else if (aParam == "-hex"
7090           || aParam == "hex")
7091     {
7092       toShowHex = Standard_True;
7093     }
7094     else
7095     {
7096       Message::SendFail() << "Syntax error at '" << aParam << "'";
7097       return 1;
7098     }
7099   }
7100
7101   Image_PixMap anImage;
7102   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
7103   {
7104     Message::SendFail ("Error: image allocation failed");
7105     return 1;
7106   }
7107   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
7108   {
7109     Message::SendFail ("Error: image dump failed");
7110     return 1;
7111   }
7112
7113   // redirect possible warning messages that could have been added by ToPixMap
7114   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
7115   // contaminate result of the command
7116   Standard_CString aWarnLog = theDI.Result();
7117   if (aWarnLog != NULL && aWarnLog[0] != '\0')
7118   {
7119     std::cout << aWarnLog << std::endl;
7120   }
7121   theDI.Reset();
7122
7123   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
7124   if (toShowName)
7125   {
7126     if (aBufferType == Graphic3d_BT_RGBA)
7127     {
7128       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
7129     }
7130     else
7131     {
7132       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
7133     }
7134   }
7135   else if (toShowHex)
7136   {
7137     if (aBufferType == Graphic3d_BT_RGBA)
7138     {
7139       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
7140     }
7141     else
7142     {
7143       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
7144     }
7145   }
7146   else
7147   {
7148     switch (aBufferType)
7149     {
7150       default:
7151       case Graphic3d_BT_RGB:
7152       {
7153         if (toShowHls)
7154         {
7155           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
7156         }
7157         else if (toShow_sRGB)
7158         {
7159           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
7160           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
7161         }
7162         else
7163         {
7164           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
7165         }
7166         break;
7167       }
7168       case Graphic3d_BT_RGBA:
7169       {
7170         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
7171         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
7172         break;
7173       }
7174       case Graphic3d_BT_Depth:
7175       {
7176         theDI << aColor.GetRGB().Red();
7177         break;
7178       }
7179     }
7180   }
7181
7182   return 0;
7183 }
7184
7185 //! Auxiliary presentation for an image plane.
7186 class ViewerTest_ImagePrs : public AIS_InteractiveObject
7187 {
7188 public:
7189   //! Main constructor.
7190   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
7191                        const Standard_Real theWidth,
7192                        const Standard_Real theHeight,
7193                        const TCollection_AsciiString& theLabel)
7194   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
7195   {
7196     SetDisplayMode (0);
7197     SetHilightMode (1);
7198     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
7199     {
7200       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
7201       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
7202       Graphic3d_MaterialAspect aMat;
7203       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
7204       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
7205       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
7206       aMat.SetSpecularColor (Quantity_NOC_BLACK);
7207       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
7208       aFillAspect->SetFrontMaterial (aMat);
7209       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
7210       aFillAspect->SetTextureMapOn();
7211     }
7212     {
7213       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
7214       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
7215       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
7216       myDrawer->SetTextAspect (aTextAspect);
7217     }
7218     {
7219       const gp_Dir aNorm (0.0, 0.0, 1.0);
7220       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
7221       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
7222       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
7223       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
7224       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
7225       myTris->AddEdge (1);
7226       myTris->AddEdge (2);
7227       myTris->AddEdge (3);
7228       myTris->AddEdge (3);
7229       myTris->AddEdge (2);
7230       myTris->AddEdge (4);
7231
7232       myRect = new Graphic3d_ArrayOfPolylines (4);
7233       myRect->AddVertex (myTris->Vertice (1));
7234       myRect->AddVertex (myTris->Vertice (3));
7235       myRect->AddVertex (myTris->Vertice (4));
7236       myRect->AddVertex (myTris->Vertice (2));
7237     }
7238   }
7239
7240   //! Returns TRUE for accepted display modes.
7241   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
7242
7243   //! Compute presentation.
7244   virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& , const Handle(Prs3d_Presentation)& thePrs, const Standard_Integer theMode) Standard_OVERRIDE
7245   {
7246     switch (theMode)
7247     {
7248       case 0:
7249       {
7250         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7251         aGroup->AddPrimitiveArray (myTris);
7252         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
7253         aGroup->AddPrimitiveArray (myRect);
7254         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7255         return;
7256       }
7257       case 1:
7258       {
7259         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
7260         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7261         aGroup->AddPrimitiveArray (myRect);
7262         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7263         return;
7264       }
7265     }
7266   }
7267
7268   //! Compute selection.
7269   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
7270   {
7271     if (theMode == 0)
7272     {
7273       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
7274       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
7275       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
7276       theSel->Add (aSensitive);
7277     }
7278   }
7279
7280 private:
7281   Handle(Graphic3d_ArrayOfTriangles) myTris;
7282   Handle(Graphic3d_ArrayOfPolylines) myRect;
7283   TCollection_AsciiString myLabel;
7284   Standard_Real myWidth;
7285   Standard_Real myHeight;
7286 };
7287
7288 //==============================================================================
7289 //function : VDiffImage
7290 //purpose  : The draw-command compares two images.
7291 //==============================================================================
7292
7293 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
7294 {
7295   if (theArgNb < 3)
7296   {
7297     Message::SendFail ("Syntax error: not enough arguments");
7298     return 1;
7299   }
7300
7301   Standard_Integer anArgIter = 1;
7302   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
7303   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
7304   TCollection_AsciiString aDiffImagePath;
7305   Standard_Real    aTolColor        = -1.0;
7306   Standard_Integer toBlackWhite     = -1;
7307   Standard_Integer isBorderFilterOn = -1;
7308   Standard_Boolean isOldSyntax = Standard_False;
7309   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
7310   for (; anArgIter < theArgNb; ++anArgIter)
7311   {
7312     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7313     anArg.LowerCase();
7314     if (anArgIter + 1 < theArgNb
7315      && (anArg == "-toleranceofcolor"
7316       || anArg == "-tolerancecolor"
7317       || anArg == "-tolerance"
7318       || anArg == "-toler"))
7319     {
7320       aTolColor = Atof (theArgVec[++anArgIter]);
7321       if (aTolColor < 0.0 || aTolColor > 1.0)
7322       {
7323         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7324         return 1;
7325       }
7326     }
7327     else if (anArg == "-blackwhite")
7328     {
7329       Standard_Boolean toEnable = Standard_True;
7330       if (anArgIter + 1 < theArgNb
7331        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7332       {
7333         ++anArgIter;
7334       }
7335       toBlackWhite = toEnable ? 1 : 0;
7336     }
7337     else if (anArg == "-borderfilter")
7338     {
7339       Standard_Boolean toEnable = Standard_True;
7340       if (anArgIter + 1 < theArgNb
7341        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7342       {
7343         ++anArgIter;
7344       }
7345       isBorderFilterOn = toEnable ? 1 : 0;
7346     }
7347     else if (anArg == "-exitonclose")
7348     {
7349       ViewerTest_EventManager::ToExitOnCloseView() = true;
7350       if (anArgIter + 1 < theArgNb
7351        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
7352       {
7353         ++anArgIter;
7354       }
7355     }
7356     else if (anArg == "-closeonescape"
7357           || anArg == "-closeonesc")
7358     {
7359       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
7360       if (anArgIter + 1 < theArgNb
7361        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
7362       {
7363         ++anArgIter;
7364       }
7365     }
7366     else if (anArgIter + 3 < theArgNb
7367           && anArg == "-display")
7368     {
7369       aViewName   = theArgVec[++anArgIter];
7370       aPrsNameRef = theArgVec[++anArgIter];
7371       aPrsNameNew = theArgVec[++anArgIter];
7372       if (anArgIter + 1 < theArgNb
7373       && *theArgVec[anArgIter + 1] != '-')
7374       {
7375         aPrsNameDiff = theArgVec[++anArgIter];
7376       }
7377     }
7378     else if (aTolColor < 0.0
7379           && anArg.IsRealValue())
7380     {
7381       isOldSyntax = Standard_True;
7382       aTolColor = anArg.RealValue();
7383       if (aTolColor < 0.0 || aTolColor > 1.0)
7384       {
7385         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7386         return 1;
7387       }
7388     }
7389     else if (isOldSyntax
7390           && toBlackWhite == -1
7391           && (anArg == "0" || anArg == "1"))
7392     {
7393       toBlackWhite = anArg == "1" ? 1 : 0;
7394     }
7395     else if (isOldSyntax
7396           && isBorderFilterOn == -1
7397           && (anArg == "0" || anArg == "1"))
7398     {
7399       isBorderFilterOn = anArg == "1" ? 1 : 0;
7400     }
7401     else if (aDiffImagePath.IsEmpty())
7402     {
7403       aDiffImagePath = theArgVec[anArgIter];
7404     }
7405     else
7406     {
7407       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7408       return 1;
7409     }
7410   }
7411
7412   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
7413   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
7414   if (!anImgRef->Load (anImgPathRef))
7415   {
7416     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
7417     return 1;
7418   }
7419   if (!anImgNew->Load (anImgPathNew))
7420   {
7421     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
7422     return 1;
7423   }
7424
7425   // compare the images
7426   Image_Diff aComparer;
7427   Standard_Integer aDiffColorsNb = -1;
7428   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
7429   {
7430     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
7431     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
7432     aDiffColorsNb = aComparer.Compare();
7433     theDI << aDiffColorsNb << "\n";
7434   }
7435
7436   // save image of difference
7437   Handle(Image_AlienPixMap) aDiff;
7438   if (aDiffColorsNb > 0
7439   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
7440   {
7441     aDiff = new Image_AlienPixMap();
7442     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
7443     {
7444       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
7445       return 1;
7446     }
7447     aComparer.SaveDiffImage (*aDiff);
7448     if (!aDiffImagePath.IsEmpty()
7449      && !aDiff->Save (aDiffImagePath))
7450     {
7451       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
7452       return 1;
7453     }
7454   }
7455
7456   if (aViewName.IsEmpty())
7457   {
7458     return 0;
7459   }
7460
7461   ViewerTest_Names aViewNames (aViewName);
7462   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
7463   {
7464     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
7465     theDI.Eval (aCommand.ToCString());
7466   }
7467
7468   Standard_Integer aPxLeft = 0;
7469   Standard_Integer aPxTop  = 0;
7470   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
7471   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
7472                               ? int(anImgRef->SizeY() * 2)
7473                               : int(anImgRef->SizeY());
7474   TCollection_AsciiString aDisplayName;
7475   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
7476                                                             aViewName, aDisplayName);
7477
7478   Standard_Real aRatio = anImgRef->Ratio();
7479   Standard_Real aSizeX = 1.0;
7480   Standard_Real aSizeY = aSizeX / aRatio;
7481   {
7482     OSD_Path aPath (anImgPathRef);
7483     TCollection_AsciiString aLabelRef;
7484     if (!aPath.Name().IsEmpty())
7485     {
7486       aLabelRef = aPath.Name() + aPath.Extension();
7487     }
7488     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
7489
7490     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
7491     gp_Trsf aTrsfRef;
7492     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
7493     anImgRefPrs->SetLocalTransformation (aTrsfRef);
7494     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
7495   }
7496   {
7497     OSD_Path aPath (anImgPathNew);
7498     TCollection_AsciiString aLabelNew;
7499     if (!aPath.Name().IsEmpty())
7500     {
7501       aLabelNew = aPath.Name() + aPath.Extension();
7502     }
7503     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
7504
7505     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
7506     gp_Trsf aTrsfRef;
7507     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
7508     anImgNewPrs->SetLocalTransformation (aTrsfRef);
7509     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
7510   }
7511   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
7512   if (!aDiff.IsNull())
7513   {
7514     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
7515     gp_Trsf aTrsfDiff;
7516     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
7517     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
7518   }
7519   if (!aPrsNameDiff.IsEmpty())
7520   {
7521     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
7522   }
7523   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
7524   ViewerTest::CurrentView()->FitAll();
7525   return 0;
7526 }
7527
7528 //=======================================================================
7529 //function : VSelect
7530 //purpose  : Emulates different types of selection by mouse:
7531 //           1) single click selection
7532 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
7533 //           3) selection with polygon having corners at
7534 //           pixel positions (x1,y1),...,(xn,yn)
7535 //           4) any of these selections with shift button pressed
7536 //=======================================================================
7537 static Standard_Integer VSelect (Draw_Interpretor& ,
7538                                  Standard_Integer theNbArgs,
7539                                  const char** theArgVec)
7540 {
7541   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
7542   if (aCtx.IsNull())
7543   {
7544     Message::SendFail ("Error: no active viewer");
7545     return 1;
7546   }
7547
7548   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
7549   bool isShiftSelection = false, toAllowOverlap = false;
7550   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7551   {
7552     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7553     anArg.LowerCase();
7554     if (anArg == "-allowoverlap")
7555     {
7556       toAllowOverlap = true;
7557       if (anArgIter + 1 < theNbArgs
7558        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
7559       {
7560         ++anArgIter;
7561       }
7562     }
7563     else if (anArgIter + 1 < theNbArgs
7564           && anArg.IsIntegerValue()
7565           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
7566     {
7567       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
7568       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
7569     }
7570     else if (anArgIter + 1 == theNbArgs
7571           && anArg.IsIntegerValue())
7572     {
7573       isShiftSelection = anArg.IntegerValue() == 1;
7574     }
7575     else
7576     {
7577       Message::SendFail() << "Syntax error at '" << anArg << "'";
7578       return 1;
7579     }
7580   }
7581
7582   if (toAllowOverlap)
7583   {
7584     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
7585   }
7586
7587   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
7588   if (aPnts.IsEmpty())
7589   {
7590     if (isShiftSelection)
7591     {
7592       aCtx->ShiftSelect (false);
7593     }
7594     else
7595     {
7596       aCtx->Select (false);
7597     }
7598     aCtx->CurrentViewer()->Invalidate();
7599   }
7600   else if (aPnts.Length() == 2)
7601   {
7602     if (toAllowOverlap
7603      && aPnts.First().y() < aPnts.Last().y())
7604     {
7605       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7606     }
7607     else if (!toAllowOverlap
7608            && aPnts.First().y() > aPnts.Last().y())
7609     {
7610       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7611     }
7612     aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection);
7613   }
7614   else
7615   {
7616     aCurrentEventManager->SelectInViewer (aPnts, isShiftSelection);
7617   }
7618   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
7619   return 0;
7620 }
7621
7622 //=======================================================================
7623 //function : VMoveTo
7624 //purpose  : Emulates cursor movement to defined pixel position
7625 //=======================================================================
7626 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
7627                                 Standard_Integer theNbArgs,
7628                                 const char**     theArgVec)
7629 {
7630   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
7631   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
7632   if (aContext.IsNull())
7633   {
7634     Message::SendFail ("Error: no active viewer");
7635     return 1;
7636   }
7637
7638   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
7639   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7640   {
7641     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
7642     anArgStr.LowerCase();
7643     if (anArgStr == "-reset"
7644      || anArgStr == "-clear")
7645     {
7646       if (anArgIter + 1 < theNbArgs)
7647       {
7648         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
7649         return 1;
7650       }
7651
7652       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->Grid()->IsActive()
7653                                        && aContext->CurrentViewer()->GridEcho();
7654       if (toEchoGrid)
7655       {
7656         aContext->CurrentViewer()->HideGridEcho (aView);
7657       }
7658       if (aContext->ClearDetected() || toEchoGrid)
7659       {
7660         aContext->CurrentViewer()->RedrawImmediate();
7661       }
7662       return 0;
7663     }
7664     else if (aMousePos.x() == IntegerLast()
7665           && anArgStr.IsIntegerValue())
7666     {
7667       aMousePos.x() = anArgStr.IntegerValue();
7668     }
7669     else if (aMousePos.y() == IntegerLast()
7670           && anArgStr.IsIntegerValue())
7671     {
7672       aMousePos.y() = anArgStr.IntegerValue();
7673     }
7674     else
7675     {
7676       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7677       return 1;
7678     }
7679   }
7680
7681   if (aMousePos.x() == IntegerLast()
7682    || aMousePos.y() == IntegerLast())
7683   {
7684     Message::SendFail ("Syntax error: wrong number of arguments");
7685     return 1;
7686   }
7687
7688   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
7689   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
7690   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
7691
7692   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
7693   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
7694   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
7695   {
7696     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
7697     {
7698       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
7699       break;
7700     }
7701   }
7702   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
7703   return 0;
7704 }
7705
7706 namespace
7707 {
7708   //! Global map storing all animations registered in ViewerTest.
7709   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
7710
7711   //! The animation calling the Draw Harness command.
7712   class ViewerTest_AnimationProc : public AIS_Animation
7713   {
7714   public:
7715
7716     //! Main constructor.
7717     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
7718                               Draw_Interpretor* theDI,
7719                               const TCollection_AsciiString& theCommand)
7720     : AIS_Animation (theAnimationName),
7721       myDrawInter(theDI),
7722       myCommand  (theCommand)
7723     {
7724       //
7725     }
7726
7727   protected:
7728
7729     //! Evaluate the command.
7730     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
7731     {
7732       TCollection_AsciiString aCmd = myCommand;
7733       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
7734       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
7735       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
7736       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
7737       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
7738       myDrawInter->Eval (aCmd.ToCString());
7739     }
7740
7741     //! Find the keyword in the command and replace it with value.
7742     //! @return the position of the keyword to pass value
7743     void replace (TCollection_AsciiString&       theCmd,
7744                   const TCollection_AsciiString& theKey,
7745                   const TCollection_AsciiString& theVal)
7746     {
7747       TCollection_AsciiString aCmd (theCmd);
7748       aCmd.LowerCase();
7749       const Standard_Integer aPos = aCmd.Search (theKey);
7750       if (aPos == -1)
7751       {
7752         return;
7753       }
7754
7755       TCollection_AsciiString aPart1, aPart2;
7756       Standard_Integer aPart1To = aPos - 1;
7757       if (aPart1To >= 1
7758        && aPart1To <= theCmd.Length())
7759       {
7760         aPart1 = theCmd.SubString (1, aPart1To);
7761       }
7762
7763       Standard_Integer aPart2From = aPos + theKey.Length();
7764       if (aPart2From >= 1
7765        && aPart2From <= theCmd.Length())
7766       {
7767         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
7768       }
7769
7770       theCmd = aPart1 + theVal + aPart2;
7771     }
7772
7773   protected:
7774
7775     Draw_Interpretor*       myDrawInter;
7776     TCollection_AsciiString myCommand;
7777
7778   };
7779
7780   //! Replace the animation with the new one.
7781   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
7782                                 Handle(AIS_Animation)&       theAnimation,
7783                                 const Handle(AIS_Animation)& theAnimationNew)
7784   {
7785     theAnimationNew->CopyFrom (theAnimation);
7786     if (!theParentAnimation.IsNull())
7787     {
7788       theParentAnimation->Replace (theAnimation, theAnimationNew);
7789     }
7790     else
7791     {
7792       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
7793       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
7794     }
7795     theAnimation = theAnimationNew;
7796   }
7797
7798   //! Parse the point.
7799   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
7800   {
7801     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
7802     if (!anXYZ[0].IsRealValue()
7803      || !anXYZ[1].IsRealValue()
7804      || !anXYZ[2].IsRealValue())
7805     {
7806       return Standard_False;
7807     }
7808
7809     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
7810     return Standard_True;
7811   }
7812
7813   //! Parse the quaternion.
7814   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
7815   {
7816     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
7817     if (!anXYZW[0].IsRealValue()
7818      || !anXYZW[1].IsRealValue()
7819      || !anXYZW[2].IsRealValue()
7820      || !anXYZW[3].IsRealValue())
7821     {
7822       return Standard_False;
7823     }
7824
7825     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
7826     return Standard_True;
7827   }
7828
7829   //! Auxiliary class for flipping image upside-down.
7830   class ImageFlipper
7831   {
7832   public:
7833
7834     //! Empty constructor.
7835     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
7836
7837     //! Perform flipping.
7838     Standard_Boolean FlipY (Image_PixMap& theImage)
7839     {
7840       if (theImage.IsEmpty()
7841        || theImage.SizeX() == 0
7842        || theImage.SizeY() == 0)
7843       {
7844         return Standard_False;
7845       }
7846
7847       const Standard_Size aRowSize = theImage.SizeRowBytes();
7848       if (myTmp.Size() < aRowSize
7849       && !myTmp.Allocate (aRowSize))
7850       {
7851         return Standard_False;
7852       }
7853
7854       // for odd height middle row should be left as is
7855       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
7856       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
7857       {
7858         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
7859         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
7860         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
7861         memcpy (aTop,               aBot,         aRowSize);
7862         memcpy (aBot,               myTmp.Data(), aRowSize);
7863       }
7864       return Standard_True;
7865     }
7866
7867   private:
7868     NCollection_Buffer myTmp;
7869   };
7870
7871 }
7872
7873 //=================================================================================================
7874 //function : VViewParams
7875 //purpose  : Gets or sets AIS View characteristics
7876 //=================================================================================================
7877 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
7878 {
7879   Handle(V3d_View) aView = ViewerTest::CurrentView();
7880   if (aView.IsNull())
7881   {
7882     Message::SendFail ("Error: no active viewer");
7883     return 1;
7884   }
7885
7886   Standard_Boolean toSetProj     = Standard_False;
7887   Standard_Boolean toSetUp       = Standard_False;
7888   Standard_Boolean toSetAt       = Standard_False;
7889   Standard_Boolean toSetEye      = Standard_False;
7890   Standard_Boolean toSetScale    = Standard_False;
7891   Standard_Boolean toSetSize     = Standard_False;
7892   Standard_Boolean toSetCenter2d = Standard_False;
7893   Standard_Real    aViewScale = aView->Scale();
7894   Standard_Real    aViewSize  = 1.0;
7895   Graphic3d_Vec2i  aCenter2d;
7896   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
7897   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
7898   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
7899   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
7900   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
7901   if (theArgsNb == 1)
7902   {
7903     // print all of the available view parameters
7904     char aText[4096];
7905     Sprintf (aText,
7906              "Scale: %g\n"
7907              "Proj:  %12g %12g %12g\n"
7908              "Up:    %12g %12g %12g\n"
7909              "At:    %12g %12g %12g\n"
7910              "Eye:   %12g %12g %12g\n",
7911               aViewScale,
7912               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7913               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7914               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
7915               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z());
7916     theDi << aText;
7917     return 0;
7918   }
7919
7920   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
7921   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
7922   {
7923     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7924     anArg.LowerCase();
7925     if (anUpdateTool.parseRedrawMode (anArg))
7926     {
7927       continue;
7928     }
7929     else if (anArg == "-cmd"
7930           || anArg == "-command"
7931           || anArg == "-args")
7932     {
7933       char aText[4096];
7934       Sprintf (aText,
7935                "-scale %g "
7936                "-proj %g %g %g "
7937                "-up %g %g %g "
7938                "-at %g %g %g\n",
7939                 aViewScale,
7940                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7941                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7942                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
7943       theDi << aText;
7944     }
7945     else if (anArg == "-scale"
7946           || anArg == "-size")
7947     {
7948       if (anArgIter + 1 < theArgsNb
7949        && *theArgVec[anArgIter + 1] != '-')
7950       {
7951         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7952         if (aValueArg.IsRealValue())
7953         {
7954           ++anArgIter;
7955           if (anArg == "-scale")
7956           {
7957             toSetScale = Standard_True;
7958             aViewScale = aValueArg.RealValue();
7959           }
7960           else if (anArg == "-size")
7961           {
7962             toSetSize = Standard_True;
7963             aViewSize = aValueArg.RealValue();
7964           }
7965           continue;
7966         }
7967       }
7968       if (anArg == "-scale")
7969       {
7970         theDi << "Scale: " << aView->Scale() << "\n";
7971       }
7972       else if (anArg == "-size")
7973       {
7974         Graphic3d_Vec2d aSizeXY;
7975         aView->Size (aSizeXY.x(), aSizeXY.y());
7976         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
7977       }
7978     }
7979     else if (anArg == "-eye"
7980           || anArg == "-at"
7981           || anArg == "-up"
7982           || anArg == "-proj")
7983     {
7984       if (anArgIter + 3 < theArgsNb)
7985       {
7986         gp_XYZ anXYZ;
7987         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
7988         {
7989           anArgIter += 3;
7990           if (anArg == "-eye")
7991           {
7992             toSetEye = Standard_True;
7993             aViewEye = anXYZ;
7994           }
7995           else if (anArg == "-at")
7996           {
7997             toSetAt = Standard_True;
7998             aViewAt = anXYZ;
7999           }
8000           else if (anArg == "-up")
8001           {
8002             toSetUp = Standard_True;
8003             aViewUp = anXYZ;
8004           }
8005           else if (anArg == "-proj")
8006           {
8007             toSetProj = Standard_True;
8008             aViewProj = anXYZ;
8009           }
8010           continue;
8011         }
8012       }
8013
8014       if (anArg == "-eye")
8015       {
8016         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
8017       }
8018       else if (anArg == "-at")
8019       {
8020         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
8021       }
8022       else if (anArg == "-up")
8023       {
8024         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
8025       }
8026       else if (anArg == "-proj")
8027       {
8028         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
8029       }
8030     }
8031     else if (anArg == "-center")
8032     {
8033       if (anArgIter + 2 < theArgsNb)
8034       {
8035         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
8036         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
8037         if (anX.IsIntegerValue()
8038          && anY.IsIntegerValue())
8039         {
8040           toSetCenter2d = Standard_True;
8041           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
8042         }
8043       }
8044     }
8045     else
8046     {
8047       Message::SendFail() << "Syntax error at '" << anArg << "'";
8048       return 1;
8049     }
8050   }
8051
8052   // change view parameters in proper order
8053   if (toSetScale)
8054   {
8055     aView->SetScale (aViewScale);
8056   }
8057   if (toSetSize)
8058   {
8059     aView->SetSize (aViewSize);
8060   }
8061   if (toSetEye)
8062   {
8063     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
8064   }
8065   if (toSetAt)
8066   {
8067     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
8068   }
8069   if (toSetProj)
8070   {
8071     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
8072   }
8073   if (toSetUp)
8074   {
8075     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
8076   }
8077   if (toSetCenter2d)
8078   {
8079     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
8080   }
8081
8082   return 0;
8083 }
8084
8085 //==============================================================================
8086 //function : V2DMode
8087 //purpose  :
8088 //==============================================================================
8089 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
8090 {
8091   bool is2dMode = true;
8092   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
8093   if (aV3dView.IsNull())
8094   {
8095     Message::SendFail ("Error: no active viewer");
8096     return 1;
8097   }
8098   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
8099   {
8100     const TCollection_AsciiString anArg = theArgVec[anArgIt];
8101     TCollection_AsciiString anArgCase = anArg;
8102     anArgCase.LowerCase();
8103     if (anArgIt + 1 < theArgsNb
8104      && anArgCase == "-name")
8105     {
8106       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
8107       TCollection_AsciiString aViewName = aViewNames.GetViewName();
8108       if (!ViewerTest_myViews.IsBound1 (aViewName))
8109       {
8110         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
8111         return 1;
8112       }
8113       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
8114     }
8115     else if (anArgCase == "-mode")
8116     {
8117       if (anArgIt + 1 < theArgsNb
8118        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
8119       {
8120         ++anArgIt;
8121       }
8122     }
8123     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
8124     {
8125       //
8126     }
8127     else
8128     {
8129       Message::SendFail() << "Syntax error: unknown argument " << anArg;
8130       return 1;
8131     }
8132   }
8133
8134   aV3dView->SetView2DMode (is2dMode);
8135   return 0;
8136 }
8137
8138 //==============================================================================
8139 //function : VAnimation
8140 //purpose  :
8141 //==============================================================================
8142 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
8143                                     Standard_Integer  theArgNb,
8144                                     const char**      theArgVec)
8145 {
8146   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
8147   if (theArgNb < 2)
8148   {
8149     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
8150          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
8151     {
8152       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
8153     }
8154     return 0;
8155   }
8156   if (aCtx.IsNull())
8157   {
8158     Message::SendFail ("Error: no active viewer");
8159     return 1;
8160   }
8161
8162   Standard_Integer anArgIter = 1;
8163   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
8164   if (aNameArg.IsEmpty())
8165   {
8166     Message::SendFail ("Syntax error: animation name is not defined");
8167     return 1;
8168   }
8169
8170   TCollection_AsciiString aNameArgLower = aNameArg;
8171   aNameArgLower.LowerCase();
8172   if (aNameArgLower == "-reset"
8173    || aNameArgLower == "-clear")
8174   {
8175     ViewerTest_AnimationTimelineMap.Clear();
8176     return 0;
8177   }
8178   else if (aNameArg.Value (1) == '-')
8179   {
8180     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
8181     return 1;
8182   }
8183
8184   const char* aNameSplitter = "/";
8185   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
8186   if (aSplitPos == -1)
8187   {
8188     aNameSplitter = ".";
8189     aSplitPos = aNameArg.Search (aNameSplitter);
8190   }
8191
8192   // find existing or create a new animation by specified name within syntax "parent.child".
8193   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
8194   for (; !aNameArg.IsEmpty();)
8195   {
8196     TCollection_AsciiString aNameParent;
8197     if (aSplitPos != -1)
8198     {
8199       if (aSplitPos == aNameArg.Length())
8200       {
8201         Message::SendFail ("Syntax error: animation name is not defined");
8202         return 1;
8203       }
8204
8205       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
8206       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
8207
8208       aSplitPos = aNameArg.Search (aNameSplitter);
8209     }
8210     else
8211     {
8212       aNameParent = aNameArg;
8213       aNameArg.Clear();
8214     }
8215
8216     if (anAnimation.IsNull())
8217     {
8218       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
8219       {
8220         anAnimation = new AIS_Animation (aNameParent);
8221         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
8222       }
8223       aRootAnimation = anAnimation;
8224     }
8225     else
8226     {
8227       aParentAnimation = anAnimation;
8228       anAnimation = aParentAnimation->Find (aNameParent);
8229       if (anAnimation.IsNull())
8230       {
8231         anAnimation = new AIS_Animation (aNameParent);
8232         aParentAnimation->Add (anAnimation);
8233       }
8234     }
8235   }
8236
8237   if (anArgIter >= theArgNb)
8238   {
8239     // just print the list of children
8240     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
8241     {
8242       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
8243     }
8244     return 0;
8245   }
8246
8247   // animation parameters
8248   Standard_Boolean toPlay = Standard_False;
8249   Standard_Real aPlaySpeed     = 1.0;
8250   Standard_Real aPlayStartTime = anAnimation->StartPts();
8251   Standard_Real aPlayDuration  = anAnimation->Duration();
8252   Standard_Boolean isFreeCamera = Standard_False;
8253   Standard_Boolean isLockLoop   = Standard_False;
8254
8255   // video recording parameters
8256   TCollection_AsciiString aRecFile;
8257   Image_VideoParams aRecParams;
8258
8259   Handle(V3d_View) aView = ViewerTest::CurrentView();
8260   for (; anArgIter < theArgNb; ++anArgIter)
8261   {
8262     TCollection_AsciiString anArg (theArgVec[anArgIter]);
8263     anArg.LowerCase();
8264     // general options
8265     if (anArg == "-reset"
8266      || anArg == "-clear")
8267     {
8268       anAnimation->Clear();
8269     }
8270     else if (anArg == "-remove"
8271           || anArg == "-del"
8272           || anArg == "-delete")
8273     {
8274       if (!aParentAnimation.IsNull())
8275       {
8276         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
8277       }
8278       else
8279       {
8280         aParentAnimation->Remove (anAnimation);
8281       }
8282     }
8283     // playback options
8284     else if (anArg == "-play")
8285     {
8286       toPlay = Standard_True;
8287       if (++anArgIter < theArgNb)
8288       {
8289         if (*theArgVec[anArgIter] == '-')
8290         {
8291           --anArgIter;
8292           continue;
8293         }
8294         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
8295
8296         if (++anArgIter < theArgNb)
8297         {
8298           if (*theArgVec[anArgIter] == '-')
8299           {
8300             --anArgIter;
8301             continue;
8302           }
8303           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8304         }
8305       }
8306     }
8307     else if (anArg == "-resume")
8308     {
8309       toPlay = Standard_True;
8310       aPlayStartTime = anAnimation->ElapsedTime();
8311       if (++anArgIter < theArgNb)
8312       {
8313         if (*theArgVec[anArgIter] == '-')
8314         {
8315           --anArgIter;
8316           continue;
8317         }
8318
8319         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8320       }
8321     }
8322     else if (anArg == "-playspeed"
8323           || anArg == "-speed")
8324     {
8325       if (++anArgIter >= theArgNb)
8326       {
8327         Message::SendFail() << "Syntax error at " << anArg << "";
8328         return 1;
8329       }
8330       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
8331     }
8332     else if (anArg == "-lock"
8333           || anArg == "-lockloop"
8334           || anArg == "-playlockloop")
8335     {
8336       isLockLoop = Standard_True;
8337     }
8338     else if (anArg == "-freecamera"
8339           || anArg == "-playfreecamera"
8340           || anArg == "-freelook")
8341     {
8342       isFreeCamera = Standard_True;
8343     }
8344     // video recodring options
8345     else if (anArg == "-rec"
8346           || anArg == "-record")
8347     {
8348       if (++anArgIter >= theArgNb)
8349       {
8350         Message::SendFail() << "Syntax error at " << anArg;
8351         return 1;
8352       }
8353
8354       aRecFile = theArgVec[anArgIter];
8355       if (aRecParams.FpsNum <= 0)
8356       {
8357         aRecParams.FpsNum = 24;
8358       }
8359
8360       if (anArgIter + 2 < theArgNb
8361       && *theArgVec[anArgIter + 1] != '-'
8362       && *theArgVec[anArgIter + 2] != '-')
8363       {
8364         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
8365         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
8366         if (aWidthArg .IsIntegerValue()
8367          && aHeightArg.IsIntegerValue())
8368         {
8369           aRecParams.Width  = aWidthArg .IntegerValue();
8370           aRecParams.Height = aHeightArg.IntegerValue();
8371           anArgIter += 2;
8372         }
8373       }
8374     }
8375     else if (anArg == "-fps")
8376     {
8377       if (++anArgIter >= theArgNb)
8378       {
8379         Message::SendFail() << "Syntax error at " << anArg;
8380         return 1;
8381       }
8382
8383       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
8384       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
8385       if (aSplitIndex == 0)
8386       {
8387         aRecParams.FpsNum = aFpsArg.IntegerValue();
8388       }
8389       else
8390       {
8391         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
8392         aFpsArg.Split (aFpsArg.Length() - 1);
8393         const TCollection_AsciiString aNumStr = aFpsArg;
8394         aRecParams.FpsNum = aNumStr.IntegerValue();
8395         aRecParams.FpsDen = aDenStr.IntegerValue();
8396         if (aRecParams.FpsDen < 1)
8397         {
8398           Message::SendFail() << "Syntax error at " << anArg;
8399           return 1;
8400         }
8401       }
8402     }
8403     else if (anArg == "-format")
8404     {
8405       if (++anArgIter >= theArgNb)
8406       {
8407         Message::SendFail() << "Syntax error at " << anArg;
8408         return 1;
8409       }
8410       aRecParams.Format = theArgVec[anArgIter];
8411     }
8412     else if (anArg == "-pix_fmt"
8413           || anArg == "-pixfmt"
8414           || anArg == "-pixelformat")
8415     {
8416       if (++anArgIter >= theArgNb)
8417       {
8418         Message::SendFail() << "Syntax error at " << anArg;
8419         return 1;
8420       }
8421       aRecParams.PixelFormat = theArgVec[anArgIter];
8422     }
8423     else if (anArg == "-codec"
8424           || anArg == "-vcodec"
8425           || anArg == "-videocodec")
8426     {
8427       if (++anArgIter >= theArgNb)
8428       {
8429         Message::SendFail() << "Syntax error at " << anArg;
8430         return 1;
8431       }
8432       aRecParams.VideoCodec = theArgVec[anArgIter];
8433     }
8434     else if (anArg == "-crf"
8435           || anArg == "-preset"
8436           || anArg == "-qp")
8437     {
8438       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
8439       if (++anArgIter >= theArgNb)
8440       {
8441         Message::SendFail() << "Syntax error at " << anArg;
8442         return 1;
8443       }
8444
8445       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
8446     }
8447     // animation definition options
8448     else if (anArg == "-start"
8449           || anArg == "-starttime"
8450           || anArg == "-startpts")
8451     {
8452       if (++anArgIter >= theArgNb)
8453       {
8454         Message::SendFail() << "Syntax error at " << anArg;
8455         return 1;
8456       }
8457
8458       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
8459       aRootAnimation->UpdateTotalDuration();
8460     }
8461     else if (anArg == "-end"
8462           || anArg == "-endtime"
8463           || anArg == "-endpts")
8464     {
8465       if (++anArgIter >= theArgNb)
8466       {
8467         Message::SendFail() << "Syntax error at " << anArg;
8468         return 1;
8469       }
8470
8471       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
8472       aRootAnimation->UpdateTotalDuration();
8473     }
8474     else if (anArg == "-dur"
8475           || anArg == "-duration")
8476     {
8477       if (++anArgIter >= theArgNb)
8478       {
8479         Message::SendFail() << "Syntax error at " << anArg;
8480         return 1;
8481       }
8482
8483       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
8484       aRootAnimation->UpdateTotalDuration();
8485     }
8486     else if (anArg == "-command"
8487           || anArg == "-cmd"
8488           || anArg == "-invoke"
8489           || anArg == "-eval"
8490           || anArg == "-proc")
8491     {
8492       if (++anArgIter >= theArgNb)
8493       {
8494         Message::SendFail() << "Syntax error at " << anArg;
8495         return 1;
8496       }
8497
8498       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
8499       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
8500     }
8501     else if (anArg == "-objecttrsf"
8502           || anArg == "-objectransformation"
8503           || anArg == "-objtransformation"
8504           || anArg == "-objtrsf"
8505           || anArg == "-object"
8506           || anArg == "-obj")
8507     {
8508       if (++anArgIter >= theArgNb)
8509       {
8510         Message::SendFail() << "Syntax error at " << anArg;
8511         return 1;
8512       }
8513
8514       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
8515       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
8516       Handle(AIS_InteractiveObject) anObject;
8517       if (!aMapOfAIS.Find2 (anObjName, anObject))
8518       {
8519         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
8520         return 1;
8521       }
8522
8523       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
8524       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
8525       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
8526       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
8527       Standard_Boolean isTrsfSet = Standard_False;
8528       Standard_Integer aTrsfArgIter = anArgIter + 1;
8529       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
8530       {
8531         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
8532         aTrsfArg.LowerCase();
8533         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
8534         if (aTrsfArg.StartsWith ("-rotation")
8535          || aTrsfArg.StartsWith ("-rot"))
8536         {
8537           isTrsfSet = Standard_True;
8538           if (aTrsfArgIter + 4 >= theArgNb
8539           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
8540           {
8541             Message::SendFail() << "Syntax error at " << aTrsfArg;
8542             return 1;
8543           }
8544           aTrsfArgIter += 4;
8545         }
8546         else if (aTrsfArg.StartsWith ("-location")
8547               || aTrsfArg.StartsWith ("-loc"))
8548         {
8549           isTrsfSet = Standard_True;
8550           if (aTrsfArgIter + 3 >= theArgNb
8551           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
8552           {
8553             Message::SendFail() << "Syntax error at " << aTrsfArg;
8554             return 1;
8555           }
8556           aTrsfArgIter += 3;
8557         }
8558         else if (aTrsfArg.StartsWith ("-scale"))
8559         {
8560           isTrsfSet = Standard_True;
8561           if (++aTrsfArgIter >= theArgNb)
8562           {
8563             Message::SendFail() << "Syntax error at " << aTrsfArg;
8564             return 1;
8565           }
8566
8567           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
8568           if (!aScaleStr.IsRealValue())
8569           {
8570             Message::SendFail() << "Syntax error at " << aTrsfArg;
8571             return 1;
8572           }
8573           aScales[anIndex] = aScaleStr.RealValue();
8574         }
8575         else
8576         {
8577           anArgIter = aTrsfArgIter - 1;
8578           break;
8579         }
8580       }
8581       if (!isTrsfSet)
8582       {
8583         Message::SendFail() << "Syntax error at " << anArg;
8584         return 1;
8585       }
8586       else if (aTrsfArgIter >= theArgNb)
8587       {
8588         anArgIter = theArgNb;
8589       }
8590
8591       aTrsfs[0].SetRotation        (aRotQuats[0]);
8592       aTrsfs[1].SetRotation        (aRotQuats[1]);
8593       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
8594       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
8595       aTrsfs[0].SetScaleFactor     (aScales[0]);
8596       aTrsfs[1].SetScaleFactor     (aScales[1]);
8597
8598       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
8599       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
8600     }
8601     else if (anArg == "-viewtrsf"
8602           || anArg == "-view")
8603     {
8604       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
8605       if (aCamAnimation.IsNull())
8606       {
8607         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
8608         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
8609       }
8610
8611       Handle(Graphic3d_Camera) aCams[2] =
8612       {
8613         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
8614         new Graphic3d_Camera (aCamAnimation->View()->Camera())
8615       };
8616
8617       Standard_Boolean isTrsfSet = Standard_False;
8618       Standard_Integer aViewArgIter = anArgIter + 1;
8619       for (; aViewArgIter < theArgNb; ++aViewArgIter)
8620       {
8621         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
8622         aViewArg.LowerCase();
8623         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
8624         if (aViewArg.StartsWith ("-scale"))
8625         {
8626           isTrsfSet = Standard_True;
8627           if (++aViewArgIter >= theArgNb)
8628           {
8629             Message::SendFail() << "Syntax error at " << anArg;
8630             return 1;
8631           }
8632
8633           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
8634           if (!aScaleStr.IsRealValue())
8635           {
8636             Message::SendFail() << "Syntax error at " << aViewArg;
8637             return 1;
8638           }
8639           Standard_Real aScale = aScaleStr.RealValue();
8640           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
8641           aCams[anIndex]->SetScale (aScale);
8642         }
8643         else if (aViewArg.StartsWith ("-eye")
8644               || aViewArg.StartsWith ("-center")
8645               || aViewArg.StartsWith ("-at")
8646               || aViewArg.StartsWith ("-up"))
8647         {
8648           isTrsfSet = Standard_True;
8649           gp_XYZ anXYZ;
8650           if (aViewArgIter + 3 >= theArgNb
8651           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
8652           {
8653             Message::SendFail() << "Syntax error at " << aViewArg;
8654             return 1;
8655           }
8656           aViewArgIter += 3;
8657
8658           if (aViewArg.StartsWith ("-eye"))
8659           {
8660             aCams[anIndex]->SetEye (anXYZ);
8661           }
8662           else if (aViewArg.StartsWith ("-center")
8663                 || aViewArg.StartsWith ("-at"))
8664           {
8665             aCams[anIndex]->SetCenter (anXYZ);
8666           }
8667           else if (aViewArg.StartsWith ("-up"))
8668           {
8669             aCams[anIndex]->SetUp (anXYZ);
8670           }
8671         }
8672         else
8673         {
8674           anArgIter = aViewArgIter - 1;
8675           break;
8676         }
8677       }
8678       if (!isTrsfSet)
8679       {
8680         Message::SendFail() << "Syntax error at " << anArg;
8681         return 1;
8682       }
8683       else if (aViewArgIter >= theArgNb)
8684       {
8685         anArgIter = theArgNb;
8686       }
8687
8688       aCamAnimation->SetCameraStart(aCams[0]);
8689       aCamAnimation->SetCameraEnd  (aCams[1]);
8690     }
8691     else
8692     {
8693       Message::SendFail() << "Syntax error at " << anArg;
8694       return 1;
8695     }
8696   }
8697
8698   if (!toPlay && aRecFile.IsEmpty())
8699   {
8700     return 0;
8701   }
8702
8703   // Start animation timeline and process frame updating.
8704   TheIsAnimating = Standard_True;
8705   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
8706   Handle(Graphic3d_Camera) aCameraBack = new Graphic3d_Camera (aView->Camera());
8707   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
8708   if (isFreeCamera)
8709   {
8710     aView->Camera()->Copy (aCameraBack);
8711   }
8712
8713   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
8714   if (aRecParams.FpsNum <= 0)
8715   {
8716     while (!anAnimation->IsStopped())
8717     {
8718       aCameraBack->Copy (aView->Camera());
8719       const Standard_Real aPts = anAnimation->UpdateTimer();
8720       if (isFreeCamera)
8721       {
8722         aView->Camera()->Copy (aCameraBack);
8723       }
8724
8725       if (aPts >= anUpperPts)
8726       {
8727         anAnimation->Pause();
8728         break;
8729       }
8730
8731       if (aView->IsInvalidated())
8732       {
8733         aView->Redraw();
8734       }
8735       else
8736       {
8737         aView->RedrawImmediate();
8738       }
8739
8740       if (!isLockLoop)
8741       {
8742         // handle user events
8743         theDI.Eval ("after 1 set waiter 1");
8744         theDI.Eval ("vwait waiter");
8745       }
8746       if (!TheIsAnimating)
8747       {
8748         anAnimation->Pause();
8749         theDI << aPts;
8750         break;
8751       }
8752     }
8753
8754     if (aView->IsInvalidated())
8755     {
8756       aView->Redraw();
8757     }
8758     else
8759     {
8760       aView->RedrawImmediate();
8761     }
8762   }
8763   else
8764   {
8765     OSD_Timer aPerfTimer;
8766     aPerfTimer.Start();
8767
8768     Handle(Image_VideoRecorder) aRecorder;
8769     ImageFlipper aFlipper;
8770     Handle(Draw_ProgressIndicator) aProgress;
8771     if (!aRecFile.IsEmpty())
8772     {
8773       if (aRecParams.Width  <= 0
8774        || aRecParams.Height <= 0)
8775       {
8776         aView->Window()->Size (aRecParams.Width, aRecParams.Height);
8777       }
8778
8779       aRecorder = new Image_VideoRecorder();
8780       if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
8781       {
8782         Message::SendFail ("Error: failed to open video file for recording");
8783         return 0;
8784       }
8785
8786       aProgress = new Draw_ProgressIndicator (theDI, 1);
8787     }
8788
8789     // Manage frame-rated animation here
8790     Standard_Real aPts = aPlayStartTime;
8791     int64_t aNbFrames = 0;
8792     Message_ProgressSentry aPSentry (aProgress, "Video recording, sec", 0, Max (1, Standard_Integer(aPlayDuration / aPlaySpeed)), 1);
8793     Standard_Integer aSecondsProgress = 0;
8794     for (; aPts <= anUpperPts && aPSentry.More();)
8795     {
8796       const Standard_Real aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
8797       aPts = aPlayStartTime + aRecPts;
8798       ++aNbFrames;
8799       if (!anAnimation->Update (aPts))
8800       {
8801         break;
8802       }
8803
8804       if (!aRecorder.IsNull())
8805       {
8806         V3d_ImageDumpOptions aDumpParams;
8807         aDumpParams.Width          = aRecParams.Width;
8808         aDumpParams.Height         = aRecParams.Height;
8809         aDumpParams.BufferType     = Graphic3d_BT_RGBA;
8810         aDumpParams.StereoOptions  = V3d_SDO_MONO;
8811         aDumpParams.ToAdjustAspect = Standard_True;
8812         if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
8813         {
8814           Message::SendFail ("Error: view dump is failed");
8815           return 0;
8816         }
8817         aFlipper.FlipY (aRecorder->ChangeFrame());
8818         if (!aRecorder->PushFrame())
8819         {
8820           return 0;
8821         }
8822       }
8823       else
8824       {
8825         aView->Redraw();
8826       }
8827
8828       while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
8829       {
8830         aPSentry.Next();
8831         ++aSecondsProgress;
8832       }
8833     }
8834
8835     aPerfTimer.Stop();
8836     anAnimation->Stop();
8837     const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
8838     theDI << "Average FPS: " << aRecFps << "\n"
8839           << "Nb. Frames: "  << Standard_Real(aNbFrames);
8840
8841     aView->Redraw();
8842   }
8843
8844   aView->SetImmediateUpdate (wasImmediateUpdate);
8845   TheIsAnimating = Standard_False;
8846   return 0;
8847 }
8848
8849
8850 //=======================================================================
8851 //function : VChangeSelected
8852 //purpose  : Adds the shape to selection or remove one from it
8853 //=======================================================================
8854 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
8855                                 Standard_Integer argc,
8856                                 const char ** argv)
8857 {
8858   if(argc != 2)
8859   {
8860     di<<"Usage : " << argv[0] << " shape \n";
8861     return 1;
8862   }
8863   //get AIS_Shape:
8864   TCollection_AsciiString aName(argv[1]);
8865   Handle(AIS_InteractiveObject) anAISObject;
8866   if (!GetMapOfAIS().Find2 (aName, anAISObject)
8867     || anAISObject.IsNull())
8868   {
8869     di<<"Use 'vdisplay' before";
8870     return 1;
8871   }
8872
8873   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
8874   return 0;
8875 }
8876
8877 //=======================================================================
8878 //function : VNbSelected
8879 //purpose  : Returns number of selected objects
8880 //=======================================================================
8881 static Standard_Integer VNbSelected (Draw_Interpretor& di,
8882                                 Standard_Integer argc,
8883                                 const char ** argv)
8884 {
8885   if(argc != 1)
8886   {
8887     di << "Usage : " << argv[0] << "\n";
8888     return 1;
8889   }
8890   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8891   if(aContext.IsNull())
8892   {
8893     di << "use 'vinit' command before " << argv[0] << "\n";
8894     return 1;
8895   }
8896   di << aContext->NbSelected() << "\n";
8897   return 0;
8898 }
8899
8900 //=======================================================================
8901 //function : VPurgeDisplay
8902 //purpose  : Switches altialiasing on or off
8903 //=======================================================================
8904 static Standard_Integer VPurgeDisplay (Draw_Interpretor& di,
8905                                 Standard_Integer argc,
8906                                 const char ** argv)
8907 {
8908   if (argc > 1)
8909   {
8910     di << "Usage : " << argv[0] << "\n";
8911     return 1;
8912   }
8913   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8914   if (aContext.IsNull())
8915   {
8916     di << "use 'vinit' command before " << argv[0] << "\n";
8917     return 1;
8918   }
8919
8920   di << aContext->PurgeDisplay() << "\n";
8921   return 0;
8922 }
8923
8924 //=======================================================================
8925 //function : VSetViewSize
8926 //purpose  :
8927 //=======================================================================
8928 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
8929                                 Standard_Integer argc,
8930                                 const char ** argv)
8931 {
8932   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8933   if(aContext.IsNull())
8934   {
8935     di << "use 'vinit' command before " << argv[0] << "\n";
8936     return 1;
8937   }
8938   if(argc != 2)
8939   {
8940     di<<"Usage : " << argv[0] << " Size\n";
8941     return 1;
8942   }
8943   Standard_Real aSize = Draw::Atof (argv[1]);
8944   if (aSize <= 0.)
8945   {
8946     di<<"Bad Size value  : " << aSize << "\n";
8947     return 1;
8948   }
8949
8950   Handle(V3d_View) aView = ViewerTest::CurrentView();
8951   aView->SetSize(aSize);
8952   return 0;
8953 }
8954
8955 //=======================================================================
8956 //function : VMoveView
8957 //purpose  :
8958 //=======================================================================
8959 static Standard_Integer VMoveView (Draw_Interpretor& di,
8960                                 Standard_Integer argc,
8961                                 const char ** argv)
8962 {
8963   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8964   if(aContext.IsNull())
8965   {
8966     di << "use 'vinit' command before " << argv[0] << "\n";
8967     return 1;
8968   }
8969   if(argc < 4 || argc > 5)
8970   {
8971     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8972     return 1;
8973   }
8974   Standard_Real Dx = Draw::Atof (argv[1]);
8975   Standard_Real Dy = Draw::Atof (argv[2]);
8976   Standard_Real Dz = Draw::Atof (argv[3]);
8977   Standard_Boolean aStart = Standard_True;
8978   if (argc == 5)
8979   {
8980       aStart = (Draw::Atoi (argv[4]) > 0);
8981   }
8982
8983   Handle(V3d_View) aView = ViewerTest::CurrentView();
8984   aView->Move(Dx,Dy,Dz,aStart);
8985   return 0;
8986 }
8987
8988 //=======================================================================
8989 //function : VTranslateView
8990 //purpose  :
8991 //=======================================================================
8992 static Standard_Integer VTranslateView (Draw_Interpretor& di,
8993                                 Standard_Integer argc,
8994                                 const char ** argv)
8995 {
8996   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8997   if(aContext.IsNull())
8998   {
8999     di << "use 'vinit' command before " << argv[0] << "\n";
9000     return 1;
9001   }
9002   if(argc < 4 || argc > 5)
9003   {
9004     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
9005     return 1;
9006   }
9007   Standard_Real Dx = Draw::Atof (argv[1]);
9008   Standard_Real Dy = Draw::Atof (argv[2]);
9009   Standard_Real Dz = Draw::Atof (argv[3]);
9010   Standard_Boolean aStart = Standard_True;
9011   if (argc == 5)
9012   {
9013       aStart = (Draw::Atoi (argv[4]) > 0);
9014   }
9015
9016   Handle(V3d_View) aView = ViewerTest::CurrentView();
9017   aView->Translate(Dx,Dy,Dz,aStart);
9018   return 0;
9019 }
9020
9021 //=======================================================================
9022 //function : VTurnView
9023 //purpose  :
9024 //=======================================================================
9025 static Standard_Integer VTurnView (Draw_Interpretor& di,
9026                                 Standard_Integer argc,
9027                                 const char ** argv)
9028 {
9029   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
9030   if(aContext.IsNull()) {
9031     di << "use 'vinit' command before " << argv[0] << "\n";
9032     return 1;
9033   }
9034   if(argc < 4 || argc > 5){
9035     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
9036     return 1;
9037   }
9038   Standard_Real Ax = Draw::Atof (argv[1]);
9039   Standard_Real Ay = Draw::Atof (argv[2]);
9040   Standard_Real Az = Draw::Atof (argv[3]);
9041   Standard_Boolean aStart = Standard_True;
9042   if (argc == 5)
9043   {
9044       aStart = (Draw::Atoi (argv[4]) > 0);
9045   }
9046
9047   Handle(V3d_View) aView = ViewerTest::CurrentView();
9048   aView->Turn(Ax,Ay,Az,aStart);
9049   return 0;
9050 }
9051
9052 //==============================================================================
9053 //function : VTextureEnv
9054 //purpose  : ENables or disables environment mapping
9055 //==============================================================================
9056 class OCC_TextureEnv : public Graphic3d_TextureEnv
9057 {
9058 public:
9059   OCC_TextureEnv(const Standard_CString FileName);
9060   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
9061   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
9062                             const Standard_Boolean theModulateFlag,
9063                             const Graphic3d_TypeOfTextureFilter theFilter,
9064                             const Standard_ShortReal theXScale,
9065                             const Standard_ShortReal theYScale,
9066                             const Standard_ShortReal theXShift,
9067                             const Standard_ShortReal theYShift,
9068                             const Standard_ShortReal theAngle);
9069   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
9070 };
9071 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
9072
9073 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
9074   : Graphic3d_TextureEnv(theFileName)
9075 {
9076 }
9077
9078 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
9079   : Graphic3d_TextureEnv(theTexId)
9080 {
9081 }
9082
9083 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
9084                                           const Standard_Boolean theModulateFlag,
9085                                           const Graphic3d_TypeOfTextureFilter theFilter,
9086                                           const Standard_ShortReal theXScale,
9087                                           const Standard_ShortReal theYScale,
9088                                           const Standard_ShortReal theXShift,
9089                                           const Standard_ShortReal theYShift,
9090                                           const Standard_ShortReal theAngle)
9091 {
9092   myParams->SetRepeat     (theRepeatFlag);
9093   myParams->SetModulate   (theModulateFlag);
9094   myParams->SetFilter     (theFilter);
9095   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
9096   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
9097   myParams->SetRotation   (theAngle);
9098 }
9099
9100 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
9101 {
9102   // get the active view
9103   Handle(V3d_View) aView = ViewerTest::CurrentView();
9104   if (aView.IsNull())
9105   {
9106     Message::SendFail ("Error: no active viewer");
9107     return 1;
9108   }
9109
9110   // Checking the input arguments
9111   Standard_Boolean anEnableFlag = Standard_False;
9112   Standard_Boolean isOk         = theArgNb >= 2;
9113   if (isOk)
9114   {
9115     TCollection_AsciiString anEnableOpt(theArgVec[1]);
9116     anEnableFlag = anEnableOpt.IsEqual("on");
9117     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
9118   }
9119   if (anEnableFlag)
9120   {
9121     isOk = (theArgNb == 3 || theArgNb == 11);
9122     if (isOk)
9123     {
9124       TCollection_AsciiString aTextureOpt(theArgVec[2]);
9125       isOk = (!aTextureOpt.IsIntegerValue() ||
9126              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
9127
9128       if (isOk && theArgNb == 11)
9129       {
9130         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
9131                                 aModulateOpt(theArgVec[4]),
9132                                 aFilterOpt  (theArgVec[5]),
9133                                 aSScaleOpt  (theArgVec[6]),
9134                                 aTScaleOpt  (theArgVec[7]),
9135                                 aSTransOpt  (theArgVec[8]),
9136                                 aTTransOpt  (theArgVec[9]),
9137                                 anAngleOpt  (theArgVec[10]);
9138         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
9139                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
9140                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
9141                 aSScaleOpt.IsRealValue() && aTScaleOpt.IsRealValue() &&
9142                 aSTransOpt.IsRealValue() && aTTransOpt.IsRealValue() &&
9143                 anAngleOpt.IsRealValue());
9144       }
9145     }
9146   }
9147
9148   if (!isOk)
9149   {
9150     Message::SendFail() << "Usage:\n"
9151                         << theArgVec[0] << " off\n"
9152                         << 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]";
9153     return 1;
9154   }
9155
9156   if (anEnableFlag)
9157   {
9158     TCollection_AsciiString aTextureOpt(theArgVec[2]);
9159     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
9160                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
9161                                      new OCC_TextureEnv(theArgVec[2]);
9162
9163     if (theArgNb == 11)
9164     {
9165       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
9166       aTexEnv->SetTextureParameters(
9167         aRepeatOpt.  IsEqual("repeat"),
9168         aModulateOpt.IsEqual("modulate"),
9169         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
9170                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
9171                                                                            Graphic3d_TOTF_TRILINEAR,
9172         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
9173         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
9174         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
9175         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
9176         (Standard_ShortReal)Draw::Atof(theArgVec[10])
9177         );
9178     }
9179     aView->SetTextureEnv(aTexEnv);
9180   }
9181   else // Disabling environment mapping
9182   {
9183     Handle(Graphic3d_TextureEnv) aTexture;
9184     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
9185   }
9186
9187   aView->Redraw();
9188   return 0;
9189 }
9190
9191 namespace
9192 {
9193   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
9194
9195   //! Remove registered clipping plane from all views and objects.
9196   static void removePlane (MapOfPlanes& theRegPlanes,
9197                            const TCollection_AsciiString& theName)
9198   {
9199     Handle(Graphic3d_ClipPlane) aClipPlane;
9200     if (!theRegPlanes.Find (theName, aClipPlane))
9201     {
9202       Message::SendWarning ("Warning: no such plane");
9203       return;
9204     }
9205
9206     theRegPlanes.UnBind (theName);
9207     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
9208          anIObjIt.More(); anIObjIt.Next())
9209     {
9210       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
9211       aPrs->RemoveClipPlane (aClipPlane);
9212     }
9213
9214     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
9215          aViewIt.More(); aViewIt.Next())
9216     {
9217       const Handle(V3d_View)& aView = aViewIt.Key2();
9218       aView->RemoveClipPlane(aClipPlane);
9219     }
9220
9221     ViewerTest::RedrawAllViews();
9222   }
9223 }
9224
9225 //===============================================================================================
9226 //function : VClipPlane
9227 //purpose  :
9228 //===============================================================================================
9229 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9230 {
9231   // use short-cut for created clip planes map of created (or "registered by name") clip planes
9232   static MapOfPlanes aRegPlanes;
9233
9234   if (theArgsNb < 2)
9235   {
9236     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
9237     {
9238       theDi << aPlaneIter.Key() << " ";
9239     }
9240     return 0;
9241   }
9242
9243   TCollection_AsciiString aCommand (theArgVec[1]);
9244   aCommand.LowerCase();
9245   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
9246   if (anActiveView.IsNull())
9247   {
9248     Message::SendFail ("Error: no active viewer");
9249     return 1;
9250   }
9251
9252   // print maximum number of planes for current viewer
9253   if (aCommand == "-maxplanes"
9254    || aCommand == "maxplanes")
9255   {
9256     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
9257           << " plane slots provided by driver.\n";
9258     return 0;
9259   }
9260
9261   // create / delete plane instance
9262   if (aCommand == "-create"
9263    || aCommand == "create"
9264    || aCommand == "-delete"
9265    || aCommand == "delete"
9266    || aCommand == "-clone"
9267    || aCommand == "clone")
9268   {
9269     if (theArgsNb < 3)
9270     {
9271       Message::SendFail ("Syntax error: plane name is required");
9272       return 1;
9273     }
9274
9275     Standard_Boolean toCreate = aCommand == "-create"
9276                              || aCommand == "create";
9277     Standard_Boolean toClone  = aCommand == "-clone"
9278                              || aCommand == "clone";
9279     Standard_Boolean toDelete = aCommand == "-delete"
9280                              || aCommand == "delete";
9281     TCollection_AsciiString aPlane (theArgVec[2]);
9282
9283     if (toCreate)
9284     {
9285       if (aRegPlanes.IsBound (aPlane))
9286       {
9287         std::cout << "Warning: existing plane has been overridden.\n";
9288         toDelete = true;
9289       }
9290       else
9291       {
9292         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9293         return 0;
9294       }
9295     }
9296     else if (toClone) // toClone
9297     {
9298       if (!aRegPlanes.IsBound (aPlane))
9299       {
9300         Message::SendFail ("Error: no such plane");
9301         return 1;
9302       }
9303       else if (theArgsNb < 4)
9304       {
9305         Message::SendFail ("Syntax error: enter name for new plane");
9306         return 1;
9307       }
9308
9309       TCollection_AsciiString aClone (theArgVec[3]);
9310       if (aRegPlanes.IsBound (aClone))
9311       {
9312         Message::SendFail ("Error: plane name is in use");
9313         return 1;
9314       }
9315
9316       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
9317
9318       aRegPlanes.Bind (aClone, aClipPlane->Clone());
9319       return 0;
9320     }
9321
9322     if (toDelete)
9323     {
9324       if (aPlane == "ALL"
9325        || aPlane == "all"
9326        || aPlane == "*")
9327       {
9328         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
9329         {
9330           aPlane = aPlaneIter.Key();
9331           removePlane (aRegPlanes, aPlane);
9332           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
9333         }
9334       }
9335       else
9336       {
9337         removePlane (aRegPlanes, aPlane);
9338       }
9339     }
9340
9341     if (toCreate)
9342     {
9343       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9344     }
9345     return 0;
9346   }
9347
9348   // set / unset plane command
9349   if (aCommand == "set"
9350    || aCommand == "unset")
9351   {
9352     if (theArgsNb < 5)
9353     {
9354       Message::SendFail ("Syntax error: need more arguments");
9355       return 1;
9356     }
9357
9358     // redirect to new syntax
9359     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
9360     anArgVec.SetValue (1, theArgVec[0]);
9361     anArgVec.SetValue (2, theArgVec[2]);
9362     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
9363     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
9364     {
9365       anArgVec.SetValue (anIt, theArgVec[anIt]);
9366     }
9367
9368     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
9369   }
9370
9371   // change plane command
9372   TCollection_AsciiString aPlaneName;
9373   Handle(Graphic3d_ClipPlane) aClipPlane;
9374   Standard_Integer anArgIter = 0;
9375   if (aCommand == "-change"
9376    || aCommand == "change")
9377   {
9378     // old syntax support
9379     if (theArgsNb < 3)
9380     {
9381       Message::SendFail ("Syntax error: need more arguments");
9382       return 1;
9383     }
9384
9385     anArgIter  = 3;
9386     aPlaneName = theArgVec[2];
9387     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
9388     {
9389       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
9390       return 1;
9391     }
9392   }
9393   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
9394   {
9395     anArgIter  = 2;
9396     aPlaneName = theArgVec[1];
9397   }
9398   else
9399   {
9400     anArgIter  = 2;
9401     aPlaneName = theArgVec[1];
9402     aClipPlane = new Graphic3d_ClipPlane();
9403     aRegPlanes.Bind (aPlaneName, aClipPlane);
9404     theDi << "Created new plane " << aPlaneName << ".\n";
9405   }
9406
9407   if (theArgsNb - anArgIter < 1)
9408   {
9409     Message::SendFail ("Syntax error: need more arguments");
9410     return 1;
9411   }
9412
9413   for (; anArgIter < theArgsNb; ++anArgIter)
9414   {
9415     const char**     aChangeArgs   = theArgVec + anArgIter;
9416     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
9417     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
9418     aChangeArg.LowerCase();
9419
9420     Standard_Boolean toEnable = Standard_True;
9421     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
9422     {
9423       aClipPlane->SetOn (toEnable);
9424     }
9425     else if (aChangeArg.StartsWith ("-equation")
9426           || aChangeArg.StartsWith ("equation"))
9427     {
9428       if (aNbChangeArgs < 5)
9429       {
9430         Message::SendFail ("Syntax error: need more arguments");
9431         return 1;
9432       }
9433
9434       Standard_Integer aSubIndex = 1;
9435       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
9436       if (aPrefixLen < aChangeArg.Length())
9437       {
9438         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
9439         if (!aSubStr.IsIntegerValue()
9440           || aSubStr.IntegerValue() <= 0)
9441         {
9442           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9443           return 1;
9444         }
9445         aSubIndex = aSubStr.IntegerValue();
9446       }
9447
9448       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
9449       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
9450       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
9451       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
9452       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9453       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
9454       {
9455         if (aSubPln->ChainNextPlane().IsNull())
9456         {
9457           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9458         }
9459         aSubPln = aSubPln->ChainNextPlane();
9460       }
9461       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9462       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
9463       anArgIter += 4;
9464     }
9465     else if ((aChangeArg == "-boxinterior"
9466            || aChangeArg == "-boxint"
9467            || aChangeArg == "-box")
9468             && aNbChangeArgs >= 7)
9469     {
9470       Graphic3d_BndBox3d aBndBox;
9471       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
9472       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
9473       anArgIter += 6;
9474
9475       Standard_Integer aNbSubPlanes = 6;
9476       const Graphic3d_Vec3d aDirArray[6] =
9477       {
9478         Graphic3d_Vec3d (-1, 0, 0),
9479         Graphic3d_Vec3d ( 1, 0, 0),
9480         Graphic3d_Vec3d ( 0,-1, 0),
9481         Graphic3d_Vec3d ( 0, 1, 0),
9482         Graphic3d_Vec3d ( 0, 0,-1),
9483         Graphic3d_Vec3d ( 0, 0, 1),
9484       };
9485       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9486       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
9487       {
9488         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
9489         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
9490         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
9491         if (aSubPlaneIter + 1 == aNbSubPlanes)
9492         {
9493           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9494         }
9495         else
9496         {
9497           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9498         }
9499         aSubPln = aSubPln->ChainNextPlane();
9500       }
9501     }
9502     else if (aChangeArg == "-capping"
9503           || aChangeArg == "capping")
9504     {
9505       if (aNbChangeArgs < 2)
9506       {
9507         Message::SendFail ("Syntax error: need more arguments");
9508         return 1;
9509       }
9510
9511       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9512       {
9513         aClipPlane->SetCapping (toEnable);
9514         anArgIter += 1;
9515       }
9516       else
9517       {
9518         // just skip otherwise (old syntax)
9519       }
9520     }
9521     else if (aChangeArg == "-useobjectmaterial"
9522           || aChangeArg == "-useobjectmat"
9523           || aChangeArg == "-useobjmat"
9524           || aChangeArg == "-useobjmaterial")
9525     {
9526       if (aNbChangeArgs < 2)
9527       {
9528         Message::SendFail ("Syntax error: need more arguments");
9529         return 1;
9530       }
9531
9532       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9533       {
9534         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
9535         anArgIter += 1;
9536       }
9537     }
9538     else if (aChangeArg == "-useobjecttexture"
9539           || aChangeArg == "-useobjecttex"
9540           || aChangeArg == "-useobjtexture"
9541           || aChangeArg == "-useobjtex")
9542     {
9543       if (aNbChangeArgs < 2)
9544       {
9545         Message::SendFail ("Syntax error: need more arguments");
9546         return 1;
9547       }
9548
9549       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9550       {
9551         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
9552         anArgIter += 1;
9553       }
9554     }
9555     else if (aChangeArg == "-useobjectshader"
9556           || aChangeArg == "-useobjshader")
9557     {
9558       if (aNbChangeArgs < 2)
9559       {
9560         Message::SendFail ("Syntax error: need more arguments");
9561         return 1;
9562       }
9563
9564       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9565       {
9566         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
9567         anArgIter += 1;
9568       }
9569     }
9570     else if (aChangeArg == "-color"
9571           || aChangeArg == "color")
9572     {
9573       Quantity_Color aColor;
9574       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
9575                                                      aChangeArgs + 1,
9576                                                      aColor);
9577       if (aNbParsed == 0)
9578       {
9579         Message::SendFail ("Syntax error: need more arguments");
9580         return 1;
9581       }
9582       aClipPlane->SetCappingColor (aColor);
9583       anArgIter += aNbParsed;
9584     }
9585     else if (aNbChangeArgs >= 1
9586           && (aChangeArg == "-material"
9587            || aChangeArg == "material"))
9588     {
9589       ++anArgIter;
9590       Graphic3d_NameOfMaterial aMatName;
9591       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
9592       {
9593         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
9594         return 1;
9595       }
9596       aClipPlane->SetCappingMaterial (aMatName);
9597     }
9598     else if ((aChangeArg == "-transparency"
9599            || aChangeArg == "-transp")
9600           && aNbChangeArgs >= 2)
9601     {
9602       TCollection_AsciiString aValStr (aChangeArgs[1]);
9603       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
9604       if (aValStr.IsRealValue())
9605       {
9606         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
9607         aMat.SetTransparency ((float )aValStr.RealValue());
9608         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
9609         aClipPlane->SetCappingMaterial (aMat);
9610       }
9611       else
9612       {
9613         aValStr.LowerCase();
9614         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
9615         if (aValStr == "opaque")
9616         {
9617           aMode = Graphic3d_AlphaMode_Opaque;
9618         }
9619         else if (aValStr == "mask")
9620         {
9621           aMode = Graphic3d_AlphaMode_Mask;
9622         }
9623         else if (aValStr == "blend")
9624         {
9625           aMode = Graphic3d_AlphaMode_Blend;
9626         }
9627         else if (aValStr == "blendauto")
9628         {
9629           aMode = Graphic3d_AlphaMode_BlendAuto;
9630         }
9631         else
9632         {
9633           Message::SendFail() << "Syntax error at '" << aValStr << "'";
9634           return 1;
9635         }
9636         anAspect->SetAlphaMode (aMode);
9637         aClipPlane->SetCappingAspect (anAspect);
9638       }
9639       anArgIter += 1;
9640     }
9641     else if (aChangeArg == "-texname"
9642           || aChangeArg == "texname")
9643     {
9644       if (aNbChangeArgs < 2)
9645       {
9646         Message::SendFail ("Syntax error: need more arguments");
9647         return 1;
9648       }
9649
9650       TCollection_AsciiString aTextureName (aChangeArgs[1]);
9651       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
9652       if (!aTexture->IsDone())
9653       {
9654         aClipPlane->SetCappingTexture (NULL);
9655       }
9656       else
9657       {
9658         aTexture->EnableModulate();
9659         aTexture->EnableRepeat();
9660         aClipPlane->SetCappingTexture (aTexture);
9661       }
9662       anArgIter += 1;
9663     }
9664     else if (aChangeArg == "-texscale"
9665           || aChangeArg == "texscale")
9666     {
9667       if (aClipPlane->CappingTexture().IsNull())
9668       {
9669         Message::SendFail ("Error: no texture is set");
9670         return 1;
9671       }
9672
9673       if (aNbChangeArgs < 3)
9674       {
9675         Message::SendFail ("Syntax error: need more arguments");
9676         return 1;
9677       }
9678
9679       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9680       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9681       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
9682       anArgIter += 2;
9683     }
9684     else if (aChangeArg == "-texorigin"
9685           || aChangeArg == "texorigin") // texture origin
9686     {
9687       if (aClipPlane->CappingTexture().IsNull())
9688       {
9689         Message::SendFail ("Error: no texture is set");
9690         return 1;
9691       }
9692
9693       if (aNbChangeArgs < 3)
9694       {
9695         Message::SendFail ("Syntax error: need more arguments");
9696         return 1;
9697       }
9698
9699       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9700       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9701
9702       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
9703       anArgIter += 2;
9704     }
9705     else if (aChangeArg == "-texrotate"
9706           || aChangeArg == "texrotate") // texture rotation
9707     {
9708       if (aClipPlane->CappingTexture().IsNull())
9709       {
9710         Message::SendFail ("Error: no texture is set");
9711         return 1;
9712       }
9713
9714       if (aNbChangeArgs < 2)
9715       {
9716         Message::SendFail ("Syntax error: need more arguments");
9717         return 1;
9718       }
9719
9720       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9721       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
9722       anArgIter += 1;
9723     }
9724     else if (aChangeArg == "-hatch"
9725           || aChangeArg == "hatch")
9726     {
9727       if (aNbChangeArgs < 2)
9728       {
9729         Message::SendFail ("Syntax error: need more arguments");
9730         return 1;
9731       }
9732
9733       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
9734       aHatchStr.LowerCase();
9735       if (aHatchStr == "on")
9736       {
9737         aClipPlane->SetCappingHatchOn();
9738       }
9739       else if (aHatchStr == "off")
9740       {
9741         aClipPlane->SetCappingHatchOff();
9742       }
9743       else
9744       {
9745         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
9746       }
9747       anArgIter += 1;
9748     }
9749     else if (aChangeArg == "-delete"
9750           || aChangeArg == "delete")
9751     {
9752       removePlane (aRegPlanes, aPlaneName);
9753       return 0;
9754     }
9755     else if (aChangeArg == "-set"
9756           || aChangeArg == "-unset"
9757           || aChangeArg == "-setoverrideglobal")
9758     {
9759       // set / unset plane command
9760       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
9761       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
9762       Standard_Integer anIt = 1;
9763       for (; anIt < aNbChangeArgs; ++anIt)
9764       {
9765         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
9766         if (anEntityName.IsEmpty()
9767          || anEntityName.Value (1) == '-')
9768         {
9769           break;
9770         }
9771         else if (!toOverrideGlobal
9772                && ViewerTest_myViews.IsBound1 (anEntityName))
9773         {
9774           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
9775           if (toSet)
9776           {
9777             aView->AddClipPlane (aClipPlane);
9778           }
9779           else
9780           {
9781             aView->RemoveClipPlane (aClipPlane);
9782           }
9783           continue;
9784         }
9785         else if (GetMapOfAIS().IsBound2 (anEntityName))
9786         {
9787           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
9788           if (toSet)
9789           {
9790             aIObj->AddClipPlane (aClipPlane);
9791           }
9792           else
9793           {
9794             aIObj->RemoveClipPlane (aClipPlane);
9795           }
9796           if (!aIObj->ClipPlanes().IsNull())
9797           {
9798             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
9799           }
9800         }
9801         else
9802         {
9803           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
9804           return 1;
9805         }
9806       }
9807
9808       if (anIt == 1)
9809       {
9810         // apply to active view
9811         if (toSet)
9812         {
9813           anActiveView->AddClipPlane (aClipPlane);
9814         }
9815         else
9816         {
9817           anActiveView->RemoveClipPlane (aClipPlane);
9818         }
9819       }
9820       else
9821       {
9822         anArgIter = anArgIter + anIt - 1;
9823       }
9824     }
9825     else
9826     {
9827       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9828       return 1;
9829     }
9830   }
9831
9832   ViewerTest::RedrawAllViews();
9833   return 0;
9834 }
9835
9836 //===============================================================================================
9837 //function : VZRange
9838 //purpose  :
9839 //===============================================================================================
9840 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9841 {
9842   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9843
9844   if (aCurrentView.IsNull())
9845   {
9846     Message::SendFail ("Error: no active viewer");
9847     return 1;
9848   }
9849
9850   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
9851
9852   if (theArgsNb < 2)
9853   {
9854     theDi << "ZNear: " << aCamera->ZNear() << "\n";
9855     theDi << "ZFar: " << aCamera->ZFar() << "\n";
9856     return 0;
9857   }
9858
9859   if (theArgsNb == 3)
9860   {
9861     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
9862     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
9863
9864     if (aNewZNear >= aNewZFar)
9865     {
9866       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
9867       return 1;
9868     }
9869
9870     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
9871     {
9872       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
9873       return 1;
9874     }
9875
9876     aCamera->SetZRange (aNewZNear, aNewZFar);
9877   }
9878   else
9879   {
9880     Message::SendFail ("Syntax error: wrong command arguments");
9881     return 1;
9882   }
9883
9884   aCurrentView->Redraw();
9885
9886   return 0;
9887 }
9888
9889 //===============================================================================================
9890 //function : VAutoZFit
9891 //purpose  :
9892 //===============================================================================================
9893 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9894 {
9895   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9896
9897   if (aCurrentView.IsNull())
9898   {
9899     Message::SendFail ("Error: no active viewer");
9900     return 1;
9901   }
9902
9903   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
9904
9905   if (theArgsNb > 3)
9906   {
9907     Message::SendFail ("Syntax error: wrong command arguments");
9908     return 1;
9909   }
9910
9911   if (theArgsNb < 2)
9912   {
9913     theDi << "Auto z-fit mode: \n"
9914           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
9915           << "Scale: " << aScale << "\n";
9916     return 0;
9917   }
9918
9919   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
9920
9921   if (theArgsNb >= 3)
9922   {
9923     aScale = Draw::Atoi (theArgVec[2]);
9924   }
9925
9926   aCurrentView->SetAutoZFitMode (isOn, aScale);
9927   aCurrentView->Redraw();
9928   return 0;
9929 }
9930
9931 //! Auxiliary function to print projection type
9932 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
9933 {
9934   switch (theProjType)
9935   {
9936     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
9937     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
9938     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
9939     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
9940     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
9941   }
9942   return "UNKNOWN";
9943 }
9944
9945 //===============================================================================================
9946 //function : VCamera
9947 //purpose  :
9948 //===============================================================================================
9949 static int VCamera (Draw_Interpretor& theDI,
9950                     Standard_Integer  theArgsNb,
9951                     const char**      theArgVec)
9952 {
9953   Handle(V3d_View) aView = ViewerTest::CurrentView();
9954   if (aView.IsNull())
9955   {
9956     Message::SendFail ("Error: no active viewer");
9957     return 1;
9958   }
9959
9960   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9961   if (theArgsNb < 2)
9962   {
9963     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
9964     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
9965     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
9966     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
9967     theDI << "Distance:   " << aCamera->Distance() << "\n";
9968     theDI << "IOD:        " << aCamera->IOD() << "\n";
9969     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
9970     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
9971     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
9972     return 0;
9973   }
9974
9975   TCollection_AsciiString aPrsName;
9976   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9977   {
9978     Standard_CString        anArg = theArgVec[anArgIter];
9979     TCollection_AsciiString anArgCase (anArg);
9980     anArgCase.LowerCase();
9981     if (anArgCase == "-proj"
9982      || anArgCase == "-projection"
9983      || anArgCase == "-projtype"
9984      || anArgCase == "-projectiontype")
9985     {
9986       theDI << projTypeName (aCamera->ProjectionType()) << " ";
9987     }
9988     else if (anArgCase == "-ortho"
9989           || anArgCase == "-orthographic")
9990     {
9991       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
9992     }
9993     else if (anArgCase == "-persp"
9994           || anArgCase == "-perspective"
9995           || anArgCase == "-perspmono"
9996           || anArgCase == "-perspectivemono"
9997           || anArgCase == "-mono")
9998     {
9999       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10000     }
10001     else if (anArgCase == "-stereo"
10002           || anArgCase == "-stereoscopic"
10003           || anArgCase == "-perspstereo"
10004           || anArgCase == "-perspectivestereo")
10005     {
10006       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10007     }
10008     else if (anArgCase == "-left"
10009           || anArgCase == "-lefteye"
10010           || anArgCase == "-monoleft"
10011           || anArgCase == "-monolefteye"
10012           || anArgCase == "-perpsleft"
10013           || anArgCase == "-perpslefteye")
10014     {
10015       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
10016     }
10017     else if (anArgCase == "-right"
10018           || anArgCase == "-righteye"
10019           || anArgCase == "-monoright"
10020           || anArgCase == "-monorighteye"
10021           || anArgCase == "-perpsright")
10022     {
10023       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
10024     }
10025     else if (anArgCase == "-dist"
10026           || anArgCase == "-distance")
10027     {
10028       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10029       if (anArgValue != NULL
10030       && *anArgValue != '-')
10031       {
10032         ++anArgIter;
10033         aCamera->SetDistance (Draw::Atof (anArgValue));
10034         continue;
10035       }
10036       theDI << aCamera->Distance() << " ";
10037     }
10038     else if (anArgCase == "-iod")
10039     {
10040       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10041       if (anArgValue != NULL
10042       && *anArgValue != '-')
10043       {
10044         ++anArgIter;
10045         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
10046         continue;
10047       }
10048       theDI << aCamera->IOD() << " ";
10049     }
10050     else if (anArgCase == "-iodtype")
10051     {
10052       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10053       TCollection_AsciiString anValueCase (anArgValue);
10054       anValueCase.LowerCase();
10055       if (anValueCase == "abs"
10056        || anValueCase == "absolute")
10057       {
10058         ++anArgIter;
10059         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
10060         continue;
10061       }
10062       else if (anValueCase == "rel"
10063             || anValueCase == "relative")
10064       {
10065         ++anArgIter;
10066         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
10067         continue;
10068       }
10069       else if (*anArgValue != '-')
10070       {
10071         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
10072         return 1;
10073       }
10074       switch (aCamera->GetIODType())
10075       {
10076         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
10077         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
10078       }
10079     }
10080     else if (anArgCase == "-zfocus")
10081     {
10082       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10083       if (anArgValue != NULL
10084       && *anArgValue != '-')
10085       {
10086         ++anArgIter;
10087         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
10088         continue;
10089       }
10090       theDI << aCamera->ZFocus() << " ";
10091     }
10092     else if (anArgCase == "-zfocustype")
10093     {
10094       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10095       TCollection_AsciiString anValueCase (anArgValue);
10096       anValueCase.LowerCase();
10097       if (anValueCase == "abs"
10098        || anValueCase == "absolute")
10099       {
10100         ++anArgIter;
10101         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
10102         continue;
10103       }
10104       else if (anValueCase == "rel"
10105             || anValueCase == "relative")
10106       {
10107         ++anArgIter;
10108         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
10109         continue;
10110       }
10111       else if (*anArgValue != '-')
10112       {
10113         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
10114         return 1;
10115       }
10116       switch (aCamera->ZFocusType())
10117       {
10118         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
10119         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
10120       }
10121     }
10122     else if (anArgCase == "-lockzup"
10123           || anArgCase == "-turntable")
10124     {
10125       bool toLockUp = true;
10126       if (++anArgIter < theArgsNb
10127       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
10128       {
10129         --anArgIter;
10130       }
10131       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
10132     }
10133     else if (anArgCase == "-fov"
10134           || anArgCase == "-fovy"
10135           || anArgCase == "-fovx"
10136           || anArgCase == "-fov2d")
10137     {
10138       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10139       if (anArgValue != NULL
10140       && *anArgValue != '-')
10141       {
10142         ++anArgIter;
10143         if (anArgCase == "-fov2d")
10144         {
10145           aCamera->SetFOV2d (Draw::Atof (anArgValue));
10146         }
10147         else if (anArgCase == "-fovx")
10148         {
10149           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
10150         }
10151         else
10152         {
10153           aCamera->SetFOVy (Draw::Atof (anArgValue));
10154         }
10155         continue;
10156       }
10157       if (anArgCase == "-fov2d")
10158       {
10159         theDI << aCamera->FOV2d() << " ";
10160       }
10161       else if (anArgCase == "-fovx")
10162       {
10163         theDI << aCamera->FOVx() << " ";
10164       }
10165       else
10166       {
10167         theDI << aCamera->FOVy() << " ";
10168       }
10169     }
10170     else if (anArgIter + 1 < theArgsNb
10171           && anArgCase == "-xrpose")
10172     {
10173       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
10174       anXRArg.LowerCase();
10175       if (anXRArg == "base")
10176       {
10177         aCamera = aView->View()->BaseXRCamera();
10178       }
10179       else if (anXRArg == "head")
10180       {
10181         aCamera = aView->View()->PosedXRCamera();
10182       }
10183       else
10184       {
10185         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
10186         return 1;
10187       }
10188       if (aCamera.IsNull())
10189       {
10190         Message::SendFail() << "Error: undefined XR pose";
10191         return 0;
10192       }
10193       if (aView->AutoZFitMode())
10194       {
10195         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
10196         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
10197         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
10198       }
10199     }
10200     else if (aPrsName.IsEmpty()
10201          && !anArgCase.StartsWith ("-"))
10202     {
10203       aPrsName = anArg;
10204     }
10205     else
10206     {
10207       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
10208       return 1;
10209     }
10210   }
10211
10212   if (aPrsName.IsEmpty()
10213    || theArgsNb > 2)
10214   {
10215     aView->Redraw();
10216   }
10217
10218   if (!aPrsName.IsEmpty())
10219   {
10220     Handle(AIS_CameraFrustum) aCameraFrustum;
10221     if (GetMapOfAIS().IsBound2 (aPrsName))
10222     {
10223       // find existing object
10224       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
10225       if (aCameraFrustum.IsNull())
10226       {
10227         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
10228         return 1;
10229       }
10230     }
10231
10232     if (aCameraFrustum.IsNull())
10233     {
10234       aCameraFrustum = new AIS_CameraFrustum();
10235     }
10236     else
10237     {
10238       // not include displayed object of old camera frustum in the new one.
10239       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
10240       aView->ZFitAll();
10241     }
10242     aCameraFrustum->SetCameraFrustum (aCamera);
10243
10244     ViewerTest::Display (aPrsName, aCameraFrustum);
10245   }
10246
10247   return 0;
10248 }
10249
10250 //! Parse stereo output mode
10251 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
10252                                          Graphic3d_StereoMode& theMode)
10253 {
10254   TCollection_AsciiString aFlag (theArg);
10255   aFlag.LowerCase();
10256   if (aFlag == "quadbuffer")
10257   {
10258     theMode = Graphic3d_StereoMode_QuadBuffer;
10259   }
10260   else if (aFlag == "anaglyph")
10261   {
10262     theMode = Graphic3d_StereoMode_Anaglyph;
10263   }
10264   else if (aFlag == "row"
10265         || aFlag == "rowinterlaced")
10266   {
10267     theMode = Graphic3d_StereoMode_RowInterlaced;
10268   }
10269   else if (aFlag == "col"
10270         || aFlag == "colinterlaced"
10271         || aFlag == "columninterlaced")
10272   {
10273     theMode = Graphic3d_StereoMode_ColumnInterlaced;
10274   }
10275   else if (aFlag == "chess"
10276         || aFlag == "chessboard")
10277   {
10278     theMode = Graphic3d_StereoMode_ChessBoard;
10279   }
10280   else if (aFlag == "sbs"
10281         || aFlag == "sidebyside")
10282   {
10283     theMode = Graphic3d_StereoMode_SideBySide;
10284   }
10285   else if (aFlag == "ou"
10286         || aFlag == "overunder")
10287   {
10288     theMode = Graphic3d_StereoMode_OverUnder;
10289   }
10290   else if (aFlag == "pageflip"
10291         || aFlag == "softpageflip")
10292   {
10293     theMode = Graphic3d_StereoMode_SoftPageFlip;
10294   }
10295   else if (aFlag == "openvr"
10296         || aFlag == "vr")
10297   {
10298     theMode = Graphic3d_StereoMode_OpenVR;
10299   }
10300   else
10301   {
10302     return Standard_False;
10303   }
10304   return Standard_True;
10305 }
10306
10307 //! Parse anaglyph filter
10308 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
10309                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
10310 {
10311   TCollection_AsciiString aFlag (theArg);
10312   aFlag.LowerCase();
10313   if (aFlag == "redcyansimple")
10314   {
10315     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10316   }
10317   else if (aFlag == "redcyan"
10318         || aFlag == "redcyanoptimized")
10319   {
10320     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
10321   }
10322   else if (aFlag == "yellowbluesimple")
10323   {
10324     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
10325   }
10326   else if (aFlag == "yellowblue"
10327         || aFlag == "yellowblueoptimized")
10328   {
10329     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
10330   }
10331   else if (aFlag == "greenmagenta"
10332         || aFlag == "greenmagentasimple")
10333   {
10334     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
10335   }
10336   else
10337   {
10338     return Standard_False;
10339   }
10340   return Standard_True;
10341 }
10342
10343 //==============================================================================
10344 //function : VStereo
10345 //purpose  :
10346 //==============================================================================
10347
10348 static int VStereo (Draw_Interpretor& theDI,
10349                     Standard_Integer  theArgNb,
10350                     const char**      theArgVec)
10351 {
10352   Handle(V3d_View) aView = ViewerTest::CurrentView();
10353   if (theArgNb < 2)
10354   {
10355     if (aView.IsNull())
10356     {
10357       Message::SendFail ("Error: no active viewer");
10358       return 0;
10359     }
10360
10361     Standard_Boolean isActive = ViewerTest_myDefaultCaps.contextStereo;
10362     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
10363     if (isActive)
10364     {
10365       TCollection_AsciiString aMode;
10366       switch (aView->RenderingParams().StereoMode)
10367       {
10368         case Graphic3d_StereoMode_QuadBuffer       : aMode = "quadBuffer";       break;
10369         case Graphic3d_StereoMode_RowInterlaced    : aMode = "rowInterlaced";    break;
10370         case Graphic3d_StereoMode_ColumnInterlaced : aMode = "columnInterlaced"; break;
10371         case Graphic3d_StereoMode_ChessBoard       : aMode = "chessBoard";       break;
10372         case Graphic3d_StereoMode_SideBySide       : aMode = "sideBySide";       break;
10373         case Graphic3d_StereoMode_OverUnder        : aMode = "overUnder";        break;
10374         case Graphic3d_StereoMode_SoftPageFlip     : aMode = "softpageflip";     break;
10375         case Graphic3d_StereoMode_OpenVR           : aMode = "openVR";           break;
10376         case Graphic3d_StereoMode_Anaglyph  :
10377           aMode = "anaglyph";
10378           switch (aView->RenderingParams().AnaglyphFilter)
10379           {
10380             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
10381             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
10382             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
10383             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
10384             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
10385             default: break;
10386           }
10387         default: break;
10388       }
10389       theDI << "Mode " << aMode << "\n";
10390     }
10391     return 0;
10392   }
10393
10394   Handle(Graphic3d_Camera) aCamera;
10395   Graphic3d_RenderingParams*   aParams   = NULL;
10396   Graphic3d_StereoMode         aMode     = Graphic3d_StereoMode_QuadBuffer;
10397   if (!aView.IsNull())
10398   {
10399     aParams   = &aView->ChangeRenderingParams();
10400     aMode     = aParams->StereoMode;
10401     aCamera   = aView->Camera();
10402   }
10403
10404   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10405   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10406   {
10407     Standard_CString        anArg = theArgVec[anArgIter];
10408     TCollection_AsciiString aFlag (anArg);
10409     aFlag.LowerCase();
10410     if (anUpdateTool.parseRedrawMode (aFlag))
10411     {
10412       continue;
10413     }
10414     else if (aFlag == "0"
10415           || aFlag == "off")
10416     {
10417       if (++anArgIter < theArgNb)
10418       {
10419         Message::SendFail ("Error: wrong number of arguments");
10420         return 1;
10421       }
10422
10423       if (!aCamera.IsNull()
10424        &&  aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
10425       {
10426         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10427       }
10428       ViewerTest_myDefaultCaps.contextStereo = Standard_False;
10429       return 0;
10430     }
10431     else if (aFlag == "1"
10432           || aFlag == "on")
10433     {
10434       if (++anArgIter < theArgNb)
10435       {
10436         Message::SendFail ("Error: wrong number of arguments");
10437         return 1;
10438       }
10439
10440       if (!aCamera.IsNull())
10441       {
10442         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10443       }
10444       ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10445       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
10446       {
10447         return 0;
10448       }
10449     }
10450     else if (aFlag == "-reverse"
10451           || aFlag == "-reversed"
10452           || aFlag == "-swap")
10453     {
10454       Standard_Boolean toEnable = Standard_True;
10455       if (++anArgIter < theArgNb
10456       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10457       {
10458         --anArgIter;
10459       }
10460       aParams->ToReverseStereo = toEnable;
10461     }
10462     else if (aFlag == "-noreverse"
10463           || aFlag == "-noswap")
10464     {
10465       Standard_Boolean toDisable = Standard_True;
10466       if (++anArgIter < theArgNb
10467       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
10468       {
10469         --anArgIter;
10470       }
10471       aParams->ToReverseStereo = !toDisable;
10472     }
10473     else if (aFlag == "-mode"
10474           || aFlag == "-stereomode")
10475     {
10476       if (++anArgIter >= theArgNb
10477       || !parseStereoMode (theArgVec[anArgIter], aMode))
10478       {
10479         Message::SendFail() << "Syntax error at '" << anArg << "'";
10480         return 1;
10481       }
10482
10483       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10484       {
10485         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10486       }
10487     }
10488     else if (aFlag == "-anaglyph"
10489           || aFlag == "-anaglyphfilter")
10490     {
10491       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10492       if (++anArgIter >= theArgNb
10493       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
10494       {
10495         Message::SendFail() << "Syntax error at '" << anArg << "'";
10496         return 1;
10497       }
10498
10499       aMode = Graphic3d_StereoMode_Anaglyph;
10500       aParams->AnaglyphFilter = aFilter;
10501     }
10502     else if (parseStereoMode (anArg, aMode)) // short syntax
10503     {
10504       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10505       {
10506         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10507       }
10508     }
10509     else if (anArgIter + 1 < theArgNb
10510           && aFlag == "-hmdfov2d")
10511     {
10512       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
10513       if (aParams->HmdFov2d < 10.0f
10514        || aParams->HmdFov2d > 180.0f)
10515       {
10516         Message::SendFail() << "Error: FOV is out of range";
10517         return 1;
10518       }
10519     }
10520     else if (aFlag == "-mirror"
10521           || aFlag == "-mirrorcomposer")
10522     {
10523       Standard_Boolean toEnable = Standard_True;
10524       if (++anArgIter < theArgNb
10525       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10526       {
10527         --anArgIter;
10528       }
10529       aParams->ToMirrorComposer = toEnable;
10530     }
10531     else if (anArgIter + 1 < theArgNb
10532           && (aFlag == "-unitfactor"
10533            || aFlag == "-unitscale"))
10534     {
10535       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
10536     }
10537     else
10538     {
10539       Message::SendFail() << "Syntax error at '" << anArg << "'";
10540       return 1;
10541     }
10542   }
10543
10544   if (!aView.IsNull())
10545   {
10546     aParams->StereoMode = aMode;
10547     aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10548     if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
10549     {
10550       // initiate implicit continuous rendering
10551       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
10552     }
10553   }
10554   return 0;
10555 }
10556
10557 //===============================================================================================
10558 //function : VDefaults
10559 //purpose  :
10560 //===============================================================================================
10561 static int VDefaults (Draw_Interpretor& theDi,
10562                       Standard_Integer  theArgsNb,
10563                       const char**      theArgVec)
10564 {
10565   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
10566   if (aCtx.IsNull())
10567   {
10568     Message::SendFail ("Error: no active viewer");
10569     return 1;
10570   }
10571
10572   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
10573   if (theArgsNb < 2)
10574   {
10575     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
10576     {
10577       theDi << "DeflType:           relative\n"
10578             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
10579     }
10580     else
10581     {
10582       theDi << "DeflType:           absolute\n"
10583             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
10584     }
10585     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
10586     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
10587     return 0;
10588   }
10589
10590   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
10591   {
10592     TCollection_AsciiString anArg (theArgVec[anArgIter]);
10593     anArg.UpperCase();
10594     if (anArg == "-ABSDEFL"
10595      || anArg == "-ABSOLUTEDEFLECTION"
10596      || anArg == "-DEFL"
10597      || anArg == "-DEFLECTION")
10598     {
10599       if (++anArgIter >= theArgsNb)
10600       {
10601         Message::SendFail() << "Syntax error at " << anArg;
10602         return 1;
10603       }
10604       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
10605       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
10606     }
10607     else if (anArg == "-RELDEFL"
10608           || anArg == "-RELATIVEDEFLECTION"
10609           || anArg == "-DEVCOEFF"
10610           || anArg == "-DEVIATIONCOEFF"
10611           || anArg == "-DEVIATIONCOEFFICIENT")
10612     {
10613       if (++anArgIter >= theArgsNb)
10614       {
10615         Message::SendFail() << "Syntax error at " << anArg;
10616         return 1;
10617       }
10618       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
10619       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
10620     }
10621     else if (anArg == "-ANGDEFL"
10622           || anArg == "-ANGULARDEFL"
10623           || anArg == "-ANGULARDEFLECTION")
10624     {
10625       if (++anArgIter >= theArgsNb)
10626       {
10627         Message::SendFail() << "Syntax error at " << anArg;
10628         return 1;
10629       }
10630       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
10631     }
10632     else if (anArg == "-AUTOTR"
10633           || anArg == "-AUTOTRIANG"
10634           || anArg == "-AUTOTRIANGULATION")
10635     {
10636       ++anArgIter;
10637       bool toTurnOn = true;
10638       if (anArgIter >= theArgsNb
10639       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
10640       {
10641         Message::SendFail() << "Syntax error at '" << anArg << "'";
10642         return 1;
10643       }
10644       aDefParams->SetAutoTriangulation (toTurnOn);
10645     }
10646     else
10647     {
10648       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
10649       return 1;
10650     }
10651   }
10652
10653   return 0;
10654 }
10655
10656 //! Auxiliary method
10657 inline void addLight (const Handle(V3d_Light)& theLightNew,
10658                       const Graphic3d_ZLayerId theLayer,
10659                       const Standard_Boolean   theIsGlobal)
10660 {
10661   if (theLightNew.IsNull())
10662   {
10663     return;
10664   }
10665
10666   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10667   if (theLayer == Graphic3d_ZLayerId_UNKNOWN)
10668   {
10669     aViewer->AddLight (theLightNew);
10670     if (theIsGlobal)
10671     {
10672       aViewer->SetLightOn (theLightNew);
10673     }
10674     else
10675     {
10676       ViewerTest::CurrentView()->SetLightOn (theLightNew);
10677     }
10678   }
10679   else
10680   {
10681     Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (theLayer);
10682     if (aSettings.Lights().IsNull())
10683     {
10684       aSettings.SetLights (new Graphic3d_LightSet());
10685     }
10686     aSettings.Lights()->Add (theLightNew);
10687     aViewer->SetZLayerSettings (theLayer, aSettings);
10688   }
10689 }
10690
10691 //! Auxiliary method
10692 inline Standard_Integer getLightId (const TCollection_AsciiString& theArgNext)
10693 {
10694   TCollection_AsciiString anArgNextCase (theArgNext);
10695   anArgNextCase.UpperCase();
10696   if (anArgNextCase.Length() > 5
10697    && anArgNextCase.SubString (1, 5).IsEqual ("LIGHT"))
10698   {
10699     return theArgNext.SubString (6, theArgNext.Length()).IntegerValue();
10700   }
10701   else
10702   {
10703     return theArgNext.IntegerValue();
10704   }
10705 }
10706
10707 //===============================================================================================
10708 //function : VLight
10709 //purpose  :
10710 //===============================================================================================
10711 static int VLight (Draw_Interpretor& theDi,
10712                    Standard_Integer  theArgsNb,
10713                    const char**      theArgVec)
10714 {
10715   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
10716   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10717   if (aView.IsNull()
10718    || aViewer.IsNull())
10719   {
10720     Message::SendFail ("Error: no active viewer");
10721     return 1;
10722   }
10723
10724   Standard_Real anXYZ[3]   = {};
10725   Standard_Real anAtten[2] = {};
10726   if (theArgsNb < 2)
10727   {
10728     // print lights info
10729     Standard_Integer aLightId = 0;
10730     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
10731     {
10732       Handle(V3d_Light) aLight = aLightIter.Value();
10733       const Quantity_Color aColor = aLight->Color();
10734       theDi << "Light #" << aLightId
10735             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
10736             << " [" << aLight->GetId() << "]" << "\n";
10737       switch (aLight->Type())
10738       {
10739         case V3d_AMBIENT:
10740         {
10741           theDi << "  Type:       Ambient\n";
10742           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10743           break;
10744         }
10745         case V3d_DIRECTIONAL:
10746         {
10747           theDi << "  Type:       Directional\n";
10748           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10749           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10750           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10751           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10752           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10753           break;
10754         }
10755         case V3d_POSITIONAL:
10756         {
10757           theDi << "  Type:       Positional\n";
10758           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10759           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10760           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10761           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10762           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10763           aLight->Attenuation (anAtten[0], anAtten[1]);
10764           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10765           theDi << "  Range:      " << aLight->Range() << "\n";
10766           break;
10767         }
10768         case V3d_SPOT:
10769         {
10770           theDi << "  Type:       Spot\n";
10771           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10772           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10773           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10774           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10775           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10776           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10777           aLight->Attenuation (anAtten[0], anAtten[1]);
10778           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10779           theDi << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n";
10780           theDi << "  Exponent:   " << aLight->Concentration() << "\n";
10781           theDi << "  Range:      " << aLight->Range() << "\n";
10782           break;
10783         }
10784         default:
10785         {
10786           theDi << "  Type:       UNKNOWN\n";
10787           break;
10788         }
10789       }
10790       theDi << "  Color:      " << aColor.Red() << ", " << aColor.Green() << ", " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
10791     }
10792   }
10793
10794   Handle(V3d_Light) aLightNew;
10795   Handle(V3d_Light) aLightOld;
10796   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
10797   Standard_Boolean  isGlobal = Standard_True;
10798   Standard_Boolean  toCreate = Standard_False;
10799   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10800   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
10801   {
10802     Handle(V3d_Light) aLightCurr = aLightNew.IsNull() ? aLightOld : aLightNew;
10803
10804     TCollection_AsciiString aName, aValue;
10805     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
10806     TCollection_AsciiString anArgCase (anArg);
10807     anArgCase.UpperCase();
10808     if (anUpdateTool.parseRedrawMode (anArg))
10809     {
10810       continue;
10811     }
10812
10813     if (anArgCase.IsEqual ("NEW")
10814      || anArgCase.IsEqual ("ADD")
10815      || anArgCase.IsEqual ("CREATE")
10816      || anArgCase.IsEqual ("-NEW")
10817      || anArgCase.IsEqual ("-ADD")
10818      || anArgCase.IsEqual ("-CREATE"))
10819     {
10820       toCreate = Standard_True;
10821     }
10822     else if (anArgCase.IsEqual ("-LAYER")
10823           || anArgCase.IsEqual ("-ZLAYER"))
10824     {
10825       if (++anArgIt >= theArgsNb)
10826       {
10827         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10828         return 1;
10829       }
10830
10831       TCollection_AsciiString aValStr (theArgVec[anArgIt]);
10832       aValStr.LowerCase();
10833       if (aValStr == "default"
10834        || aValStr == "def")
10835       {
10836         aLayer = Graphic3d_ZLayerId_Default;
10837       }
10838       else if (aValStr == "top")
10839       {
10840         aLayer = Graphic3d_ZLayerId_Top;
10841       }
10842       else if (aValStr == "topmost")
10843       {
10844         aLayer = Graphic3d_ZLayerId_Topmost;
10845       }
10846       else if (aValStr == "toposd"
10847             || aValStr == "osd")
10848       {
10849         aLayer = Graphic3d_ZLayerId_TopOSD;
10850       }
10851       else if (aValStr == "botosd"
10852             || aValStr == "bottom")
10853       {
10854         aLayer = Graphic3d_ZLayerId_BotOSD;
10855       }
10856       else if (aValStr.IsIntegerValue())
10857       {
10858         aLayer = Draw::Atoi (theArgVec[anArgIt]);
10859       }
10860       else
10861       {
10862         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10863         return 1;
10864       }
10865     }
10866     else if (anArgCase.IsEqual ("GLOB")
10867           || anArgCase.IsEqual ("GLOBAL")
10868           || anArgCase.IsEqual ("-GLOB")
10869           || anArgCase.IsEqual ("-GLOBAL"))
10870     {
10871       isGlobal = Standard_True;
10872     }
10873     else if (anArgCase.IsEqual ("LOC")
10874           || anArgCase.IsEqual ("LOCAL")
10875           || anArgCase.IsEqual ("-LOC")
10876           || anArgCase.IsEqual ("-LOCAL"))
10877     {
10878       isGlobal = Standard_False;
10879     }
10880     else if (anArgCase.IsEqual ("DEF")
10881           || anArgCase.IsEqual ("DEFAULTS")
10882           || anArgCase.IsEqual ("-DEF")
10883           || anArgCase.IsEqual ("-DEFAULTS"))
10884     {
10885       toCreate = Standard_False;
10886       aViewer->SetDefaultLights();
10887     }
10888     else if (anArgCase.IsEqual ("CLR")
10889           || anArgCase.IsEqual ("CLEAR")
10890           || anArgCase.IsEqual ("-CLR")
10891           || anArgCase.IsEqual ("-CLEAR"))
10892     {
10893       toCreate = Standard_False;
10894
10895       TColStd_SequenceOfInteger aLayers;
10896       aViewer->GetAllZLayers (aLayers);
10897       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10898       {
10899         if (aLayeriter.Value() == aLayer
10900          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10901         {
10902           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10903           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10904           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10905           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10906           {
10907             break;
10908           }
10909         }
10910       }
10911
10912       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10913       {
10914         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10915         {
10916           Handle(V3d_Light) aLight = aLightIter.Value();
10917           aViewer->DelLight (aLight);
10918           aLightIter = aView->ActiveLightIterator();
10919         }
10920       }
10921     }
10922     else if (anArgCase.IsEqual ("AMB")
10923           || anArgCase.IsEqual ("AMBIENT")
10924           || anArgCase.IsEqual ("AMBLIGHT"))
10925     {
10926       if (!toCreate)
10927       {
10928         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10929         return 1;
10930       }
10931
10932       addLight (aLightNew, aLayer, isGlobal);
10933       toCreate  = Standard_False;
10934       aLightNew = new V3d_AmbientLight();
10935     }
10936     else if (anArgCase.IsEqual ("DIRECTIONAL")
10937           || anArgCase.IsEqual ("DIRLIGHT"))
10938     {
10939       if (!toCreate)
10940       {
10941         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10942         return 1;
10943       }
10944
10945       addLight (aLightNew, aLayer, isGlobal);
10946       toCreate  = Standard_False;
10947       aLightNew = new V3d_DirectionalLight();
10948     }
10949     else if (anArgCase.IsEqual ("SPOT")
10950           || anArgCase.IsEqual ("SPOTLIGHT"))
10951     {
10952       if (!toCreate)
10953       {
10954         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10955         return 1;
10956       }
10957
10958       addLight (aLightNew, aLayer, isGlobal);
10959       toCreate  = Standard_False;
10960       aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
10961     }
10962     else if (anArgCase.IsEqual ("POSLIGHT")
10963           || anArgCase.IsEqual ("POSITIONAL"))
10964     {
10965       if (!toCreate)
10966       {
10967         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10968         return 1;
10969       }
10970
10971       addLight (aLightNew, aLayer, isGlobal);
10972       toCreate  = Standard_False;
10973       aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
10974     }
10975     else if (anArgCase.IsEqual ("CHANGE")
10976           || anArgCase.IsEqual ("-CHANGE"))
10977     {
10978       if (++anArgIt >= theArgsNb)
10979       {
10980         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10981         return 1;
10982       }
10983
10984       addLight (aLightNew, aLayer, isGlobal);
10985       aLightNew.Nullify();
10986       const Standard_Integer aLightId = getLightId (theArgVec[anArgIt]);
10987       Standard_Integer aLightIt = 0;
10988       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
10989       {
10990         if (aLightIt == aLightId)
10991         {
10992           aLightOld = aLightIter.Value();
10993           break;
10994         }
10995       }
10996
10997       if (aLightOld.IsNull())
10998       {
10999         Message::SendFail() << "Error: Light " << theArgVec[anArgIt] << " is undefined";
11000         return 1;
11001       }
11002     }
11003     else if (anArgCase.IsEqual ("DEL")
11004           || anArgCase.IsEqual ("DELETE")
11005           || anArgCase.IsEqual ("-DEL")
11006           || anArgCase.IsEqual ("-DELETE"))
11007     {
11008       Handle(V3d_Light) aLightDel;
11009       if (++anArgIt >= theArgsNb)
11010       {
11011         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11012         return 1;
11013       }
11014
11015       const TCollection_AsciiString anArgNext (theArgVec[anArgIt]);
11016       const Standard_Integer aLightDelId = getLightId (theArgVec[anArgIt]);
11017       Standard_Integer aLightIt = 0;
11018       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
11019       {
11020         aLightDel = aLightIter.Value();
11021         if (aLightIt == aLightDelId)
11022         {
11023           break;
11024         }
11025       }
11026       if (aLightDel.IsNull())
11027       {
11028         continue;
11029       }
11030
11031       TColStd_SequenceOfInteger aLayers;
11032       aViewer->GetAllZLayers (aLayers);
11033       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
11034       {
11035         if (aLayeriter.Value() == aLayer
11036          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
11037         {
11038           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
11039           if (!aSettings.Lights().IsNull())
11040           {
11041             aSettings.Lights()->Remove (aLightDel);
11042             if (aSettings.Lights()->IsEmpty())
11043             {
11044               aSettings.SetLights (Handle(Graphic3d_LightSet)());
11045             }
11046           }
11047           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
11048           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
11049           {
11050             break;
11051           }
11052         }
11053       }
11054
11055       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
11056       {
11057         aViewer->DelLight (aLightDel);
11058       }
11059     }
11060     else if (anArgCase.IsEqual ("COLOR")
11061           || anArgCase.IsEqual ("COLOUR")
11062           || anArgCase.IsEqual ("-COLOR")
11063           || anArgCase.IsEqual ("-COLOUR"))
11064     {
11065       Quantity_Color aColor;
11066       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
11067                                                      theArgVec + anArgIt + 1,
11068                                                      aColor);
11069       anArgIt += aNbParsed;
11070       if (aNbParsed == 0
11071        || aLightCurr.IsNull())
11072       {
11073         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11074         return 1;
11075       }
11076       aLightCurr->SetColor (aColor);
11077     }
11078     else if (anArgCase.IsEqual ("POS")
11079           || anArgCase.IsEqual ("POSITION")
11080           || anArgCase.IsEqual ("-POS")
11081           || anArgCase.IsEqual ("-POSITION"))
11082     {
11083       if ((anArgIt + 3) >= theArgsNb
11084        || aLightCurr.IsNull()
11085        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11086         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11087       {
11088         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11089         return 1;
11090       }
11091
11092       anXYZ[0] = Atof (theArgVec[++anArgIt]);
11093       anXYZ[1] = Atof (theArgVec[++anArgIt]);
11094       anXYZ[2] = Atof (theArgVec[++anArgIt]);
11095       aLightCurr->SetPosition (anXYZ[0], anXYZ[1], anXYZ[2]);
11096     }
11097     else if (anArgCase.IsEqual ("DIR")
11098           || anArgCase.IsEqual ("DIRECTION")
11099           || anArgCase.IsEqual ("-DIR")
11100           || anArgCase.IsEqual ("-DIRECTION"))
11101     {
11102       if ((anArgIt + 3) >= theArgsNb
11103        || aLightCurr.IsNull()
11104        || (aLightCurr->Type() != Graphic3d_TOLS_DIRECTIONAL
11105         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11106       {
11107         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11108         return 1;
11109       }
11110
11111       anXYZ[0] = Atof (theArgVec[++anArgIt]);
11112       anXYZ[1] = Atof (theArgVec[++anArgIt]);
11113       anXYZ[2] = Atof (theArgVec[++anArgIt]);
11114       aLightCurr->SetDirection (anXYZ[0], anXYZ[1], anXYZ[2]);
11115     }
11116     else if (anArgCase.IsEqual ("SM")
11117           || anArgCase.IsEqual ("SMOOTHNESS")
11118           || anArgCase.IsEqual ("-SM")
11119           || anArgCase.IsEqual ("-SMOOTHNESS"))
11120     {
11121       if (++anArgIt >= theArgsNb
11122        || aLightCurr.IsNull())
11123       {
11124         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11125         return 1;
11126       }
11127
11128       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11129       if (Abs (aSmoothness) <= ShortRealEpsilon())
11130       {
11131         aLightCurr->SetIntensity (1.f);
11132       }
11133       else if (Abs (aLightCurr->Smoothness()) <= ShortRealEpsilon())
11134       {
11135         aLightCurr->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
11136       }
11137       else
11138       {
11139         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightCurr->Smoothness());
11140         aLightCurr->SetIntensity (aLightCurr->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
11141       }
11142
11143       if (aLightCurr->Type() == Graphic3d_TOLS_POSITIONAL)
11144       {
11145         aLightCurr->SetSmoothRadius (aSmoothness);
11146       }
11147       else if (aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11148       {
11149         aLightCurr->SetSmoothAngle (aSmoothness);
11150       }
11151     }
11152     else if (anArgCase.IsEqual ("INT")
11153           || anArgCase.IsEqual ("INTENSITY")
11154           || anArgCase.IsEqual ("-INT")
11155           || anArgCase.IsEqual ("-INTENSITY"))
11156     {
11157       if (++anArgIt >= theArgsNb
11158        || aLightCurr.IsNull())
11159       {
11160         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11161         return 1;
11162       }
11163
11164       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11165       aLightCurr->SetIntensity (aIntensity);
11166     }
11167     else if (anArgCase.IsEqual ("ANG")
11168           || anArgCase.IsEqual ("ANGLE")
11169           || anArgCase.IsEqual ("-ANG")
11170           || anArgCase.IsEqual ("-ANGLE"))
11171     {
11172       if (++anArgIt >= theArgsNb
11173        || aLightCurr.IsNull()
11174        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11175       {
11176         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11177         return 1;
11178       }
11179
11180       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11181       aLightCurr->SetAngle (Standard_ShortReal (anAngle / 180.0 * M_PI));
11182     }
11183     else if (anArgCase.IsEqual ("CONSTATTEN")
11184           || anArgCase.IsEqual ("CONSTATTENUATION")
11185           || anArgCase.IsEqual ("-CONSTATTEN")
11186           || anArgCase.IsEqual ("-CONSTATTENUATION"))
11187     {
11188       if (++anArgIt >= theArgsNb
11189        || aLightCurr.IsNull()
11190        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11191         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11192       {
11193         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11194         return 1;
11195       }
11196
11197       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11198       anAtten[0] = Atof (theArgVec[anArgIt]);
11199       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11200     }
11201     else if (anArgCase.IsEqual ("LINATTEN")
11202           || anArgCase.IsEqual ("LINEARATTEN")
11203           || anArgCase.IsEqual ("LINEARATTENUATION")
11204           || anArgCase.IsEqual ("-LINATTEN")
11205           || anArgCase.IsEqual ("-LINEARATTEN")
11206           || anArgCase.IsEqual ("-LINEARATTENUATION"))
11207     {
11208       if (++anArgIt >= theArgsNb
11209        || aLightCurr.IsNull()
11210        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11211         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11212       {
11213         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11214         return 1;
11215       }
11216
11217       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11218       anAtten[1] = Atof (theArgVec[anArgIt]);
11219       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11220     }
11221     else if (anArgCase.IsEqual ("EXP")
11222           || anArgCase.IsEqual ("EXPONENT")
11223           || anArgCase.IsEqual ("SPOTEXP")
11224           || anArgCase.IsEqual ("SPOTEXPONENT")
11225           || anArgCase.IsEqual ("-EXP")
11226           || anArgCase.IsEqual ("-EXPONENT")
11227           || anArgCase.IsEqual ("-SPOTEXP")
11228           || anArgCase.IsEqual ("-SPOTEXPONENT"))
11229     {
11230       if (++anArgIt >= theArgsNb
11231        || aLightCurr.IsNull()
11232        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11233       {
11234         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11235         return 1;
11236       }
11237
11238       aLightCurr->SetConcentration ((Standard_ShortReal )Atof (theArgVec[anArgIt]));
11239     }
11240     else if (anArgCase.IsEqual("RANGE")
11241           || anArgCase.IsEqual("-RANGE"))
11242     {
11243       if (++anArgIt >= theArgsNb
11244        || aLightCurr.IsNull()
11245        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT
11246        || aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11247       {
11248         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11249         return 1;
11250       }
11251
11252       aLightCurr->SetRange ((Standard_ShortReal)Atof (theArgVec[anArgIt]));
11253     }
11254     else if (anArgCase.IsEqual ("HEAD")
11255           || anArgCase.IsEqual ("HEADLIGHT")
11256           || anArgCase.IsEqual ("-HEAD")
11257           || anArgCase.IsEqual ("-HEADLIGHT"))
11258     {
11259       if (aLightCurr.IsNull()
11260        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
11261       {
11262         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11263         return 1;
11264       }
11265
11266       Standard_Boolean isHeadLight = Standard_True;
11267       if (anArgIt + 1 < theArgsNb
11268        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
11269       {
11270         ++anArgIt;
11271       }
11272       aLightCurr->SetHeadlight (isHeadLight);
11273     }
11274     else
11275     {
11276       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
11277     }
11278   }
11279
11280   addLight (aLightNew, aLayer, isGlobal);
11281   return 0;
11282 }
11283
11284 //===============================================================================================
11285 //function : VPBREnvironment
11286 //purpose  :
11287 //===============================================================================================
11288 static int VPBREnvironment (Draw_Interpretor&,
11289                             Standard_Integer theArgsNb,
11290                             const char**     theArgVec)
11291 {
11292   if (theArgsNb > 2)
11293   {
11294     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
11295     return 1;
11296   }
11297
11298   Handle(V3d_View) aView = ViewerTest::CurrentView();
11299   if (aView.IsNull())
11300   {
11301     Message::SendFail ("Error: no active viewer");
11302     return 1;
11303   }
11304
11305   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
11306   anArg.LowerCase();
11307
11308   if (anArg == "-generate"
11309    || anArg == "-gen")
11310   {
11311     aView->GeneratePBREnvironment (Standard_True);
11312   }
11313   else if (anArg == "-clear")
11314   {
11315     aView->ClearPBREnvironment (Standard_True);
11316   }
11317   else
11318   {
11319     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
11320     return 1;
11321   }
11322
11323   return 0;
11324 }
11325
11326 //! Read Graphic3d_RenderingParams::PerfCounters flag.
11327 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
11328                                             Standard_Boolean& theToReset,
11329                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
11330                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
11331 {
11332   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
11333   TCollection_AsciiString aVal = theValue;
11334   Standard_Boolean toReverse = Standard_False;
11335   if (aVal == "none")
11336   {
11337     theToReset = Standard_True;
11338     return Standard_True;
11339   }
11340   else if (aVal.StartsWith ("-"))
11341   {
11342     toReverse = Standard_True;
11343     aVal = aVal.SubString (2, aVal.Length());
11344   }
11345   else if (aVal.StartsWith ("no"))
11346   {
11347     toReverse = Standard_True;
11348     aVal = aVal.SubString (3, aVal.Length());
11349   }
11350   else if (aVal.StartsWith ("+"))
11351   {
11352     aVal = aVal.SubString (2, aVal.Length());
11353   }
11354   else
11355   {
11356     theToReset = Standard_True;
11357   }
11358
11359   if (     aVal == "fps"
11360         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11361   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
11362   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
11363   else if (aVal == "structs"
11364         || aVal == "structures"
11365         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
11366   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
11367   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
11368   else if (aVal == "tris"
11369         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
11370   else if (aVal == "pnts"
11371         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
11372   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
11373   else if (aVal == "mem"
11374         || aVal == "gpumem"
11375         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
11376   else if (aVal == "skipimmediate"
11377         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
11378   else if (aVal == "frametime"
11379         || aVal == "frametimers"
11380         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
11381   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
11382   else if (aVal == "extended"
11383         || aVal == "verbose"
11384         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
11385   else if (aVal == "full"
11386         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
11387   else
11388   {
11389     return Standard_False;
11390   }
11391
11392   if (toReverse)
11393   {
11394     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
11395   }
11396   else
11397   {
11398     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
11399   }
11400   return Standard_True;
11401 }
11402
11403 //! Read Graphic3d_RenderingParams::PerfCounters flags.
11404 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
11405                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
11406 {
11407   TCollection_AsciiString aValue = theValue;
11408   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
11409   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
11410   Standard_Boolean toReset = Standard_False;
11411   for (;;)
11412   {
11413     Standard_Integer aSplitPos = aValue.Search ("|");
11414     if (aSplitPos <= 0)
11415     {
11416       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
11417       {
11418         return Standard_False;
11419       }
11420       if (toReset)
11421       {
11422         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
11423       }
11424       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
11425       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
11426       return Standard_True;
11427     }
11428
11429     if (aSplitPos > 1)
11430     {
11431       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
11432       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
11433       {
11434         return Standard_False;
11435       }
11436     }
11437     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
11438   }
11439 }
11440
11441 //=======================================================================
11442 //function : VRenderParams
11443 //purpose  : Enables/disables rendering features
11444 //=======================================================================
11445
11446 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
11447                                        Standard_Integer  theArgNb,
11448                                        const char**      theArgVec)
11449 {
11450   Handle(V3d_View) aView = ViewerTest::CurrentView();
11451   if (aView.IsNull())
11452   {
11453     Message::SendFail ("Error: no active viewer");
11454     return 1;
11455   }
11456
11457   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
11458   TCollection_AsciiString aCmdName (theArgVec[0]);
11459   aCmdName.LowerCase();
11460   if (aCmdName == "vraytrace")
11461   {
11462     if (theArgNb == 1)
11463     {
11464       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
11465       return 0;
11466     }
11467     else if (theArgNb == 2)
11468     {
11469       TCollection_AsciiString aValue (theArgVec[1]);
11470       aValue.LowerCase();
11471       if (aValue == "on"
11472        || aValue == "1")
11473       {
11474         aParams.Method = Graphic3d_RM_RAYTRACING;
11475         aView->Redraw();
11476         return 0;
11477       }
11478       else if (aValue == "off"
11479             || aValue == "0")
11480       {
11481         aParams.Method = Graphic3d_RM_RASTERIZATION;
11482         aView->Redraw();
11483         return 0;
11484       }
11485       else
11486       {
11487         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
11488         return 1;
11489       }
11490     }
11491     else
11492     {
11493       Message::SendFail ("Syntax error: wrong number of arguments");
11494       return 1;
11495     }
11496   }
11497
11498   if (theArgNb < 2)
11499   {
11500     theDI << "renderMode:  ";
11501     switch (aParams.Method)
11502     {
11503       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11504       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
11505     }
11506     theDI << "\n";
11507     theDI << "transparency:  ";
11508     switch (aParams.TransparencyMethod)
11509     {
11510       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
11511       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
11512                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
11513     }
11514     theDI << "\n";
11515     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
11516     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
11517     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
11518     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
11519     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
11520     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
11521     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
11522     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
11523     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
11524     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
11525     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
11526     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
11527     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
11528     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
11529     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
11530     theDI << "shadingModel: ";
11531     switch (aView->ShadingModel())
11532     {
11533       case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
11534       case Graphic3d_TOSM_UNLIT:     theDI << "unlit";     break;
11535       case Graphic3d_TOSM_FACET:     theDI << "flat";      break;
11536       case Graphic3d_TOSM_VERTEX:    theDI << "gouraud";   break;
11537       case Graphic3d_TOSM_FRAGMENT:  theDI << "phong";     break;
11538       case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
11539       case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
11540     }
11541     {
11542       theDI << "perfCounters:";
11543       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
11544       {
11545         theDI << " fps";
11546       }
11547       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
11548       {
11549         theDI << " cpu";
11550       }
11551       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
11552       {
11553         theDI << " structs";
11554       }
11555       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
11556       {
11557         theDI << " groups";
11558       }
11559       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
11560       {
11561         theDI << " arrays";
11562       }
11563       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
11564       {
11565         theDI << " tris";
11566       }
11567       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
11568       {
11569         theDI << " lines";
11570       }
11571       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
11572       {
11573         theDI << " pnts";
11574       }
11575       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
11576       {
11577         theDI << " gpumem";
11578       }
11579       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
11580       {
11581         theDI << " frameTime";
11582       }
11583       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
11584       {
11585         theDI << " skipimmediate";
11586       }
11587       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
11588       {
11589         theDI << " none";
11590       }
11591       theDI << "\n";
11592     }
11593     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
11594     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
11595     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
11596                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
11597                                                                                                                     "noUpdate") << "\n";
11598     theDI << "\n";
11599     return 0;
11600   }
11601
11602   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
11603   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
11604   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11605   {
11606     Standard_CString        anArg (theArgVec[anArgIter]);
11607     TCollection_AsciiString aFlag (anArg);
11608     aFlag.LowerCase();
11609     if (anUpdateTool.parseRedrawMode (aFlag))
11610     {
11611       continue;
11612     }
11613     else if (aFlag == "-echo"
11614           || aFlag == "-print")
11615     {
11616       toPrint = Standard_True;
11617       anUpdateTool.Invalidate();
11618     }
11619     else if (aFlag == "-reset")
11620     {
11621       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
11622     }
11623     else if (aFlag == "-sync"
11624           && (anArgIter + 1 < theArgNb))
11625     {
11626       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
11627       aSyncFlag.LowerCase();
11628       if (aSyncFlag == "default"
11629        || aSyncFlag == "defaults"
11630        || aSyncFlag == "viewer")
11631       {
11632         toSyncDefaults = true;
11633       }
11634       else if (aSyncFlag == "allviews"
11635             || aSyncFlag == "views")
11636       {
11637         toSyncAllViews = true;
11638       }
11639       else
11640       {
11641         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
11642         return 1;
11643       }
11644     }
11645     else if (aFlag == "-mode"
11646           || aFlag == "-rendermode"
11647           || aFlag == "-render_mode")
11648     {
11649       if (toPrint)
11650       {
11651         switch (aParams.Method)
11652         {
11653           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11654           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
11655         }
11656         continue;
11657       }
11658       else
11659       {
11660         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11661         return 1;
11662       }
11663     }
11664     else if (aFlag == "-ray"
11665           || aFlag == "-raytrace")
11666     {
11667       if (toPrint)
11668       {
11669         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
11670         continue;
11671       }
11672
11673       bool isRayTrace = true;
11674       if (anArgIter + 1 < theArgNb
11675        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
11676       {
11677         ++anArgIter;
11678       }
11679       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
11680     }
11681     else if (aFlag == "-rast"
11682           || aFlag == "-raster"
11683           || aFlag == "-rasterization")
11684     {
11685       if (toPrint)
11686       {
11687         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
11688         continue;
11689       }
11690
11691       bool isRaster = true;
11692       if (anArgIter + 1 < theArgNb
11693        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
11694       {
11695         ++anArgIter;
11696       }
11697       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
11698     }
11699     else if (aFlag == "-msaa")
11700     {
11701       if (toPrint)
11702       {
11703         theDI << aParams.NbMsaaSamples << " ";
11704         continue;
11705       }
11706       else if (++anArgIter >= theArgNb)
11707       {
11708         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11709         return 1;
11710       }
11711
11712       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11713       if (aNbSamples < 0)
11714       {
11715         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11716         return 1;
11717       }
11718       else
11719       {
11720         aParams.NbMsaaSamples = aNbSamples;
11721       }
11722     }
11723     else if (aFlag == "-linefeather"
11724           || aFlag == "-edgefeather"
11725           || aFlag == "-feather")
11726     {
11727       if (toPrint)
11728       {
11729         theDI << " " << aParams.LineFeather << " ";
11730         continue;
11731       }
11732       else if (++anArgIter >= theArgNb)
11733       {
11734         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11735         return 1;
11736       }
11737
11738       TCollection_AsciiString aParam = theArgVec[anArgIter];
11739       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11740       if (aFeather <= 0.0f)
11741       {
11742         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
11743         return 1;
11744       }
11745       aParams.LineFeather = aFeather;
11746     }
11747     else if (aFlag == "-oit")
11748     {
11749       if (toPrint)
11750       {
11751         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
11752         {
11753           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
11754         }
11755         else
11756         {
11757           theDI << "off" << " ";
11758         }
11759         continue;
11760       }
11761       else if (++anArgIter >= theArgNb)
11762       {
11763         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11764         return 1;
11765       }
11766
11767       TCollection_AsciiString aParam = theArgVec[anArgIter];
11768       aParam.LowerCase();
11769       if (aParam.IsRealValue())
11770       {
11771         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
11772         if (aWeight < 0.f || aWeight > 1.f)
11773         {
11774           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
11775           return 1;
11776         }
11777
11778         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
11779         aParams.OitDepthFactor     = aWeight;
11780       }
11781       else if (aParam == "off")
11782       {
11783         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
11784       }
11785       else
11786       {
11787         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11788         return 1;
11789       }
11790     }
11791     else if (aFlag == "-depthprepass")
11792     {
11793       if (toPrint)
11794       {
11795         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
11796         continue;
11797       }
11798       aParams.ToEnableDepthPrepass = Standard_True;
11799       if (anArgIter + 1 < theArgNb
11800        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
11801       {
11802         ++anArgIter;
11803       }
11804     }
11805     else if (aFlag == "-samplealphatocoverage"
11806           || aFlag == "-alphatocoverage")
11807     {
11808       if (toPrint)
11809       {
11810         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
11811         continue;
11812       }
11813       aParams.ToEnableAlphaToCoverage = Standard_True;
11814       if (anArgIter + 1 < theArgNb
11815        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
11816       {
11817         ++anArgIter;
11818       }
11819     }
11820     else if (aFlag == "-rendscale"
11821           || aFlag == "-renderscale"
11822           || aFlag == "-renderresolutionscale")
11823     {
11824       if (toPrint)
11825       {
11826         theDI << aParams.RenderResolutionScale << " ";
11827         continue;
11828       }
11829       else if (++anArgIter >= theArgNb)
11830       {
11831         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11832         return 1;
11833       }
11834
11835       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
11836       if (aScale < 0.01)
11837       {
11838         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
11839         return 1;
11840       }
11841       else
11842       {
11843         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
11844       }
11845     }
11846     else if (aFlag == "-raydepth"
11847           || aFlag == "-ray_depth")
11848     {
11849       if (toPrint)
11850       {
11851         theDI << aParams.RaytracingDepth << " ";
11852         continue;
11853       }
11854       else if (++anArgIter >= theArgNb)
11855       {
11856         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11857         return 1;
11858       }
11859
11860       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
11861
11862       // We allow RaytracingDepth be more than 10 in case of GI enabled
11863       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
11864       {
11865         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
11866         return 1;
11867       }
11868       else
11869       {
11870         aParams.RaytracingDepth = aDepth;
11871       }
11872     }
11873     else if (aFlag == "-shad"
11874           || aFlag == "-shadows")
11875     {
11876       if (toPrint)
11877       {
11878         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
11879         continue;
11880       }
11881
11882       Standard_Boolean toEnable = Standard_True;
11883       if (++anArgIter < theArgNb
11884       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11885       {
11886         --anArgIter;
11887       }
11888       aParams.IsShadowEnabled = toEnable;
11889     }
11890     else if (aFlag == "-refl"
11891           || aFlag == "-reflections")
11892     {
11893       if (toPrint)
11894       {
11895         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
11896         continue;
11897       }
11898
11899       Standard_Boolean toEnable = Standard_True;
11900       if (++anArgIter < theArgNb
11901       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11902       {
11903         --anArgIter;
11904       }
11905       aParams.IsReflectionEnabled = toEnable;
11906     }
11907     else if (aFlag == "-fsaa")
11908     {
11909       if (toPrint)
11910       {
11911         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
11912         continue;
11913       }
11914
11915       Standard_Boolean toEnable = Standard_True;
11916       if (++anArgIter < theArgNb
11917       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11918       {
11919         --anArgIter;
11920       }
11921       aParams.IsAntialiasingEnabled = toEnable;
11922     }
11923     else if (aFlag == "-gleam")
11924     {
11925       if (toPrint)
11926       {
11927         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
11928         continue;
11929       }
11930
11931       Standard_Boolean toEnable = Standard_True;
11932       if (++anArgIter < theArgNb
11933       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11934       {
11935         --anArgIter;
11936       }
11937       aParams.IsTransparentShadowEnabled = toEnable;
11938     }
11939     else if (aFlag == "-gi")
11940     {
11941       if (toPrint)
11942       {
11943         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
11944         continue;
11945       }
11946
11947       Standard_Boolean toEnable = Standard_True;
11948       if (++anArgIter < theArgNb
11949       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11950       {
11951         --anArgIter;
11952       }
11953       aParams.IsGlobalIlluminationEnabled = toEnable;
11954       if (!toEnable)
11955       {
11956         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
11957       }
11958     }
11959     else if (aFlag == "-blockedrng"
11960           || aFlag == "-brng")
11961     {
11962       if (toPrint)
11963       {
11964         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
11965         continue;
11966       }
11967
11968       Standard_Boolean toEnable = Standard_True;
11969       if (++anArgIter < theArgNb
11970         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
11971       {
11972         --anArgIter;
11973       }
11974       aParams.CoherentPathTracingMode = toEnable;
11975     }
11976     else if (aFlag == "-maxrad")
11977     {
11978       if (toPrint)
11979       {
11980         theDI << aParams.RadianceClampingValue << " ";
11981         continue;
11982       }
11983       else if (++anArgIter >= theArgNb)
11984       {
11985         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11986         return 1;
11987       }
11988
11989       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
11990       if (!aMaxRadStr.IsRealValue())
11991       {
11992         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11993         return 1;
11994       }
11995
11996       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
11997       if (aMaxRadiance <= 0.0)
11998       {
11999         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
12000         return 1;
12001       }
12002       else
12003       {
12004         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
12005       }
12006     }
12007     else if (aFlag == "-iss")
12008     {
12009       if (toPrint)
12010       {
12011         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
12012         continue;
12013       }
12014
12015       Standard_Boolean toEnable = Standard_True;
12016       if (++anArgIter < theArgNb
12017         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12018       {
12019         --anArgIter;
12020       }
12021       aParams.AdaptiveScreenSampling = toEnable;
12022     }
12023     else if (aFlag == "-issatomic")
12024     {
12025       if (toPrint)
12026       {
12027         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
12028         continue;
12029       }
12030
12031       Standard_Boolean toEnable = Standard_True;
12032       if (++anArgIter < theArgNb
12033       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12034       {
12035         --anArgIter;
12036       }
12037       aParams.AdaptiveScreenSamplingAtomic = toEnable;
12038     }
12039     else if (aFlag == "-issd")
12040     {
12041       if (toPrint)
12042       {
12043         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
12044         continue;
12045       }
12046
12047       Standard_Boolean toEnable = Standard_True;
12048       if (++anArgIter < theArgNb
12049         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12050       {
12051         --anArgIter;
12052       }
12053       aParams.ShowSamplingTiles = toEnable;
12054     }
12055     else if (aFlag == "-tilesize")
12056     {
12057       if (toPrint)
12058       {
12059         theDI << aParams.RayTracingTileSize << " ";
12060         continue;
12061       }
12062       else if (++anArgIter >= theArgNb)
12063       {
12064         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12065         return 1;
12066       }
12067
12068       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
12069       if (aTileSize < 1)
12070       {
12071         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
12072         return 1;
12073       }
12074       aParams.RayTracingTileSize = aTileSize;
12075     }
12076     else if (aFlag == "-nbtiles")
12077     {
12078       if (toPrint)
12079       {
12080         theDI << aParams.NbRayTracingTiles << " ";
12081         continue;
12082       }
12083       else if (++anArgIter >= theArgNb)
12084       {
12085         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12086         return 1;
12087       }
12088
12089       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
12090       if (aNbTiles < -1)
12091       {
12092         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
12093         return 1;
12094       }
12095       else if (aNbTiles > 0
12096             && (aNbTiles < 64
12097              || aNbTiles > 1024))
12098       {
12099         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
12100       }
12101       aParams.NbRayTracingTiles = aNbTiles;
12102     }
12103     else if (aFlag == "-env")
12104     {
12105       if (toPrint)
12106       {
12107         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
12108         continue;
12109       }
12110
12111       Standard_Boolean toEnable = Standard_True;
12112       if (++anArgIter < theArgNb
12113         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12114       {
12115         --anArgIter;
12116       }
12117       aParams.UseEnvironmentMapBackground = toEnable;
12118     }
12119     else if (aFlag == "-ignorenormalmap")
12120     {
12121       if (toPrint)
12122       {
12123         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
12124         continue;
12125       }
12126
12127       Standard_Boolean toEnable = Standard_True;
12128       if (++anArgIter < theArgNb
12129         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12130       {
12131         --anArgIter;
12132       }
12133       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
12134     }
12135     else if (aFlag == "-twoside")
12136     {
12137       if (toPrint)
12138       {
12139         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
12140         continue;
12141       }
12142
12143       Standard_Boolean toEnable = Standard_True;
12144       if (++anArgIter < theArgNb
12145         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12146       {
12147         --anArgIter;
12148       }
12149       aParams.TwoSidedBsdfModels = toEnable;
12150     }
12151     else if (aFlag == "-shademodel"
12152           || aFlag == "-shadingmodel"
12153           || aFlag == "-shading")
12154     {
12155       if (toPrint)
12156       {
12157         switch (aView->ShadingModel())
12158         {
12159           case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
12160           case Graphic3d_TOSM_UNLIT:     theDI << "unlit ";    break;
12161           case Graphic3d_TOSM_FACET:     theDI << "flat ";     break;
12162           case Graphic3d_TOSM_VERTEX:    theDI << "gouraud ";  break;
12163           case Graphic3d_TOSM_FRAGMENT:  theDI << "phong ";    break;
12164           case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
12165           case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
12166         }
12167         continue;
12168       }
12169
12170       if (++anArgIter >= theArgNb)
12171       {
12172         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12173       }
12174
12175       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TOSM_DEFAULT;
12176       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
12177        && aModel != Graphic3d_TOSM_DEFAULT)
12178       {
12179         aView->SetShadingModel (aModel);
12180       }
12181       else
12182       {
12183         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
12184         return 1;
12185       }
12186     }
12187     else if (aFlag == "-pbrenvpow2size"
12188           || aFlag == "-pbrenvp2s"
12189           || aFlag == "-pep2s")
12190     {
12191       if (++anArgIter >= theArgNb)
12192       {
12193         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12194         return 1;
12195       }
12196
12197       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
12198       if (aPbrEnvPow2Size < 1)
12199       {
12200         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
12201         return 1;
12202       }
12203       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
12204     }
12205     else if (aFlag == "-pbrenvspecmaplevelsnumber"
12206           || aFlag == "-pbrenvspecmapnblevels"
12207           || aFlag == "-pbrenvspecmaplevels"
12208           || aFlag == "-pbrenvsmln"
12209           || aFlag == "-pesmln")
12210     {
12211       if (++anArgIter >= theArgNb)
12212       {
12213         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12214         return 1;
12215       }
12216
12217       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
12218       if (aPbrEnvSpecMapNbLevels < 2)
12219       {
12220         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
12221         return 1;
12222       }
12223       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
12224     }
12225     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
12226           || aFlag == "-pbrenvbakingdiffsamples"
12227           || aFlag == "-pbrenvbdsn")
12228     {
12229       if (++anArgIter >= theArgNb)
12230       {
12231         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12232         return 1;
12233       }
12234
12235       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
12236       if (aPbrEnvBakingDiffNbSamples < 1)
12237       {
12238         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environtment has to be greater or equal 1");
12239         return 1;
12240       }
12241       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
12242     }
12243     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
12244           || aFlag == "-pbrenvbakingspecsamples"
12245           || aFlag == "-pbrenvbssn")
12246     {
12247     if (++anArgIter >= theArgNb)
12248     {
12249       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12250       return 1;
12251     }
12252
12253     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
12254     if (aPbrEnvBakingSpecNbSamples < 1)
12255     {
12256       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environtment has to be greater or equal 1");
12257       return 1;
12258     }
12259     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
12260     }
12261     else if (aFlag == "-pbrenvbakingprobability"
12262           || aFlag == "-pbrenvbp")
12263     {
12264       if (++anArgIter >= theArgNb)
12265       {
12266         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12267         return 1;
12268       }
12269       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
12270       if (aPbrEnvBakingProbability < 0.f
12271        || aPbrEnvBakingProbability > 1.f)
12272       {
12273         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environtment has to be in range of [0, 1]");
12274         return 1;
12275       }
12276       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
12277     }
12278     else if (aFlag == "-resolution")
12279     {
12280       if (++anArgIter >= theArgNb)
12281       {
12282         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12283         return 1;
12284       }
12285
12286       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
12287       if (aResolution.IsIntegerValue())
12288       {
12289         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
12290       }
12291       else
12292       {
12293         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
12294         return 1;
12295       }
12296     }
12297     else if (aFlag == "-rebuildglsl"
12298           || aFlag == "-rebuild")
12299     {
12300       if (toPrint)
12301       {
12302         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
12303         continue;
12304       }
12305
12306       Standard_Boolean toEnable = Standard_True;
12307       if (++anArgIter < theArgNb
12308           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12309       {
12310         --anArgIter;
12311       }
12312       aParams.RebuildRayTracingShaders = toEnable;
12313     }
12314     else if (aFlag == "-focal")
12315     {
12316       if (++anArgIter >= theArgNb)
12317       {
12318         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12319         return 1;
12320       }
12321
12322       TCollection_AsciiString aParam (theArgVec[anArgIter]);
12323       if (aParam.IsRealValue())
12324       {
12325         float aFocalDist = static_cast<float> (aParam.RealValue());
12326         if (aFocalDist < 0)
12327         {
12328           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12329           return 1;
12330         }
12331         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
12332       }
12333       else
12334       {
12335         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12336         return 1;
12337       }
12338     }
12339     else if (aFlag == "-aperture")
12340     {
12341       if (++anArgIter >= theArgNb)
12342       {
12343         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12344         return 1;
12345       }
12346
12347       TCollection_AsciiString aParam(theArgVec[anArgIter]);
12348       if (aParam.IsRealValue())
12349       {
12350         float aApertureSize = static_cast<float> (aParam.RealValue());
12351         if (aApertureSize < 0)
12352         {
12353           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12354           return 1;
12355         }
12356         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
12357       }
12358       else
12359       {
12360         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12361         return 1;
12362       }
12363     }
12364     else if (aFlag == "-exposure")
12365     {
12366       if (++anArgIter >= theArgNb)
12367       {
12368         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12369         return 1;
12370       }
12371
12372       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
12373       if (anExposure.IsRealValue())
12374       {
12375         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
12376       }
12377       else
12378       {
12379         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12380         return 1;
12381       }
12382     }
12383     else if (aFlag == "-whitepoint")
12384     {
12385       if (++anArgIter >= theArgNb)
12386       {
12387         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12388         return 1;
12389       }
12390
12391       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
12392       if (aWhitePoint.IsRealValue())
12393       {
12394         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
12395       }
12396       else
12397       {
12398         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12399         return 1;
12400       }
12401     }
12402     else if (aFlag == "-tonemapping")
12403     {
12404       if (++anArgIter >= theArgNb)
12405       {
12406         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12407         return 1;
12408       }
12409
12410       TCollection_AsciiString aMode (theArgVec[anArgIter]);
12411       aMode.LowerCase();
12412
12413       if (aMode == "disabled")
12414       {
12415         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
12416       }
12417       else if (aMode == "filmic")
12418       {
12419         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
12420       }
12421       else
12422       {
12423         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12424         return 1;
12425       }
12426     }
12427     else if (aFlag == "-performancestats"
12428           || aFlag == "-performancecounters"
12429           || aFlag == "-perfstats"
12430           || aFlag == "-perfcounters"
12431           || aFlag == "-stats")
12432     {
12433       if (++anArgIter >= theArgNb)
12434       {
12435         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12436         return 1;
12437       }
12438
12439       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
12440       aFlagsStr.LowerCase();
12441       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
12442       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
12443       {
12444         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12445         return 1;
12446       }
12447       aView->ChangeRenderingParams().CollectedStats = aFlags;
12448       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
12449     }
12450     else if (aFlag == "-perfupdateinterval"
12451           || aFlag == "-statsupdateinterval")
12452     {
12453       if (++anArgIter >= theArgNb)
12454       {
12455         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12456         return 1;
12457       }
12458       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12459     }
12460     else if (aFlag == "-perfchart"
12461           || aFlag == "-statschart")
12462     {
12463       if (++anArgIter >= theArgNb)
12464       {
12465         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12466         return 1;
12467       }
12468       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
12469     }
12470     else if (aFlag == "-perfchartmax"
12471           || aFlag == "-statschartmax")
12472     {
12473       if (++anArgIter >= theArgNb)
12474       {
12475         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12476         return 1;
12477       }
12478       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12479     }
12480     else if (aFlag == "-frustumculling"
12481           || aFlag == "-culling")
12482     {
12483       if (toPrint)
12484       {
12485         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
12486                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
12487                                                                                                    "noUpdate") << " ";
12488         continue;
12489       }
12490
12491       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
12492       if (++anArgIter < theArgNb)
12493       {
12494         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
12495         aStateStr.LowerCase();
12496         bool toEnable = true;
12497         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
12498         {
12499           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
12500         }
12501         else if (aStateStr == "noupdate"
12502               || aStateStr == "freeze")
12503         {
12504           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
12505         }
12506         else
12507         {
12508           --anArgIter;
12509         }
12510       }
12511       aParams.FrustumCullingState = aState;
12512     }
12513     else
12514     {
12515       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
12516       return 1;
12517     }
12518   }
12519
12520   // set current view parameters as defaults
12521   if (toSyncDefaults)
12522   {
12523     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
12524   }
12525   if (toSyncAllViews)
12526   {
12527     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
12528     {
12529       aViewIter.Value()->ChangeRenderingParams() = aParams;
12530     }
12531   }
12532   return 0;
12533 }
12534
12535 //=======================================================================
12536 //function : searchInfo
12537 //purpose  :
12538 //=======================================================================
12539 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12540                                            const TCollection_AsciiString&              theKey)
12541 {
12542   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12543   {
12544     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12545     {
12546       return anIter.Value();
12547     }
12548   }
12549   return TCollection_AsciiString();
12550 }
12551
12552 //=======================================================================
12553 //function : VStatProfiler
12554 //purpose  :
12555 //=======================================================================
12556 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12557                                        Standard_Integer  theArgNb,
12558                                        const char**      theArgVec)
12559 {
12560   Handle(V3d_View) aView = ViewerTest::CurrentView();
12561   if (aView.IsNull())
12562   {
12563     Message::SendFail ("Error: no active viewer");
12564     return 1;
12565   }
12566
12567   Standard_Boolean toRedraw = Standard_True;
12568   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12569   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12570   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12571   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12572   {
12573     Standard_CString        anArg (theArgVec[anArgIter]);
12574     TCollection_AsciiString aFlag (anArg);
12575     aFlag.LowerCase();
12576     if (aFlag == "-noredraw")
12577     {
12578       toRedraw = Standard_False;
12579     }
12580     else
12581     {
12582       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12583       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12584       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12585       else if (aFlag == "alllayers"
12586             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12587       else if (aFlag == "allstructs"
12588             || aFlag == "allstructures"
12589             || aFlag == "structs"
12590             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12591       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12592       else if (aFlag == "allarrays"
12593             || aFlag == "fillarrays"
12594             || aFlag == "linearrays"
12595             || aFlag == "pointarrays"
12596             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12597       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12598       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12599       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12600       else if (aFlag == "geommem"
12601             || aFlag == "texturemem"
12602             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12603       else if (aFlag == "elapsedframe"
12604             || aFlag == "cpuframeaverage"
12605             || aFlag == "cpupickingaverage"
12606             || aFlag == "cpucullingaverage"
12607             || aFlag == "cpudynaverage"
12608             || aFlag == "cpuframemax"
12609             || aFlag == "cpupickingmax"
12610             || aFlag == "cpucullingmax"
12611             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12612       else
12613       {
12614         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12615         continue;
12616       }
12617
12618       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12619     }
12620   }
12621
12622   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12623   {
12624     aView->ChangeRenderingParams().CollectedStats =
12625       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12626
12627     if (toRedraw)
12628     {
12629       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12630       aView->Redraw();
12631       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12632     }
12633
12634     TColStd_IndexedDataMapOfStringString aDict;
12635     aView->StatisticInformation (aDict);
12636
12637     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12638
12639     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12640     {
12641       Standard_CString        anArg(theArgVec[anArgIter]);
12642       TCollection_AsciiString aFlag(anArg);
12643       aFlag.LowerCase();
12644       if (aFlag == "fps")
12645       {
12646         theDI << searchInfo (aDict, "FPS") << " ";
12647       }
12648       else if (aFlag == "cpu")
12649       {
12650         theDI << searchInfo (aDict, "CPU FPS") << " ";
12651       }
12652       else if (aFlag == "alllayers")
12653       {
12654         theDI << searchInfo (aDict, "Layers") << " ";
12655       }
12656       else if (aFlag == "layers")
12657       {
12658         theDI << searchInfo (aDict, "Rendered layers") << " ";
12659       }
12660       else if (aFlag == "allstructs"
12661             || aFlag == "allstructures")
12662       {
12663         theDI << searchInfo (aDict, "Structs") << " ";
12664       }
12665       else if (aFlag == "structs"
12666             || aFlag == "structures")
12667       {
12668         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
12669         if (aRend.IsEmpty()) // all structures rendered
12670         {
12671           aRend = searchInfo (aDict, "Structs");
12672         }
12673         theDI << aRend << " ";
12674       }
12675       else if (aFlag == "groups")
12676       {
12677         theDI << searchInfo (aDict, "Rendered groups") << " ";
12678       }
12679       else if (aFlag == "allarrays")
12680       {
12681         theDI << searchInfo (aDict, "Rendered arrays") << " ";
12682       }
12683       else if (aFlag == "fillarrays")
12684       {
12685         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
12686       }
12687       else if (aFlag == "linearrays")
12688       {
12689         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
12690       }
12691       else if (aFlag == "pointarrays")
12692       {
12693         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
12694       }
12695       else if (aFlag == "textarrays")
12696       {
12697         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
12698       }
12699       else if (aFlag == "triangles")
12700       {
12701         theDI << searchInfo (aDict, "Rendered triangles") << " ";
12702       }
12703       else if (aFlag == "points")
12704       {
12705         theDI << searchInfo (aDict, "Rendered points") << " ";
12706       }
12707       else if (aFlag == "geommem")
12708       {
12709         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
12710       }
12711       else if (aFlag == "texturemem")
12712       {
12713         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
12714       }
12715       else if (aFlag == "framemem")
12716       {
12717         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
12718       }
12719       else if (aFlag == "elapsedframe")
12720       {
12721         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
12722       }
12723       else if (aFlag == "cpuframe_average")
12724       {
12725         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
12726       }
12727       else if (aFlag == "cpupicking_average")
12728       {
12729         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
12730       }
12731       else if (aFlag == "cpuculling_average")
12732       {
12733         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
12734       }
12735       else if (aFlag == "cpudyn_average")
12736       {
12737         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
12738       }
12739       else if (aFlag == "cpuframe_max")
12740       {
12741         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
12742       }
12743       else if (aFlag == "cpupicking_max")
12744       {
12745         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
12746       }
12747       else if (aFlag == "cpuculling_max")
12748       {
12749         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
12750       }
12751       else if (aFlag == "cpudyn_max")
12752       {
12753         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
12754       }
12755     }
12756   }
12757   else
12758   {
12759     if (toRedraw)
12760     {
12761       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12762       aView->Redraw();
12763       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12764     }
12765     theDI << "Statistic info:\n" << aView->StatisticInformation();
12766   }
12767   return 0;
12768 }
12769
12770 //=======================================================================
12771 //function : VXRotate
12772 //purpose  :
12773 //=======================================================================
12774 static Standard_Integer VXRotate (Draw_Interpretor& di,
12775                                    Standard_Integer argc,
12776                                    const char ** argv)
12777 {
12778   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
12779   if (aContext.IsNull())
12780   {
12781     di << argv[0] << "ERROR : use 'vinit' command before \n";
12782     return 1;
12783   }
12784
12785   if (argc != 3)
12786   {
12787     di << "ERROR : Usage : " << argv[0] << " name angle\n";
12788     return 1;
12789   }
12790
12791   TCollection_AsciiString aName (argv[1]);
12792   Standard_Real anAngle = Draw::Atof (argv[2]);
12793
12794   // find object
12795   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
12796   Handle(AIS_InteractiveObject) anIObj;
12797   if (!aMap.Find2 (aName, anIObj))
12798   {
12799     di << "Use 'vdisplay' before\n";
12800     return 1;
12801   }
12802
12803   gp_Trsf aTransform;
12804   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
12805   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
12806
12807   aContext->SetLocation (anIObj, aTransform);
12808   aContext->UpdateCurrentViewer();
12809   return 0;
12810 }
12811
12812 //===============================================================================================
12813 //function : VManipulator
12814 //purpose  :
12815 //===============================================================================================
12816 static int VManipulator (Draw_Interpretor& theDi,
12817                          Standard_Integer  theArgsNb,
12818                          const char**      theArgVec)
12819 {
12820   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
12821   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
12822   ViewerTest::GetAISContext()->MainSelector()->SetPickClosest (Standard_False);
12823   if (aCurrentView.IsNull()
12824    || aViewer.IsNull())
12825   {
12826     Message::SendFail ("Error: no active viewer");
12827     return 1;
12828   }
12829
12830   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
12831   Standard_Integer anArgIter = 1;
12832   for (; anArgIter < theArgsNb; ++anArgIter)
12833   {
12834     anUpdateTool.parseRedrawMode (theArgVec[anArgIter]);
12835   }
12836
12837   ViewerTest_CmdParser aCmd;
12838   aCmd.SetDescription ("Manages manipulator for interactive objects:");
12839   aCmd.AddOption ("attach",         "... object - attach manipulator to an object");
12840   aCmd.AddOption ("adjustPosition", "... {0|1} - adjust position when attaching");
12841   aCmd.AddOption ("adjustSize",     "... {0|1} - adjust size when attaching ");
12842   aCmd.AddOption ("enableModes",    "... {0|1} - enable modes when attaching ");
12843   aCmd.AddOption ("view",           "... {active | [view name]} - define view in which manipulator will be displayed, 'all' by default");
12844   aCmd.AddOption ("detach",         "...       - detach manipulator");
12845
12846   aCmd.AddOption ("startTransform",   "... mouse_x mouse_y - invoke start transformation");
12847   aCmd.AddOption ("transform",        "... mouse_x mouse_y - invoke transformation");
12848   aCmd.AddOption ("stopTransform",    "... [abort] - invoke stop transformation");
12849
12850   aCmd.AddOption ("move",   "... x y z - move object");
12851   aCmd.AddOption ("rotate", "... x y z dx dy dz angle - rotate object");
12852   aCmd.AddOption ("scale",  "... factor - scale object");
12853
12854   aCmd.AddOption ("autoActivate",      "... {0|1} - set activation on detection");
12855   aCmd.AddOption ("followTranslation", "... {0|1} - set following translation transform");
12856   aCmd.AddOption ("followRotation",    "... {0|1} - set following rotation transform");
12857   aCmd.AddOption ("followDragging",    "... {0|1} - set following dragging transform");
12858   aCmd.AddOption ("gap",               "... value - set gap between sub-parts");
12859   aCmd.AddOption ("part",              "... axis mode {0|1} - set visual part");
12860   aCmd.AddOption ("parts",             "... all axes mode {0|1} - set visual part");
12861   aCmd.AddOption ("pos",               "... x y z [nx ny nz [xx xy xz]] - set position of manipulator");
12862   aCmd.AddOption ("size",              "... size - set size of manipulator");
12863   aCmd.AddOption ("zoomable",          "... {0|1} - set zoom persistence");
12864
12865   aCmd.Parse (theArgsNb, theArgVec);
12866
12867   if (aCmd.HasOption ("help"))
12868   {
12869     theDi.PrintHelp (theArgVec[0]);
12870     return 0;
12871   }
12872
12873   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
12874
12875   TCollection_AsciiString aName (aCmd.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0).c_str());
12876
12877   if (aName.IsEmpty())
12878   {
12879     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
12880     return 1;
12881   }
12882
12883   // ----------------------------------
12884   // detach existing manipulator object
12885   // ----------------------------------
12886
12887   if (aCmd.HasOption ("detach"))
12888   {
12889     if (!aMapAIS.IsBound2 (aName))
12890     {
12891       Message::SendFail() << "Syntax error: could not find \"" << aName << "\" AIS object";
12892       return 1;
12893     }
12894
12895     Handle(AIS_Manipulator) aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12896     if (aManipulator.IsNull())
12897     {
12898       Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12899       return 1;
12900     }
12901
12902     aManipulator->Detach();
12903     aMapAIS.UnBind2 (aName);
12904     ViewerTest::GetAISContext()->Remove (aManipulator, Standard_True);
12905
12906     return 0;
12907   }
12908
12909   // -----------------------------------------------
12910   // find or create manipulator if it does not exist
12911   // -----------------------------------------------
12912
12913   Handle(AIS_Manipulator) aManipulator;
12914   if (!aMapAIS.IsBound2 (aName))
12915   {
12916     std::cout << theArgVec[0] << ": AIS object \"" << aName << "\" has been created.\n";
12917
12918     aManipulator = new AIS_Manipulator();
12919     aManipulator->SetModeActivationOnDetection (true);
12920     aMapAIS.Bind (aManipulator, aName);
12921   }
12922   else
12923   {
12924     aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
12925     if (aManipulator.IsNull())
12926     {
12927       Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
12928       return 1;
12929     }
12930   }
12931
12932   // -----------------------------------------
12933   // change properties of manipulator instance
12934   // -----------------------------------------
12935
12936   if (aCmd.HasOption ("autoActivate", 1, Standard_True))
12937   {
12938     aManipulator->SetModeActivationOnDetection (aCmd.ArgBool ("autoActivate"));
12939   }
12940   if (aCmd.HasOption ("followTranslation", 1, Standard_True))
12941   {
12942     aManipulator->ChangeTransformBehavior().SetFollowTranslation (aCmd.ArgBool ("followTranslation"));
12943   }
12944   if (aCmd.HasOption ("followRotation", 1, Standard_True))
12945   {
12946     aManipulator->ChangeTransformBehavior().SetFollowRotation (aCmd.ArgBool ("followRotation"));
12947   }
12948   if (aCmd.HasOption("followDragging", 1, Standard_True))
12949   {
12950     aManipulator->ChangeTransformBehavior().SetFollowDragging(aCmd.ArgBool("followDragging"));
12951   }
12952   if (aCmd.HasOption ("gap", 1, Standard_True))
12953   {
12954     aManipulator->SetGap (aCmd.ArgFloat ("gap"));
12955   }
12956   if (aCmd.HasOption ("part", 3, Standard_True))
12957   {
12958     Standard_Integer anAxis = aCmd.ArgInt  ("part", 0);
12959     Standard_Integer aMode  = aCmd.ArgInt  ("part", 1);
12960     Standard_Boolean aOnOff = aCmd.ArgBool ("part", 2);
12961     if (aMode < 1 || aMode > 4)
12962     {
12963       Message::SendFail ("Syntax error: mode value should be in range [1, 4]");
12964       return 1;
12965     }
12966
12967     aManipulator->SetPart (anAxis, static_cast<AIS_ManipulatorMode> (aMode), aOnOff);
12968   }
12969   if (aCmd.HasOption("parts", 2, Standard_True))
12970   {
12971     Standard_Integer aMode = aCmd.ArgInt("parts", 0);
12972     Standard_Boolean aOnOff = aCmd.ArgBool("parts", 1);
12973     if (aMode < 1 || aMode > 4)
12974     {
12975       Message::SendFail ("Syntax error: mode value should be in range [1, 4]");
12976       return 1;
12977     }
12978
12979     aManipulator->SetPart(static_cast<AIS_ManipulatorMode>(aMode), aOnOff);
12980   }
12981   if (aCmd.HasOption ("pos", 3, Standard_True))
12982   {
12983     gp_Pnt aLocation = aCmd.ArgPnt ("pos", 0);
12984     gp_Dir aVDir     = aCmd.HasOption ("pos", 6) ? gp_Dir (aCmd.ArgVec ("pos", 3)) : aManipulator->Position().Direction();
12985     gp_Dir aXDir     = aCmd.HasOption ("pos", 9) ? gp_Dir (aCmd.ArgVec ("pos", 6)) : aManipulator->Position().XDirection();
12986
12987     aManipulator->SetPosition (gp_Ax2 (aLocation, aVDir, aXDir));
12988   }
12989   if (aCmd.HasOption ("size", 1, Standard_True))
12990   {
12991     aManipulator->SetSize (aCmd.ArgFloat ("size"));
12992   }
12993   if (aCmd.HasOption ("zoomable", 1, Standard_True))
12994   {
12995     aManipulator->SetZoomPersistence (!aCmd.ArgBool ("zoomable"));
12996
12997     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
12998     {
12999       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
13000       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
13001     }
13002   }
13003
13004   // ---------------------------------------------------
13005   // attach, detach or access manipulator from an object
13006   // ---------------------------------------------------
13007
13008   if (aCmd.HasOption ("attach"))
13009   {
13010     // Find an object and attach manipulator to it
13011     if (!aCmd.HasOption ("attach", 1, Standard_True))
13012     {
13013       return 1;
13014     }
13015
13016     TCollection_AsciiString anObjName (aCmd.Arg ("attach", 0).c_str());
13017     Handle(AIS_InteractiveObject) anObject;
13018     if (!aMapAIS.Find2 (anObjName, anObject))
13019     {
13020       Message::SendFail() << "Syntax error: AIS object \"" << anObjName << "\" does not exist";
13021       return 1;
13022     }
13023
13024     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS);
13025          anIter.More(); anIter.Next())
13026     {
13027       Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
13028       if (!aManip.IsNull()
13029        && aManip->IsAttached()
13030        && aManip->Object() == anObject)
13031       {
13032         Message::SendFail() << "Syntax error: AIS object \"" << anObjName << "\" already has manipulator";
13033         return 1;
13034       }
13035     }
13036
13037     AIS_Manipulator::OptionsForAttach anOptions;
13038     if (aCmd.HasOption ("adjustPosition", 1, Standard_True))
13039     {
13040       anOptions.SetAdjustPosition (aCmd.ArgBool ("adjustPosition"));
13041     }
13042     if (aCmd.HasOption ("adjustSize", 1, Standard_True))
13043     {
13044       anOptions.SetAdjustSize (aCmd.ArgBool ("adjustSize"));
13045     }
13046     if (aCmd.HasOption ("enableModes", 1, Standard_True))
13047     {
13048       anOptions.SetEnableModes (aCmd.ArgBool ("enableModes"));
13049     }
13050
13051     aManipulator->Attach (anObject, anOptions);
13052
13053     // Check view option
13054     if (aCmd.HasOption ("view"))
13055     {
13056       if (!aCmd.HasOption ("view", 1, Standard_True))
13057       {
13058         return 1;
13059       }
13060       TCollection_AsciiString aViewString (aCmd.Arg ("view", 0).c_str());
13061       Handle(V3d_View) aView;
13062       if (aViewString.IsEqual ("active"))
13063       {
13064         aView = ViewerTest::CurrentView();
13065       }
13066       else // Check view name
13067       {
13068         ViewerTest_Names aViewNames (aViewString);
13069         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
13070         {
13071           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
13072           return 1;
13073         }
13074         aView = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
13075         if (aView.IsNull())
13076         {
13077           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
13078           return 1;
13079         }
13080       }
13081       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
13082         anIter (ViewerTest_myViews); anIter.More(); anIter.Next())
13083       {
13084         ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), Standard_False);
13085       }
13086       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aView, Standard_True);
13087     }
13088   }
13089
13090   // --------------------------------------
13091   // apply transformation using manipulator
13092   // --------------------------------------
13093
13094   if (aCmd.HasOption ("startTransform", 2, Standard_True))
13095   {
13096     aManipulator->StartTransform (aCmd.ArgInt ("startTransform", 0), aCmd.ArgInt ("startTransform", 1), ViewerTest::CurrentView());
13097   }
13098   if (aCmd.HasOption ("transform", 2, Standard_True))
13099   {
13100     aManipulator->Transform (aCmd.ArgInt ("transform", 0), aCmd.ArgInt ("transform", 1), ViewerTest::CurrentView());
13101   }
13102   if (aCmd.HasOption ("stopTransform"))
13103   {
13104     Standard_Boolean toApply = !aCmd.HasOption ("stopTransform", 1) || (aCmd.Arg ("stopTransform", 0) != "abort");
13105
13106     aManipulator->StopTransform (toApply);
13107   }
13108
13109   gp_Trsf aT;
13110   if (aCmd.HasOption ("move", 3, Standard_True))
13111   {
13112     aT.SetTranslationPart (aCmd.ArgVec ("move"));
13113   }
13114   if (aCmd.HasOption ("rotate", 7, Standard_True))
13115   {
13116     aT.SetRotation (gp_Ax1 (aCmd.ArgPnt ("rotate", 0), aCmd.ArgVec ("rotate", 3)), aCmd.ArgDouble ("rotate", 6));
13117   }
13118   if (aCmd.HasOption ("scale", 1))
13119   {
13120     aT.SetScale (gp_Pnt(), aCmd.ArgDouble("scale"));
13121   }
13122
13123   if (aT.Form() != gp_Identity)
13124   {
13125     aManipulator->Transform (aT);
13126   }
13127
13128   ViewerTest::GetAISContext()->Redisplay (aManipulator, Standard_True);
13129
13130   return 0;
13131 }
13132
13133 //===============================================================================================
13134 //function : VSelectionProperties
13135 //purpose  :
13136 //===============================================================================================
13137 static int VSelectionProperties (Draw_Interpretor& theDi,
13138                                  Standard_Integer  theArgsNb,
13139                                  const char**      theArgVec)
13140 {
13141   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
13142   if (aCtx.IsNull())
13143   {
13144     Message::SendFail ("Error: no active viewer");
13145     return 1;
13146   }
13147
13148   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
13149   {
13150     // handle obsolete alias
13151     bool toEnable = true;
13152     if (theArgsNb < 2)
13153     {
13154       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
13155       return 0;
13156     }
13157     else if (theArgsNb != 2
13158          || !Draw::ParseOnOff (theArgVec[1], toEnable))
13159     {
13160       Message::SendFail ("Syntax error: wrong number of parameters");
13161       return 1;
13162     }
13163     if (toEnable != aCtx->ToHilightSelected())
13164     {
13165       aCtx->ClearDetected();
13166       aCtx->SetToHilightSelected (toEnable);
13167     }
13168     return 0;
13169   }
13170
13171   Standard_Boolean toPrint  = theArgsNb == 1;
13172   Standard_Boolean toRedraw = Standard_False;
13173   Standard_Integer anArgIter = 1;
13174   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
13175   if (anArgIter < theArgsNb)
13176   {
13177     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
13178     anArgFirst.LowerCase();
13179     ++anArgIter;
13180     if (anArgFirst == "dynhighlight"
13181      || anArgFirst == "dynhilight"
13182      || anArgFirst == "dynamichighlight"
13183      || anArgFirst == "dynamichilight")
13184     {
13185       aType = Prs3d_TypeOfHighlight_Dynamic;
13186     }
13187     else if (anArgFirst == "localdynhighlight"
13188           || anArgFirst == "localdynhilight"
13189           || anArgFirst == "localdynamichighlight"
13190           || anArgFirst == "localdynamichilight")
13191     {
13192       aType = Prs3d_TypeOfHighlight_LocalDynamic;
13193     }
13194     else if (anArgFirst == "selhighlight"
13195           || anArgFirst == "selhilight"
13196           || anArgFirst == "selectedhighlight"
13197           || anArgFirst == "selectedhilight")
13198     {
13199       aType = Prs3d_TypeOfHighlight_Selected;
13200     }
13201     else if (anArgFirst == "localselhighlight"
13202           || anArgFirst == "localselhilight"
13203           || anArgFirst == "localselectedhighlight"
13204           || anArgFirst == "localselectedhilight")
13205     {
13206       aType = Prs3d_TypeOfHighlight_LocalSelected;
13207     }
13208     else
13209     {
13210       --anArgIter;
13211     }
13212   }
13213   for (; anArgIter < theArgsNb; ++anArgIter)
13214   {
13215     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13216     anArg.LowerCase();
13217     if (anArg == "-help")
13218     {
13219       theDi.PrintHelp (theArgVec[0]);
13220       return 0;
13221     }
13222     else if (anArg == "-print")
13223     {
13224       toPrint = Standard_True;
13225     }
13226     else if (anArg == "-autoactivate")
13227     {
13228       Standard_Boolean toEnable = Standard_True;
13229       if (anArgIter + 1 < theArgsNb
13230        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13231       {
13232         ++anArgIter;
13233       }
13234       aCtx->SetAutoActivateSelection (toEnable);
13235     }
13236     else if (anArg == "-automatichighlight"
13237           || anArg == "-automatichilight"
13238           || anArg == "-autohighlight"
13239           || anArg == "-autohilight")
13240     {
13241       Standard_Boolean toEnable = Standard_True;
13242       if (anArgIter + 1 < theArgsNb
13243        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13244       {
13245         ++anArgIter;
13246       }
13247       aCtx->ClearSelected (false);
13248       aCtx->ClearDetected();
13249       aCtx->SetAutomaticHilight (toEnable);
13250       toRedraw = true;
13251     }
13252     else if (anArg == "-highlightselected"
13253           || anArg == "-hilightselected")
13254     {
13255       Standard_Boolean toEnable = Standard_True;
13256       if (anArgIter + 1 < theArgsNb
13257        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13258       {
13259         ++anArgIter;
13260       }
13261       aCtx->ClearDetected();
13262       aCtx->SetToHilightSelected (toEnable);
13263       toRedraw = true;
13264     }
13265     else if (anArg == "-pickstrategy"
13266           || anArg == "-pickingstrategy")
13267     {
13268       if (++anArgIter >= theArgsNb)
13269       {
13270         Message::SendFail ("Syntax error: type of highlighting is undefined");
13271         return 1;
13272       }
13273
13274       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13275       TCollection_AsciiString aVal (theArgVec[anArgIter]);
13276       aVal.LowerCase();
13277       if (aVal == "first"
13278        || aVal == "firstaccepted"
13279        || aVal == "firstacceptable")
13280       {
13281         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13282       }
13283       else if (aVal == "topmost"
13284             || aVal == "onlyTopmost")
13285       {
13286         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
13287       }
13288       else
13289       {
13290         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
13291         return 1;
13292       }
13293
13294       aCtx->SetPickingStrategy (aStrategy);
13295     }
13296     else if (anArg == "-pixtol"
13297           && anArgIter + 1 < theArgsNb)
13298     {
13299       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
13300     }
13301     else if ((anArg == "-mode"
13302            || anArg == "-dispmode")
13303           && anArgIter + 1 < theArgsNb)
13304     {
13305       if (aType == Prs3d_TypeOfHighlight_None)
13306       {
13307         Message::SendFail ("Syntax error: type of highlighting is undefined");
13308         return 1;
13309       }
13310
13311       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13312       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13313       aStyle->SetDisplayMode (aDispMode);
13314       toRedraw = Standard_True;
13315     }
13316     else if (anArg == "-layer"
13317           && anArgIter + 1 < theArgsNb)
13318     {
13319       if (aType == Prs3d_TypeOfHighlight_None)
13320       {
13321         Message::SendFail ("Syntax error: type of highlighting is undefined");
13322         return 1;
13323       }
13324
13325       ++anArgIter;
13326       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13327       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13328       {
13329         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13330         return 1;
13331       }
13332
13333       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13334       aStyle->SetZLayer (aNewLayer);
13335       toRedraw = Standard_True;
13336     }
13337     else if (anArg == "-hicolor"
13338           || anArg == "-selcolor"
13339           || anArg == "-color")
13340     {
13341       if (anArg.StartsWith ("-hi"))
13342       {
13343         aType = Prs3d_TypeOfHighlight_Dynamic;
13344       }
13345       else if (anArg.StartsWith ("-sel"))
13346       {
13347         aType = Prs3d_TypeOfHighlight_Selected;
13348       }
13349       else if (aType == Prs3d_TypeOfHighlight_None)
13350       {
13351         Message::SendFail ("Syntax error: type of highlighting is undefined");
13352         return 1;
13353       }
13354
13355       Quantity_Color aColor;
13356       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13357                                                      theArgVec + anArgIter + 1,
13358                                                      aColor);
13359       if (aNbParsed == 0)
13360       {
13361         Message::SendFail ("Syntax error: need more arguments");
13362         return 1;
13363       }
13364       anArgIter += aNbParsed;
13365
13366       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13367       aStyle->SetColor (aColor);
13368       toRedraw = Standard_True;
13369     }
13370     else if ((anArg == "-transp"
13371            || anArg == "-transparency"
13372            || anArg == "-hitransp"
13373            || anArg == "-seltransp"
13374            || anArg == "-hitransplocal"
13375            || anArg == "-seltransplocal")
13376           && anArgIter + 1 < theArgsNb)
13377     {
13378       if (anArg.StartsWith ("-hi"))
13379       {
13380         aType = Prs3d_TypeOfHighlight_Dynamic;
13381       }
13382       else if (anArg.StartsWith ("-sel"))
13383       {
13384         aType = Prs3d_TypeOfHighlight_Selected;
13385       }
13386       else if (aType == Prs3d_TypeOfHighlight_None)
13387       {
13388         Message::SendFail ("Syntax error: type of highlighting is undefined");
13389         return 1;
13390       }
13391
13392       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13393       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13394       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13395       toRedraw = Standard_True;
13396     }
13397     else if ((anArg == "-mat"
13398            || anArg == "-material")
13399           && anArgIter + 1 < theArgsNb)
13400     {
13401       if (aType == Prs3d_TypeOfHighlight_None)
13402       {
13403         Message::SendFail ("Syntax error: type of highlighting is undefined");
13404         return 1;
13405       }
13406
13407       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13408       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13409       if (aMatName != Graphic3d_NOM_DEFAULT)
13410       {
13411         ++anArgIter;
13412         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13413         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13414         Graphic3d_MaterialAspect aMat (aMatName);
13415         aMat.SetColor (aStyle->Color());
13416         aMat.SetTransparency (aStyle->Transparency());
13417         anAspect->SetFrontMaterial (aMat);
13418         anAspect->SetInteriorColor (aStyle->Color());
13419         aStyle->SetBasicFillAreaAspect (anAspect);
13420       }
13421       else
13422       {
13423         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
13424       }
13425       toRedraw = Standard_True;
13426     }
13427     else
13428     {
13429       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
13430     }
13431   }
13432
13433   if (toPrint)
13434   {
13435     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
13436     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
13437     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
13438     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
13439     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
13440     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
13441     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
13442     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
13443     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
13444     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
13445     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
13446     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
13447     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
13448     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
13449   }
13450
13451   if (aCtx->NbSelected() != 0 && toRedraw)
13452   {
13453     aCtx->HilightSelected (Standard_True);
13454   }
13455
13456   return 0;
13457 }
13458
13459 //===============================================================================================
13460 //function : VDumpSelectionImage
13461 //purpose  :
13462 //===============================================================================================
13463 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
13464                                 Standard_Integer  theArgsNb,
13465                                 const char**      theArgVec)
13466 {
13467   if (theArgsNb < 2)
13468   {
13469     Message::SendFail() << "Syntax error: wrong number arguments for '" << theArgVec[0] << "'";
13470     return 1;
13471   }
13472
13473   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13474   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13475   if (aContext.IsNull())
13476   {
13477     Message::SendFail ("Error: no active viewer");
13478     return 1;
13479   }
13480
13481   TCollection_AsciiString aFile;
13482   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13483   Handle(Graphic3d_Camera) aCustomCam;
13484   Image_Format anImgFormat = Image_Format_BGR;
13485   Standard_Integer aPickedIndex = 1;
13486   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
13487   {
13488     TCollection_AsciiString aParam (theArgVec[anArgIter]);
13489     aParam.LowerCase();
13490     if (aParam == "-type")
13491     {
13492       if (++anArgIter >= theArgsNb)
13493       {
13494         Message::SendFail ("Syntax error: wrong number parameters of flag '-depth'");
13495         return 1;
13496       }
13497
13498       TCollection_AsciiString aValue (theArgVec[anArgIter]);
13499       aValue.LowerCase();
13500       if (aValue == "depth"
13501        || aValue == "normdepth"
13502        || aValue == "normalizeddepth")
13503       {
13504         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
13505         anImgFormat = Image_Format_GrayF;
13506       }
13507       if (aValue == "depthinverted"
13508        || aValue == "normdepthinverted"
13509        || aValue == "normalizeddepthinverted"
13510        || aValue == "inverted")
13511       {
13512         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
13513         anImgFormat = Image_Format_GrayF;
13514       }
13515       else if (aValue == "unnormdepth"
13516             || aValue == "unnormalizeddepth")
13517       {
13518         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
13519         anImgFormat = Image_Format_GrayF;
13520       }
13521       else if (aValue == "objectcolor"
13522             || aValue == "object"
13523             || aValue == "color")
13524       {
13525         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
13526       }
13527       else if (aValue == "entitycolor"
13528             || aValue == "entity")
13529       {
13530         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
13531       }
13532       else if (aValue == "ownercolor"
13533             || aValue == "owner")
13534       {
13535         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
13536       }
13537       else if (aValue == "selectionmodecolor"
13538             || aValue == "selectionmode"
13539             || aValue == "selmodecolor"
13540             || aValue == "selmode")
13541       {
13542         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
13543       }
13544     }
13545     else if (aParam == "-picked"
13546           || aParam == "-pickeddepth"
13547           || aParam == "-pickedindex")
13548     {
13549       if (++anArgIter >= theArgsNb)
13550       {
13551         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
13552         return 1;
13553       }
13554
13555       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
13556     }
13557     else if (anArgIter + 1 < theArgsNb
13558           && aParam == "-xrpose")
13559     {
13560       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
13561       anXRArg.LowerCase();
13562       if (anXRArg == "base")
13563       {
13564         aCustomCam = aView->View()->BaseXRCamera();
13565       }
13566       else if (anXRArg == "head")
13567       {
13568         aCustomCam = aView->View()->PosedXRCamera();
13569       }
13570       else
13571       {
13572         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
13573         return 1;
13574       }
13575       if (aCustomCam.IsNull())
13576       {
13577         Message::SendFail() << "Error: undefined XR pose";
13578         return 0;
13579       }
13580     }
13581     else if (aFile.IsEmpty())
13582     {
13583       aFile = theArgVec[anArgIter];
13584     }
13585     else
13586     {
13587       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13588       return 1;
13589     }
13590   }
13591   if (aFile.IsEmpty())
13592   {
13593     Message::SendFail ("Syntax error: image file name is missing");
13594     return 1;
13595   }
13596
13597   Standard_Integer aWidth = 0, aHeight = 0;
13598   aView->Window()->Size (aWidth, aHeight);
13599
13600   Image_AlienPixMap aPixMap;
13601   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
13602   {
13603     Message::SendFail ("Error: can't allocate image");
13604     return 1;
13605   }
13606
13607   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
13608   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
13609   if (!aCustomCam.IsNull())
13610   {
13611     aView->SetCamera (aCustomCam);
13612   }
13613   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
13614   {
13615     Message::SendFail ("Error: can't generate selection image");
13616     return 1;
13617   }
13618   if (!aCustomCam.IsNull())
13619   {
13620     aView->SetCamera (aCamBack);
13621   }
13622   aView->SetImmediateUpdate (wasImmUpdate);
13623
13624   if (!aPixMap.Save (aFile))
13625   {
13626     Message::SendFail ("Error: can't save selection image");
13627     return 0;
13628   }
13629   return 0;
13630 }
13631
13632 //===============================================================================================
13633 //function : VViewCube
13634 //purpose  :
13635 //===============================================================================================
13636 static int VViewCube (Draw_Interpretor& ,
13637                       Standard_Integer  theNbArgs,
13638                       const char**      theArgVec)
13639 {
13640   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
13641   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
13642   if (aContext.IsNull() || aView.IsNull())
13643   {
13644     Message::SendFail ("Error: no active viewer");
13645     return 1;
13646   }
13647   else if (theNbArgs < 2)
13648   {
13649     Message::SendFail ("Syntax error: wrong number arguments");
13650     return 1;
13651   }
13652
13653   Handle(AIS_ViewCube) aViewCube;
13654   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
13655   Quantity_Color aColorRgb;
13656   TCollection_AsciiString aName;
13657   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
13658   {
13659     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13660     anArg.LowerCase();
13661     if (anUpdateTool.parseRedrawMode (anArg))
13662     {
13663       //
13664     }
13665     else if (aViewCube.IsNull())
13666     {
13667       aName = theArgVec[anArgIter];
13668       if (aName.StartsWith ("-"))
13669       {
13670         Message::SendFail ("Syntax error: object name should be specified");
13671         return 1;
13672       }
13673       Handle(AIS_InteractiveObject) aPrs;
13674       GetMapOfAIS().Find2 (aName, aPrs);
13675       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
13676       if (aViewCube.IsNull())
13677       {
13678         aViewCube = new AIS_ViewCube();
13679         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
13680         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
13681         aViewCube->SetFixedAnimationLoop (false);
13682       }
13683     }
13684     else if (anArg == "-reset")
13685     {
13686       aViewCube->ResetStyles();
13687     }
13688     else if (anArg == "-color"
13689           || anArg == "-boxcolor"
13690           || anArg == "-boxsidecolor"
13691           || anArg == "-sidecolor"
13692           || anArg == "-boxedgecolor"
13693           || anArg == "-edgecolor"
13694           || anArg == "-boxcornercolor"
13695           || anArg == "-cornercolor"
13696           || anArg == "-innercolor"
13697           || anArg == "-textcolor")
13698     {
13699       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
13700                                                      theArgVec + anArgIter + 1,
13701                                                      aColorRgb);
13702       if (aNbParsed == 0)
13703       {
13704         Message::SendFail() << "Syntax error at '" << anArg << "'";
13705         return 1;
13706       }
13707       anArgIter += aNbParsed;
13708       if (anArg == "-boxcolor")
13709       {
13710         aViewCube->SetBoxColor (aColorRgb);
13711       }
13712       else if (anArg == "-boxsidecolor"
13713             || anArg == "-sidecolor")
13714       {
13715         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
13716         aViewCube->SynchronizeAspects();
13717       }
13718       else if (anArg == "-boxedgecolor"
13719             || anArg == "-edgecolor")
13720       {
13721         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
13722         aViewCube->SynchronizeAspects();
13723       }
13724       else if (anArg == "-boxcornercolor"
13725             || anArg == "-cornercolor")
13726       {
13727         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
13728         aViewCube->SynchronizeAspects();
13729       }
13730       else if (anArg == "-innercolor")
13731       {
13732         aViewCube->SetInnerColor (aColorRgb);
13733       }
13734       else if (anArg == "-textcolor")
13735       {
13736         aViewCube->SetTextColor (aColorRgb);
13737       }
13738       else
13739       {
13740         aViewCube->SetColor (aColorRgb);
13741       }
13742     }
13743     else if (anArgIter + 1 < theNbArgs
13744           && (anArg == "-transparency"
13745            || anArg == "-boxtransparency"))
13746     {
13747       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
13748       if (aValue < 0.0 || aValue > 1.0)
13749       {
13750         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
13751         return 1;
13752       }
13753
13754       if (anArg == "-boxtransparency")
13755       {
13756         aViewCube->SetBoxTransparency (aValue);
13757       }
13758       else
13759       {
13760         aViewCube->SetTransparency (aValue);
13761       }
13762     }
13763     else if (anArg == "-axes"
13764           || anArg == "-edges"
13765           || anArg == "-vertices"
13766           || anArg == "-vertexes"
13767           || anArg == "-fixedanimation")
13768     {
13769       bool toShow = true;
13770       if (anArgIter + 1 < theNbArgs
13771        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
13772       {
13773         ++anArgIter;
13774       }
13775       if (anArg == "-fixedanimation")
13776       {
13777         aViewCube->SetFixedAnimationLoop (toShow);
13778       }
13779       else if (anArg == "-axes")
13780       {
13781         aViewCube->SetDrawAxes (toShow);
13782       }
13783       else if (anArg == "-edges")
13784       {
13785         aViewCube->SetDrawEdges (toShow);
13786       }
13787       else
13788       {
13789         aViewCube->SetDrawVertices (toShow);
13790       }
13791     }
13792     else if (anArg == "-yup"
13793           || anArg == "-zup")
13794     {
13795       bool isOn = true;
13796       if (anArgIter + 1 < theNbArgs
13797        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
13798       {
13799         ++anArgIter;
13800       }
13801       if (anArg == "-yup")
13802       {
13803         aViewCube->SetYup (isOn);
13804       }
13805       else
13806       {
13807         aViewCube->SetYup (!isOn);
13808       }
13809     }
13810     else if (anArgIter + 1 < theNbArgs
13811           && anArg == "-font")
13812     {
13813       aViewCube->SetFont (theArgVec[++anArgIter]);
13814     }
13815     else if (anArgIter + 1 < theNbArgs
13816           && anArg == "-fontheight")
13817     {
13818       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
13819     }
13820     else if (anArgIter + 1 < theNbArgs
13821           && (anArg == "-size"
13822            || anArg == "-boxsize"))
13823     {
13824       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
13825                           anArg != "-boxsize");
13826     }
13827     else if (anArgIter + 1 < theNbArgs
13828           && (anArg == "-boxfacet"
13829            || anArg == "-boxfacetextension"
13830            || anArg == "-facetextension"
13831            || anArg == "-extension"))
13832     {
13833       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
13834     }
13835     else if (anArgIter + 1 < theNbArgs
13836           && (anArg == "-boxedgegap"
13837            || anArg == "-edgegap"))
13838     {
13839       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
13840     }
13841     else if (anArgIter + 1 < theNbArgs
13842           && (anArg == "-boxedgeminsize"
13843            || anArg == "-edgeminsize"))
13844     {
13845       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
13846     }
13847     else if (anArgIter + 1 < theNbArgs
13848           && (anArg == "-boxcornerminsize"
13849            || anArg == "-cornerminsize"))
13850     {
13851       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
13852     }
13853     else if (anArgIter + 1 < theNbArgs
13854           && anArg == "-axespadding")
13855     {
13856       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
13857     }
13858     else if (anArgIter + 1 < theNbArgs
13859           && anArg == "-roundradius")
13860     {
13861       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
13862     }
13863     else if (anArgIter + 1 < theNbArgs
13864           && anArg == "-duration")
13865     {
13866       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
13867     }
13868     else if (anArgIter + 1 < theNbArgs
13869           && anArg == "-axesradius")
13870     {
13871       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
13872     }
13873     else if (anArgIter + 1 < theNbArgs
13874           && anArg == "-axesconeradius")
13875     {
13876       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
13877     }
13878     else if (anArgIter + 1 < theNbArgs
13879           && anArg == "-axessphereradius")
13880     {
13881       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
13882     }
13883     else
13884     {
13885       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
13886       return 1;
13887     }
13888   }
13889   if (aViewCube.IsNull())
13890   {
13891     Message::SendFail ("Syntax error: wrong number of arguments");
13892     return 1;
13893   }
13894
13895   ViewerTest::Display (aName, aViewCube, false);
13896   return 0;
13897 }
13898
13899 //===============================================================================================
13900 //function : VColorConvert
13901 //purpose  :
13902 //===============================================================================================
13903 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13904 {
13905   if (theNbArgs != 6)
13906   {
13907     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13908     return 1;
13909   }
13910
13911   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
13912   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
13913   {
13914     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
13915     return 1;
13916   }
13917
13918   const char* aTypeStr = theArgVec[2];
13919   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
13920   if (! strcasecmp (aTypeStr, "srgb"))
13921   {
13922     aType = Quantity_TOC_sRGB;
13923   }
13924   else if (! strcasecmp (aTypeStr, "hls"))
13925   {
13926     aType = Quantity_TOC_HLS;
13927   }
13928   else if (! strcasecmp (aTypeStr, "lab"))
13929   {
13930     aType = Quantity_TOC_CIELab;
13931   }
13932   else if (! strcasecmp (aTypeStr, "lch"))
13933   {
13934     aType = Quantity_TOC_CIELch;
13935   }
13936   else
13937   {
13938     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
13939     return 1;
13940   }
13941
13942   double aC1 = Draw::Atof (theArgVec[3]);
13943   double aC2 = Draw::Atof (theArgVec[4]);
13944   double aC3 = Draw::Atof (theArgVec[5]);
13945
13946   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
13947   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
13948
13949   // print values with 6 decimal digits
13950   char buffer[1024];
13951   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
13952   theDI << buffer;
13953
13954   return 0;
13955 }
13956  
13957 //===============================================================================================
13958 //function : VColorDiff
13959 //purpose  :
13960 //===============================================================================================
13961 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
13962 {
13963   if (theNbArgs != 7)
13964   {
13965     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
13966     return 1;
13967   }
13968
13969   double aR1 = Draw::Atof (theArgVec[1]);
13970   double aG1 = Draw::Atof (theArgVec[2]);
13971   double aB1 = Draw::Atof (theArgVec[3]);
13972   double aR2 = Draw::Atof (theArgVec[4]);
13973   double aG2 = Draw::Atof (theArgVec[5]);
13974   double aB2 = Draw::Atof (theArgVec[6]);
13975
13976   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
13977   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
13978
13979   theDI << aColor1.DeltaE2000 (aColor2);
13980
13981   return 0;
13982 }
13983  
13984 //=======================================================================
13985 //function : ViewerCommands
13986 //purpose  :
13987 //=======================================================================
13988
13989 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
13990 {
13991
13992   const char *group = "ZeViewer";
13993   theCommands.Add("vinit",
13994           "vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]"
13995     "\n\t\t:     [-exitOnClose] [-closeOnEscape] [-cloneActive] [-2d_mode {on|off}=off]"
13996   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
13997     "\n\t\t:     [-display displayName]"
13998   #endif
13999     "\n\t\t: Creates new View window with specified name viewName."
14000     "\n\t\t: By default the new view is created in the viewer and in"
14001     "\n\t\t: graphic driver shared with active view."
14002     "\n\t\t:  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}"
14003     "\n\t\t: If driverName isn't specified the driver will be shared with active view."
14004     "\n\t\t: If viewerName isn't specified the viewer will be shared with active view."
14005 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
14006     "\n\t\t:  -display HostName.DisplayNumber[:ScreenNumber]"
14007     "\n\t\t: Display name will be used within creation of graphic driver, when specified."
14008 #endif
14009     "\n\t\t:  -left,  -top    pixel position of left top corner of the window."
14010     "\n\t\t:  -width, -height width and heigth of window respectively."
14011     "\n\t\t:  -cloneActive floag to copy camera and dimensions of active view."
14012     "\n\t\t:  -exitOnClose when specified, closing the view will exit application."
14013     "\n\t\t:  -closeOnEscape when specified, view will be closed on pressing Escape."
14014     "\n\t\t:  -2d_mode when on, view will not react on rotate scene events"
14015     "\n\t\t: Additional commands for operations with views: vclose, vactivate, vviewlist.",
14016     __FILE__,VInit,group);
14017   theCommands.Add("vclose" ,
14018     "[view_id [keep_context=0|1]]\n"
14019     "or vclose ALL - to remove all created views\n"
14020     " - removes view(viewer window) defined by its view_id.\n"
14021     " - keep_context: by default 0; if 1 and the last view is deleted"
14022     " the current context is not removed.",
14023     __FILE__,VClose,group);
14024   theCommands.Add("vactivate" ,
14025     "vactivate view_id [-noUpdate]"
14026     " - activates view(viewer window) defined by its view_id",
14027     __FILE__,VActivate,group);
14028   theCommands.Add("vviewlist",
14029     "vviewlist [format={tree, long}]"
14030     " - prints current list of views per viewer and graphic_driver ID shared between viewers"
14031     " - format: format of result output, if tree the output is a tree view;"
14032     "otherwise it's a list of full view names. By default format = tree",
14033     __FILE__,VViewList,group);
14034   theCommands.Add("vhelp" ,
14035     "vhelp            : display help on the viewer commands",
14036     __FILE__,VHelp,group);
14037   theCommands.Add("vviewproj",
14038           "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]"
14039     "\n\t\t:         [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]"
14040     "\n\t\t: Setup view direction"
14041     "\n\t\t:   -Yup      use Y-up convention instead of Zup (which is default)."
14042     "\n\t\t:   +-X+-Y+-Z define direction as combination of DX, DY and DZ;"
14043     "\n\t\t:             for example '+Z' will show front of the model,"
14044     "\n\t\t:             '-X-Y+Z' will define left axonometrical view."
14045     "\n\t\t:   -frame    define camera Up and Right directions (regardless Up convention);"
14046     "\n\t\t:             for example '+X+Z' will show front of the model with Z-up."
14047     __FILE__,VViewProj,group);
14048   theCommands.Add("vtop" ,
14049     "vtop or <T>      : Top view. Orientation +X+Y" ,
14050     __FILE__,VViewProj,group);
14051   theCommands.Add("vbottom" ,
14052     "vbottom          : Bottom view. Orientation +X-Y" ,
14053     __FILE__,VViewProj,group);
14054   theCommands.Add("vleft" ,
14055     "vleft            : Left view. Orientation -Y+Z" ,
14056     __FILE__,VViewProj,group);
14057   theCommands.Add("vright" ,
14058     "vright           : Right view. Orientation +Y+Z" ,
14059     __FILE__,VViewProj,group);
14060   theCommands.Add("vaxo" ,
14061     " vaxo or <A>     : Axonometric view. Orientation +X-Y+Z",
14062     __FILE__,VViewProj,group);
14063   theCommands.Add("vfront" ,
14064     "vfront           : Front view. Orientation +X+Z" ,
14065     __FILE__,VViewProj,group);
14066   theCommands.Add("vback" ,
14067     "vback            : Back view. Orientation -X+Z" ,
14068     __FILE__,VViewProj,group);
14069   theCommands.Add("vpick" ,
14070     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
14071     VPick,group);
14072   theCommands.Add("vfit",
14073     "vfit or <F> [-selected] [-noupdate]"
14074     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
14075     __FILE__,VFit,group);
14076   theCommands.Add ("vfitarea",
14077     "vfitarea x1 y1 x2 y2"
14078     "\n\t\t: vfitarea x1 y1 z1 x2 y2 z2"
14079     "\n\t\t: Fit view to show area located between two points"
14080     "\n\t\t: given in world 2D or 3D corrdinates.",
14081     __FILE__, VFitArea, group);
14082   theCommands.Add ("vzfit", "vzfit [scale]\n"
14083     "   Matches Z near, Z far view volume planes to the displayed objects.\n"
14084     "   \"scale\" - specifies factor to scale computed z range.\n",
14085     __FILE__, VZFit, group);
14086   theCommands.Add("vrepaint",
14087             "vrepaint [-immediate] [-continuous FPS]"
14088     "\n\t\t: force redraw of active View"
14089     "\n\t\t:   -immediate  flag performs redraw of immediate layers only;"
14090     "\n\t\t:   -continuous activates/deactivates continuous redraw of active View,"
14091     "\n\t\t:                0 means no continuous rendering,"
14092     "\n\t\t:               -1 means non-stop redraws,"
14093     "\n\t\t:               >0 specifies target framerate,",
14094     __FILE__,VRepaint,group);
14095   theCommands.Add("vclear",
14096     "vclear          : vclear"
14097     "\n\t\t: remove all the object from the viewer",
14098     __FILE__,VClear,group);
14099   theCommands.Add (
14100     "vbackground",
14101     "Changes background or some background settings.\n"
14102     "\n"
14103     "Usage:\n"
14104     "  vbackground -imageFile ImageFile [-imageMode FillType]\n"
14105     "  vbackground -imageMode FillType\n"
14106     "  vbackground -gradient Color1 Color2 [-gradientMode FillMethod]\n"
14107     "  vbackground -gradientMode FillMethod\n"
14108     "  vbackground -cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]\n"
14109     "  vbackground -color Color\n"
14110     "  vbackground -default -gradient Color1 Color2 [-gradientMode FillType]\n"
14111     "  vbackground -default -color Color\n"
14112     "  vbackground -help\n"
14113     "\n"
14114     "Options:\n"
14115     "  -imageFile    (-imgFile, -image, -img):             sets filename of image used as background\n"
14116     "  -imageMode    (-imgMode, -imageMd, -imgMd):         sets image fill type\n"
14117     "  -gradient     (-grad, -gr):                         sets background gradient starting and ending colors\n"
14118     "  -gradientMode (-gradMode, -gradMd, -grMode, -grMd): sets gradient fill method\n"
14119     "  -cubemap      (-cmap, -cm):                         sets environmet cubemap as background\n"
14120     "  -invertedz    (-invz, -iz):                         sets inversion of Z axis for background cubemap rendering\n"
14121     "  -order        (-o):                                 defines order of tiles in one image cubemap\n"
14122     "                                                      (has no effect in case of multi image cubemaps)\n"
14123     "  -color        (-col):                               sets background color\n"
14124     "  -default      (-def):                               sets background default gradient or color\n"
14125     "  -help         (-h):                                 outputs short help message\n"
14126     "\n"
14127     "Arguments:\n"
14128     "  Color:        Red Green Blue  - where Red, Green, Blue must be integers within the range [0, 255]\n"
14129     "                                  or reals within the range [0.0, 1.0]\n"
14130     "                ColorName       - one of WHITE, BLACK, RED, GREEN, BLUE, etc.\n"
14131     "                #HHH, [#]HHHHHH - where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F)\n"
14132     "  FillMethod:   one of NONE, HOR[IZONTAL], VER[TICAL], DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, "
14133     "CORNER4\n"
14134     "  FillType:     one of CENTERED, TILED, STRETCH, NONE\n"
14135     "  ImageFile:    a name of the file with the image used as a background\n"
14136     "  CubemapFilei: a name of the file with one image packed cubemap or names of separate files with every cubemap side\n"
14137     "  TileIndexi:   a cubemap side index in range [0, 5] for i tile of one image packed cubemap\n",
14138     __FILE__,
14139     vbackground,
14140     group);
14141   theCommands.Add ("vsetbg",
14142                    "Loads image as background."
14143                    "\n\t\t: vsetbg ImageFile [FillType]"
14144                    "\n\t\t: vsetbg -imageFile ImageFile [-imageMode FillType]"
14145                    "\n\t\t: Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.",
14146                    __FILE__,
14147                    vbackground,
14148                    group);
14149   theCommands.Add ("vsetbgmode",
14150                    "Changes background image fill type."
14151                    "\n\t\t: vsetbgmode [-imageMode] FillType"
14152                    "\n\t\t: Alias for 'vbackground -imageMode FillType'.",
14153                    __FILE__,
14154                    vbackground,
14155                    group);
14156   theCommands.Add ("vsetgradientbg",
14157                    "Mounts gradient background."
14158                    "\n\t\t: vsetgradientbg Color1 Color2 [FillMethod]"
14159                    "\n\t\t: vsetgradientbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14160                    "\n\t\t: Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.",
14161                    __FILE__,
14162                    vbackground,
14163                    group);
14164   theCommands.Add ("vsetgrbgmode",
14165                    "Changes gradient background fill method."
14166                    "\n\t\t: vsetgrbgmode [-gradientMode] FillMethod"
14167                    "\n\t\t: Alias for 'vbackground -gradientMode FillMethod'.",
14168                    __FILE__,
14169                    vbackground,
14170                    group);
14171   theCommands.Add ("vsetcolorbg",
14172                    "Sets background color."
14173                    "\n\t\t: vsetcolorbg [-color] Color."
14174                    "\n\t\t: Alias for 'vbackground -color Color'.",
14175                    __FILE__,
14176                    vbackground,
14177                    group);
14178   theCommands.Add ("vsetdefaultbg",
14179                    "Sets default viewer background fill color (flat/gradient)."
14180                    "\n\t\t: vsetdefaultbg Color1 Color2 [FillMethod]"
14181                    "\n\t\t: vsetdefaultbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14182                    "\n\t\t: Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'."
14183                    "\n\t\t: vsetdefaultbg [-color] Color"
14184                    "\n\t\t: Alias for 'vbackground -default -color Color'.",
14185                    __FILE__,
14186                    vbackground,
14187                    group);
14188   theCommands.Add("vscale",
14189     "vscale          : vscale X Y Z",
14190     __FILE__,VScale,group);
14191   theCommands.Add("vzbufftrihedron",
14192             "vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]"
14193     "\n\t\t:       [-position center|left_lower|left_upper|right_lower|right_upper]"
14194     "\n\t\t:       [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]"
14195     "\n\t\t:       [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]"
14196     "\n\t\t:       [-nbfacets value=12] [-colorLabels color=WHITE]"
14197     "\n\t\t: Displays a trihedron",
14198     __FILE__,VZBuffTrihedron,group);
14199   theCommands.Add("vrotate",
14200     "vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]"
14201     "\n                : Option -mouseStart starts rotation according to the mouse position"
14202     "\n                : Option -mouseMove continues rotation with angle computed"
14203     "\n                : from last and new mouse position."
14204     "\n                : vrotate AX AY AZ [X Y Z]",
14205     __FILE__,VRotate,group);
14206   theCommands.Add("vzoom",
14207     "vzoom           : vzoom coef",
14208     __FILE__,VZoom,group);
14209   theCommands.Add("vpan",
14210     "vpan            : vpan dx dy",
14211     __FILE__,VPan,group);
14212   theCommands.Add("vcolorscale",
14213     "vcolorscale name [-noupdate|-update] [-demo]"
14214     "\n\t\t:       [-range RangeMin=0 RangeMax=1 NbIntervals=10]"
14215     "\n\t\t:       [-font HeightFont=20]"
14216     "\n\t\t:       [-logarithmic {on|off}=off] [-reversed {on|off}=off]"
14217     "\n\t\t:       [-smoothTransition {on|off}=off]"
14218     "\n\t\t:       [-hueRange MinAngle=230 MaxAngle=0]"
14219     "\n\t\t:       [-colorRange MinColor=BLUE1 MaxColor=RED]"
14220     "\n\t\t:       [-textpos {left|right|center|none}=right]"
14221     "\n\t\t:       [-labelAtBorder {on|off}=on]"
14222     "\n\t\t:       [-colors Color1 Color2 ...] [-color Index Color]"
14223     "\n\t\t:       [-labels Label1 Label2 ...] [-label Index Label]"
14224     "\n\t\t:       [-freeLabels NbOfLabels Label1 Label2 ...]"
14225     "\n\t\t:       [-xy Left=0 Bottom=0]"
14226     "\n\t\t:       [-uniform lightness hue_from hue_to]"
14227     "\n\t\t:  -demo     - displays a color scale with demonstratio values"
14228     "\n\t\t:  -colors   - set colors for all intervals"
14229     "\n\t\t:  -color    - set color for specific interval"
14230     "\n\t\t:  -uniform  - generate colors with the same lightness"
14231     "\n\t\t:  -textpos  - horizontal label position relative to color scale bar"
14232     "\n\t\t:  -labelAtBorder - vertical label position relative to color interval;"
14233     "\n\t\t:              at border means the value inbetween neighbor intervals,"
14234     "\n\t\t:              at center means the center value within current interval"
14235     "\n\t\t:  -labels   - set labels for all intervals"
14236     "\n\t\t:  -freeLabels - same as -labels but does not require"
14237     "\n\t\t:              matching the number of intervals"
14238     "\n\t\t:  -label    - set label for specific interval"
14239     "\n\t\t:  -title    - set title"
14240     "\n\t\t:  -reversed - setup smooth color transition between intervals"
14241     "\n\t\t:  -smoothTransition - swap colorscale direction"
14242     "\n\t\t:  -hueRange - set hue angles corresponding to minimum and maximum values",
14243     __FILE__, VColorScale, group);
14244   theCommands.Add("vgraduatedtrihedron",
14245     "vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
14246     "\t[-namefont Name] [-valuesfont Name]\n"
14247     "\t[-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]\n"
14248     "\t[-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]"
14249     "\t[-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]\n"
14250     "\t[-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]\n"
14251     "\t[-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]"
14252     "\t[-xcolor Color] [-ycolor Color] [-zcolor Color]\n"
14253     "\t[-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]\n"
14254     "\t[-xticks Number] [-yticks Number] [-zticks Number]\n"
14255     "\t[-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]\n"
14256     "\t[-drawgrid on/off] [-drawaxes on/off]\n"
14257     " - Displays or erases graduated trihedron"
14258     " - xname, yname, zname - names of axes, default: X, Y, Z\n"
14259     " - namefont - font of axes names. Default: Arial\n"
14260     " - xnameoffset, ynameoffset, znameoffset - offset of name from values or tickmarks or axis. Default: 30\n"
14261     " - xnamecolor, ynamecolor, znamecolor - colors of axes names\n"
14262     " - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values from tickmarks or axis. Default: 10\n"
14263     " - valuesfont - font of axes values. Default: Arial\n"
14264     " - xcolor, ycolor, zcolor - color of axis and values\n"
14265     " - xticks, yticks, xzicks - number of tickmark on axes. Default: 5\n"
14266     " - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10\n",
14267     __FILE__,VGraduatedTrihedron,group);
14268   theCommands.Add("vtile" ,
14269             "vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]"
14270     "\n\t\t: Setup view to draw a tile (a part of virtual bigger viewport)."
14271     "\n\t\t:  -totalSize the size of virtual bigger viewport"
14272     "\n\t\t:  -tileSize  tile size (the view size will be used if omitted)"
14273     "\n\t\t:  -lowerLeft tile offset as lower left corner"
14274     "\n\t\t:  -upperLeft tile offset as upper left corner",
14275     __FILE__, VTile, group);
14276   theCommands.Add("vzlayer",
14277               "vzlayer [layerId]"
14278       "\n\t\t:         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]"
14279       "\n\t\t:         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]"
14280       "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
14281       "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]"
14282       "\n\t\t: ZLayer list management:"
14283       "\n\t\t:   -add      add new z layer to viewer and print its id"
14284       "\n\t\t:   -insertBefore add new z layer and insert it before existing one"
14285       "\n\t\t:   -insertAfter  add new z layer and insert it after  existing one"
14286       "\n\t\t:   -delete   delete z layer"
14287       "\n\t\t:   -get      print sequence of z layers"
14288       "\n\t\t:   -settings print status of z layer settings"
14289       "\n\t\t:   -disable  disables given setting"
14290       "\n\t\t:   -enable   enables  given setting",
14291     __FILE__,VZLayer,group);
14292   theCommands.Add("vlayerline",
14293     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
14294     __FILE__,VLayerLine,group);
14295   theCommands.Add("vgrid",
14296               "vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]"
14297       "\n\t\t:       [-step X Y] [-size DX DY]"
14298       "\n\t\t:       [-step StepRadius NbDivisions] [-radius Radius]",
14299     __FILE__, VGrid, group);
14300   theCommands.Add ("vpriviledgedplane",
14301     "vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]"
14302     "\n\t\t:   Ox, Oy, Oz - plane origin"
14303     "\n\t\t:   Nx, Ny, Nz - plane normal direction"
14304     "\n\t\t:   Xx, Xy, Xz - plane x-reference axis direction"
14305     "\n\t\t: Sets or prints viewer's priviledged plane geometry.",
14306     __FILE__, VPriviledgedPlane, group);
14307   theCommands.Add ("vconvert",
14308     "vconvert v [Mode={window|view}]"
14309     "\n\t\t: vconvert x y [Mode={window|view|grid|ray}]"
14310     "\n\t\t: vconvert x y z [Mode={window|grid}]"
14311     "\n\t\t:   window - convert to window coordinates, pixels"
14312     "\n\t\t:   view   - convert to view projection plane"
14313     "\n\t\t:   grid   - convert to model coordinates, given on grid"
14314     "\n\t\t:   ray    - convert projection ray to model coordiantes"
14315     "\n\t\t: - vconvert v window : convert view to window;"
14316     "\n\t\t: - vconvert v view   : convert window to view;"
14317     "\n\t\t: - vconvert x y window : convert view to window;"
14318     "\n\t\t: - vconvert x y view : convert window to view;"
14319     "\n\t\t: - vconvert x y : convert window to model;"
14320     "\n\t\t: - vconvert x y grid : convert window to model using grid;"
14321     "\n\t\t: - vconvert x y ray : convert window projection line to model;"
14322     "\n\t\t: - vconvert x y z window : convert model to window;"
14323     "\n\t\t: - vconvert x y z grid : convert view to model using grid;"
14324     "\n\t\t: Converts the given coordinates to window/view/model space.",
14325     __FILE__, VConvert, group);
14326   theCommands.Add ("vfps",
14327     "vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view",
14328     __FILE__, VFps, group);
14329   theCommands.Add ("vgldebug",
14330             "vgldebug [-sync {0|1}] [-debug {0|1}] [-glslWarn {0|1}]"
14331     "\n\t\t:          [-glslCode {off|short|full}] [-extraMsg {0|1}] [{0|1}]"
14332     "\n\t\t: Request debug GL context. Should be called BEFORE vinit."
14333     "\n\t\t: Debug context can be requested only on Windows"
14334     "\n\t\t: with GL_ARB_debug_output extension implemented by GL driver!"
14335     "\n\t\t:  -sync     - request synchronized debug GL context"
14336     "\n\t\t:  -glslWarn - log GLSL compiler/linker warnings,"
14337     "\n\t\t:              which are suppressed by default,"
14338     "\n\t\t:  -glslCode - log GLSL program source code,"
14339     "\n\t\t:              which are suppressed by default,"
14340     "\n\t\t:  -extraMsg - log extra diagnostic messages from GL context,"
14341     "\n\t\t:              which are suppressed by default",
14342     __FILE__, VGlDebug, group);
14343   theCommands.Add ("vvbo",
14344     "vvbo [{0|1}] : turn VBO usage On/Off; affects only newly displayed objects",
14345     __FILE__, VVbo, group);
14346   theCommands.Add ("vstereo",
14347             "vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
14348     "\n\t\t:         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]"
14349     "\n\t\t:         [-anaglyph Filter]"
14350     "\n\t\t: Control stereo output mode."
14351     "\n\t\t: When -mirrorComposer is specified, VR rendered frame will be mirrored in window (debug)."
14352     "\n\t\t: Parameter -unitFactor specifies meters scale factor for mapping VR input."
14353     "\n\t\t: Available modes for -mode:"
14354     "\n\t\t:  quadBuffer        - OpenGL QuadBuffer stereo,"
14355     "\n\t\t:                     requires driver support."
14356     "\n\t\t:                     Should be called BEFORE vinit!"
14357     "\n\t\t:  anaglyph         - Anaglyph glasses"
14358     "\n\t\t:  rowInterlaced    - row-interlaced display"
14359     "\n\t\t:  columnInterlaced - column-interlaced display"
14360     "\n\t\t:  chessBoard       - chess-board output"
14361     "\n\t\t:  sideBySide       - horizontal pair"
14362     "\n\t\t:  overUnder        - vertical   pair"
14363     "\n\t\t:  openVR           - OpenVR (HMD)"
14364     "\n\t\t: Available Anaglyph filters for -anaglyph:"
14365     "\n\t\t:  redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
14366     "\n\t\t:  greenMagentaSimple",
14367     __FILE__, VStereo, group);
14368   theCommands.Add ("vcaps",
14369             "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
14370     "\n\t\t:       [-compatibleProfile {0|1}] [-compressedTextures {0|1}]"
14371     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}]"
14372     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
14373     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
14374     "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
14375     "\n\t\t: Modify particular graphic driver options:"
14376     "\n\t\t:  sRGB     - enable/disable sRGB rendering"
14377     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
14378     "\n\t\t:             built-in GLSL programs"
14379     "\n\t\t:            (requires compatible profile)"
14380     "\n\t\t:  polygonMode - use Polygon Mode instead of built-in GLSL programs"
14381     "\n\t\t:  compressedTexture - allow uploading of GPU-supported compressed texture formats"
14382     "\n\t\t:  VBO      - use Vertex Buffer Object (copy vertex"
14383     "\n\t\t:             arrays to GPU memory)"
14384     "\n\t\t:  sprite   - use textured sprites instead of bitmaps"
14385     "\n\t\t:  vsync    - switch VSync on or off"
14386     "\n\t\t:  winBuffer - allow using window buffer for rendering"
14387     "\n\t\t: Context creation options:"
14388     "\n\t\t:  softMode          - software OpenGL implementation"
14389     "\n\t\t:  compatibleProfile - backward-compatible profile"
14390     "\n\t\t:  quadbuffer        - QuadBuffer"
14391     "\n\t\t:  noExtensions      - disallow usage of extensions"
14392     "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
14393     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
14394     "\n\t\t: rendering paths producing the same visual result when"
14395     "\n\t\t: possible."
14396     "\n\t\t: Command is intended for testing old hardware compatibility.",
14397     __FILE__, VCaps, group);
14398   theCommands.Add ("vmemgpu",
14399     "vmemgpu [f]: print system-dependent GPU memory information if available;"
14400     " with f option returns free memory in bytes",
14401     __FILE__, VMemGpu, group);
14402   theCommands.Add ("vreadpixel",
14403     "vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]"
14404     " : Read pixel value for active view",
14405     __FILE__, VReadPixel, group);
14406   theCommands.Add("diffimage",
14407             "diffimage imageFile1 imageFile2 [diffImageFile]"
14408     "\n\t\t:           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]"
14409     "\n\t\t:           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]"
14410     "\n\t\t: Compare two images by content and generate difference image."
14411     "\n\t\t: When -exitOnClose is specified, closing the view will exit application."
14412     "\n\t\t: When -closeOnEscape is specified, view will be closed on pressing Escape.",
14413     __FILE__, VDiffImage, group);
14414   theCommands.Add ("vselect",
14415     "vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1] [shift_selection = 0|1]\n"
14416     "- emulates different types of selection:\n"
14417     "- 1) single click selection\n"
14418     "- 2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)\n"
14419     "- 3) selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn)\n"
14420     "- 4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.\n"
14421     "     If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined \n"
14422     "     rectangle or polygon will be detected, otherwise algorithm will chose only fully included sensitives.\n"
14423     "     Default behavior is to detect only full inclusion. (partial inclusion - overlap - is not allowed by default)\n"
14424     "- 5) any of these selections with shift button pressed",
14425     __FILE__, VSelect, group);
14426   theCommands.Add ("vmoveto",
14427     "vmoveto [x y] [-reset]"
14428     "\n\t\t: Emulates cursor movement to pixel position (x,y)."
14429     "\n\t\t:   -reset resets current highlighting",
14430     __FILE__, VMoveTo, group);
14431   theCommands.Add ("vviewparams",
14432               "vviewparams [-args] [-scale [s]]"
14433       "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
14434       "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
14435       "\n\t\t: Manage current view parameters or prints all"
14436       "\n\t\t: current values when called without argument."
14437       "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
14438       "\n\t\t:   -eye  [x y z] prints or sets eye location"
14439       "\n\t\t:   -at   [x y z] prints or sets center of look"
14440       "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
14441       "\n\t\t:   -proj [x y z] prints or sets direction of look"
14442       "\n\t\t:   -center x y   sets location of center of the screen in pixels"
14443       "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
14444       "\n\t\t:                 or changes the size of its maximum dimension"
14445       "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
14446     __FILE__, VViewParams, group);
14447
14448   theCommands.Add("v2dmode",
14449     "v2dmode [-name viewName] [-mode {-on|-off}=-on]"
14450     "\n\t\t:   name   - name of existing view, if not defined, the active view is changed"
14451     "\n\t\t:   mode   - switches On/Off rotation mode"
14452     "\n\t\t: Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:"
14453     "\n\t\t:   - rotation of the view by 3rd mouse button with Ctrl active"
14454     "\n\t\t:   - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right"
14455     "\n\t\t: View camera position might be changed only by commands.",
14456     __FILE__, V2DMode, group);
14457
14458   theCommands.Add("vanimation", "Alias for vanim",
14459     __FILE__, VAnimation, group);
14460
14461   theCommands.Add("vanim",
14462             "List existing animations:"
14463     "\n\t\t:  vanim"
14464     "\n\t\t: Animation playback:"
14465     "\n\t\t:  vanim name -play|-resume [playFrom [playDuration]]"
14466     "\n\t\t:            [-speed Coeff] [-freeLook] [-lockLoop]"
14467     "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
14468     "\n\t\t:   -freeLook skip camera animations"
14469     "\n\t\t:   -lockLoop disable any interactions"
14470     "\n\t\t:"
14471     "\n\t\t: Animation definition:"
14472     "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
14473     "\n\t\t:        [start TimeSec] [duration TimeSec]"
14474     "\n\t\t:"
14475     "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
14476     "\n\t\t: specifies nested animations."
14477     "\n\t\t: There is no syntax to explicitly add new animation,"
14478     "\n\t\t: and all non-existing animations within the name will be"
14479     "\n\t\t: implicitly created on first use (including parents)."
14480     "\n\t\t:"
14481     "\n\t\t: Each animation might define the SINGLE action (see below),"
14482     "\n\t\t: like camera transition, object transformation or custom callback."
14483     "\n\t\t: Child animations can be used for defining concurrent actions."
14484     "\n\t\t:"
14485     "\n\t\t: Camera animation:"
14486     "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
14487     "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
14488     "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
14489     "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
14490     "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
14491     "\n\t\t:   -atX    camera Center positions pair"
14492     "\n\t\t:   -upX    camera Up directions pair"
14493     "\n\t\t:   -scaleX camera Scale factors pair"
14494     "\n\t\t: Object animation:"
14495     "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
14496     "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
14497     "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
14498     "\n\t\t:   -locX   object Location points pair (translation)"
14499     "\n\t\t:   -rotX   object Orientations pair (quaternions)"
14500     "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
14501     "\n\t\t: Custom callback:"
14502     "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
14503     "\n\t\t:   %Pts        overall animation presentation timestamp"
14504     "\n\t\t:   %LocalPts   local animation timestamp"
14505     "\n\t\t:   %Normalized local animation normalized value in range 0..1"
14506     "\n\t\t:"
14507     "\n\t\t: Video recording:"
14508     "\n\t\t:  vanim name -record FileName [Width Height] [-fps FrameRate=24]"
14509     "\n\t\t:             [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]"
14510     "\n\t\t:             [-crf Value] [-preset Preset]"
14511     "\n\t\t:   -fps     video framerate"
14512     "\n\t\t:   -format  file format, container (matroska, etc.)"
14513     "\n\t\t:   -vcodec  video codec identifier (ffv1, mjpeg, etc.)"
14514     "\n\t\t:   -pix_fmt image pixel format (yuv420p, rgb24, etc.)"
14515     "\n\t\t:   -crf     constant rate factor (specific to codec)"
14516     "\n\t\t:   -preset  codec parameters preset (specific to codec)"
14517     __FILE__, VAnimation, group);
14518
14519   theCommands.Add("vchangeselected",
14520     "vchangeselected shape"
14521     "- adds to shape to selection or remove one from it",
14522                 __FILE__, VChangeSelected, group);
14523   theCommands.Add ("vnbselected",
14524     "vnbselected"
14525     "\n\t\t: Returns number of selected objects", __FILE__, VNbSelected, group);
14526   theCommands.Add ("vcamera",
14527               "vcamera [PrsName] [-ortho] [-projtype]"
14528       "\n\t\t:         [-persp]"
14529       "\n\t\t:         [-fovy   [Angle]] [-distance [Distance]]"
14530       "\n\t\t:         [-stereo] [-leftEye] [-rightEye]"
14531       "\n\t\t:         [-iod [Distance]] [-iodType    [absolute|relative]]"
14532       "\n\t\t:         [-zfocus [Value]] [-zfocusType [absolute|relative]]"
14533       "\n\t\t:         [-fov2d  [Angle]] [-lockZup {0|1}]"
14534       "\n\t\t:         [-xrPose base|head=base]"
14535       "\n\t\t: Manages camera parameters."
14536       "\n\t\t: Displays frustum when presntation name PrsName is specified."
14537       "\n\t\t: Prints current value when option called without argument."
14538       "\n\t\t: Orthographic camera:"
14539       "\n\t\t:   -ortho      activate orthographic projection"
14540       "\n\t\t: Perspective camera:"
14541       "\n\t\t:   -persp      activate perspective  projection (mono)"
14542       "\n\t\t:   -fovy       field of view in y axis, in degrees"
14543       "\n\t\t:   -fov2d      field of view limit for 2d on-screen elements"
14544       "\n\t\t:   -distance   distance of eye from camera center"
14545       "\n\t\t:   -lockZup    lock Z up (tunrtable mode)"
14546       "\n\t\t: Stereoscopic camera:"
14547       "\n\t\t:   -stereo     perspective  projection (stereo)"
14548       "\n\t\t:   -leftEye    perspective  projection (left  eye)"
14549       "\n\t\t:   -rightEye   perspective  projection (right eye)"
14550       "\n\t\t:   -iod        intraocular distance value"
14551       "\n\t\t:   -iodType    distance type, absolute or relative"
14552       "\n\t\t:   -zfocus     stereographic focus value"
14553       "\n\t\t:   -zfocusType focus type, absolute or relative",
14554     __FILE__, VCamera, group);
14555   theCommands.Add ("vautozfit", "command to enable or disable automatic z-range adjusting\n"
14556     "- vautozfit [on={1|0}] [scale]\n"
14557     "    Prints or changes parameters of automatic z-fit mode:\n"
14558     "   \"on\" - turns automatic z-fit on or off\n"
14559     "   \"scale\" - specifies factor to scale computed z range.\n",
14560     __FILE__, VAutoZFit, group);
14561   theCommands.Add ("vzrange", "command to manually access znear and zfar values\n"
14562     "   vzrange                - without parameters shows current values\n"
14563     "   vzrange [znear] [zfar] - applies provided values to view",
14564     __FILE__,VZRange, group);
14565   theCommands.Add ("vpurgedisplay",
14566     "vpurgedisplay"
14567     "- removes structures which don't belong to objects displayed in neutral point",
14568     __FILE__, VPurgeDisplay, group);
14569   theCommands.Add("vsetviewsize",
14570     "vsetviewsize size",
14571     __FILE__,VSetViewSize,group);
14572   theCommands.Add("vmoveview",
14573     "vmoveview Dx Dy Dz [Start = 1|0]",
14574     __FILE__,VMoveView,group);
14575   theCommands.Add("vtranslateview",
14576     "vtranslateview Dx Dy Dz [Start = 1|0)]",
14577     __FILE__,VTranslateView,group);
14578   theCommands.Add("vturnview",
14579     "vturnview Ax Ay Az [Start = 1|0]",
14580     __FILE__,VTurnView,group);
14581   theCommands.Add("vtextureenv",
14582     "Enables or disables environment mapping in the 3D view, loading the texture from the given standard "
14583     "or user-defined file and optionally applying texture mapping parameters\n"
14584     "                  Usage:\n"
14585     "                  vtextureenv off - disables environment mapping\n"
14586     "                  vtextureenv on {std_texture|texture_file_name} [rep mod flt ss st ts tt rot] - enables environment mapping\n"
14587     "                              std_texture = (0..7)\n"
14588     "                              rep         = {clamp|repeat}\n"
14589     "                              mod         = {decal|modulate}\n"
14590     "                              flt         = {nearest|bilinear|trilinear}\n"
14591     "                              ss, st      - scale factors for s and t texture coordinates\n"
14592     "                              ts, tt      - translation for s and t texture coordinates\n"
14593     "                              rot         - texture rotation angle in degrees",
14594     __FILE__, VTextureEnv, group);
14595   theCommands.Add("vhlr",
14596             "vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]"
14597       "\n\t\t: Hidden Line Removal algorithm."
14598       "\n\t\t:   -showHidden if set ON, hidden lines are drawn as dotted ones"
14599       "\n\t\t:   -algoType   type of HLR algorithm.\n",
14600     __FILE__,VHLR,group);
14601   theCommands.Add("vhlrtype",
14602               "vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]"
14603       "\n\t\t: Changes the type of HLR algorithm using for shapes:"
14604       "\n\t\t:   'algo' - exact HLR algorithm is applied"
14605       "\n\t\t:   'polyAlgo' - polygonal HLR algorithm is applied"
14606       "\n\t\t: If shapes are not given - option is applied to all shapes in the view",
14607     __FILE__,VHLRType,group);
14608   theCommands.Add("vclipplane",
14609               "vclipplane planeName [{0|1}]"
14610       "\n\t\t:   [-equation1 A B C D]"
14611       "\n\t\t:   [-equation2 A B C D]"
14612       "\n\t\t:   [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]"
14613       "\n\t\t:   [-set|-unset|-setOverrideGlobal [objects|views]]"
14614       "\n\t\t:   [-maxPlanes]"
14615       "\n\t\t:   [-capping {0|1}]"
14616       "\n\t\t:     [-color R G B] [-transparency Value] [-hatch {on|off|ID}]"
14617       "\n\t\t:     [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]"
14618       "\n\t\t:       [-texRotate Angle]"
14619       "\n\t\t:     [-useObjMaterial {0|1}] [-useObjTexture {0|1}]"
14620       "\n\t\t:       [-useObjShader {0|1}]"
14621       "\n\t\t: Clipping planes management:"
14622       "\n\t\t:   -maxPlanes   print plane limit for view"
14623       "\n\t\t:   -delete      delete plane with given name"
14624       "\n\t\t:   {off|on|0|1} turn clipping on/off"
14625       "\n\t\t:   -set|-unset  set/unset plane for Object or View list;"
14626       "\n\t\t:                applied to active View when list is omitted"
14627       "\n\t\t:   -equation A B C D change plane equation"
14628       "\n\t\t:   -clone SourcePlane NewPlane clone the plane definition."
14629       "\n\t\t: Capping options:"
14630       "\n\t\t:   -capping {off|on|0|1} turn capping on/off"
14631       "\n\t\t:   -color R G B          set capping color"
14632       "\n\t\t:   -transparency Value   set capping transparency 0..1"
14633       "\n\t\t:   -texName Texture      set capping texture"
14634       "\n\t\t:   -texScale SX SY       set capping tex scale"
14635       "\n\t\t:   -texOrigin TX TY      set capping tex origin"
14636       "\n\t\t:   -texRotate Angle      set capping tex rotation"
14637       "\n\t\t:   -hatch {on|off|ID}    set capping hatching mask"
14638       "\n\t\t:   -useObjMaterial {off|on|0|1} use material of clipped object"
14639       "\n\t\t:   -useObjTexture  {off|on|0|1} use texture of clipped object"
14640       "\n\t\t:   -useObjShader   {off|on|0|1} use shader program of object",
14641       __FILE__, VClipPlane, group);
14642   theCommands.Add("vdefaults",
14643                "vdefaults [-absDefl value]"
14644        "\n\t\t:           [-devCoeff value]"
14645        "\n\t\t:           [-angDefl value]"
14646        "\n\t\t:           [-autoTriang {off/on | 0/1}]"
14647     , __FILE__, VDefaults, group);
14648   theCommands.Add("vlight",
14649     "tool to manage light sources, without arguments shows list of lights."
14650     "\n    Main commands: "
14651     "\n      '-clear' to clear lights"
14652     "\n      '-{def}aults' to load deafault lights"
14653     "\n      '-add' <type> to add any light source"
14654     "\n          where <type> is one of {amb}ient|directional|{spot}light|positional"
14655     "\n      'change' <lightId> to edit light source with specified lightId"
14656     "\n\n      In addition to 'add' and 'change' commands you can use light parameters:"
14657     "\n        -layer Id"
14658     "\n        -{pos}ition X Y Z"
14659     "\n        -{dir}ection X Y Z (for directional light or for spotlight)"
14660     "\n        -color colorName"
14661     "\n        -{head}light 0|1"
14662     "\n        -{sm}oothness value"
14663     "\n        -{int}ensity value"
14664     "\n        -{constAtten}uation value"
14665     "\n        -{linearAtten}uation value"
14666     "\n        -angle angleDeg"
14667     "\n        -{spotexp}onent value"
14668     "\n        -range value"
14669     "\n        -local|-global"
14670     "\n\n        example: vlight -add positional -head 1 -pos 0 1 1 -color red"
14671     "\n        example: vlight -change 0 -direction 0 -1 0 -linearAttenuation 0.2",
14672     __FILE__, VLight, group);
14673   theCommands.Add("vpbrenv",
14674     "vpbrenv -clear|-generate"
14675     "\n\t\t: Clears or generates PBR environment map of active view."
14676     "\n\t\t:  -clear clears PBR environment (fills by white color)"
14677     "\n\t\t:  -generate generates PBR environment from current background cubemap",
14678     __FILE__, VPBREnvironment, group);
14679   theCommands.Add("vraytrace",
14680             "vraytrace [0|1]"
14681     "\n\t\t: Turns on/off ray-tracing renderer."
14682     "\n\t\t:   'vraytrace 0' alias for 'vrenderparams -raster'."
14683     "\n\t\t:   'vraytrace 1' alias for 'vrenderparams -rayTrace'.",
14684     __FILE__, VRenderParams, group);
14685   theCommands.Add("vrenderparams",
14686     "\n\t\t: Manages rendering parameters, affecting visual appearance, quality and performance."
14687     "\n\t\t: Should be applied taking into account GPU hardware capabilities and performance."
14688     "\n\t\t: Common parameters:"
14689     "\n\t\t: vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]"
14690     "\n\t\t:               [-msaa 0..8=0] [-rendScale scale=1] [-resolution value=72]"
14691     "\n\t\t:               [-oit {off|0.0-1.0}=off]"
14692     "\n\t\t:               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]"
14693     "\n\t\t:               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]"
14694     "\n\t\t:               [-sync {default|views}] [-reset]"
14695     "\n\t\t:   -raster          Disables GPU ray-tracing."
14696     "\n\t\t:   -shadingModel    Controls shading model."
14697     "\n\t\t:   -msaa            Specifies number of samples for MSAA."
14698     "\n\t\t:   -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA)."
14699     "\n\t\t:   -resolution      Sets new pixels density (PPI) used as text scaling factor."
14700     "\n\t\t:   -lineFeather     Sets line feather factor while displaying mesh edges."
14701     "\n\t\t:   -alphaToCoverage Enables/disables alpha to coverage (needs MSAA)."
14702     "\n\t\t:   -oit             Enables/disables order-independent transparency (OIT) rendering;"
14703     "\n\t\t:                    weight OIT fixes transparency artifacts at the cost of blurry result,"
14704     "\n\t\t:                    it is managed by depth weight factor (0.0 value also enables weight OIT)."
14705     "\n\t\t:   -depthPrePass    Enables/disables depth pre-pass."
14706     "\n\t\t:   -frustumCulling  Enables/disables objects frustum clipping or"
14707     "\n\t\t:                    sets state to check structures culled previously."
14708     "\n\t\t:   -sync            Sets active View parameters as Viewer defaults / to other Views."
14709     "\n\t\t:   -reset           Resets active View parameters to Viewer defaults."
14710     "\n\t\t: Diagnostic output (on-screen overlay):"
14711     "\n\t\t: vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points"
14712     "\n\t\t:                             |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]"
14713     "\n\t\t:               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]"
14714     "\n\t\t:   -perfCounters       Show/hide performance counters (flags can be combined)."
14715     "\n\t\t:   -perfUpdateInterval Performance counters update interval."
14716     "\n\t\t:   -perfChart          Show frame timers chart limited by specified number of frames."
14717     "\n\t\t:   -perfChartMax       Maximum time in seconds with the chart."
14718     "\n\t\t: Ray-Tracing options:"
14719     "\n\t\t: vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-shadows {on|off}=on] [-reflections {on|off}=off]"
14720     "\n\t\t:               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]"
14721     "\n\t\t:               [-gi {on|off}=off] [-brng {on|off}=off]"
14722     "\n\t\t:               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]"
14723     "\n\t\t:               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]"
14724     "\n\t\t:               [-maxRad {value>0}=30.0]"
14725     "\n\t\t:               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]"
14726     "\n\t\t:               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]"
14727     "\n\t\t:   -rayTrace     Enables  GPU ray-tracing."
14728     "\n\t\t:   -rayDepth     Defines maximum ray-tracing depth."
14729     "\n\t\t:   -shadows      Enables/disables shadows rendering."
14730     "\n\t\t:   -reflections  Enables/disables specular reflections."
14731     "\n\t\t:   -fsaa         Enables/disables adaptive anti-aliasing."
14732     "\n\t\t:   -gleam        Enables/disables transparency shadow effects."
14733     "\n\t\t:   -gi           Enables/disables global illumination effects (Path-Tracing)."
14734     "\n\t\t:   -env          Enables/disables environment map background."
14735     "\n\t\t:   -ignoreNormalMap Enables/disables normal map ignoring during path tracing."
14736     "\n\t\t:   -twoSide      Enables/disables two-sided BSDF models (PT mode)."
14737     "\n\t\t:   -iss          Enables/disables adaptive screen sampling (PT mode)."
14738     "\n\t\t:   -maxRad       Value used for clamping radiance estimation (PT mode)."
14739     "\n\t\t:   -tileSize     Specifies   size of screen tiles in ISS mode (32 by default)."
14740     "\n\t\t:   -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default)."
14741     "\n\t\t:   -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF)."
14742     "\n\t\t:   -focal        Focal distance of perspective camera for depth-of-field effect."
14743     "\n\t\t:   -exposure     Exposure value for tone mapping (0.0 value disables the effect)."
14744     "\n\t\t:   -whitePoint   White point value for filmic tone mapping."
14745     "\n\t\t:   -toneMapping  Tone mapping mode (disabled, filmic)."
14746     "\n\t\t: PBR environment baking parameters (advanced/debug):"
14747     "\n\t\t: vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]"
14748     "\n\t\t:               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]"
14749     "\n\t\t:   -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size)."
14750     "\n\t\t:   -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map."
14751     "\n\t\t:   -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during"
14752     "\n\t\t:                   diffuse IBL map's sherical harmonics calculation."
14753     "\n\t\t:   -pbrEnvBSSN     Controls maximum number of samples per mipmap level"
14754     "\n\t\t:                   in Monte-Carlo integration during specular IBL maps generation."
14755     "\n\t\t:   -pbrEnvBP       Controls strength of samples number reducing"
14756     "\n\t\t:                   during specular IBL maps generation (1 disables reducing)."
14757     "\n\t\t: Debug options:"
14758     "\n\t\t: vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]"
14759     "\n\t\t:   -issd         Shows screen sampling distribution in ISS mode."
14760     "\n\t\t:   -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging)."
14761     "\n\t\t:   -brng         Enables/disables blocked RNG (fast coherent PT).",
14762     __FILE__, VRenderParams, group);
14763   theCommands.Add("vstatprofiler",
14764     "\n vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups"
14765     "\n                |allArrays|fillArrays|lineArrays|pointArrays|textArrays"
14766     "\n                |triangles|points|geomMem|textureMem|frameMem"
14767     "\n                |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage"
14768     "\n                |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]"
14769     "\n                [-noredraw]"
14770     "\n\t\t: Prints rendering statistics."
14771     "\n\t\t:   If there are some parameters - print corresponding statistic counters values,"
14772     "\n\t\t:   else - print all performance counters set previously."
14773     "\n\t\t:   '-noredraw' Flag to avoid additional redraw call and use already collected values.\n",
14774     __FILE__, VStatProfiler, group);
14775   theCommands.Add ("vplace",
14776             "vplace dx dy"
14777     "\n\t\t: Places the point (in pixels) at the center of the window",
14778     __FILE__, VPlace, group);
14779   theCommands.Add("vxrotate",
14780     "vxrotate",
14781     __FILE__,VXRotate,group);
14782
14783     theCommands.Add("vmanipulator",
14784       "\n    vmanipulator Name [-attach AISObject | -detach | ...]"
14785       "\n    tool to create and manage AIS manipulators."
14786       "\n    Options: "
14787       "\n      '-attach AISObject'                 attach manipulator to AISObject"
14788       "\n      '-adjustPosition {0|1}'             adjust position when attaching"
14789       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
14790       "\n      '-enableModes    {0|1}'             enable modes when attaching"
14791       "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
14792       "\n                                          by default it is displayed in all views of the current viewer"
14793       "\n      '-detach'                           detach manipulator"
14794       "\n      '-startTransform mouse_x mouse_y' - invoke start of transformation"
14795       "\n      '-transform      mouse_x mouse_y' - invoke transformation"
14796       "\n      '-stopTransform  [abort]'         - invoke stop of transformation"
14797       "\n      '-move x y z'                     - move attached object"
14798       "\n      '-rotate x y z dx dy dz angle'    - rotate attached object"
14799       "\n      '-scale factor'                   - scale attached object"
14800       "\n      '-autoActivate      {0|1}'        - set activation on detection"
14801       "\n      '-followTranslation {0|1}'        - set following translation transform"
14802       "\n      '-followRotation    {0|1}'        - set following rotation transform"
14803       "\n      '-followDragging    {0|1}'        - set following dragging transform"
14804       "\n      '-gap value'                      - set gap between sub-parts"
14805       "\n      '-part axis mode    {0|1}'        - set visual part"
14806       "\n      '-parts axis mode   {0|1}'        - set visual part"
14807       "\n      '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator"
14808       "\n      '-size value'                     - set size of manipulator"
14809       "\n      '-zoomable {0|1}'                 - set zoom persistence",
14810     __FILE__, VManipulator, group);
14811
14812   theCommands.Add("vselprops",
14813     "\n    vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]"
14814     "\n    Customizes selection and dynamic highlight parameters for the whole interactive context:"
14815     "\n    -autoActivate {0|1}     : disables|enables default computation and activation of global selection mode"
14816     "\n    -autoHighlight {0|1}    : disables|enables automatic highlighting in 3D Viewer"
14817     "\n    -highlightSelected {0|1}: disables|enables highlighting of detected object in selected state"
14818     "\n    -pickStrategy {first|topmost} : defines picking strategy"
14819     "\n                            'first'   to pick first acceptable (default)"
14820     "\n                            'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)"
14821     "\n    -pixTol    value        : sets up pixel tolerance"
14822     "\n    -dispMode  dispMode     : sets display mode for highlighting"
14823     "\n    -layer     ZLayer       : sets ZLayer for highlighting"
14824     "\n    -color     {name|r g b} : sets highlight color"
14825     "\n    -transp    value        : sets transparency coefficient for highlight"
14826     "\n    -material  material     : sets highlight material"
14827     "\n    -print                  : prints current state of all mentioned parameters",
14828     __FILE__, VSelectionProperties, group);
14829   theCommands.Add ("vhighlightselected",
14830                    "vhighlightselected [0|1]: alias for vselprops -highlightSelected.\n",
14831                    __FILE__, VSelectionProperties, group);
14832
14833   theCommands.Add ("vseldump",
14834                    "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
14835                    "\n\t\t:       [-xrPose base|head=base]"
14836                    "\n\t\t: Generate an image based on detection results:"
14837                    "\n\t\t:   depth       normalized depth values"
14838                    "\n\t\t:   unnormDepth unnormalized depth values"
14839                    "\n\t\t:   object      color of detected object"
14840                    "\n\t\t:   owner       color of detected owner"
14841                    "\n\t\t:   selMode     color of selection mode"
14842                    "\n\t\t:   entity      color of etected entity",
14843                    __FILE__, VDumpSelectionImage, group);
14844
14845   theCommands.Add ("vviewcube",
14846                    "vviewcube name"
14847                    "\n\t\t: Displays interactive view manipualtion object."
14848                    "\n\t\t: Options: "
14849                    "\n\t\t:   -reset                   reset geomertical and visual attributes'"
14850                    "\n\t\t:   -size Size               adapted size of View Cube"
14851                    "\n\t\t:   -boxSize Size            box size"
14852                    "\n\t\t:   -axes {0|1 }             show/hide axes (trihedron)"
14853                    "\n\t\t:   -edges {0|1}             show/hide edges of View Cube"
14854                    "\n\t\t:   -vertices {0|1}          show/hide vertices of View Cube"
14855                    "\n\t\t:   -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation"
14856                    "\n\t\t:   -color Color             color of View Cube"
14857                    "\n\t\t:   -boxColor Color          box color"
14858                    "\n\t\t:   -boxSideColor Color      box sides color"
14859                    "\n\t\t:   -boxEdgeColor Color      box edges color"
14860                    "\n\t\t:   -boxCornerColor Color    box corner color"
14861                    "\n\t\t:   -textColor Color         color of side text of view cube"
14862                    "\n\t\t:   -innerColor Color        inner box color"
14863                    "\n\t\t:   -transparency Value      transparency of object within [0, 1] range"
14864                    "\n\t\t:   -boxTransparency Value   transparency of box    within [0, 1] range"
14865                    "\n\t\t:   -font Name               font name"
14866                    "\n\t\t:   -fontHeight Value        font height"
14867                    "\n\t\t:   -boxFacetExtension Value box facet extension"
14868                    "\n\t\t:   -boxEdgeGap Value        gap between box edges and box sides"
14869                    "\n\t\t:   -boxEdgeMinSize Value    minimal box edge size"
14870                    "\n\t\t:   -boxCornerMinSize Value  minimal box corner size"
14871                    "\n\t\t:   -axesPadding Value       padding between box and arrows"
14872                    "\n\t\t:   -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range"
14873                    "\n\t\t:   -axesRadius Value        radius of axes of the trihedron"
14874                    "\n\t\t:   -axesConeRadius Value    radius of the cone (arrow) of the trihedron"
14875                    "\n\t\t:   -axesSphereRadius Value  radius of the sphere (central point) of trihedron"
14876                    "\n\t\t:   -fixedanimation {0|1}    uninterruptible animation loop"
14877                    "\n\t\t:   -duration Seconds        animation duration in seconds",
14878     __FILE__, VViewCube, group);
14879
14880   theCommands.Add("vcolorconvert" ,
14881                   "vcolorconvert {from|to} type C1 C2 C2"
14882                   "\n\t\t: vcolorconvert from type C1 C2 C2: Converts color from specified color space to linear RGB"
14883                   "\n\t\t: vcolorconvert to type R G B: Converts linear RGB color to specified color space"
14884                   "\n\t\t: type can be sRGB, HLS, Lab, or Lch",
14885                   __FILE__,VColorConvert,group);
14886   theCommands.Add("vcolordiff" ,
14887                   "vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
14888                   __FILE__,VColorDiff,group);
14889 }