5e37d27fe5a106cc4e1e2b878d4df099aa9c94db
[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_LightSource.hxx>
26 #include <AIS_ListOfInteractive.hxx>
27 #include <AIS_ListIteratorOfListOfInteractive.hxx>
28 #include <AIS_Manipulator.hxx>
29 #include <AIS_ViewCube.hxx>
30 #include <AIS_Shape.hxx>
31 #include <Aspect_DisplayConnection.hxx>
32 #include <Aspect_Grid.hxx>
33 #include <Aspect_TypeOfLine.hxx>
34 #include <Draw.hxx>
35 #include <Draw_Appli.hxx>
36 #include <Draw_Interpretor.hxx>
37 #include <Draw_ProgressIndicator.hxx>
38 #include <gp_Dir.hxx>
39 #include <gp_Pln.hxx>
40 #include <gp_Pnt.hxx>
41 #include <Graphic3d_ArrayOfPolylines.hxx>
42 #include <Graphic3d_AspectFillArea3d.hxx>
43 #include <Graphic3d_AspectMarker3d.hxx>
44 #include <Graphic3d_ClipPlane.hxx>
45 #include <Graphic3d_CubeMapPacked.hxx>
46 #include <Graphic3d_CubeMapSeparate.hxx>
47 #include <Graphic3d_GraduatedTrihedron.hxx>
48 #include <Graphic3d_NameOfTextureEnv.hxx>
49 #include <Graphic3d_Texture2Dmanual.hxx>
50 #include <Graphic3d_TextureEnv.hxx>
51 #include <Graphic3d_TextureParams.hxx>
52 #include <Graphic3d_TypeOfTextureFilter.hxx>
53 #include <Image_AlienPixMap.hxx>
54 #include <Image_Diff.hxx>
55 #include <Image_VideoRecorder.hxx>
56 #include <Message_ProgressScope.hxx>
57 #include <Message_ProgressRange.hxx>
58 #include <NCollection_DataMap.hxx>
59 #include <NCollection_List.hxx>
60 #include <NCollection_LocalArray.hxx>
61 #include <NCollection_Vector.hxx>
62 #include <OSD.hxx>
63 #include <OSD_Parallel.hxx>
64 #include <OSD_Timer.hxx>
65 #include <OpenGl_GraphicDriver.hxx>
66 #include <Prs3d_ShadingAspect.hxx>
67 #include <Prs3d_DatumAspect.hxx>
68 #include <Prs3d_Drawer.hxx>
69 #include <Prs3d_LineAspect.hxx>
70 #include <Prs3d_Text.hxx>
71 #include <Select3D_SensitivePrimitiveArray.hxx>
72 #include <TColStd_HSequenceOfAsciiString.hxx>
73 #include <TColStd_SequenceOfInteger.hxx>
74 #include <TColStd_HSequenceOfReal.hxx>
75 #include <TColgp_Array1OfPnt2d.hxx>
76 #include <TColStd_MapOfAsciiString.hxx>
77 #include <ViewerTest_AutoUpdater.hxx>
78 #include <ViewerTest_ContinuousRedrawer.hxx>
79 #include <ViewerTest_EventManager.hxx>
80 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
81 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
82 #include <ViewerTest_CmdParser.hxx>
83 #include <ViewerTest_V3dView.hxx>
84 #include <V3d_AmbientLight.hxx>
85 #include <V3d_DirectionalLight.hxx>
86 #include <V3d_PositionalLight.hxx>
87 #include <V3d_SpotLight.hxx>
88 #include <V3d_Trihedron.hxx>
89
90 #include <tcl.h>
91
92 #include <cstdlib>
93
94 #if defined(_WIN32)
95   #include <WNT_WClass.hxx>
96   #include <WNT_Window.hxx>
97   #include <WNT_HIDSpaceMouse.hxx>
98 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
99   #include <Cocoa_Window.hxx>
100 #else
101   #include <Xw_Window.hxx>
102   #include <X11/Xlib.h> /* contains some dangerous #defines such as Status, True etc. */
103   #include <X11/Xutil.h>
104   #include <tk.h>
105 #endif
106
107 //==============================================================================
108 //  VIEWER GLOBAL VARIABLES
109 //==============================================================================
110
111 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
112 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
113
114 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
115 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
116
117 #if defined(_WIN32)
118 static Handle(WNT_Window)& VT_GetWindow() {
119   static Handle(WNT_Window) WNTWin;
120   return WNTWin;
121 }
122 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
123 static Handle(Cocoa_Window)& VT_GetWindow()
124 {
125   static Handle(Cocoa_Window) aWindow;
126   return aWindow;
127 }
128 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
129 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
130
131 #else
132 static Handle(Xw_Window)& VT_GetWindow(){
133   static Handle(Xw_Window) XWWin;
134   return XWWin;
135 }
136
137 static void VProcessEvents(ClientData,int);
138 #endif
139
140 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
141 {
142   static Handle(Aspect_DisplayConnection) aDisplayConnection;
143   return aDisplayConnection;
144 }
145
146 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
147 {
148   GetDisplayConnection() = theDisplayConnection;
149 }
150
151 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
152 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
153 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
154 static OpenGl_Caps ViewerTest_myDefaultCaps;
155
156 static void OSWindowSetup();
157
158 static struct
159 {
160   Quantity_Color FlatColor;
161   Quantity_Color GradientColor1;
162   Quantity_Color GradientColor2;
163   Aspect_GradientFillMethod FillMethod;
164 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
165
166 //==============================================================================
167 //  EVENT GLOBAL VARIABLES
168 //==============================================================================
169
170 Standard_Boolean TheIsAnimating = Standard_False;
171
172 namespace
173 {
174
175   //! Checks if some set is a subset of other set
176   //! @tparam TheSuperSet the type of the superset
177   //! @tparam TheSubSet the type of the subset
178   //! @param theSuperSet the superset
179   //! @param theSubSet the subset to be checked
180   //! @return true if the superset includes subset, or false otherwise
181   template <typename TheSuperSet, typename TheSubSet>
182   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
183   {
184     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
185   }
186
187   //! A variable set of keys for command-line options.
188   //! It includes a set of mandatory keys and a set of all possible keys.
189   class CommandOptionKeyVariableSet
190   {
191   public:
192     //! Default constructor
193     CommandOptionKeyVariableSet()
194     {
195     }
196
197     //! Constructor
198     //! @param theMandatoryKeySet the set of the mandatory option keys
199     //! @param theAdditionalKeySet the set of additional options that could be omitted
200     CommandOptionKeyVariableSet (
201       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
202       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
203     : myMandatoryKeySet (theMandatoryKeySet)
204     {
205       std::set_union (theMandatoryKeySet.begin(),
206                       theMandatoryKeySet.end(),
207                       theAdditionalKeySet.begin(),
208                       theAdditionalKeySet.end(),
209                       std::inserter (myFullKeySet, myFullKeySet.begin()));
210     }
211
212     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
213     //! and be contained in the full key set)
214     //! @param theCheckedKeySet the set of option keys to be checked
215     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
216     {
217       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
218     }
219
220   private:
221     //! A set of mandatory command-line option keys
222     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
223
224     //! A full set of command-line option keys (includes mandatory and additional option keys)
225     ViewerTest_CommandOptionKeySet myFullKeySet;
226   };
227
228   //! Gets some code by its name
229   //! @tparam TheCode the type of a code to be found
230   //! @param theCodeNameMap the map from code names to codes
231   //! @param theCodeName the name of a code to be found
232   //! @param theCode the code to be found
233   //! @return true if a code is found, or false otherwise
234   template <typename TheCode>
235   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
236                                  TCollection_AsciiString                           theCodeName,
237                                  TheCode&                                          theCode)
238   {
239     theCodeName.LowerCase();
240     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
241       theCodeName);
242     if (aCodeIterator == theCodeNameMap.end())
243     {
244       return false;
245     }
246     theCode = aCodeIterator->second;
247     return true;
248   }
249
250   // Defines possible commands related to background changing
251   enum BackgroundCommand
252   {
253     BackgroundCommand_Main,              //!< The main command that manages other commands through options
254     BackgroundCommand_Image,             //!< Sets an image as a background
255     BackgroundCommand_ImageMode,         //!< Changes a background image mode
256     BackgroundCommand_Gradient,          //!< Sets a gradient as a background
257     BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
258     BackgroundCommand_Color,             //!< Fills background with a specified color
259     BackgroundCommand_Default            //!< Sets the background default color or gradient
260   };
261
262   //! Map from background command names to its codes
263   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
264
265   //! Creates a map from background command names to its codes
266   //! @return a map from background command names to its codes
267   static BackgroundCommandNameMap createBackgroundCommandNameMap()
268   {
269     BackgroundCommandNameMap aBackgroundCommandNameMap;
270     aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
271     aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
272     aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
273     aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
274     aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
275     aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
276     aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
277     return aBackgroundCommandNameMap;
278   }
279
280   //! Gets a background command by its name
281   //! @param theBackgroundCommandName the name of the background command
282   //! @param theBackgroundCommand the background command to be found
283   //! @return true if a background command is found, or false otherwise
284   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
285                                           BackgroundCommand&             theBackgroundCommand)
286   {
287     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
288     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
289   }
290
291   //! Map from background image fill method names to its codes
292   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
293
294   //! Creates a map from background image fill method names to its codes
295   //! @return a map from background image fill method names to its codes
296   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
297   {
298     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
299     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
300     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
301     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
302     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
303     return aBackgroundImageFillMethodNameMap;
304   }
305
306   //! Gets a background image fill method by its name
307   //! @param theBackgroundImageFillMethodName the name of the background image fill method
308   //! @param theBackgroundImageFillMethod the background image fill method to be found
309   //! @return true if a background image fill method is found, or false otherwise
310   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
311                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
312   {
313     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
314       createBackgroundImageFillMethodNameMap();
315     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
316                               theBackgroundImageFillMethodName,
317                               theBackgroundImageFillMethod);
318   }
319
320   //! Map from background gradient fill method names to its codes
321   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
322
323   //! Creates a map from background gradient fill method names to its codes
324   //! @return a map from background gradient fill method names to its codes
325   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
326   {
327     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
328     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
329     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
330     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
331     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
332     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
333     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
334     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
335     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
336     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
337     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
338     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
339     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
340     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
341     return aBackgroundGradientFillMethodNameMap;
342   }
343
344   //! Gets a gradient fill method by its name
345   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
346   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
347   //! @return true if a gradient fill method is found, or false otherwise
348   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
349                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
350   {
351     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
352       createBackgroundGradientFillMethodNameMap();
353     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
354                               theBackgroundGradientFillMethodName,
355                               theBackgroundGradientFillMethod);
356   }
357
358   //! Changes the background in accordance with passed command line options
359   class BackgroundChanger
360   {
361   public:
362     //! Constructor. Prepares the command parser
363     BackgroundChanger()
364     {
365       prepareCommandParser();
366     }
367
368     //! Processes the command line and changes the background
369     //! @param theDrawInterpretor the interpreter of the Draw Harness application
370     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
371     //! @param theCommandLineArguments the array of command line arguments
372     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
373                              const Standard_Integer   theNumberOfCommandLineArguments,
374                              const char* const* const theCommandLineArguments)
375     {
376       const char* const aBackgroundCommandName = theCommandLineArguments[0];
377       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
378       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
379       {
380         return false;
381       }
382       addCommandDescription (aBackgroundCommand);
383       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
384       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
385     }
386
387   private:
388     //! The type of functions that are able to set gradient background filling
389     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
390                                       const Quantity_Color& /* theColor2 */,
391                                       const Aspect_GradientFillMethod /* theGradientMode */);
392
393     //! The type of functions that are able to fill a background with a specific color
394     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
395
396     //! the command parser used to parse command line options and its arguments
397     ViewerTest_CmdParser myCommandParser;
398
399     //! the option key for the command that sets an image as a background
400     ViewerTest_CommandOptionKey myImageOptionKey;
401
402     //! the option key for the command that sets a background image fill type
403     ViewerTest_CommandOptionKey myImageModeOptionKey;
404
405     //! the option key for the command that sets a gradient filling for the background
406     ViewerTest_CommandOptionKey myGradientOptionKey;
407
408     //! the option key for the command that sets a background gradient filling method
409     ViewerTest_CommandOptionKey myGradientModeOptionKey;
410
411     //! the option key for the command that fills background with a specific color
412     ViewerTest_CommandOptionKey myColorOptionKey;
413
414     //! the option key for the command that sets default background gradient or color
415     ViewerTest_CommandOptionKey myDefaultOptionKey;
416
417     //! the option key for the command that sets an environment cubemap as a background
418     ViewerTest_CommandOptionKey myCubeMapOptionKey;
419
420     //! the option key for the command that defines order of tiles in one image packed cubemap
421     ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
422
423     //! the option key for the command that sets inversion of Z axis for background cubemap
424     ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
425
426     //! the option key for the command that allows skip IBL map generation
427     ViewerTest_CommandOptionKey myCubeMapDoNotGenPBREnvOptionKey;
428
429     //! the variable set of options that are allowed for the old scenario (without any option passed)
430     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
431
432     //! the variable set of options that are allowed for setting an environment cubemap as background
433     CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
434
435     //! the variable set of options that are allowed for setting an image as a background
436     CommandOptionKeyVariableSet myImageOptionVariableSet;
437
438     //! the variable set of options that are allowed for setting a background image fill type
439     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
440
441     //! the variable set of options that are allowed for setting a gradient filling for the background
442     CommandOptionKeyVariableSet myGradientOptionVariableSet;
443
444     //! the variable set of options that are allowed for setting a background gradient filling method
445     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
446
447     //! the variable set of options that are allowed for filling a background with a specific color
448     CommandOptionKeyVariableSet myColorOptionVariableSet;
449
450     //! the variable set of options that are allowed for setting a default background gradient
451     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
452
453     //! the variable set of options that are allowed for setting a default background color
454     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
455
456     //! the variable set of options that are allowed for printing help
457     CommandOptionKeyVariableSet myHelpOptionVariableSet;
458
459     //! Adds options to command parser
460     void addOptionsToCommandParser()
461     {
462       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
463                                                     "filename of image used as background");
464       myImageModeOptionKey = myCommandParser.AddOption (
465         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
466       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
467                                                        "sets background gradient starting and ending colors");
468       myGradientModeOptionKey =
469         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
470                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
471                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
472       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
473       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
474
475       myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
476       myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
477       myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
478         "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
479       myCubeMapDoNotGenPBREnvOptionKey = myCommandParser.AddOption ("nopbrenv", "whether IBL map generation should be skipped");
480     }
481
482     //! Creates option sets used to determine if a passed option set is valid or not
483     void createOptionSets()
484     {
485       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
486       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
487       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
488
489       ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
490       aCubeMapOptionSet.insert (myCubeMapOptionKey);
491       ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
492       aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
493       aCubeMapAdditionalOptionKeySet.insert (myCubeMapDoNotGenPBREnvOptionKey);
494       aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
495       myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
496
497       ViewerTest_CommandOptionKeySet anImageOptionSet;
498       anImageOptionSet.insert (myImageOptionKey);
499       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
500       anImageModeOptionSet.insert (myImageModeOptionKey);
501       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
502       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
503
504       ViewerTest_CommandOptionKeySet aGradientOptionSet;
505       aGradientOptionSet.insert (myGradientOptionKey);
506       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
507       aGradientModeOptionSet.insert (myGradientModeOptionKey);
508       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
509       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
510
511       ViewerTest_CommandOptionKeySet aColorOptionSet;
512       aColorOptionSet.insert (myColorOptionKey);
513       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
514
515       aGradientOptionSet.insert (myDefaultOptionKey);
516       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
517       aColorOptionSet.insert (myDefaultOptionKey);
518       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
519
520       ViewerTest_CommandOptionKeySet aHelpOptionSet;
521       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
522       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
523     }
524
525     //! Prepares the command parser. Adds options and creates option sets used to determine
526     //! if a passed option set is valid or not
527     void prepareCommandParser()
528     {
529       addOptionsToCommandParser();
530       createOptionSets();
531     }
532
533     //! Adds a command description to the command parser
534     //! @param theBackgroundCommand the key of the command which description is added to the command parser
535     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
536     {
537       std::string aDescription;
538       bool        isMainCommand = false;
539       switch (theBackgroundCommand)
540       {
541         case BackgroundCommand_Main:
542           aDescription  = "Command: vbackground (changes background or some background settings)";
543           isMainCommand = true;
544           break;
545         case BackgroundCommand_Image:
546           aDescription = "Command: vsetbg (loads image as a background)";
547           break;
548         case BackgroundCommand_ImageMode:
549           aDescription = "Command: vsetbgmode (changes background fill type)";
550           break;
551         case BackgroundCommand_Gradient:
552           aDescription = "Command: vsetgradientbg (mounts gradient background)";
553           break;
554         case BackgroundCommand_GradientMode:
555           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
556           break;
557         case BackgroundCommand_Color:
558           aDescription = "Command: vsetcolorbg (sets color background)";
559           break;
560         case BackgroundCommand_Default:
561           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
562           break;
563         default:
564           return;
565       }
566       if (!isMainCommand)
567       {
568         aDescription += "\nThis command is obsolete. Use vbackground instead.";
569       }
570       myCommandParser.SetDescription (aDescription);
571     }
572
573     //! Check if a viewer is needed to be initialized
574     //! @param theBackgroundCommand the key of the command that changes the background
575     //! @return true if processing was successful, or false otherwise
576     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
577     {
578       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
579       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
580       const bool                           aViewerIsNotNeeded =
581         (theBackgroundCommand == BackgroundCommand_Default)
582         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
583         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
584         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
585       return !aViewerIsNotNeeded;
586     }
587
588     //! Check if a viewer is initialized
589     //! @param theBackgroundCommandName the name of the command that changes the background
590     //! @param theDrawInterpretor the interpreter of the Draw Harness application
591     //! @return true if a viewer is initialized, or false otherwise
592     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
593                                           Draw_Interpretor& theDrawInterpretor)
594     {
595       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
596       if (anAISContext.IsNull())
597       {
598         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
599         return false;
600       }
601       return true;
602     }
603
604     //! Processes command options
605     //! @param theBackgroundCommandName the name of the command that changes the background
606     //! @param theBackgroundCommand the key of the command that changes the background
607     //! @param theDrawInterpretor the interpreter of the Draw Harness application
608     //! @return true if processing was successful, or false otherwise
609     bool processCommandOptions (const char* const       theBackgroundCommandName,
610                                 const BackgroundCommand theBackgroundCommand,
611                                 Draw_Interpretor&       theDrawInterpretor) const
612     {
613       if (myCommandParser.HasNoOption())
614       {
615         return printHelp (theBackgroundCommandName, theDrawInterpretor);
616       }
617       if (checkViewerIsNeeded (theBackgroundCommand)
618           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
619       {
620         return false;
621       }
622       if (myCommandParser.HasOnlyUnnamedOption())
623       {
624         return processUnnamedOption (theBackgroundCommand);
625       }
626       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
627     }
628
629     //! Processes the unnamed option
630     //! @param theBackgroundCommand the key of the command that changes the background
631     //! @return true if processing was successful, or false otherwise
632     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
633     {
634       switch (theBackgroundCommand)
635       {
636         case BackgroundCommand_Main:
637           return false;
638         case BackgroundCommand_Image:
639           return processImageUnnamedOption();
640         case BackgroundCommand_ImageMode:
641           return processImageModeUnnamedOption();
642         case BackgroundCommand_Gradient:
643           return processGradientUnnamedOption();
644         case BackgroundCommand_GradientMode:
645           return processGradientModeUnnamedOption();
646         case BackgroundCommand_Color:
647           return processColorUnnamedOption();
648         case BackgroundCommand_Default:
649           return processDefaultUnnamedOption();
650         default:
651           return false;
652       }
653     }
654
655     //! Processes the image unnamed option
656     //! @return true if processing was successful, or false otherwise
657     bool processImageUnnamedOption() const
658     {
659       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
660         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
661       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
662       {
663         return false;
664       }
665       std::string anImageFileName;
666       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
667       {
668         return false;
669       }
670       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
671       if (aNumberOfImageUnnamedOptionArguments == 2)
672       {
673         std::string anImageModeString;
674         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
675         {
676           return false;
677         }
678         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
679         {
680           return false;
681         }
682       }
683       setImage (anImageFileName.c_str(), anImageMode);
684       return true;
685     }
686
687     //! Processes the image mode unnamed option
688     //! @return true if processing was successful, or false otherwise
689     bool processImageModeUnnamedOption() const
690     {
691       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
692     }
693
694     //! Processes the gradient unnamed option
695     //! @param theSetGradient the function used to set a background gradient filling
696     //! @return true if processing was successful, or false otherwise
697     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
698     {
699       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
700         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
701       if (aNumberOfGradientUnnamedOptionArguments < 2)
702       {
703         return false;
704       }
705
706       Standard_Integer anArgumentIndex = 0;
707       Quantity_Color   aColor1;
708       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
709       {
710         return false;
711       }
712       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
713       {
714         return false;
715       }
716
717       Quantity_Color aColor2;
718       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
719       {
720         return false;
721       }
722       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
723       {
724         return false;
725       }
726
727       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
728       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
729       {
730         std::string anGradientModeString;
731
732         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
733                                   anArgumentIndex,
734                                   anGradientModeString))
735         {
736           return false;
737         }
738         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
739         {
740           return false;
741         }
742         ++anArgumentIndex;
743       }
744       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
745       {
746         return false;
747       }
748       theSetGradient (aColor1, aColor2, aGradientMode);
749       return true;
750     }
751
752     //! Processes the gradient mode unnamed option
753     //! @return true if processing was successful, or false otherwise
754     bool processGradientModeUnnamedOption() const
755     {
756       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
757     }
758
759     //! Processes the color unnamed option
760     //! @param theSetColor the function used to set a background color
761     //! @return true if processing was successful, or false otherwise
762     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
763     {
764       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
765     }
766
767     //! Processes the default back unnamed option
768     //! @return true if processing was successful, or false otherwise
769     bool processDefaultUnnamedOption() const
770     {
771       if (processGradientUnnamedOption (setDefaultGradient))
772       {
773         return true;
774       }
775       return processColorUnnamedOption (setDefaultColor);
776     }
777
778     //! Processes named options
779     //! @param theBackgroundCommandName the name of the command that changes the background
780     //! @param theBackgroundCommand the key of the command that changes the background
781     //! @param theDrawInterpretor the interpreter of the Draw Harness application
782     //! @return true if processing was successful, or false otherwise
783     bool processNamedOptions (const char* const       theBackgroundCommandName,
784                               const BackgroundCommand theBackgroundCommand,
785                               Draw_Interpretor&       theDrawInterpretor) const
786     {
787       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
788       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
789       if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
790       {
791         return processCubeMapOptionSet();
792       }
793       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
794           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
795       {
796         return processImageOptionSet();
797       }
798       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
799           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
800       {
801         return processImageModeOptionSet();
802       }
803       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
804           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
805       {
806         return processGradientOptionSet();
807       }
808       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
809           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
810       {
811         return processGradientModeOptionSet();
812       }
813       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
814           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
815       {
816         return processColorOptionSet();
817       }
818       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
819           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
820               && (theBackgroundCommand == BackgroundCommand_Default)))
821       {
822         return processDefaultGradientOptionSet();
823       }
824       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
825           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
826       {
827         return processDefaultColorOptionSet();
828       }
829       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
830       {
831         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
832       }
833       return false;
834     }
835
836     //! Process the cubemap option set in named and unnamed case.
837     //! @return true if processing was successful, or false otherwise
838     bool processCubeMapOptionSet() const
839     {
840       NCollection_Array1<TCollection_AsciiString> aFilePaths;
841
842       if (!processCubeMapOptions (aFilePaths))
843       {
844         return false;
845       }
846
847       Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
848
849       if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
850       {
851         if (!processCubeMapOrderOptions (anOrder))
852         {
853           return false;
854         }
855       }
856
857       bool aZIsInverted = false;
858       if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
859       {
860         if (!processCubeMapInvertedZOptionSet())
861         {
862           return false;
863         }
864         aZIsInverted = true;
865       }
866
867       bool aToGenPBREnv = true;
868       if (myCommandParser.HasOption (myCubeMapDoNotGenPBREnvOptionKey))
869       {
870         if (!processCubeMapDoNotGenPBREnvOptionSet())
871         {
872           return false;
873         }
874         aToGenPBREnv = false;
875       }
876
877       setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted, aToGenPBREnv);
878       return true;
879     }
880
881     //! Processes the image option set
882     //! @return true if processing was successful, or false otherwise
883     bool processImageOptionSet() const
884     {
885       std::string anImageFileName;
886       if (!processImageOption (anImageFileName))
887       {
888         return false;
889       }
890       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
891       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
892       {
893         return false;
894       }
895       setImage (anImageFileName.c_str(), anImageMode);
896       return true;
897     }
898
899     //! Processes the image mode option set
900     //! @return true if processing was successful, or false otherwise
901     bool processImageModeOptionSet() const
902     {
903       return processImageModeOptionSet (myImageModeOptionKey);
904     }
905
906     //! Processes the image mode option set
907     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
908     //! @return true if processing was successful, or false otherwise
909     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
910     {
911       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
912       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
913       {
914         return false;
915       }
916       setImageMode (anImageMode);
917       return true;
918     }
919
920     //! Processes the gradient option set
921     //! @param theSetGradient the function used to set a background gradient filling
922     //! @return true if processing was successful, or false otherwise
923     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
924     {
925       Quantity_Color aColor1;
926       Quantity_Color aColor2;
927       if (!processGradientOption (aColor1, aColor2))
928       {
929         return false;
930       }
931       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
932       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
933       {
934         return false;
935       }
936       theSetGradient (aColor1, aColor2, aGradientMode);
937       return true;
938     }
939
940     //! Processes the gradient mode option set
941     //! @return true if processing was successful, or false otherwise
942     bool processGradientModeOptionSet() const
943     {
944       return processGradientModeOptionSet (myGradientModeOptionKey);
945     }
946
947     //! Processes the gradient mode option set
948     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
949     //! @return true if processing was successful, or false otherwise
950     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
951     {
952       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
953       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
954       {
955         return false;
956       }
957       setGradientMode (aGradientMode);
958       return true;
959     }
960
961     //! Processes the color option set
962     //! @param theSetColor the function used to set a background color
963     //! @return true if processing was successful, or false otherwise
964     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
965     {
966       return processColorOptionSet (myColorOptionKey, theSetColor);
967     }
968
969     //! Processes the default color option set
970     //! @return true if processing was successful, or false otherwise
971     bool processDefaultGradientOptionSet() const
972     {
973       return processGradientOptionSet (setDefaultGradient);
974     }
975
976     //! Processes the default gradient option set
977     //! @return true if processing was successful, or false otherwise
978     bool processDefaultColorOptionSet() const
979     {
980       return processColorOptionSet (setDefaultColor);
981     }
982
983     //! Processes the color option set
984     //! @param theColorOptionKey the key of the option that is interpreted as a color option
985     //! @param theSetColor the function used to set a background color
986     //! @return true if processing was successful, or false otherwise
987     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
988                                 SetColorFunction* const           theSetColor = setColor) const
989     {
990       Quantity_Color aColor;
991       if (!processColorOption (theColorOptionKey, aColor))
992       {
993         return false;
994       }
995       theSetColor (aColor);
996       return true;
997     }
998
999     //! Processes the help option set
1000     //! @param theBackgroundCommandName the name of the command that changes the background
1001     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1002     //! @return true if processing was successful, or false otherwise
1003     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
1004     {
1005       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1006         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
1007       if (aNumberOfHelpOptionArguments != 0)
1008       {
1009         return false;
1010       }
1011       return printHelp (theBackgroundCommandName, theDrawInterpretor);
1012     }
1013
1014     //! Processes the cubemap option
1015     //! @param theFilePaths the array of filenames of cubemap sides
1016     //! @return true if processing was successful, or false otherwise
1017     bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
1018     {
1019       const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
1020
1021       if (aNumberOfCubeMapOptionArguments != 1
1022        && aNumberOfCubeMapOptionArguments != 6)
1023       {
1024         return false;
1025       }
1026
1027       theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
1028
1029       for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
1030       {
1031         std::string aCubeMapFileName;
1032         if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
1033         {
1034           return false;
1035         }
1036         theFilePaths[i] = aCubeMapFileName.c_str();
1037       }
1038
1039       return true;
1040     }
1041
1042     //! Processes the inverted z cubemap option
1043     //! @return true if processing was successful, or false otherwise
1044     bool processCubeMapInvertedZOptionSet () const
1045     {
1046       const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
1047         myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
1048
1049       if (aNumberOfCubeMapZInversionOptionArguments != 0)
1050       {
1051         return false;
1052       }
1053
1054       return true;
1055     }
1056
1057     //! Processes the option allowing to skip IBM maps generation
1058     //! @return true if processing was successful, or false otherwise
1059     bool processCubeMapDoNotGenPBREnvOptionSet() const
1060     {
1061       const Standard_Integer aNumberOfCubeMapDoNotGenPBREnvOptionArguments =
1062         myCommandParser.GetNumberOfOptionArguments(myCubeMapDoNotGenPBREnvOptionKey);
1063
1064       if (aNumberOfCubeMapDoNotGenPBREnvOptionArguments != 0)
1065       {
1066         return false;
1067       }
1068
1069       return true;
1070     }
1071
1072     //! Processes the tiles order option
1073     //! @param theOrder the array of indexes if cubemap sides in tile grid
1074     //! @return true if processing was successful, or false otherwise
1075     bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
1076     {
1077       const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
1078         myCubeMapOrderOptionKey);
1079
1080       if (aNumberOfCubeMapOrderOptionArguments != 6)
1081       {
1082         return false;
1083       }
1084
1085
1086       for (unsigned int i = 0; i < 6; ++i)
1087       {
1088         std::string anOrderItem;
1089         if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
1090         {
1091           return false;
1092         }
1093
1094         theOrder.Set (Graphic3d_CubeMapSide (i),
1095                       static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
1096       }
1097
1098       return theOrder.IsValid();
1099     }
1100
1101     //! Processes the image option
1102     //! @param theImageFileName the filename of the image to be used as a background
1103     //! @return true if processing was successful, or false otherwise
1104     bool processImageOption (std::string& theImageFileName) const
1105     {
1106       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1107         myImageOptionKey);
1108       if (aNumberOfImageOptionArguments != 1)
1109       {
1110         return false;
1111       }
1112       std::string anImageFileName;
1113       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
1114       {
1115         return false;
1116       }
1117       theImageFileName = anImageFileName;
1118       return true;
1119     }
1120
1121     //! Processes the image mode option
1122     //! @param theImageMode the fill type used for a background image
1123     //! @return true if processing was successful, or false otherwise
1124     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
1125     {
1126       return processImageModeOption (myImageModeOptionKey, theImageMode);
1127     }
1128
1129     //! Processes the image mode option
1130     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
1131     //! @param theImageMode the fill type used for a background image
1132     //! @return true if processing was successful, or false otherwise
1133     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
1134                                  Aspect_FillMethod&                theImageMode) const
1135     {
1136       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
1137     }
1138
1139     //! Processes the gradient option
1140     //! @param theColor1 the gradient starting color
1141     //! @param theColor2 the gradient ending color
1142     //! @return true if processing was successful, or false otherwise
1143     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
1144     {
1145       Standard_Integer anArgumentIndex = 0;
1146       Quantity_Color   aColor1;
1147       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
1148       {
1149         return false;
1150       }
1151       Quantity_Color aColor2;
1152       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
1153       {
1154         return false;
1155       }
1156       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1157         myGradientOptionKey);
1158       if (anArgumentIndex != aNumberOfGradientOptionArguments)
1159       {
1160         return false;
1161       }
1162       theColor1 = aColor1;
1163       theColor2 = aColor2;
1164       return true;
1165     }
1166
1167     //! Processes the gradient mode option
1168     //! @param theGradientMode the fill method used for a background gradient filling
1169     //! @return true if processing was successful, or false otherwise
1170     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
1171     {
1172       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
1173     }
1174
1175     //! Processes the gradient mode option
1176     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1177     //! @param theGradientMode the fill method used for a background gradient filling
1178     //! @return true if processing was successful, or false otherwise
1179     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1180                                     Aspect_GradientFillMethod&        theGradientMode) const
1181     {
1182       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1183     }
1184
1185     //! Processes some mode option
1186     //! @tparam TheMode the type of a mode to be processed
1187     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1188     //! @param theMode a mode to be processed
1189     //! @return true if processing was successful, or false otherwise
1190     template <typename TheMode>
1191     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1192                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1193                                                             TheMode& /* theMode */),
1194                             TheMode& theMode) const
1195     {
1196       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1197         theModeOptionKey);
1198       if (aNumberOfModeOptionArguments != 1)
1199       {
1200         return false;
1201       }
1202       std::string aModeString;
1203       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1204       {
1205         return false;
1206       }
1207       TheMode aMode = TheMode();
1208       if (!theGetModeByName (aModeString.c_str(), aMode))
1209       {
1210         return false;
1211       }
1212       theMode = aMode;
1213       return true;
1214     }
1215
1216     //! Processes the color option
1217     //! @param theColor a color used for filling a background
1218     //! @return true if processing was successful, or false otherwise
1219     bool processColorOption (Quantity_Color& theColor) const
1220     {
1221       return processColorOption (myColorOptionKey, theColor);
1222     }
1223
1224     //! Processes the color option
1225     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1226     //! @param theColor a color used for filling a background
1227     //! @return true if processing was successful, or false otherwise
1228     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1229     {
1230       Standard_Integer anArgumentIndex = 0;
1231       Quantity_Color   aColor;
1232       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1233       {
1234         return false;
1235       }
1236       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1237         theColorOptionKey);
1238       if (anArgumentIndex != aNumberOfColorOptionArguments)
1239       {
1240         return false;
1241       }
1242       theColor = aColor;
1243       return true;
1244     }
1245
1246     //! Prints helping message
1247     //! @param theBackgroundCommandName the name of the command that changes the background
1248     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1249     //! @return true if printing was successful, or false otherwise
1250     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1251     {
1252       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1253     }
1254
1255     //! Sets the cubemap as a background
1256     //! @param theFileNames the array of filenames of packed or multifile cubemap
1257     //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
1258     static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
1259                             const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
1260                             bool                                               theZIsInverted = false,
1261                             bool                                               theToGenPBREnv = true)
1262     {
1263       const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
1264       Handle(Graphic3d_CubeMap) aCubeMap;
1265
1266       if (theFileNames.Size() == 1)
1267         aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
1268       else
1269         aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
1270
1271       aCubeMap->SetZInversion (theZIsInverted);
1272
1273       aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
1274       aCubeMap->GetParams()->SetRepeat(Standard_False);
1275       aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
1276
1277       aCurrentView->SetBackgroundCubeMap (aCubeMap, theToGenPBREnv, Standard_True);
1278     }
1279
1280     //! Sets the image as a background
1281     //! @param theImageFileName the filename of the image to be used as a background
1282     //! @param theImageMode the fill type used for a background image
1283     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1284     {
1285       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1286       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1287     }
1288
1289     //! Sets the fill type used for a background image
1290     //! @param theImageMode the fill type used for a background image
1291     static void setImageMode (const Aspect_FillMethod theImageMode)
1292     {
1293       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1294       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1295     }
1296
1297     //! Sets the gradient filling for a background
1298     //! @param theColor1 the gradient starting color
1299     //! @param theColor2 the gradient ending color
1300     //! @param theGradientMode the fill method used for a background gradient filling
1301     static void setGradient (const Quantity_Color&           theColor1,
1302                              const Quantity_Color&           theColor2,
1303                              const Aspect_GradientFillMethod theGradientMode)
1304     {
1305       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1306       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1307     }
1308
1309     //! Sets the fill method used for a background gradient filling
1310     //! @param theGradientMode the fill method used for a background gradient filling
1311     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1312     {
1313       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1314       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1315     }
1316
1317     //! Sets the color used for filling a background
1318     //! @param theColor the color used for filling a background
1319     static void setColor (const Quantity_Color& theColor)
1320     {
1321       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1322       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1323       aCurrentView->SetBackgroundColor (theColor);
1324       aCurrentView->Update();
1325     }
1326
1327     //! Sets the gradient filling for a background in a default viewer
1328     //! @param theColor1 the gradient starting color
1329     //! @param theColor2 the gradient ending color
1330     //! @param theGradientMode the fill method used for a background gradient filling
1331     static void setDefaultGradient (const Quantity_Color&           theColor1,
1332                                     const Quantity_Color&           theColor2,
1333                                     const Aspect_GradientFillMethod theGradientMode)
1334     {
1335       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1336       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1337       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1338       setDefaultGradient();
1339     }
1340
1341     //! Sets the color used for filling a background in a default viewer
1342     //! @param theColor the color used for filling a background
1343     static void setDefaultColor (const Quantity_Color& theColor)
1344     {
1345       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1346       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1347       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1348       ViewerTest_DefaultBackground.FlatColor      = theColor;
1349       setDefaultGradient();
1350       setDefaultColor();
1351     }
1352
1353     //! Sets the gradient filling for a background in a default viewer.
1354     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1355     static void setDefaultGradient()
1356     {
1357       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1358              anInteractiveContextIterator (ViewerTest_myContexts);
1359            anInteractiveContextIterator.More();
1360            anInteractiveContextIterator.Next())
1361       {
1362         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1363         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1364                                              ViewerTest_DefaultBackground.GradientColor2,
1365                                              ViewerTest_DefaultBackground.FillMethod);
1366       }
1367     }
1368
1369     //! Sets the color used for filling a background in a default viewer.
1370     //! The color value is taken from ViewerTest_DefaultBackground structure
1371     static void setDefaultColor()
1372     {
1373       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1374              anInteractiveContextIterator (ViewerTest_myContexts);
1375            anInteractiveContextIterator.More();
1376            anInteractiveContextIterator.Next())
1377       {
1378         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1379         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1380       }
1381     }
1382   };
1383
1384 } // namespace
1385
1386 //==============================================================================
1387
1388 #ifdef _WIN32
1389 static LRESULT WINAPI ViewerWindowProc(
1390                                        HWND hwnd,
1391                                        UINT uMsg,
1392                                        WPARAM wParam,
1393                                        LPARAM lParam );
1394 static LRESULT WINAPI AdvViewerWindowProc(
1395   HWND hwnd,
1396   UINT uMsg,
1397   WPARAM wParam,
1398   LPARAM lParam );
1399 #endif
1400
1401
1402 //==============================================================================
1403 //function : WClass
1404 //purpose  :
1405 //==============================================================================
1406
1407 const Handle(WNT_WClass)& ViewerTest::WClass()
1408 {
1409   static Handle(WNT_WClass) theWClass;
1410 #if defined(_WIN32)
1411   if (theWClass.IsNull())
1412   {
1413     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1414                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1415                                 ::LoadCursor (NULL, IDC_ARROW));
1416   }
1417 #endif
1418   return theWClass;
1419 }
1420
1421 //==============================================================================
1422 //function : CreateName
1423 //purpose  : Create numerical name for new object in theMap
1424 //==============================================================================
1425 template <typename ObjectType>
1426 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1427                                     const TCollection_AsciiString& theDefaultString)
1428 {
1429   if (theObjectMap.IsEmpty())
1430     return theDefaultString + TCollection_AsciiString(1);
1431
1432   Standard_Integer aNextKey = 1;
1433   Standard_Boolean isFound = Standard_False;
1434   while (!isFound)
1435   {
1436     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1437     // Look for objects with default names
1438     if (theObjectMap.IsBound1(aStringKey))
1439     {
1440       aNextKey++;
1441     }
1442     else
1443       isFound = Standard_True;
1444   }
1445
1446   return theDefaultString + TCollection_AsciiString(aNextKey);
1447 }
1448
1449 //==============================================================================
1450 //structure : ViewerTest_Names
1451 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1452 //==============================================================================
1453 struct ViewerTest_Names
1454 {
1455 private:
1456   TCollection_AsciiString myDriverName;
1457   TCollection_AsciiString myViewerName;
1458   TCollection_AsciiString myViewName;
1459
1460 public:
1461
1462   const TCollection_AsciiString& GetDriverName () const
1463   {
1464     return myDriverName;
1465   }
1466   void SetDriverName (const TCollection_AsciiString& theDriverName)
1467   {
1468     myDriverName = theDriverName;
1469   }
1470   const TCollection_AsciiString& GetViewerName () const
1471   {
1472     return myViewerName;
1473   }
1474   void SetViewerName (const TCollection_AsciiString& theViewerName)
1475   {
1476     myViewerName = theViewerName;
1477   }
1478   const TCollection_AsciiString& GetViewName () const
1479   {
1480     return myViewName;
1481   }
1482   void SetViewName (const TCollection_AsciiString& theViewName)
1483   {
1484     myViewName = theViewName;
1485   }
1486
1487   //===========================================================================
1488   //function : Constructor for ViewerTest_Names
1489   //purpose  : Get view, viewer, driver names from custom string
1490   //===========================================================================
1491
1492   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1493   {
1494     TCollection_AsciiString aName(theInputString);
1495     if (theInputString.IsEmpty())
1496     {
1497       // Get current configuration
1498       if (ViewerTest_myDrivers.IsEmpty())
1499         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1500           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1501       else
1502         myDriverName = ViewerTest_myDrivers.Find2
1503         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1504
1505       if(ViewerTest_myContexts.IsEmpty())
1506       {
1507         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1508           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1509       }
1510       else
1511       {
1512         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1513       }
1514
1515       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1516     }
1517     else
1518     {
1519       // There is at least view name
1520       Standard_Integer aParserNumber = 0;
1521       for (Standard_Integer i = 0; i < 3; ++i)
1522       {
1523         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1524         if(aParserPos != -1)
1525         {
1526           aParserNumber++;
1527           aName.Split(aParserPos-1);
1528         }
1529         else
1530           break;
1531       }
1532       if (aParserNumber == 0)
1533       {
1534         // Only view name
1535         if (!ViewerTest::GetAISContext().IsNull())
1536         {
1537           myDriverName = ViewerTest_myDrivers.Find2
1538           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1539           myViewerName = ViewerTest_myContexts.Find2
1540           (ViewerTest::GetAISContext());
1541         }
1542         else
1543         {
1544           // There is no opened contexts here, need to create names for viewer and driver
1545           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1546             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1547
1548           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1549             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1550         }
1551         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1552       }
1553       else if (aParserNumber == 1)
1554       {
1555         // Here is viewerName/viewName
1556         if (!ViewerTest::GetAISContext().IsNull())
1557           myDriverName = ViewerTest_myDrivers.Find2
1558           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1559         else
1560         {
1561           // There is no opened contexts here, need to create name for driver
1562           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1563             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1564         }
1565         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1566
1567         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1568       }
1569       else
1570       {
1571         //Here is driverName/viewerName/viewName
1572         myDriverName = TCollection_AsciiString(aName);
1573
1574         TCollection_AsciiString aViewerName(theInputString);
1575         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1576         myViewerName = TCollection_AsciiString(aViewerName);
1577
1578         myViewName = TCollection_AsciiString(theInputString);
1579       }
1580     }
1581   }
1582 };
1583
1584 //==============================================================================
1585 //function : FindContextByView
1586 //purpose  : Find AIS_InteractiveContext by View
1587 //==============================================================================
1588
1589 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1590 {
1591   Handle(AIS_InteractiveContext) anAISContext;
1592
1593   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1594        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1595   {
1596     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1597        return anIter.Key2();
1598   }
1599   return anAISContext;
1600 }
1601
1602 //==============================================================================
1603 //function : IsWindowOverlapped
1604 //purpose  : Check if theWindow overlapp another view
1605 //==============================================================================
1606
1607 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1608                                      const Standard_Integer thePxTop,
1609                                      const Standard_Integer thePxRight,
1610                                      const Standard_Integer thePxBottom,
1611                                      TCollection_AsciiString& theViewId)
1612 {
1613   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1614       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1615   {
1616     Standard_Integer aTop = 0,
1617       aLeft = 0,
1618       aRight = 0,
1619       aBottom = 0;
1620     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1621     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1622         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1623         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1624         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1625     {
1626       theViewId = anIter.Key1();
1627       return Standard_True;
1628     }
1629   }
1630   return Standard_False;
1631 }
1632
1633 // Workaround: to create and delete non-orthographic views outside ViewerTest
1634 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1635 {
1636   ViewerTest_myViews.UnBind1 (theName);
1637 }
1638
1639 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1640                                const Handle(V3d_View)& theView)
1641 {
1642   ViewerTest_myViews.Bind (theName, theView);
1643 }
1644
1645 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1646 {
1647   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1648 }
1649
1650 //==============================================================================
1651 //function : ViewerInit
1652 //purpose  : Create the window viewer and initialize all the global variable
1653 //==============================================================================
1654
1655 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1656                                                 const Standard_Integer thePxTop,
1657                                                 const Standard_Integer thePxWidth,
1658                                                 const Standard_Integer thePxHeight,
1659                                                 const TCollection_AsciiString& theViewName,
1660                                                 const TCollection_AsciiString& theDisplayName,
1661                                                 const Handle(V3d_View)& theViewToClone,
1662                                                 const Standard_Boolean theIsVirtual)
1663 {
1664   // Default position and dimension of the viewer window.
1665   // Note that left top corner is set to be sufficiently small to have
1666   // window fit in the small screens (actual for remote desktops, see #23003).
1667   // The position corresponds to the window's client area, thus some
1668   // gap is added for window frame to be visible.
1669   Standard_Integer aPxLeft   = 20;
1670   Standard_Integer aPxTop    = 40;
1671   Standard_Integer aPxWidth  = 409;
1672   Standard_Integer aPxHeight = 409;
1673   Standard_Boolean toCreateViewer = Standard_False;
1674   const Standard_Boolean isVirtual = Draw_VirtualWindows || theIsVirtual;
1675   if (!theViewToClone.IsNull())
1676   {
1677     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1678   }
1679
1680   Handle(OpenGl_GraphicDriver) aGraphicDriver;
1681   ViewerTest_Names aViewNames(theViewName);
1682   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1683     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1684
1685   if (thePxLeft != 0)
1686     aPxLeft = thePxLeft;
1687   if (thePxTop != 0)
1688     aPxTop = thePxTop;
1689   if (thePxWidth != 0)
1690     aPxWidth = thePxWidth;
1691   if (thePxHeight != 0)
1692     aPxHeight = thePxHeight;
1693
1694   // Get graphic driver (create it or get from another view)
1695   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1696   if (isNewDriver)
1697   {
1698     // Get connection string
1699   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1700     if (!theDisplayName.IsEmpty())
1701     {
1702       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1703     }
1704     else
1705     {
1706       ::Display* aDispX = NULL;
1707       // create dedicated display connection instead of reusing Tk connection
1708       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
1709       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1710       Tcl_Interp* aTclInterp = aCommands.Interp();
1711       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1712       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1713       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1714     }
1715   #else
1716     (void)theDisplayName; // avoid warning on unused argument
1717     SetDisplayConnection (new Aspect_DisplayConnection ());
1718   #endif
1719
1720     if (isVirtual)
1721     {
1722       // don't waste the time waiting for VSync when window is not displayed on the screen
1723       ViewerTest_myDefaultCaps.swapInterval = 0;
1724       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
1725       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
1726     }
1727     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
1728     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
1729     aGraphicDriver->InitContext();
1730
1731     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1732     toCreateViewer = Standard_True;
1733   }
1734   else
1735   {
1736     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
1737   }
1738
1739   //Dispose the window if input parameters are default
1740   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1741   {
1742     Standard_Integer aTop = 0,
1743                      aLeft = 0,
1744                      aRight = 0,
1745                      aBottom = 0,
1746                      aScreenWidth = 0,
1747                      aScreenHeight = 0;
1748
1749     // Get screen resolution
1750 #if defined(_WIN32) || defined(__WIN32__)
1751     RECT aWindowSize;
1752     GetClientRect(GetDesktopWindow(), &aWindowSize);
1753     aScreenHeight = aWindowSize.bottom;
1754     aScreenWidth = aWindowSize.right;
1755 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1756     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1757 #else
1758     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
1759     aScreenWidth = WidthOfScreen(aScreen);
1760     aScreenHeight = HeightOfScreen(aScreen);
1761 #endif
1762
1763     TCollection_AsciiString anOverlappedViewId("");
1764
1765     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1766     {
1767       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1768
1769       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1770         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1771       {
1772         if (aBottom + aPxHeight + 40 > aScreenHeight)
1773         {
1774           aPxLeft = 20;
1775           aPxTop = 40;
1776           break;
1777         }
1778         aPxLeft = 20;
1779         aPxTop = aBottom + 40;
1780       }
1781       else
1782         aPxLeft = aRight + 20;
1783     }
1784   }
1785
1786   // Get viewer name
1787   TCollection_AsciiString aTitle("3D View - ");
1788   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1789
1790   // Change name of current active window
1791   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1792   {
1793     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1794   }
1795
1796   // Create viewer
1797   Handle(V3d_Viewer) a3DViewer;
1798   // If it's the single view, we first look for empty context
1799   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1800   {
1801     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1802       anIter(ViewerTest_myContexts);
1803     if (anIter.More())
1804       ViewerTest::SetAISContext (anIter.Value());
1805     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1806   }
1807   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1808   {
1809     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1810     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1811   }
1812   else if (a3DViewer.IsNull())
1813   {
1814     toCreateViewer = Standard_True;
1815     a3DViewer = new V3d_Viewer(aGraphicDriver);
1816     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1817     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1818                                            ViewerTest_DefaultBackground.GradientColor2,
1819                                            ViewerTest_DefaultBackground.FillMethod);
1820   }
1821
1822   // AIS context setup
1823   if (ViewerTest::GetAISContext().IsNull() ||
1824       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1825   {
1826     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1827     ViewerTest::SetAISContext (aContext);
1828     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1829   }
1830   else
1831   {
1832     ViewerTest::ResetEventManager();
1833   }
1834
1835   // Create window
1836 #if defined(_WIN32)
1837   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
1838                                    isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1839                                     aPxLeft, aPxTop,
1840                                     aPxWidth, aPxHeight,
1841                                     Quantity_NOC_BLACK);
1842   VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
1843 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1844   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1845                                      aPxLeft, aPxTop,
1846                                      aPxWidth, aPxHeight);
1847   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1848 #else
1849   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1850                                   aTitle.ToCString(),
1851                                   aPxLeft, aPxTop,
1852                                   aPxWidth, aPxHeight);
1853 #endif
1854   VT_GetWindow()->SetVirtual (isVirtual);
1855
1856   // View setup
1857   Handle(V3d_View) aView;
1858   if (!theViewToClone.IsNull())
1859   {
1860     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1861   }
1862   else
1863   {
1864     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1865   }
1866
1867   aView->SetWindow (VT_GetWindow());
1868   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1869
1870   ViewerTest::CurrentView(aView);
1871   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1872
1873   // Setup for X11 or NT
1874   OSWindowSetup();
1875
1876   // Set parameters for V3d_View and V3d_Viewer
1877   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1878   aV3dView->SetComputedMode(Standard_False);
1879
1880   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1881   if (toCreateViewer)
1882   {
1883     a3DViewer->SetDefaultLights();
1884     a3DViewer->SetLightOn();
1885   }
1886
1887 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1888   if (isNewDriver)
1889   {
1890     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
1891     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1892   }
1893 #endif
1894
1895   VT_GetWindow()->Map();
1896
1897   // Set the handle of created view in the event manager
1898   ViewerTest::ResetEventManager();
1899
1900   ViewerTest::CurrentView()->Redraw();
1901
1902   aView.Nullify();
1903   a3DViewer.Nullify();
1904
1905   return aViewNames.GetViewName();
1906 }
1907
1908 //==============================================================================
1909 //function : RedrawAllViews
1910 //purpose  : Redraw all created views
1911 //==============================================================================
1912 void ViewerTest::RedrawAllViews()
1913 {
1914   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1915   for (; aViewIt.More(); aViewIt.Next())
1916   {
1917     const Handle(V3d_View)& aView = aViewIt.Key2();
1918     aView->Redraw();
1919   }
1920 }
1921
1922 //==============================================================================
1923 //function : Vinit
1924 //purpose  : Create the window viewer and initialize all the global variable
1925 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
1926 //==============================================================================
1927
1928 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1929 {
1930   TCollection_AsciiString aViewName, aDisplayName;
1931   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
1932   Standard_Boolean isVirtual = false;
1933   Handle(V3d_View) aCopyFrom;
1934   TCollection_AsciiString aName, aValue;
1935   int is2dMode = -1;
1936   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
1937   {
1938     const TCollection_AsciiString anArg = theArgVec[anArgIt];
1939     TCollection_AsciiString anArgCase = anArg;
1940     anArgCase.LowerCase();
1941     if (anArgIt + 1 < theArgsNb
1942      && anArgCase == "-name")
1943     {
1944       aViewName = theArgVec[++anArgIt];
1945     }
1946     else if (anArgIt + 1 < theArgsNb
1947           && (anArgCase == "-left"
1948            || anArgCase == "-l"))
1949     {
1950       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
1951     }
1952     else if (anArgIt + 1 < theArgsNb
1953           && (anArgCase == "-top"
1954            || anArgCase == "-t"))
1955     {
1956       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
1957     }
1958     else if (anArgIt + 1 < theArgsNb
1959           && (anArgCase == "-width"
1960            || anArgCase == "-w"))
1961     {
1962       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
1963     }
1964     else if (anArgIt + 1 < theArgsNb
1965           && (anArgCase == "-height"
1966            || anArgCase == "-h"))
1967     {
1968       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
1969     }
1970     else if (anArgCase == "-virtual"
1971           || anArgCase == "-offscreen")
1972     {
1973       isVirtual = true;
1974       if (anArgIt + 1 < theArgsNb
1975        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isVirtual))
1976       {
1977         ++anArgIt;
1978       }
1979     }
1980     else if (anArgCase == "-exitonclose")
1981     {
1982       ViewerTest_EventManager::ToExitOnCloseView() = true;
1983       if (anArgIt + 1 < theArgsNb
1984        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
1985       {
1986         ++anArgIt;
1987       }
1988     }
1989     else if (anArgCase == "-closeonescape"
1990           || anArgCase == "-closeonesc")
1991     {
1992       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
1993       if (anArgIt + 1 < theArgsNb
1994        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
1995       {
1996         ++anArgIt;
1997       }
1998     }
1999     else if (anArgCase == "-2d_mode"
2000           || anArgCase == "-2dmode"
2001           || anArgCase == "-2d")
2002     {
2003       bool toEnable = true;
2004       if (anArgIt + 1 < theArgsNb
2005        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
2006       {
2007         ++anArgIt;
2008       }
2009       is2dMode = toEnable ? 1 : 0;
2010     }
2011     else if (anArgIt + 1 < theArgsNb
2012           && (anArgCase == "-disp"
2013            || anArgCase == "-display"))
2014     {
2015       aDisplayName = theArgVec[++anArgIt];
2016     }
2017     else if (!ViewerTest::CurrentView().IsNull()
2018           &&  aCopyFrom.IsNull()
2019           && (anArgCase == "-copy"
2020            || anArgCase == "-clone"
2021            || anArgCase == "-cloneactive"
2022            || anArgCase == "-cloneactiveview"))
2023     {
2024       aCopyFrom = ViewerTest::CurrentView();
2025     }
2026     // old syntax
2027     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2028     {
2029       aName.LowerCase();
2030       if (aName == "name")
2031       {
2032         aViewName = aValue;
2033       }
2034       else if (aName == "l"
2035             || aName == "left")
2036       {
2037         aPxLeft = aValue.IntegerValue();
2038       }
2039       else if (aName == "t"
2040             || aName == "top")
2041       {
2042         aPxTop = aValue.IntegerValue();
2043       }
2044       else if (aName == "disp"
2045             || aName == "display")
2046       {
2047         aDisplayName = aValue;
2048       }
2049       else if (aName == "w"
2050             || aName == "width")
2051       {
2052         aPxWidth = aValue.IntegerValue();
2053       }
2054       else if (aName == "h"
2055             || aName == "height")
2056       {
2057         aPxHeight = aValue.IntegerValue();
2058       }
2059       else
2060       {
2061         Message::SendFail() << "Syntax error: unknown argument " << anArg;
2062         return 1;
2063       }
2064     }
2065     else if (aViewName.IsEmpty())
2066     {
2067       aViewName = anArg;
2068     }
2069     else
2070     {
2071       Message::SendFail() << "Syntax error: unknown argument " << anArg;
2072       return 1;
2073     }
2074   }
2075
2076 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
2077   if (!aDisplayName.IsEmpty())
2078   {
2079     aDisplayName.Clear();
2080     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
2081   }
2082 #endif
2083
2084   ViewerTest_Names aViewNames (aViewName);
2085   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2086   {
2087     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2088     theDi.Eval (aCommand.ToCString());
2089     if (is2dMode != -1)
2090     {
2091       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2092     }
2093     return 0;
2094   }
2095
2096   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2097                                                             aViewName, aDisplayName, aCopyFrom, isVirtual);
2098   if (is2dMode != -1)
2099   {
2100     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2101   }
2102   theDi << aViewId;
2103   return 0;
2104 }
2105
2106 //! Parse HLR algo type.
2107 static Standard_Boolean parseHlrAlgoType (const char* theName,
2108                                           Prs3d_TypeOfHLR& theType)
2109 {
2110   TCollection_AsciiString aName (theName);
2111   aName.LowerCase();
2112   if (aName == "polyalgo")
2113   {
2114     theType = Prs3d_TOH_PolyAlgo;
2115   }
2116   else if (aName == "algo")
2117   {
2118     theType = Prs3d_TOH_Algo;
2119   }
2120   else
2121   {
2122     return Standard_False;
2123   }
2124   return Standard_True;
2125 }
2126
2127 //==============================================================================
2128 //function : VHLR
2129 //purpose  : hidden lines removal algorithm
2130 //==============================================================================
2131
2132 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2133 {
2134   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2135   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2136   if (aView.IsNull())
2137   {
2138     Message::SendFail ("Error: no active viewer");
2139     return 1;
2140   }
2141
2142   Standard_Boolean hasHlrOnArg = Standard_False;
2143   Standard_Boolean hasShowHiddenArg = Standard_False;
2144   Standard_Boolean isHLROn = Standard_False;
2145   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2146   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2147   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2148   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2149   {
2150     TCollection_AsciiString anArg (argv[anArgIter]);
2151     anArg.LowerCase();
2152     if (anUpdateTool.parseRedrawMode (anArg))
2153     {
2154       continue;
2155     }
2156     else if (anArg == "-showhidden"
2157           && anArgIter + 1 < argc
2158           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2159     {
2160       ++anArgIter;
2161       hasShowHiddenArg = Standard_True;
2162       continue;
2163     }
2164     else if ((anArg == "-type"
2165            || anArg == "-algo"
2166            || anArg == "-algotype")
2167           && anArgIter + 1 < argc
2168           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2169     {
2170       ++anArgIter;
2171       continue;
2172     }
2173     else if (!hasHlrOnArg
2174           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
2175     {
2176       hasHlrOnArg = Standard_True;
2177       continue;
2178     }
2179     // old syntax
2180     else if (!hasShowHiddenArg
2181           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
2182     {
2183       hasShowHiddenArg = Standard_True;
2184       continue;
2185     }
2186     else
2187     {
2188       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
2189       return 1;
2190     }
2191   }
2192   if (!hasHlrOnArg)
2193   {
2194     di << "HLR:        " << aView->ComputedMode() << "\n";
2195     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2196     di << "HlrAlgo:    ";
2197     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2198     {
2199       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2200       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2201       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2202     }
2203     anUpdateTool.Invalidate();
2204     return 0;
2205   }
2206
2207   Standard_Boolean toRecompute = Standard_False;
2208   if (aTypeOfHLR != Prs3d_TOH_NotSet
2209    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2210   {
2211     toRecompute = Standard_True;
2212     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2213   }
2214   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2215   {
2216     toRecompute = Standard_True;
2217     if (toShowHidden)
2218     {
2219       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2220     }
2221     else
2222     {
2223       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2224     }
2225   }
2226
2227   // redisplay shapes
2228   if (aView->ComputedMode() && isHLROn && toRecompute)
2229   {
2230     AIS_ListOfInteractive aListOfShapes;
2231     aCtx->DisplayedObjects (aListOfShapes);
2232     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2233     {
2234       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2235       {
2236         aCtx->Redisplay (aShape, Standard_False);
2237       }
2238     }
2239   }
2240
2241   aView->SetComputedMode (isHLROn);
2242   return 0;
2243 }
2244
2245 //==============================================================================
2246 //function : VHLRType
2247 //purpose  : change type of using HLR algorithm
2248 //==============================================================================
2249
2250 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2251 {
2252   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2253   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2254   if (aView.IsNull())
2255   {
2256     Message::SendFail ("Error: no active viewer");
2257     return 1;
2258   }
2259
2260   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2261   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2262   AIS_ListOfInteractive aListOfShapes;
2263   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2264   {
2265     TCollection_AsciiString anArg (argv[anArgIter]);
2266     anArg.LowerCase();
2267     if (anUpdateTool.parseRedrawMode (anArg))
2268     {
2269       continue;
2270     }
2271     else if ((anArg == "-type"
2272            || anArg == "-algo"
2273            || anArg == "-algotype")
2274           && anArgIter + 1 < argc
2275           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2276     {
2277       ++anArgIter;
2278       continue;
2279     }
2280     // old syntax
2281     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2282           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2283     {
2284       continue;
2285     }
2286     else
2287     {
2288       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2289       TCollection_AsciiString aName (argv[anArgIter]);
2290       if (!aMap.IsBound2 (aName))
2291       {
2292         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
2293         return 1;
2294       }
2295
2296       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2297       if (aShape.IsNull())
2298       {
2299         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
2300         return 1;
2301       }
2302       aListOfShapes.Append (aShape);
2303       continue;
2304     }
2305   }
2306   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2307   {
2308     Message::SendFail ("Syntax error: wrong number of arguments");
2309     return 1;
2310   }
2311
2312   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2313   if (isGlobal)
2314   {
2315     aCtx->DisplayedObjects (aListOfShapes);
2316     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2317   }
2318
2319   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2320   {
2321     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2322     if (aShape.IsNull())
2323     {
2324       continue;
2325     }
2326
2327     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2328                             && aView->ComputedMode();
2329     if (!isGlobal
2330      || aShape->TypeOfHLR() != aTypeOfHLR)
2331     {
2332       aShape->SetTypeOfHLR (aTypeOfHLR);
2333     }
2334     if (toUpdateShape)
2335     {
2336       aCtx->Redisplay (aShape, Standard_False);
2337     }
2338   }
2339   return 0;
2340 }
2341
2342 //==============================================================================
2343 //function : FindViewIdByWindowHandle
2344 //purpose  : Find theView Id in the map of views by window handle
2345 //==============================================================================
2346 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2347 TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2348 {
2349   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2350        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2351   {
2352     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2353     if (aWindowHandle == theWindowHandle)
2354       return anIter.Key1();
2355   }
2356   return TCollection_AsciiString("");
2357 }
2358 #endif
2359
2360 //! Make the view active
2361 void ActivateView (const TCollection_AsciiString& theViewName,
2362                    Standard_Boolean theToUpdate = Standard_True)
2363 {
2364   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2365   if (aView.IsNull())
2366   {
2367     return;
2368   }
2369
2370   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2371   if (!anAISContext.IsNull())
2372   {
2373     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2374     {
2375       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2376     }
2377
2378     ViewerTest::CurrentView (aView);
2379     ViewerTest::SetAISContext (anAISContext);
2380     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2381 #if defined(_WIN32)
2382     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2383 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
2384     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2385 #else
2386     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2387 #endif
2388     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2389     if (theToUpdate)
2390     {
2391       ViewerTest::CurrentView()->Redraw();
2392     }
2393   }
2394 }
2395
2396 //==============================================================================
2397 //function : RemoveView
2398 //purpose  :
2399 //==============================================================================
2400 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2401                              const Standard_Boolean  theToRemoveContext)
2402 {
2403   if (!ViewerTest_myViews.IsBound2 (theView))
2404   {
2405     return;
2406   }
2407
2408   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2409   RemoveView (aViewName, theToRemoveContext);
2410 }
2411
2412 //==============================================================================
2413 //function : RemoveView
2414 //purpose  : Close and remove view from display, clear maps if necessary
2415 //==============================================================================
2416 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2417 {
2418   if (!ViewerTest_myViews.IsBound1(theViewName))
2419   {
2420     Message::SendFail() << "Wrong view name";
2421     return;
2422   }
2423
2424   // Activate another view if it's active now
2425   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2426   {
2427     if (ViewerTest_myViews.Extent() > 1)
2428     {
2429       TCollection_AsciiString aNewViewName;
2430       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2431            anIter.More(); anIter.Next())
2432       {
2433         if (anIter.Key1() != theViewName)
2434         {
2435           aNewViewName = anIter.Key1();
2436           break;
2437         }
2438       }
2439       ActivateView (aNewViewName);
2440     }
2441     else
2442     {
2443       VT_GetWindow().Nullify();
2444       ViewerTest::CurrentView (Handle(V3d_View)());
2445       if (isContextRemoved)
2446       {
2447         Handle(AIS_InteractiveContext) anEmptyContext;
2448         ViewerTest::SetAISContext(anEmptyContext);
2449       }
2450     }
2451   }
2452
2453   // Delete view
2454   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2455   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2456   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2457   aRedrawer.Stop (aView->Window());
2458
2459   // Remove view resources
2460   ViewerTest_myViews.UnBind1(theViewName);
2461   aView->Window()->Unmap();
2462   aView->Remove();
2463
2464 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2465   XFlush (GetDisplayConnection()->GetDisplay());
2466 #endif
2467
2468   // Keep context opened only if the closed view is last to avoid
2469   // unused empty contexts
2470   if (!aCurrentContext.IsNull())
2471   {
2472     // Check if there are more difined views in the viewer
2473     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
2474      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
2475     {
2476       // Remove driver if there is no viewers that use it
2477       Standard_Boolean isRemoveDriver = Standard_True;
2478       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2479           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2480       {
2481         if (aCurrentContext != anIter.Key2() &&
2482           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2483         {
2484           isRemoveDriver = Standard_False;
2485           break;
2486         }
2487       }
2488
2489       aCurrentContext->RemoveAll (Standard_False);
2490       if(isRemoveDriver)
2491       {
2492         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2493       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2494         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
2495       #endif
2496       }
2497
2498       ViewerTest_myContexts.UnBind2(aCurrentContext);
2499     }
2500   }
2501   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
2502   if (ViewerTest_EventManager::ToExitOnCloseView())
2503   {
2504     Draw_Interprete ("exit");
2505   }
2506 }
2507
2508 //==============================================================================
2509 //function : VClose
2510 //purpose  : Remove the view defined by its name
2511 //==============================================================================
2512
2513 static int VClose (Draw_Interpretor& /*theDi*/,
2514                    Standard_Integer  theArgsNb,
2515                    const char**      theArgVec)
2516 {
2517   NCollection_List<TCollection_AsciiString> aViewList;
2518   if (theArgsNb > 1)
2519   {
2520     TCollection_AsciiString anArg (theArgVec[1]);
2521     anArg.UpperCase();
2522     if (anArg.IsEqual ("ALL")
2523      || anArg.IsEqual ("*"))
2524     {
2525       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2526            anIter.More(); anIter.Next())
2527       {
2528         aViewList.Append (anIter.Key1());
2529       }
2530       if (aViewList.IsEmpty())
2531       {
2532         std::cout << "No view to close\n";
2533         return 0;
2534       }
2535     }
2536     else
2537     {
2538       ViewerTest_Names aViewName (theArgVec[1]);
2539       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2540       {
2541         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
2542         return 1;
2543       }
2544       aViewList.Append (aViewName.GetViewName());
2545     }
2546   }
2547   else
2548   {
2549     // close active view
2550     if (ViewerTest::CurrentView().IsNull())
2551     {
2552       Message::SendFail ("Error: no active view");
2553       return 1;
2554     }
2555     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2556   }
2557
2558   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2559   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2560        anIter.More(); anIter.Next())
2561   {
2562     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2563   }
2564
2565   return 0;
2566 }
2567
2568 //==============================================================================
2569 //function : VActivate
2570 //purpose  : Activate the view defined by its ID
2571 //==============================================================================
2572
2573 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2574 {
2575   if (theArgsNb == 1)
2576   {
2577     theDi.Eval("vviewlist");
2578     return 0;
2579   }
2580
2581   TCollection_AsciiString aNameString;
2582   Standard_Boolean toUpdate = Standard_True;
2583   Standard_Boolean toActivate = Standard_True;
2584   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2585   {
2586     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2587     anArg.LowerCase();
2588     if (toUpdate
2589      && anArg == "-noupdate")
2590     {
2591       toUpdate = Standard_False;
2592     }
2593     else if (toActivate
2594           && aNameString.IsEmpty()
2595           && anArg == "none")
2596     {
2597       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2598       VT_GetWindow().Nullify();
2599       ViewerTest::CurrentView (Handle(V3d_View)());
2600       ViewerTest::ResetEventManager();
2601       theDi << theArgVec[0] << ": all views are inactive\n";
2602       toActivate = Standard_False;
2603     }
2604     else if (toActivate
2605           && aNameString.IsEmpty())
2606     {
2607       aNameString = theArgVec[anArgIter];
2608     }
2609     else
2610     {
2611       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2612       return 1;
2613     }
2614   }
2615
2616   if (!toActivate)
2617   {
2618     return 0;
2619   }
2620   else if (aNameString.IsEmpty())
2621   {
2622     Message::SendFail ("Syntax error: wrong number of arguments");
2623     return 1;
2624   }
2625
2626   // Check if this view exists in the viewer with the driver
2627   ViewerTest_Names aViewNames (aNameString);
2628   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2629   {
2630     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2631     return 1;
2632   }
2633
2634   // Check if it is active already
2635   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2636   {
2637     theDi << theArgVec[0] << ": the view is active already\n";
2638     return 0;
2639   }
2640
2641   ActivateView (aViewNames.GetViewName(), toUpdate);
2642   return 0;
2643 }
2644
2645 //==============================================================================
2646 //function : VViewList
2647 //purpose  : Print current list of views per viewer and graphic driver ID
2648 //           shared between viewers
2649 //==============================================================================
2650
2651 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2652 {
2653   if (theArgsNb > 2)
2654   {
2655     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2656           << "Usage: " << theArgVec[0] << " name";
2657     return 1;
2658   }
2659   if (ViewerTest_myContexts.Size() < 1)
2660     return 0;
2661
2662   Standard_Boolean isTreeView =
2663     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2664
2665   if (isTreeView)
2666   {
2667     theDi << theArgVec[0] <<":\n";
2668   }
2669
2670   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2671        aDriverIter.More(); aDriverIter.Next())
2672   {
2673     if (isTreeView)
2674       theDi << aDriverIter.Key1() << ":\n";
2675
2676     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2677       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2678     {
2679       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2680       {
2681         if (isTreeView)
2682         {
2683           TCollection_AsciiString aContextName(aContextIter.Key1());
2684           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2685         }
2686
2687         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2688              aViewIter.More(); aViewIter.Next())
2689         {
2690           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2691           {
2692             TCollection_AsciiString aViewName(aViewIter.Key1());
2693             if (isTreeView)
2694             {
2695               if (aViewIter.Value() == ViewerTest::CurrentView())
2696                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2697               else
2698                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2699             }
2700             else
2701             {
2702               theDi << aViewName << " ";
2703             }
2704           }
2705         }
2706       }
2707     }
2708   }
2709   return 0;
2710 }
2711
2712 //==============================================================================
2713 //function : GetMousePosition
2714 //purpose  :
2715 //==============================================================================
2716 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2717                                    Standard_Integer& theY)
2718 {
2719   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2720   {
2721     theX = aViewCtrl->LastMousePosition().x();
2722     theY = aViewCtrl->LastMousePosition().y();
2723   }
2724 }
2725
2726 //==============================================================================
2727 //function : VViewProj
2728 //purpose  : Switch view projection
2729 //==============================================================================
2730 static int VViewProj (Draw_Interpretor& ,
2731                       Standard_Integer theNbArgs,
2732                       const char** theArgVec)
2733 {
2734   static Standard_Boolean isYup = Standard_False;
2735   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2736   if (aView.IsNull())
2737   {
2738     Message::SendFail ("Error: no active viewer");
2739     return 1;
2740   }
2741
2742   TCollection_AsciiString aCmdName (theArgVec[0]);
2743   Standard_Boolean isGeneralCmd = Standard_False;
2744   if (aCmdName == "vfront")
2745   {
2746     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2747   }
2748   else if (aCmdName == "vback")
2749   {
2750     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2751   }
2752   else if (aCmdName == "vtop")
2753   {
2754     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2755   }
2756   else if (aCmdName == "vbottom")
2757   {
2758     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2759   }
2760   else if (aCmdName == "vleft")
2761   {
2762     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2763   }
2764   else if (aCmdName == "vright")
2765   {
2766     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2767   }
2768   else if (aCmdName == "vaxo")
2769   {
2770     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2771   }
2772   else
2773   {
2774     isGeneralCmd = Standard_True;
2775     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2776     {
2777       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2778       anArgCase.LowerCase();
2779       if (anArgCase == "-zup")
2780       {
2781         isYup = Standard_False;
2782       }
2783       else if (anArgCase == "-yup")
2784       {
2785         isYup = Standard_True;
2786       }
2787       else if (anArgCase == "-front"
2788             || anArgCase == "front"
2789             || anArgCase == "-f"
2790             || anArgCase == "f")
2791       {
2792         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2793       }
2794       else if (anArgCase == "-back"
2795             || anArgCase == "back"
2796             || anArgCase == "-b"
2797             || anArgCase == "b")
2798       {
2799         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2800       }
2801       else if (anArgCase == "-top"
2802             || anArgCase == "top"
2803             || anArgCase == "-t"
2804             || anArgCase == "t")
2805       {
2806         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2807       }
2808       else if (anArgCase == "-bottom"
2809             || anArgCase == "bottom"
2810             || anArgCase == "-bot"
2811             || anArgCase == "bot"
2812             || anArgCase == "-b"
2813             || anArgCase == "b")
2814       {
2815         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2816       }
2817       else if (anArgCase == "-left"
2818             || anArgCase == "left"
2819             || anArgCase == "-l"
2820             || anArgCase == "l")
2821       {
2822         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2823       }
2824       else if (anArgCase == "-right"
2825             || anArgCase == "right"
2826             || anArgCase == "-r"
2827             || anArgCase == "r")
2828       {
2829         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2830       }
2831       else if (anArgCase == "-axoleft"
2832             || anArgCase == "-leftaxo"
2833             || anArgCase == "axoleft"
2834             || anArgCase == "leftaxo")
2835       {
2836         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
2837       }
2838       else if (anArgCase == "-axo"
2839             || anArgCase == "axo"
2840             || anArgCase == "-a"
2841             || anArgCase == "a"
2842             || anArgCase == "-axoright"
2843             || anArgCase == "-rightaxo"
2844             || anArgCase == "axoright"
2845             || anArgCase == "rightaxo")
2846       {
2847         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2848       }
2849       else if (anArgCase == "+x")
2850       {
2851         aView->SetProj (V3d_Xpos, isYup);
2852       }
2853       else if (anArgCase == "-x")
2854       {
2855         aView->SetProj (V3d_Xneg, isYup);
2856       }
2857       else if (anArgCase == "+y")
2858       {
2859         aView->SetProj (V3d_Ypos, isYup);
2860       }
2861       else if (anArgCase == "-y")
2862       {
2863         aView->SetProj (V3d_Yneg, isYup);
2864       }
2865       else if (anArgCase == "+z")
2866       {
2867         aView->SetProj (V3d_Zpos, isYup);
2868       }
2869       else if (anArgCase == "-z")
2870       {
2871         aView->SetProj (V3d_Zneg, isYup);
2872       }
2873       else if (anArgCase == "+x+y+z")
2874       {
2875         aView->SetProj (V3d_XposYposZpos, isYup);
2876       }
2877       else if (anArgCase == "+x+y-z")
2878       {
2879         aView->SetProj (V3d_XposYposZneg, isYup);
2880       }
2881       else if (anArgCase == "+x-y+z")
2882       {
2883         aView->SetProj (V3d_XposYnegZpos, isYup);
2884       }
2885       else if (anArgCase == "+x-y-z")
2886       {
2887         aView->SetProj (V3d_XposYnegZneg, isYup);
2888       }
2889       else if (anArgCase == "-x+y+z")
2890       {
2891         aView->SetProj (V3d_XnegYposZpos, isYup);
2892       }
2893       else if (anArgCase == "-x+y-z")
2894       {
2895         aView->SetProj (V3d_XnegYposZneg, isYup);
2896       }
2897       else if (anArgCase == "-x-y+z")
2898       {
2899         aView->SetProj (V3d_XnegYnegZpos, isYup);
2900       }
2901       else if (anArgCase == "-x-y-z")
2902       {
2903         aView->SetProj (V3d_XnegYnegZneg, isYup);
2904       }
2905       else if (anArgCase == "+x+y")
2906       {
2907         aView->SetProj (V3d_XposYpos, isYup);
2908       }
2909       else if (anArgCase == "+x-y")
2910       {
2911         aView->SetProj (V3d_XposYneg, isYup);
2912       }
2913       else if (anArgCase == "-x+y")
2914       {
2915         aView->SetProj (V3d_XnegYpos, isYup);
2916       }
2917       else if (anArgCase == "-x-y")
2918       {
2919         aView->SetProj (V3d_XnegYneg, isYup);
2920       }
2921       else if (anArgCase == "+x+z")
2922       {
2923         aView->SetProj (V3d_XposZpos, isYup);
2924       }
2925       else if (anArgCase == "+x-z")
2926       {
2927         aView->SetProj (V3d_XposZneg, isYup);
2928       }
2929       else if (anArgCase == "-x+z")
2930       {
2931         aView->SetProj (V3d_XnegZpos, isYup);
2932       }
2933       else if (anArgCase == "-x-z")
2934       {
2935         aView->SetProj (V3d_XnegZneg, isYup);
2936       }
2937       else if (anArgCase == "+y+z")
2938       {
2939         aView->SetProj (V3d_YposZpos, isYup);
2940       }
2941       else if (anArgCase == "+y-z")
2942       {
2943         aView->SetProj (V3d_YposZneg, isYup);
2944       }
2945       else if (anArgCase == "-y+z")
2946       {
2947         aView->SetProj (V3d_YnegZpos, isYup);
2948       }
2949       else if (anArgCase == "-y-z")
2950       {
2951         aView->SetProj (V3d_YnegZneg, isYup);
2952       }
2953       else if (anArgIter + 1 < theNbArgs
2954             && anArgCase == "-frame"
2955             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2956       {
2957         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2958         aFrameDef.LowerCase();
2959         gp_Dir aRight, anUp;
2960         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2961         {
2962           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2963           return 1;
2964         }
2965
2966         if (aFrameDef.Value (2) == 'x')
2967         {
2968           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2969         }
2970         else if (aFrameDef.Value (2) == 'y')
2971         {
2972           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2973         }
2974         else if (aFrameDef.Value (2) == 'z')
2975         {
2976           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2977         }
2978         else
2979         {
2980           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2981           return 1;
2982         }
2983
2984         if (aFrameDef.Value (4) == 'x')
2985         {
2986           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2987         }
2988         else if (aFrameDef.Value (4) == 'y')
2989         {
2990           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2991         }
2992         else if (aFrameDef.Value (4) == 'z')
2993         {
2994           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2995         }
2996         else
2997         {
2998           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2999           return 1;
3000         }
3001
3002         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
3003         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
3004         const gp_Dir aDir = anUp.Crossed (aRight);
3005         aCamera->SetCenter (gp_Pnt (0, 0, 0));
3006         aCamera->SetDirection (aDir);
3007         aCamera->SetUp (anUp);
3008         aCamera->OrthogonalizeUp();
3009
3010         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
3011         aView->Update();
3012       }
3013       else
3014       {
3015         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3016         return 1;
3017       }
3018     }
3019   }
3020
3021   if (!isGeneralCmd
3022     && theNbArgs != 1)
3023   {
3024     Message::SendFail ("Syntax error: wrong number of arguments");
3025     return 1;
3026   }
3027   return 0;
3028 }
3029
3030 //==============================================================================
3031 //function : VHelp
3032 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3033 //Draw arg : No args
3034 //==============================================================================
3035
3036 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3037 {
3038   di << "=========================\n";
3039   di << "F : FitAll\n";
3040   di << "T : TopView\n";
3041   di << "B : BottomView\n";
3042   di << "R : RightView\n";
3043   di << "L : LeftView\n";
3044   di << "Backspace : AxonometricView\n";
3045
3046   di << "=========================\n";
3047   di << "W, S : Fly   forward/backward\n";
3048   di << "A, D : Slide left/right\n";
3049   di << "Q, E : Bank  left/right\n";
3050   di << "-, + : Change flying speed\n";
3051   di << "Arrows : look left/right/up/down\n";
3052   di << "Arrows+Shift : slide left/right/up/down\n";
3053
3054   di << "=========================\n";
3055   di << "S + Ctrl : Shading\n";
3056   di << "W + Ctrl : Wireframe\n";
3057   di << "H : HiddenLineRemoval\n";
3058   di << "U : Unset display mode\n";
3059   di << "Delete : Remove selection from viewer\n";
3060
3061   di << "=========================\n";
3062   di << "Selection mode \n";
3063   di << "0 : Shape\n";
3064   di << "1 : Vertex\n";
3065   di << "2 : Edge\n";
3066   di << "3 : Wire\n";
3067   di << "4 : Face\n";
3068   di << "5 : Shell\n";
3069   di << "6 : Solid\n";
3070   di << "7 : Compound\n";
3071
3072   di << "=========================\n";
3073   di << "< : Hilight next detected\n";
3074   di << "> : Hilight previous detected\n";
3075
3076   return 0;
3077 }
3078
3079 #ifdef _WIN32
3080
3081 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3082                                            UINT theMsg,
3083                                            WPARAM wParam,
3084                                            LPARAM lParam )
3085 {
3086   if (ViewerTest_myViews.IsEmpty())
3087   {
3088     return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3089   }
3090
3091   switch (theMsg)
3092   {
3093     case WM_CLOSE:
3094     {
3095       // Delete view from map of views
3096       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3097       return 0;
3098     }
3099     case WM_ACTIVATE:
3100     {
3101       if (LOWORD(wParam) == WA_CLICKACTIVE
3102        || LOWORD(wParam) == WA_ACTIVE
3103        || ViewerTest::CurrentView().IsNull())
3104       {
3105         // Activate inactive window
3106         if (VT_GetWindow().IsNull()
3107          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3108         {
3109           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3110         }
3111       }
3112       break;
3113     }
3114     default:
3115     {
3116       return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3117     }
3118   }
3119   return 0;
3120 }
3121
3122 static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
3123                                         UINT theMsg,
3124                                         WPARAM wParam,
3125                                         LPARAM lParam)
3126 {
3127   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3128   if (aView.IsNull())
3129   {
3130     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3131   }
3132
3133   switch (theMsg)
3134   {
3135     case WM_PAINT:
3136     {
3137       PAINTSTRUCT aPaint;
3138       BeginPaint(theWinHandle, &aPaint);
3139       EndPaint  (theWinHandle, &aPaint);
3140       ViewerTest::CurrentEventManager()->ProcessExpose();
3141       break;
3142     }
3143     case WM_SIZE:
3144     {
3145       ViewerTest::CurrentEventManager()->ProcessConfigure();
3146       break;
3147     }
3148     case WM_MOVE:
3149     case WM_MOVING:
3150     case WM_SIZING:
3151     {
3152       switch (aView->RenderingParams().StereoMode)
3153       {
3154         case Graphic3d_StereoMode_RowInterlaced:
3155         case Graphic3d_StereoMode_ColumnInterlaced:
3156         case Graphic3d_StereoMode_ChessBoard:
3157         {
3158           // track window moves to reverse stereo pair
3159           aView->MustBeResized();
3160           aView->Update();
3161           break;
3162         }
3163         default:
3164           break;
3165       }
3166       break;
3167     }
3168     case WM_KEYUP:
3169     case WM_KEYDOWN:
3170     {
3171       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
3172       if (aVKey != Aspect_VKey_UNKNOWN)
3173       {
3174         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3175         if (theMsg == WM_KEYDOWN)
3176         {
3177           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3178         }
3179         else
3180         {
3181           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3182         }
3183         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3184       }
3185       break;
3186     }
3187     case WM_LBUTTONUP:
3188     case WM_MBUTTONUP:
3189     case WM_RBUTTONUP:
3190     case WM_LBUTTONDOWN:
3191     case WM_MBUTTONDOWN:
3192     case WM_RBUTTONDOWN:
3193     {
3194       const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3195       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3196       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3197       switch (theMsg)
3198       {
3199         case WM_LBUTTONUP:
3200         case WM_LBUTTONDOWN:
3201           aButton = Aspect_VKeyMouse_LeftButton;
3202           break;
3203         case WM_MBUTTONUP:
3204         case WM_MBUTTONDOWN:
3205           aButton = Aspect_VKeyMouse_MiddleButton;
3206           break;
3207         case WM_RBUTTONUP:
3208         case WM_RBUTTONDOWN:
3209           aButton = Aspect_VKeyMouse_RightButton;
3210           break;
3211       }
3212       if (theMsg == WM_LBUTTONDOWN
3213        || theMsg == WM_MBUTTONDOWN
3214        || theMsg == WM_RBUTTONDOWN)
3215       {
3216         if (aButton == Aspect_VKeyMouse_LeftButton)
3217         {
3218           TheIsAnimating = Standard_False;
3219         }
3220
3221         SetFocus  (theWinHandle);
3222         SetCapture(theWinHandle);
3223         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3224       }
3225       else
3226       {
3227         ReleaseCapture();
3228         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3229       }
3230       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3231       break;
3232     }
3233     case WM_MOUSEWHEEL:
3234     {
3235       const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
3236       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
3237       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3238       Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
3239       POINT aCursorPnt = { aPos.x(), aPos.y() };
3240       if (ScreenToClient (theWinHandle, &aCursorPnt))
3241       {
3242         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3243       }
3244
3245       ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3246       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3247       break;
3248     }
3249     case WM_MOUSEMOVE:
3250     {
3251       Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3252       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
3253       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
3254
3255       // don't make a slide-show from input events - fetch the actual mouse cursor position
3256       CURSORINFO aCursor;
3257       aCursor.cbSize = sizeof(aCursor);
3258       if (::GetCursorInfo (&aCursor) != FALSE)
3259       {
3260         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
3261         if (ScreenToClient (theWinHandle, &aCursorPnt))
3262         {
3263           // as we override mouse position, we need overriding also mouse state
3264           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3265           aButtons = WNT_Window::MouseButtonsAsync();
3266           aFlags   = WNT_Window::MouseKeyFlagsAsync();
3267         }
3268       }
3269
3270       if (VT_GetWindow().IsNull()
3271       || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3272       {
3273         // mouse move events come also for inactive windows
3274         break;
3275       }
3276
3277       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3278       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
3279       break;
3280     }
3281     case WM_INPUT:
3282     {
3283       UINT aSize = 0;
3284       ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER));
3285       NCollection_LocalArray<BYTE> aRawData (aSize);
3286       if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize)
3287       {
3288         break;
3289       }
3290
3291       const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData;
3292       if (aRawInput->header.dwType != RIM_TYPEHID)
3293       {
3294         break;
3295       }
3296
3297       RID_DEVICE_INFO aDevInfo;
3298       aDevInfo.cbSize = sizeof(RID_DEVICE_INFO);
3299       UINT aDevInfoSize = sizeof(RID_DEVICE_INFO);
3300       if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO)
3301         || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH
3302          && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION))
3303       {
3304         break;
3305       }
3306
3307       WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid);
3308       if (ViewerTest::CurrentEventManager()->Update3dMouse (aSpaceData)
3309       && !VT_GetWindow().IsNull())
3310       {
3311         VT_GetWindow()->InvalidateContent();
3312       }
3313       break;
3314     }
3315     default:
3316     {
3317       return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3318     }
3319   }
3320   return 0L;
3321 }
3322
3323 //==============================================================================
3324 //function : ViewerMainLoop
3325 //purpose  : Get a Event on the view and dispatch it
3326 //==============================================================================
3327
3328 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3329 {
3330   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3331   if (aViewCtrl.IsNull()
3332    || theNbArgs < 4)
3333   {
3334     return 0;
3335   }
3336
3337   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3338
3339   std::cout << "Start picking\n";
3340
3341   MSG aMsg;
3342   aMsg.wParam = 1;
3343   while (aViewCtrl->ToPickPoint())
3344   {
3345     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3346     if (GetMessageW (&aMsg, NULL, 0, 0))
3347     {
3348       TranslateMessage (&aMsg);
3349       DispatchMessageW (&aMsg);
3350     }
3351   }
3352
3353   std::cout << "Picking done\n";
3354   return 0;
3355 }
3356
3357 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
3358
3359 int min( int a, int b )
3360 {
3361   if( a<b )
3362     return a;
3363   else
3364     return b;
3365 }
3366
3367 int max( int a, int b )
3368 {
3369   if( a>b )
3370     return a;
3371   else
3372     return b;
3373 }
3374
3375 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3376 {
3377   static XEvent aReport;
3378   const Standard_Boolean toPick = theNbArgs > 0;
3379   if (theNbArgs > 0)
3380   {
3381     if (ViewerTest::CurrentEventManager().IsNull())
3382     {
3383       return 0;
3384     }
3385     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3386   }
3387
3388   Display* aDisplay = GetDisplayConnection()->GetDisplay();
3389   XNextEvent (aDisplay, &aReport);
3390
3391   // Handle event for the chosen display connection
3392   switch (aReport.type)
3393   {
3394     case ClientMessage:
3395     {
3396       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3397       {
3398         // Close the window
3399         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3400         return toPick ? 0 : 1;
3401       }
3402       break;
3403     }
3404     case FocusIn:
3405     {
3406       // Activate inactive view
3407       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3408       if (aWindow != aReport.xfocus.window)
3409       {
3410         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3411       }
3412       break;
3413     }
3414     case Expose:
3415     {
3416       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3417       if (anXWindow == aReport.xexpose.window)
3418       {
3419         ViewerTest::CurrentEventManager()->ProcessExpose();
3420       }
3421
3422       // remove all the ExposureMask and process them at once
3423       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3424       {
3425         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
3426         {
3427           break;
3428         }
3429       }
3430
3431       break;
3432     }
3433     case ConfigureNotify:
3434     {
3435       // remove all the StructureNotifyMask and process them at once
3436       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3437       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3438       {
3439         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
3440         {
3441           break;
3442         }
3443       }
3444
3445       if (anXWindow == aReport.xconfigure.window)
3446       {
3447         ViewerTest::CurrentEventManager()->ProcessConfigure();
3448       }
3449       break;
3450     }
3451     case KeyPress:
3452     case KeyRelease:
3453     {
3454       XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
3455       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
3456       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
3457       if (aVKey != Aspect_VKey_UNKNOWN)
3458       {
3459         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3460         if (aReport.type == KeyPress)
3461         {
3462           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3463         }
3464         else
3465         {
3466           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3467         }
3468         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3469       }
3470       break;
3471     }
3472     case ButtonPress:
3473     case ButtonRelease:
3474     {
3475       const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
3476       Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
3477       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3478       if (aReport.xbutton.button == Button1)
3479       {
3480         aButton = Aspect_VKeyMouse_LeftButton;
3481       }
3482       if (aReport.xbutton.button == Button2)
3483       {
3484         aButton = Aspect_VKeyMouse_MiddleButton;
3485       }
3486       if (aReport.xbutton.button == Button3)
3487       {
3488         aButton = Aspect_VKeyMouse_RightButton;
3489       }
3490
3491       if (aReport.xbutton.state & ControlMask)
3492       {
3493         aFlags |= Aspect_VKeyFlags_CTRL;
3494       }
3495       if (aReport.xbutton.state & ShiftMask)
3496       {
3497         aFlags |= Aspect_VKeyFlags_SHIFT;
3498       }
3499       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3500       {
3501         aFlags |= Aspect_VKeyFlags_ALT;
3502       }
3503
3504       if (aReport.xbutton.button == Button4
3505        || aReport.xbutton.button == Button5)
3506       {
3507         if (aReport.type != ButtonPress)
3508         {
3509           break;
3510         }
3511
3512         const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0);
3513         ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3514       }
3515       else if (aReport.type == ButtonPress)
3516       {
3517         if (aButton == Aspect_VKeyMouse_LeftButton)
3518         {
3519           TheIsAnimating = Standard_False;
3520         }
3521         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3522       }
3523       else
3524       {
3525         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3526       }
3527       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3528       break;
3529     }
3530     case MotionNotify:
3531     {
3532       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3533       if (anXWindow != aReport.xmotion.window)
3534       {
3535         break;
3536       }
3537
3538       // remove all the ButtonMotionMask and process them at once
3539       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3540       {
3541         if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
3542         {
3543           break;
3544         }
3545       }
3546
3547       Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y);
3548       Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
3549       Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
3550       if ((aReport.xmotion.state & Button1Mask) != 0)
3551       {
3552         aButtons |= Aspect_VKeyMouse_LeftButton;
3553       }
3554       else if ((aReport.xmotion.state & Button2Mask) != 0)
3555       {
3556         aButtons |= Aspect_VKeyMouse_MiddleButton;
3557       }
3558       else if ((aReport.xmotion.state & Button3Mask) != 0)
3559       {
3560         aButtons |= Aspect_VKeyMouse_RightButton;
3561       }
3562
3563       if (aReport.xmotion.state & ControlMask)
3564       {
3565         aFlags |= Aspect_VKeyFlags_CTRL;
3566       }
3567       if (aReport.xmotion.state & ShiftMask)
3568       {
3569         aFlags |= Aspect_VKeyFlags_SHIFT;
3570       }
3571       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3572       {
3573         aFlags |= Aspect_VKeyFlags_ALT;
3574       }
3575
3576       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3577       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3578       break;
3579     }
3580   }
3581   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
3582 }
3583
3584 //==============================================================================
3585 //function : VProcessEvents
3586 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
3587 //==============================================================================
3588 static void VProcessEvents (ClientData theDispX, int)
3589 {
3590   Display* aDispX = (Display* )theDispX;
3591   Handle(Aspect_DisplayConnection) aDispConn;
3592   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
3593        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
3594   {
3595     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
3596     if (aDispConnTmp->GetDisplay() == aDispX)
3597     {
3598       aDispConn = aDispConnTmp;
3599       break;
3600     }
3601   }
3602   if (aDispConn.IsNull())
3603   {
3604     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
3605     return;
3606   }
3607
3608   // process new events in queue
3609   SetDisplayConnection (aDispConn);
3610   int aNbRemain = 0;
3611   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
3612   {
3613     const int anEventResult = ViewerMainLoop (0, NULL);
3614     if (anEventResult == 0)
3615     {
3616       return;
3617     }
3618
3619     aNbRemain = XPending (aDispX);
3620     if (++anEventIter >= aNbEventsMax
3621      || aNbRemain <= 0)
3622     {
3623       break;
3624     }
3625   }
3626
3627   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
3628   // it is possible that new events will arrive to queue before the end of this callback
3629   // so that either this callback should go into an infinite loop (blocking processing of other events)
3630   // or to keep unprocessed events till the next queue update (which can arrive not soon).
3631   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
3632   if (aNbRemain != 0)
3633   {
3634     XEvent aDummyEvent;
3635     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
3636     aDummyEvent.type = ClientMessage;
3637     aDummyEvent.xclient.format = 32;
3638     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
3639     XFlush (aDispX);
3640   }
3641
3642   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
3643   {
3644     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
3645   }
3646 }
3647 #endif
3648
3649 //==============================================================================
3650 //function : OSWindowSetup
3651 //purpose  : Setup for the X11 window to be able to cath the event
3652 //==============================================================================
3653
3654
3655 static void OSWindowSetup()
3656 {
3657 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
3658   // X11
3659
3660   Window  window   = VT_GetWindow()->XWindow();
3661   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
3662   Display *aDisplay = GetDisplayConnection()->GetDisplay();
3663   XSynchronize(aDisplay, 1);
3664
3665   // X11 : For keyboard on SUN
3666   XWMHints wmhints;
3667   wmhints.flags = InputHint;
3668   wmhints.input = 1;
3669
3670   XSetWMHints( aDisplay, window, &wmhints);
3671
3672   XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask | KeyReleaseMask |
3673     ButtonPressMask | ButtonReleaseMask |
3674     StructureNotifyMask |
3675     PointerMotionMask |
3676     Button1MotionMask | Button2MotionMask |
3677     Button3MotionMask | FocusChangeMask
3678     );
3679   Atom aDeleteWindowAtom = GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW);
3680   XSetWMProtocols(aDisplay, window, &aDeleteWindowAtom, 1);
3681
3682   XSynchronize(aDisplay, 0);
3683
3684 #else
3685   // _WIN32
3686 #endif
3687
3688 }
3689
3690 //==============================================================================
3691 //function : VFit
3692 //purpose  :
3693 //==============================================================================
3694
3695 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3696 {
3697   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3698   if (aView.IsNull())
3699   {
3700     Message::SendFail ("Error: no active viewer");
3701     return 1;
3702   }
3703
3704   Standard_Boolean toFit = Standard_True;
3705   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3706   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3707   {
3708     TCollection_AsciiString anArg (theArgv[anArgIter]);
3709     anArg.LowerCase();
3710     if (anUpdateTool.parseRedrawMode (anArg))
3711     {
3712       continue;
3713     }
3714     else if (anArg == "-selected")
3715     {
3716       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3717       toFit = Standard_False;
3718     }
3719     else
3720     {
3721       Message::SendFail() << "Syntax error at '" << anArg << "'";
3722     }
3723   }
3724
3725   if (toFit)
3726   {
3727     aView->FitAll (0.01, Standard_False);
3728   }
3729   return 0;
3730 }
3731
3732 //=======================================================================
3733 //function : VFitArea
3734 //purpose  : Fit view to show area located between two points
3735 //         : given in world 2D or 3D coordinates.
3736 //=======================================================================
3737 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3738 {
3739   Handle(V3d_View) aView = ViewerTest::CurrentView();
3740   if (aView.IsNull())
3741   {
3742     Message::SendFail ("Error: No active viewer");
3743     return 1;
3744   }
3745
3746   // Parse arguments.
3747   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3748   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3749
3750   if (theArgNb == 5)
3751   {
3752     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3753     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3754     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3755     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3756   }
3757   else if (theArgNb == 7)
3758   {
3759     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3760     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3761     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3762     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3763     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3764     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3765   }
3766   else
3767   {
3768     Message::SendFail ("Syntax error: Invalid number of arguments");
3769     theDI.PrintHelp(theArgVec[0]);
3770     return 1;
3771   }
3772
3773   // Convert model coordinates to view space
3774   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3775   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3776   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3777
3778   // Determine fit area
3779   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3780   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3781
3782   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3783
3784   if (aDiagonal < Precision::Confusion())
3785   {
3786     Message::SendFail ("Error: view area is too small");
3787     return 1;
3788   }
3789
3790   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3791   return 0;
3792 }
3793
3794 //==============================================================================
3795 //function : VZFit
3796 //purpose  : ZFitall, no DRAW arguments
3797 //Draw arg : No args
3798 //==============================================================================
3799 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3800 {
3801   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3802
3803   if (aCurrentView.IsNull())
3804   {
3805     Message::SendFail ("Error: no active viewer");
3806     return 1;
3807   }
3808
3809   if (theArgsNb == 1)
3810   {
3811     aCurrentView->ZFitAll();
3812     aCurrentView->Redraw();
3813     return 0;
3814   }
3815
3816   Standard_Real aScale = 1.0;
3817
3818   if (theArgsNb >= 2)
3819   {
3820     aScale = Draw::Atoi (theArgVec[1]);
3821   }
3822
3823   aCurrentView->ZFitAll (aScale);
3824   aCurrentView->Redraw();
3825
3826   return 0;
3827 }
3828
3829 //==============================================================================
3830 //function : VRepaint
3831 //purpose  :
3832 //==============================================================================
3833 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3834 {
3835   Handle(V3d_View) aView = ViewerTest::CurrentView();
3836   if (aView.IsNull())
3837   {
3838     Message::SendFail ("Error: no active viewer");
3839     return 1;
3840   }
3841
3842   Standard_Boolean isImmediateUpdate = Standard_False;
3843   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3844   {
3845     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3846     anArg.LowerCase();
3847     if (anArg == "-immediate"
3848      || anArg == "-imm")
3849     {
3850       isImmediateUpdate = Standard_True;
3851       if (anArgIter + 1 < theArgNb
3852        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3853       {
3854         ++anArgIter;
3855       }
3856     }
3857     else if (anArg == "-continuous"
3858           || anArg == "-cont"
3859           || anArg == "-fps"
3860           || anArg == "-framerate")
3861     {
3862       Standard_Real aFps = -1.0;
3863       if (anArgIter + 1 < theArgNb
3864        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
3865       {
3866         aFps = Draw::Atof (theArgVec[++anArgIter]);
3867       }
3868
3869       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3870       if (Abs (aFps) >= 1.0)
3871       {
3872         aRedrawer.Start (aView->Window(), aFps);
3873       }
3874       else
3875       {
3876         aRedrawer.Stop();
3877       }
3878     }
3879     else
3880     {
3881       Message::SendFail() << "Syntax error at '" << anArg << "'";
3882       return 1;
3883     }
3884   }
3885
3886   if (isImmediateUpdate)
3887   {
3888     aView->RedrawImmediate();
3889   }
3890   else
3891   {
3892     aView->Redraw();
3893   }
3894   return 0;
3895 }
3896
3897 //==============================================================================
3898 //function : VClear
3899 //purpose  : Remove all the object from the viewer
3900 //Draw arg : No args
3901 //==============================================================================
3902
3903 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3904 {
3905   Handle(V3d_View) V = ViewerTest::CurrentView();
3906   if(!V.IsNull())
3907     ViewerTest::Clear();
3908   return 0;
3909 }
3910
3911 //==============================================================================
3912 //function : VPick
3913 //purpose  :
3914 //==============================================================================
3915
3916 static int VPick (Draw_Interpretor& ,
3917                   Standard_Integer theNbArgs,
3918                   const char** theArgVec)
3919 {
3920   if (ViewerTest::CurrentView().IsNull())
3921   {
3922     return 1;
3923   }
3924
3925   if (theNbArgs < 4)
3926   {
3927     Message::SendFail ("Syntax error: wrong number of arguments");
3928     return 1;
3929   }
3930
3931   while (ViewerMainLoop (theNbArgs, theArgVec))
3932   {
3933     //
3934   }
3935
3936   return 0;
3937 }
3938
3939 namespace
3940 {
3941
3942   //! Changes the background
3943   //! @param theDrawInterpretor the interpreter of the Draw Harness application
3944   //! @param theNumberOfCommandLineArguments the number of passed command line arguments
3945   //! @param theCommandLineArguments the array of command line arguments
3946   //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
3947   static int vbackground (Draw_Interpretor&      theDrawInterpretor,
3948                           const Standard_Integer theNumberOfCommandLineArguments,
3949                           const char** const     theCommandLineArguments)
3950   {
3951     if (theNumberOfCommandLineArguments < 1)
3952     {
3953       return TCL_ERROR;
3954     }
3955     BackgroundChanger aBackgroundChanger;
3956     if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
3957                                                 theNumberOfCommandLineArguments,
3958                                                 theCommandLineArguments))
3959     {
3960       theDrawInterpretor << "Wrong command arguments.\n"
3961                             "Type 'help "
3962                          << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
3963       return TCL_ERROR;
3964     }
3965     return TCL_OK;
3966   }
3967
3968 } // namespace
3969
3970 //==============================================================================
3971 //function : VScale
3972 //purpose  : View Scaling
3973 //==============================================================================
3974
3975 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3976 {
3977   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3978   if ( V3dView.IsNull() ) return 1;
3979
3980   if ( argc != 4 ) {
3981     di << argv[0] << "Invalid number of arguments\n";
3982     return 1;
3983   }
3984   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3985   return 0;
3986 }
3987 //==============================================================================
3988 //function : VZBuffTrihedron
3989 //purpose  :
3990 //==============================================================================
3991
3992 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3993                             Standard_Integer  theArgNb,
3994                             const char**      theArgVec)
3995 {
3996   Handle(V3d_View) aView = ViewerTest::CurrentView();
3997   if (aView.IsNull())
3998   {
3999     Message::SendFail ("Error: no active viewer");
4000     return 1;
4001   }
4002
4003   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
4004
4005   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
4006   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
4007   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
4008   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
4009   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
4010   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
4011   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
4012   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
4013   Standard_Real                 aScale        = 0.1;
4014   Standard_Real                 aSizeRatio    = 0.8;
4015   Standard_Real                 anArrowDiam   = 0.05;
4016   Standard_Integer              aNbFacets     = 12;
4017   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4018   {
4019     Standard_CString        anArg = theArgVec[anArgIter];
4020     TCollection_AsciiString aFlag (anArg);
4021     aFlag.LowerCase();
4022     if (anUpdateTool.parseRedrawMode (aFlag))
4023     {
4024       continue;
4025     }
4026     else if (aFlag == "-on")
4027     {
4028       continue;
4029     }
4030     else if (aFlag == "-off")
4031     {
4032       aView->TriedronErase();
4033       return 0;
4034     }
4035     else if (aFlag == "-pos"
4036           || aFlag == "-position"
4037           || aFlag == "-corner")
4038     {
4039       if (++anArgIter >= theArgNb)
4040       {
4041         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4042         return 1;
4043       }
4044
4045       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
4046       aPosName.LowerCase();
4047       if (aPosName == "center")
4048       {
4049         aPosition = Aspect_TOTP_CENTER;
4050       }
4051       else if (aPosName == "left_lower"
4052             || aPosName == "lower_left"
4053             || aPosName == "leftlower"
4054             || aPosName == "lowerleft")
4055       {
4056         aPosition = Aspect_TOTP_LEFT_LOWER;
4057       }
4058       else if (aPosName == "left_upper"
4059             || aPosName == "upper_left"
4060             || aPosName == "leftupper"
4061             || aPosName == "upperleft")
4062       {
4063         aPosition = Aspect_TOTP_LEFT_UPPER;
4064       }
4065       else if (aPosName == "right_lower"
4066             || aPosName == "lower_right"
4067             || aPosName == "rightlower"
4068             || aPosName == "lowerright")
4069       {
4070         aPosition = Aspect_TOTP_RIGHT_LOWER;
4071       }
4072       else if (aPosName == "right_upper"
4073             || aPosName == "upper_right"
4074             || aPosName == "rightupper"
4075             || aPosName == "upperright")
4076       {
4077         aPosition = Aspect_TOTP_RIGHT_UPPER;
4078       }
4079       else
4080       {
4081         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
4082         return 1;
4083       }
4084     }
4085     else if (aFlag == "-type")
4086     {
4087       if (++anArgIter >= theArgNb)
4088       {
4089         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4090         return 1;
4091       }
4092
4093       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
4094       aTypeName.LowerCase();
4095       if (aTypeName == "wireframe"
4096        || aTypeName == "wire")
4097       {
4098         aVisType = V3d_WIREFRAME;
4099       }
4100       else if (aTypeName == "zbuffer"
4101             || aTypeName == "shaded")
4102       {
4103         aVisType = V3d_ZBUFFER;
4104       }
4105       else
4106       {
4107         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
4108       }
4109     }
4110     else if (aFlag == "-scale")
4111     {
4112       if (++anArgIter >= theArgNb)
4113       {
4114         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4115         return 1;
4116       }
4117
4118       aScale = Draw::Atof (theArgVec[anArgIter]);
4119     }
4120     else if (aFlag == "-size"
4121           || aFlag == "-sizeratio")
4122     {
4123       if (++anArgIter >= theArgNb)
4124       {
4125         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4126         return 1;
4127       }
4128
4129       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
4130     }
4131     else if (aFlag == "-arrowdiam"
4132           || aFlag == "-arrowdiameter")
4133     {
4134       if (++anArgIter >= theArgNb)
4135       {
4136         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4137         return 1;
4138       }
4139
4140       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
4141     }
4142     else if (aFlag == "-nbfacets")
4143     {
4144       if (++anArgIter >= theArgNb)
4145       {
4146         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4147         return 1;
4148       }
4149
4150       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
4151     }
4152     else if (aFlag == "-colorlabel"
4153           || aFlag == "-colorlabels"
4154           || aFlag == "-colorlabelx"
4155           || aFlag == "-colorlabely"
4156           || aFlag == "-colorlabelz"
4157           || aFlag == "-colorarrowx"
4158           || aFlag == "-colorarrowy"
4159           || aFlag == "-colorarrowz")
4160     {
4161       Quantity_Color aColor;
4162       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
4163                                                      theArgVec + anArgIter + 1,
4164                                                      aColor);
4165       if (aNbParsed == 0)
4166       {
4167         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4168         return 1;
4169       }
4170
4171       if (aFlag == "-colorarrowx")
4172       {
4173         anArrowColorX = aColor;
4174       }
4175       else if (aFlag == "-colorarrowy")
4176       {
4177         anArrowColorY = aColor;
4178       }
4179       else if (aFlag == "-colorarrowz")
4180       {
4181         anArrowColorZ = aColor;
4182       }
4183       else if (aFlag == "-colorlabelx")
4184       {
4185         aLabelsColorX = aColor;
4186       }
4187       else if (aFlag == "-colorlabely")
4188       {
4189         aLabelsColorY = aColor;
4190       }
4191       else if (aFlag == "-colorlabelz")
4192       {
4193         aLabelsColorZ = aColor;
4194       }
4195       else
4196       {
4197         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
4198       }
4199       anArgIter += aNbParsed;
4200     }
4201     else
4202     {
4203       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4204       return 1;
4205     }
4206   }
4207
4208   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
4209   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
4210   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
4211   aTrihedron->SetSizeRatio    (aSizeRatio);
4212   aTrihedron->SetNbFacets     (aNbFacets);
4213   aTrihedron->SetArrowDiameter(anArrowDiam);
4214   aTrihedron->SetScale        (aScale);
4215   aTrihedron->SetPosition     (aPosition);
4216   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
4217   aTrihedron->Display (aView);
4218
4219   aView->ZFitAll();
4220   return 0;
4221 }
4222
4223 //==============================================================================
4224 //function : VRotate
4225 //purpose  : Camera Rotating
4226 //==============================================================================
4227
4228 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
4229 {
4230   Handle(V3d_View) aView = ViewerTest::CurrentView();
4231   if (aView.IsNull())
4232   {
4233     Message::SendFail ("Error: no active viewer");
4234     return 1;
4235   }
4236
4237   Standard_Boolean hasFlags = Standard_False;
4238   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4239   {
4240     Standard_CString        anArg (theArgVec[anArgIter]);
4241     TCollection_AsciiString aFlag (anArg);
4242     aFlag.LowerCase();
4243     if (aFlag == "-mousestart"
4244      || aFlag == "-mousefrom")
4245     {
4246       hasFlags = Standard_True;
4247       if (anArgIter + 2 >= theArgNb)
4248       {
4249         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4250         return 1;
4251       }
4252
4253       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4254       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4255       aView->StartRotation (anX, anY);
4256     }
4257     else if (aFlag == "-mousemove")
4258     {
4259       hasFlags = Standard_True;
4260       if (anArgIter + 2 >= theArgNb)
4261       {
4262         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4263         return 1;
4264       }
4265
4266       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4267       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4268       aView->Rotation (anX, anY);
4269     }
4270     else if (theArgNb != 4
4271           && theArgNb != 7)
4272     {
4273       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4274       return 1;
4275     }
4276   }
4277
4278   if (hasFlags)
4279   {
4280     return 0;
4281   }
4282   else if (theArgNb == 4)
4283   {
4284     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4285     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4286     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4287     aView->Rotate (anAX, anAY, anAZ);
4288     return 0;
4289   }
4290   else if (theArgNb == 7)
4291   {
4292     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4293     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4294     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4295
4296     Standard_Real anX = Draw::Atof (theArgVec[4]);
4297     Standard_Real anY = Draw::Atof (theArgVec[5]);
4298     Standard_Real anZ = Draw::Atof (theArgVec[6]);
4299
4300     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
4301     return 0;
4302   }
4303
4304   Message::SendFail ("Error: Invalid number of arguments");
4305   return 1;
4306 }
4307
4308 //==============================================================================
4309 //function : VZoom
4310 //purpose  : View zoom in / out (relative to current zoom)
4311 //==============================================================================
4312
4313 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4314   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4315   if ( V3dView.IsNull() ) {
4316     return 1;
4317   }
4318
4319   if ( argc == 2 ) {
4320     Standard_Real coef = Draw::Atof(argv[1]);
4321     if ( coef <= 0.0 ) {
4322       di << argv[1] << "Invalid value\n";
4323       return 1;
4324     }
4325     V3dView->SetZoom( Draw::Atof(argv[1]) );
4326     return 0;
4327   } else {
4328     di << argv[0] << " Invalid number of arguments\n";
4329     return 1;
4330   }
4331 }
4332
4333 //==============================================================================
4334 //function : VPan
4335 //purpose  : View panning (in pixels)
4336 //==============================================================================
4337
4338 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4339   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4340   if ( V3dView.IsNull() ) return 1;
4341
4342   if ( argc == 3 ) {
4343     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
4344     return 0;
4345   } else {
4346     di << argv[0] << " Invalid number of arguments\n";
4347     return 1;
4348   }
4349 }
4350
4351 //==============================================================================
4352 //function : VPlace
4353 //purpose  : Place the point (in pixels) at the center of the window
4354 //==============================================================================
4355 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
4356 {
4357   Handle(V3d_View) aView = ViewerTest::CurrentView();
4358   if (aView.IsNull())
4359   {
4360     Message::SendFail ("Error: no active viewer");
4361     return 1;
4362   }
4363
4364   if (theArgNb != 3)
4365   {
4366     Message::SendFail ("Syntax error: wrong number of arguments");
4367     return 1;
4368   }
4369
4370   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
4371
4372   return 0;
4373 }
4374
4375 static int VColorScale (Draw_Interpretor& theDI,
4376                         Standard_Integer  theArgNb,
4377                         const char**      theArgVec)
4378 {
4379   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4380   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
4381   if (aContext.IsNull())
4382   {
4383     Message::SendFail ("Error: no active viewer");
4384     return 1;
4385   }
4386   if (theArgNb <= 1)
4387   {
4388     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
4389     return 1;
4390   }
4391
4392   Handle(AIS_ColorScale) aColorScale;
4393   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
4394   {
4395     // find existing object
4396     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
4397     if (aColorScale.IsNull())
4398     {
4399       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
4400       return 1;
4401     }
4402   }
4403
4404   if (theArgNb <= 2)
4405   {
4406     if (aColorScale.IsNull())
4407     {
4408       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
4409       return 1;
4410     }
4411
4412     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
4413           << "Min range: "            << aColorScale->GetMin() << "\n"
4414           << "Max range: "            << aColorScale->GetMax() << "\n"
4415           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
4416           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
4417           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
4418           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
4419           << "Label position: ";
4420     switch (aColorScale->GetLabelPosition())
4421     {
4422       case Aspect_TOCSP_NONE:
4423         theDI << "None\n";
4424         break;
4425       case Aspect_TOCSP_LEFT:
4426         theDI << "Left\n";
4427         break;
4428       case Aspect_TOCSP_RIGHT:
4429         theDI << "Right\n";
4430         break;
4431       case Aspect_TOCSP_CENTER:
4432         theDI << "Center\n";
4433         break;
4434     }
4435     return 0;
4436   }
4437
4438   if (aColorScale.IsNull())
4439   {
4440     aColorScale = new AIS_ColorScale();
4441     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4442     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4443   }
4444
4445   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
4446   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
4447   {
4448     Standard_CString        anArg = theArgVec[anArgIter];
4449     TCollection_AsciiString aFlag (anArg);
4450     aFlag.LowerCase();
4451     if (anUpdateTool.parseRedrawMode (aFlag))
4452     {
4453       continue;
4454     }
4455     else if (aFlag == "-range")
4456     {
4457       if (anArgIter + 3 >= theArgNb)
4458       {
4459         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
4460         return 1;
4461       }
4462
4463       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
4464       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
4465       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
4466       if (!aRangeMin.IsRealValue (Standard_True)
4467        || !aRangeMax.IsRealValue (Standard_True))
4468       {
4469         Message::SendFail ("Syntax error: the range values should be real");
4470         return 1;
4471       }
4472       else if (!aNbIntervals.IsIntegerValue())
4473       {
4474         Message::SendFail ("Syntax error: the number of intervals should be integer");
4475         return 1;
4476       }
4477
4478       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
4479       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
4480     }
4481     else if (aFlag == "-font")
4482     {
4483       if (anArgIter + 1 >= theArgNb)
4484       {
4485         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4486         return 1;
4487       }
4488       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
4489       if (!aFontArg.IsIntegerValue())
4490       {
4491         Message::SendFail ("Syntax error: HeightFont value should be integer");
4492         return 1;
4493       }
4494
4495       aColorScale->SetTextHeight (aFontArg.IntegerValue());
4496       anArgIter += 1;
4497     }
4498     else if (aFlag == "-textpos")
4499     {
4500       if (anArgIter + 1 >= theArgNb)
4501       {
4502         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4503         return 1;
4504       }
4505
4506       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
4507       aTextPosArg.LowerCase();
4508       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
4509       if (aTextPosArg == "none")
4510       {
4511         aLabPosition = Aspect_TOCSP_NONE;
4512       }
4513       else if (aTextPosArg == "left")
4514       {
4515         aLabPosition = Aspect_TOCSP_LEFT;
4516       }
4517       else if (aTextPosArg == "right")
4518       {
4519         aLabPosition = Aspect_TOCSP_RIGHT;
4520       }
4521       else if (aTextPosArg == "center")
4522       {
4523         aLabPosition = Aspect_TOCSP_CENTER;
4524       }
4525       else
4526       {
4527         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
4528         return 1;
4529       }
4530       aColorScale->SetLabelPosition (aLabPosition);
4531     }
4532     else if (aFlag == "-logarithmic"
4533           || aFlag == "-log")
4534     {
4535       if (anArgIter + 1 >= theArgNb)
4536       {
4537         Message::SendFail() << "Synta error at argument '" << anArg << "'";
4538         return 1;
4539       }
4540
4541       Standard_Boolean IsLog;
4542       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
4543       {
4544         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4545         return 1;
4546       }
4547       aColorScale->SetLogarithmic (IsLog);
4548     }
4549     else if (aFlag == "-huerange"
4550           || aFlag == "-hue")
4551     {
4552       if (anArgIter + 2 >= theArgNb)
4553       {
4554         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4555         return 1;
4556       }
4557
4558       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
4559       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
4560       aColorScale->SetHueRange (aHueMin, aHueMax);
4561     }
4562     else if (aFlag == "-colorrange")
4563     {
4564       Quantity_Color aColorMin, aColorMax;
4565       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4566                                                       theArgVec + (anArgIter + 1),
4567                                                       aColorMin);
4568       anArgIter += aNbParsed1;
4569       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4570                                                       theArgVec + (anArgIter + 1),
4571                                                       aColorMax);
4572       anArgIter += aNbParsed2;
4573       if (aNbParsed1 == 0
4574        || aNbParsed2 == 0)
4575       {
4576         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4577         return 1;
4578       }
4579
4580       aColorScale->SetColorRange (aColorMin, aColorMax);
4581     }
4582     else if (aFlag == "-reversed"
4583           || aFlag == "-inverted"
4584           || aFlag == "-topdown"
4585           || aFlag == "-bottomup")
4586     {
4587       Standard_Boolean toEnable = Standard_True;
4588       if (anArgIter + 1 < theArgNb
4589        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
4590       {
4591         ++anArgIter;
4592       }
4593       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
4594     }
4595     else if (aFlag == "-smooth"
4596           || aFlag == "-smoothtransition")
4597     {
4598       Standard_Boolean toEnable = Standard_True;
4599       if (anArgIter + 1 < theArgNb
4600        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4601       {
4602         ++anArgIter;
4603       }
4604       aColorScale->SetSmoothTransition (toEnable);
4605     }
4606     else if (aFlag == "-xy")
4607     {
4608       if (anArgIter + 2 >= theArgNb)
4609       {
4610         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4611         return 1;
4612       }
4613
4614       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
4615       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
4616       if (!anX.IsIntegerValue()
4617        || !anY.IsIntegerValue())
4618       {
4619         Message::SendFail ("Syntax error: coordinates should be integer values");
4620         return 1;
4621       }
4622
4623       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
4624     }
4625     else if (aFlag == "-width"
4626           || aFlag == "-w"
4627           || aFlag == "-breadth")
4628     {
4629       if (anArgIter + 1 >= theArgNb)
4630       {
4631         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4632         return 1;
4633       }
4634
4635       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
4636       if (!aBreadth.IsIntegerValue())
4637       {
4638         Message::SendFail ("Syntax error: a width should be an integer value");
4639         return 1;
4640       }
4641       aColorScale->SetBreadth (aBreadth.IntegerValue());
4642     }
4643     else if (aFlag == "-height"
4644           || aFlag == "-h")
4645     {
4646       if (anArgIter + 1 >= theArgNb)
4647       {
4648         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4649         return 1;
4650       }
4651
4652       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
4653       if (!aHeight.IsIntegerValue())
4654       {
4655         Message::SendFail ("Syntax error: a width should be an integer value");
4656         return 1;
4657       }
4658       aColorScale->SetHeight (aHeight.IntegerValue());
4659     }
4660     else if (aFlag == "-color")
4661     {
4662       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4663       {
4664         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
4665         return 1;
4666       }
4667       else if (anArgIter + 2 >= theArgNb)
4668       {
4669         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4670         return 1;
4671       }
4672
4673       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
4674       if (!anInd.IsIntegerValue())
4675       {
4676         Message::SendFail ("Syntax error: Index value should be integer");
4677         return 1;
4678       }
4679       const Standard_Integer anIndex = anInd.IntegerValue();
4680       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
4681       {
4682         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
4683         return 1;
4684       }
4685
4686       Quantity_Color aColor;
4687       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4688                                                      theArgVec + (anArgIter + 1),
4689                                                      aColor);
4690       if (aNbParsed == 0)
4691       {
4692         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4693         return 1;
4694       }
4695       aColorScale->SetIntervalColor (aColor, anIndex);
4696       aColorScale->SetColorType (Aspect_TOCSD_USER);
4697       anArgIter += aNbParsed;
4698     }
4699     else if (aFlag == "-label")
4700     {
4701       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4702       {
4703         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
4704         return 1;
4705       }
4706       else if (anArgIter + 2 >= theArgNb)
4707       {
4708         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4709         return 1;
4710       }
4711
4712       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
4713       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
4714       {
4715         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
4716         return 1;
4717       }
4718
4719       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
4720       aColorScale->SetLabel     (aText, anIndex);
4721       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4722       anArgIter += 2;
4723     }
4724     else if (aFlag == "-labelat"
4725           || aFlag == "-labat"
4726           || aFlag == "-labelatborder"
4727           || aFlag == "-labatborder"
4728           || aFlag == "-labelatcenter"
4729           || aFlag == "-labatcenter")
4730     {
4731       Standard_Boolean toEnable = Standard_True;
4732       if (aFlag == "-labelat"
4733        || aFlag == "-labat")
4734       {
4735         Standard_Integer aLabAtBorder = -1;
4736         if (++anArgIter >= theArgNb)
4737         {
4738           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
4739           anAtBorder.LowerCase();
4740           if (anAtBorder == "border")
4741           {
4742             aLabAtBorder = 1;
4743           }
4744           else if (anAtBorder == "center")
4745           {
4746             aLabAtBorder = 0;
4747           }
4748         }
4749         if (aLabAtBorder == -1)
4750         {
4751           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4752           return 1;
4753         }
4754         toEnable = (aLabAtBorder == 1);
4755       }
4756       else if (anArgIter + 1 < theArgNb
4757             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4758       {
4759         ++anArgIter;
4760       }
4761       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
4762                                   || aFlag == "-labatcenter"
4763                                    ? !toEnable
4764                                    :  toEnable);
4765     }
4766     else if (aFlag == "-colors")
4767     {
4768       Aspect_SequenceOfColor aSeq;
4769       for (;;)
4770       {
4771         Quantity_Color aColor;
4772         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4773                                                        theArgVec + (anArgIter + 1),
4774                                                        aColor);
4775         if (aNbParsed == 0)
4776         {
4777           break;
4778         }
4779         anArgIter += aNbParsed;
4780         aSeq.Append (aColor);
4781       }
4782       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4783       {
4784         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4785                             << aColorScale->GetNumberOfIntervals() << " intervals";
4786         return 1;
4787       }
4788
4789       aColorScale->SetColors    (aSeq);
4790       aColorScale->SetColorType (Aspect_TOCSD_USER);
4791     }
4792     else if (aFlag == "-uniform")
4793     {
4794       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4795       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4796       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4797       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4798       aColorScale->SetColorType (Aspect_TOCSD_USER);
4799     }
4800     else if (aFlag == "-labels"
4801           || aFlag == "-freelabels")
4802     {
4803       if (anArgIter + 1 >= theArgNb)
4804       {
4805         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4806         return 1;
4807       }
4808
4809       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4810                                  ? aColorScale->GetNumberOfIntervals() + 1
4811                                  : aColorScale->GetNumberOfIntervals();
4812       if (aFlag == "-freelabels")
4813       {
4814         ++anArgIter;
4815         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4816       }
4817       if (anArgIter + aNbLabels >= theArgNb)
4818       {
4819         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4820         return 1;
4821       }
4822
4823       TColStd_SequenceOfExtendedString aSeq;
4824       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4825       {
4826         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
4827       }
4828       aColorScale->SetLabels (aSeq);
4829       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4830     }
4831     else if (aFlag == "-title")
4832     {
4833       if (anArgIter + 1 >= theArgNb)
4834       {
4835         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4836         return 1;
4837       }
4838
4839       Standard_Boolean isTwoArgs = Standard_False;
4840       if (anArgIter + 2 < theArgNb)
4841       {
4842         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4843         aSecondArg.LowerCase();
4844       Standard_DISABLE_DEPRECATION_WARNINGS
4845         if (aSecondArg == "none")
4846         {
4847           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4848           isTwoArgs = Standard_True;
4849         }
4850         else if (aSecondArg == "left")
4851         {
4852           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4853           isTwoArgs = Standard_True;
4854         }
4855         else if (aSecondArg == "right")
4856         {
4857           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4858           isTwoArgs = Standard_True;
4859         }
4860         else if (aSecondArg == "center")
4861         {
4862           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4863           isTwoArgs = Standard_True;
4864         }
4865       Standard_ENABLE_DEPRECATION_WARNINGS
4866       }
4867
4868       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
4869       aColorScale->SetTitle (aTitle);
4870       if (isTwoArgs)
4871       {
4872         anArgIter += 1;
4873       }
4874       anArgIter += 1;
4875     }
4876     else if (aFlag == "-demoversion"
4877           || aFlag == "-demo")
4878     {
4879       aColorScale->SetPosition (0, 0);
4880       aColorScale->SetTextHeight (16);
4881       aColorScale->SetRange (0.0, 100.0);
4882       aColorScale->SetNumberOfIntervals (10);
4883       aColorScale->SetBreadth (0);
4884       aColorScale->SetHeight  (0);
4885       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4886       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4887       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4888     }
4889     else if (aFlag == "-findcolor")
4890     {
4891       if (anArgIter + 1 >= theArgNb)
4892       {
4893         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4894         return 1;
4895       }
4896
4897       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4898
4899       if (!anArg1.IsRealValue (Standard_True))
4900       {
4901         Message::SendFail ("Syntax error: the value should be real");
4902         return 1;
4903       }
4904
4905       Quantity_Color aColor;
4906       aColorScale->FindColor (anArg1.RealValue(), aColor);
4907       theDI << Quantity_Color::StringName (aColor.Name());
4908       return 0;
4909     }
4910     else
4911     {
4912       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4913       return 1;
4914     }
4915   }
4916
4917   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4918   aView->Window()->Size (aWinWidth, aWinHeight);
4919   if (aColorScale->GetBreadth() == 0)
4920   {
4921     aColorScale->SetBreadth (aWinWidth);
4922   }
4923   if (aColorScale->GetHeight() == 0)
4924   {
4925     aColorScale->SetHeight (aWinHeight);
4926   }
4927   aColorScale->SetToUpdate();
4928   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4929   return 0;
4930 }
4931
4932 //==============================================================================
4933 //function : VGraduatedTrihedron
4934 //purpose  : Displays or hides a graduated trihedron
4935 //==============================================================================
4936 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4937                                   Quantity_Color& theColor)
4938 {
4939   Quantity_NameOfColor aColorName;
4940   TCollection_AsciiString aVal = theValue;
4941   aVal.UpperCase();
4942   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4943   {
4944     return Standard_False;
4945   }
4946   theColor = Quantity_Color (aColorName);
4947   return Standard_True;
4948 }
4949
4950 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4951 {
4952   if (theArgNum < 2)
4953   {
4954     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4955                         << theArgs[0] <<"' for more information";
4956     return 1;
4957   }
4958
4959   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4960   TCollection_AsciiString aParseKey;
4961   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4962   {
4963     TCollection_AsciiString anArg (theArgs [anArgIt]);
4964
4965     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4966     {
4967       aParseKey = anArg;
4968       aParseKey.Remove (1);
4969       aParseKey.LowerCase();
4970       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4971       continue;
4972     }
4973
4974     if (aParseKey.IsEmpty())
4975     {
4976       continue;
4977     }
4978
4979     aMapOfArgs(aParseKey)->Append (anArg);
4980   }
4981
4982   // Check parameters
4983   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4984        aMapIt.More(); aMapIt.Next())
4985   {
4986     const TCollection_AsciiString& aKey = aMapIt.Key();
4987     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4988
4989     // Bool key, without arguments
4990     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4991         && anArgs->IsEmpty())
4992     {
4993       continue;
4994     }
4995
4996     // One argument
4997     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4998           && anArgs->Length() == 1)
4999     {
5000       continue;
5001     }
5002
5003     // On/off arguments
5004     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
5005         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
5006         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
5007         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
5008         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
5009     {
5010       continue;
5011     }
5012
5013     // One string argument
5014     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
5015           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
5016           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
5017     {
5018       continue;
5019     }
5020
5021     // One integer argument
5022     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
5023           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
5024           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
5025           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
5026          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
5027     {
5028       continue;
5029     }
5030
5031     // One real argument
5032     if ( aKey.IsEqual ("arrowlength")
5033          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
5034     {
5035       continue;
5036     }
5037
5038     // Two string arguments
5039     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
5040          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
5041     {
5042       continue;
5043     }
5044
5045     TCollection_AsciiString aLowerKey;
5046     aLowerKey  = "-";
5047     aLowerKey += aKey;
5048     aLowerKey.LowerCase();
5049     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
5050                         << "Type help for more information";
5051     return 1;
5052   }
5053
5054   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
5055   if (anAISContext.IsNull())
5056   {
5057     Message::SendFail ("Error: no active viewer");
5058     return 1;
5059   }
5060
5061   Standard_Boolean toDisplay = Standard_True;
5062   Quantity_Color aColor;
5063   Graphic3d_GraduatedTrihedron aTrihedronData;
5064   // Process parameters
5065   Handle(TColStd_HSequenceOfAsciiString) aValues;
5066   if (aMapOfArgs.Find ("off", aValues))
5067   {
5068     toDisplay = Standard_False;
5069   }
5070
5071   // AXES NAMES
5072   if (aMapOfArgs.Find ("xname", aValues))
5073   {
5074     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
5075   }
5076   if (aMapOfArgs.Find ("yname", aValues))
5077   {
5078     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
5079   }
5080   if (aMapOfArgs.Find ("zname", aValues))
5081   {
5082     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
5083   }
5084   if (aMapOfArgs.Find ("xdrawname", aValues))
5085   {
5086     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5087   }
5088   if (aMapOfArgs.Find ("ydrawname", aValues))
5089   {
5090     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5091   }
5092   if (aMapOfArgs.Find ("zdrawname", aValues))
5093   {
5094     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5095   }
5096   if (aMapOfArgs.Find ("xnameoffset", aValues))
5097   {
5098     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5099   }
5100   if (aMapOfArgs.Find ("ynameoffset", aValues))
5101   {
5102     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5103   }
5104   if (aMapOfArgs.Find ("znameoffset", aValues))
5105   {
5106     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5107   }
5108
5109   // COLORS
5110   if (aMapOfArgs.Find ("xnamecolor", aValues))
5111   {
5112     if (!GetColor (aValues->Value(1), aColor))
5113     {
5114       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
5115       return 1;
5116     }
5117     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
5118   }
5119   if (aMapOfArgs.Find ("ynamecolor", aValues))
5120   {
5121     if (!GetColor (aValues->Value(1), aColor))
5122     {
5123       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
5124       return 1;
5125     }
5126     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
5127   }
5128   if (aMapOfArgs.Find ("znamecolor", aValues))
5129   {
5130     if (!GetColor (aValues->Value(1), aColor))
5131     {
5132       Message::SendFail ("Syntax error: -znamecolor wrong color name");
5133       return 1;
5134     }
5135     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
5136   }
5137   if (aMapOfArgs.Find ("xcolor", aValues))
5138   {
5139     if (!GetColor (aValues->Value(1), aColor))
5140     {
5141       Message::SendFail ("Syntax error: -xcolor wrong color name");
5142       return 1;
5143     }
5144     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
5145   }
5146   if (aMapOfArgs.Find ("ycolor", aValues))
5147   {
5148     if (!GetColor (aValues->Value(1), aColor))
5149     {
5150       Message::SendFail ("Syntax error: -ycolor wrong color name");
5151       return 1;
5152     }
5153     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
5154   }
5155   if (aMapOfArgs.Find ("zcolor", aValues))
5156   {
5157     if (!GetColor (aValues->Value(1), aColor))
5158     {
5159       Message::SendFail ("Syntax error: -zcolor wrong color name");
5160       return 1;
5161     }
5162     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
5163   }
5164
5165   // TICKMARKS
5166   if (aMapOfArgs.Find ("xticks", aValues))
5167   {
5168     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5169   }
5170   if (aMapOfArgs.Find ("yticks", aValues))
5171   {
5172     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5173   }
5174   if (aMapOfArgs.Find ("zticks", aValues))
5175   {
5176     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5177   }
5178   if (aMapOfArgs.Find ("xticklength", aValues))
5179   {
5180     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5181   }
5182   if (aMapOfArgs.Find ("yticklength", aValues))
5183   {
5184     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5185   }
5186   if (aMapOfArgs.Find ("zticklength", aValues))
5187   {
5188     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5189   }
5190   if (aMapOfArgs.Find ("xdrawticks", aValues))
5191   {
5192     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5193   }
5194   if (aMapOfArgs.Find ("ydrawticks", aValues))
5195   {
5196     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5197   }
5198   if (aMapOfArgs.Find ("zdrawticks", aValues))
5199   {
5200     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5201   }
5202
5203   // VALUES
5204   if (aMapOfArgs.Find ("xdrawvalues", aValues))
5205   {
5206     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5207   }
5208   if (aMapOfArgs.Find ("ydrawvalues", aValues))
5209   {
5210     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5211   }
5212   if (aMapOfArgs.Find ("zdrawvalues", aValues))
5213   {
5214     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5215   }
5216   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
5217   {
5218     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5219   }
5220   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
5221   {
5222     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5223   }
5224   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
5225   {
5226     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5227   }
5228
5229   // ARROWS
5230   if (aMapOfArgs.Find ("arrowlength", aValues))
5231   {
5232     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
5233   }
5234
5235   // FONTS
5236   if (aMapOfArgs.Find ("namefont", aValues))
5237   {
5238     aTrihedronData.SetNamesFont (aValues->Value(1));
5239   }
5240   if (aMapOfArgs.Find ("valuesfont", aValues))
5241   {
5242     aTrihedronData.SetValuesFont (aValues->Value(1));
5243   }
5244
5245   if (aMapOfArgs.Find ("drawgrid", aValues))
5246   {
5247     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
5248   }
5249   if (aMapOfArgs.Find ("drawaxes", aValues))
5250   {
5251     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
5252   }
5253
5254   // The final step: display of erase trihedron
5255   if (toDisplay)
5256   {
5257     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
5258   }
5259   else
5260   {
5261     ViewerTest::CurrentView()->GraduatedTrihedronErase();
5262   }
5263
5264   ViewerTest::GetAISContext()->UpdateCurrentViewer();
5265   ViewerTest::CurrentView()->Redraw();
5266
5267   return 0;
5268 }
5269
5270 //==============================================================================
5271 //function : VTile
5272 //purpose  :
5273 //==============================================================================
5274 static int VTile (Draw_Interpretor& theDI,
5275                   Standard_Integer  theArgNb,
5276                   const char**      theArgVec)
5277 {
5278   Handle(V3d_View) aView = ViewerTest::CurrentView();
5279   if (aView.IsNull())
5280   {
5281     Message::SendFail ("Error: no active viewer");
5282     return 1;
5283   }
5284
5285   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
5286   if (theArgNb < 2)
5287   {
5288     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
5289           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
5290           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
5291     return 0;
5292   }
5293
5294   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
5295   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5296   {
5297     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5298     anArg.LowerCase();
5299     if (anArg == "-lowerleft"
5300      || anArg == "-upperleft")
5301     {
5302       if (anArgIter + 3 < theArgNb)
5303       {
5304         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5305         return 1;
5306       }
5307       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
5308       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5309       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5310     }
5311     else if (anArg == "-total"
5312           || anArg == "-totalsize"
5313           || anArg == "-viewsize")
5314     {
5315       if (anArgIter + 3 < theArgNb)
5316       {
5317         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5318         return 1;
5319       }
5320       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5321       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5322       if (aTile.TotalSize.x() < 1
5323        || aTile.TotalSize.y() < 1)
5324       {
5325         Message::SendFail ("Error: total size is incorrect");
5326         return 1;
5327       }
5328     }
5329     else if (anArg == "-tilesize")
5330     {
5331       if (anArgIter + 3 < theArgNb)
5332       {
5333         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5334         return 1;
5335       }
5336
5337       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5338       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5339       if (aTile.TileSize.x() < 1
5340        || aTile.TileSize.y() < 1)
5341       {
5342         Message::SendFail ("Error: tile size is incorrect");
5343         return 1;
5344       }
5345     }
5346     else if (anArg == "-unset")
5347     {
5348       aView->Camera()->SetTile (Graphic3d_CameraTile());
5349       aView->Redraw();
5350       return 0;
5351     }
5352   }
5353
5354   if (aTile.TileSize.x() < 1
5355    || aTile.TileSize.y() < 1)
5356   {
5357     Message::SendFail ("Error: tile size is undefined");
5358     return 1;
5359   }
5360   else if (aTile.TotalSize.x() < 1
5361         || aTile.TotalSize.y() < 1)
5362   {
5363     Message::SendFail ("Error: total size is undefined");
5364     return 1;
5365   }
5366
5367   aView->Camera()->SetTile (aTile);
5368   aView->Redraw();
5369   return 0;
5370 }
5371
5372 //! Format ZLayer ID.
5373 inline const char* formZLayerId (const Standard_Integer theLayerId)
5374 {
5375   switch (theLayerId)
5376   {
5377     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
5378     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
5379     case Graphic3d_ZLayerId_Top:     return "[TOP]";
5380     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
5381     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
5382     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
5383   }
5384   return "";
5385 }
5386
5387 //! Print the ZLayer information.
5388 inline void printZLayerInfo (Draw_Interpretor& theDI,
5389                              const Graphic3d_ZLayerSettings& theLayer)
5390 {
5391   if (!theLayer.Name().IsEmpty())
5392   {
5393     theDI << "  Name: " << theLayer.Name() << "\n";
5394   }
5395   if (theLayer.IsImmediate())
5396   {
5397     theDI << "  Immediate: TRUE\n";
5398   }
5399   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
5400   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
5401   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
5402   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
5403   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
5404   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
5405   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
5406   {
5407     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
5408   }
5409 }
5410
5411 //==============================================================================
5412 //function : VZLayer
5413 //purpose  : Test z layer operations for v3d viewer
5414 //==============================================================================
5415 static int VZLayer (Draw_Interpretor& theDI,
5416                     Standard_Integer  theArgNb,
5417                     const char**      theArgVec)
5418 {
5419   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5420   if (aContextAIS.IsNull())
5421   {
5422     Message::SendFail ("Error: no active viewer");
5423     return 1;
5424   }
5425
5426   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
5427   if (theArgNb < 2)
5428   {
5429     TColStd_SequenceOfInteger aLayers;
5430     aViewer->GetAllZLayers (aLayers);
5431     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5432     {
5433       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
5434       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
5435       printZLayerInfo (theDI, aSettings);
5436     }
5437     return 1;
5438   }
5439
5440   Standard_Integer anArgIter = 1;
5441   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5442   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
5443   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5444   {
5445     ++anArgIter;
5446   }
5447
5448   {
5449     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
5450     if (aFirstArg.IsIntegerValue())
5451     {
5452       ++anArgIter;
5453       aLayerId = aFirstArg.IntegerValue();
5454     }
5455     else
5456     {
5457       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
5458       {
5459         ++anArgIter;
5460       }
5461     }
5462   }
5463
5464   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
5465   for (; anArgIter < theArgNb; ++anArgIter)
5466   {
5467     // perform operation
5468     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5469     anArg.LowerCase();
5470     if (anUpdateTool.parseRedrawMode (anArg))
5471     {
5472       //
5473     }
5474     else if (anArg == "-add"
5475           || anArg == "add")
5476     {
5477       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5478       if (!aViewer->AddZLayer (aLayerId))
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 == "-insertbefore"
5487           && anArgIter + 1 < theArgNb
5488           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5489     {
5490       ++anArgIter;
5491       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5492       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5493       {
5494         Message::SendFail ("Error: can not add a new z layer");
5495         return 0;
5496       }
5497
5498       theDI << aLayerId;
5499     }
5500     else if (anArg == "-insertafter"
5501           && anArgIter + 1 < theArgNb
5502           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5503     {
5504       ++anArgIter;
5505       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5506       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5507       {
5508         Message::SendFail ("Error: can not add a new z layer");
5509         return 0;
5510       }
5511
5512       theDI << aLayerId;
5513     }
5514     else if (anArg == "-del"
5515           || anArg == "-delete"
5516           || anArg == "del")
5517     {
5518       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5519       {
5520         if (++anArgIter >= theArgNb)
5521         {
5522           Message::SendFail ("Syntax error: id of z layer to remove is missing");
5523           return 1;
5524         }
5525
5526         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5527       }
5528
5529       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
5530        || aLayerId == Graphic3d_ZLayerId_Default
5531        || aLayerId == Graphic3d_ZLayerId_Top
5532        || aLayerId == Graphic3d_ZLayerId_Topmost
5533        || aLayerId == Graphic3d_ZLayerId_TopOSD
5534        || aLayerId == Graphic3d_ZLayerId_BotOSD)
5535       {
5536         Message::SendFail ("Syntax error: standard Z layer can not be removed");
5537         return 1;
5538       }
5539
5540       // move all object displayed in removing layer to default layer
5541       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
5542            anObjIter.More(); anObjIter.Next())
5543       {
5544         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
5545         if (aPrs.IsNull()
5546          || aPrs->ZLayer() != aLayerId)
5547         {
5548           continue;
5549         }
5550         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
5551       }
5552
5553       if (!aViewer->RemoveZLayer (aLayerId))
5554       {
5555         Message::SendFail ("Z layer can not be removed");
5556       }
5557       else
5558       {
5559         theDI << aLayerId << " ";
5560       }
5561     }
5562     else if (anArg == "-get"
5563           || anArg == "get")
5564     {
5565       TColStd_SequenceOfInteger aLayers;
5566       aViewer->GetAllZLayers (aLayers);
5567       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5568       {
5569         theDI << aLayeriter.Value() << " ";
5570       }
5571
5572       theDI << "\n";
5573     }
5574     else if (anArg == "-name")
5575     {
5576       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5577       {
5578         Message::SendFail ("Syntax error: id of Z layer is missing");
5579         return 1;
5580       }
5581
5582       if (++anArgIter >= theArgNb)
5583       {
5584         Message::SendFail ("Syntax error: name is missing");
5585         return 1;
5586       }
5587
5588       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5589       aSettings.SetName (theArgVec[anArgIter]);
5590       aViewer->SetZLayerSettings (aLayerId, aSettings);
5591     }
5592     else if (anArg == "-origin")
5593     {
5594       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5595       {
5596         Message::SendFail ("Syntax error: id of Z layer is missing");
5597         return 1;
5598       }
5599
5600       if (anArgIter + 2 >= theArgNb)
5601       {
5602         Message::SendFail ("Syntax error: origin coordinates are missing");
5603         return 1;
5604       }
5605
5606       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5607       gp_XYZ anOrigin;
5608       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
5609       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
5610       anOrigin.SetZ (0.0);
5611       if (anArgIter + 3 < theArgNb)
5612       {
5613         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
5614         anArgIter += 3;
5615       }
5616       else
5617       {
5618         anArgIter += 2;
5619       }
5620       aSettings.SetOrigin (anOrigin);
5621       aViewer->SetZLayerSettings (aLayerId, aSettings);
5622     }
5623     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5624           && anArgIter + 1 < theArgNb
5625           && (anArg == "-cullingdistance"
5626            || anArg == "-cullingdist"
5627            || anArg == "-culldistance"
5628            || anArg == "-culldist"
5629            || anArg == "-distcull"
5630            || anArg == "-distculling"
5631            || anArg == "-distanceculling"))
5632     {
5633       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5634       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
5635       aSettings.SetCullingDistance (aDist);
5636       aViewer->SetZLayerSettings (aLayerId, aSettings);
5637     }
5638     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5639           && anArgIter + 1 < theArgNb
5640           && (anArg == "-cullingsize"
5641            || anArg == "-cullsize"
5642            || anArg == "-sizecull"
5643            || anArg == "-sizeculling"))
5644     {
5645       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5646       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
5647       aSettings.SetCullingSize (aSize);
5648       aViewer->SetZLayerSettings (aLayerId, aSettings);
5649     }
5650     else if (anArg == "-settings"
5651           || anArg == "settings")
5652     {
5653       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5654       {
5655         if (++anArgIter >= theArgNb)
5656         {
5657           Message::SendFail ("Syntax error: id of Z layer is missing");
5658           return 1;
5659         }
5660
5661         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5662       }
5663
5664       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5665       printZLayerInfo (theDI, aSettings);
5666     }
5667     else if (anArg == "-enable"
5668           || anArg == "enable"
5669           || anArg == "-disable"
5670           || anArg == "disable")
5671     {
5672       const Standard_Boolean toEnable = anArg == "-enable"
5673                                      || anArg == "enable";
5674       if (++anArgIter >= theArgNb)
5675       {
5676         Message::SendFail ("Syntax error: option name is missing");
5677         return 1;
5678       }
5679
5680       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
5681       aSubOp.LowerCase();
5682       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5683       {
5684         if (++anArgIter >= theArgNb)
5685         {
5686           Message::SendFail ("Syntax error: id of Z layer is missing");
5687           return 1;
5688         }
5689
5690         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5691       }
5692
5693       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5694       if (aSubOp == "depthtest"
5695        || aSubOp == "test")
5696       {
5697         aSettings.SetEnableDepthTest (toEnable);
5698       }
5699       else if (aSubOp == "depthwrite"
5700             || aSubOp == "write")
5701       {
5702         aSettings.SetEnableDepthWrite (toEnable);
5703       }
5704       else if (aSubOp == "depthclear"
5705             || aSubOp == "clear")
5706       {
5707         aSettings.SetClearDepth (toEnable);
5708       }
5709       else if (aSubOp == "depthoffset"
5710             || aSubOp == "offset")
5711       {
5712         Graphic3d_PolygonOffset aParams;
5713         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
5714         if (toEnable)
5715         {
5716           if (anArgIter + 2 >= theArgNb)
5717           {
5718             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
5719             return 1;
5720           }
5721
5722           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5723           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5724         }
5725         aSettings.SetPolygonOffset (aParams);
5726       }
5727       else if (aSubOp == "positiveoffset"
5728             || aSubOp == "poffset")
5729       {
5730         if (toEnable)
5731         {
5732           aSettings.SetDepthOffsetPositive();
5733         }
5734         else
5735         {
5736           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
5737         }
5738       }
5739       else if (aSubOp == "negativeoffset"
5740             || aSubOp == "noffset")
5741       {
5742         if (toEnable)
5743         {
5744           aSettings.SetDepthOffsetNegative();
5745         }
5746         else
5747         {
5748           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
5749         }
5750       }
5751       else if (aSubOp == "textureenv")
5752       {
5753         aSettings.SetEnvironmentTexture (toEnable);
5754       }
5755       else if (aSubOp == "raytracing")
5756       {
5757         aSettings.SetRaytracable (toEnable);
5758       }
5759
5760       aViewer->SetZLayerSettings (aLayerId, aSettings);
5761     }
5762     else
5763     {
5764       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
5765       return 1;
5766     }
5767   }
5768
5769   return 0;
5770 }
5771
5772 // The interactive presentation of 2d layer item
5773 // for "vlayerline" command it provides a presentation of
5774 // line with user-defined linewidth, linetype and transparency.
5775 class V3d_LineItem : public AIS_InteractiveObject
5776 {
5777 public:
5778   // CASCADE RTTI
5779   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
5780
5781   // constructor
5782   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5783                                Standard_Real X2, Standard_Real Y2,
5784                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5785                                Standard_Real theWidth    = 0.5,
5786                                Standard_Real theTransp   = 1.0);
5787
5788 private:
5789
5790   virtual void Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
5791                         const Handle(Prs3d_Presentation)& thePrs,
5792                         const Standard_Integer theMode) Standard_OVERRIDE;
5793
5794   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& ,
5795                                  const Standard_Integer ) Standard_OVERRIDE
5796   {}
5797
5798 private:
5799
5800   Standard_Real       myX1, myY1, myX2, myY2;
5801   Aspect_TypeOfLine   myType;
5802   Standard_Real       myWidth;
5803 };
5804
5805 // default constructor for line item
5806 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5807                            Standard_Real X2, Standard_Real Y2,
5808                            Aspect_TypeOfLine theType,
5809                            Standard_Real theWidth,
5810                            Standard_Real theTransp) :
5811   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5812   myType(theType), myWidth(theWidth)
5813 {
5814   SetTransparency (1-theTransp);
5815 }
5816
5817 // render line
5818 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager)& ,
5819                             const Handle(Prs3d_Presentation)& thePresentation,
5820                             const Standard_Integer )
5821 {
5822   thePresentation->Clear();
5823   Quantity_Color aColor (Quantity_NOC_RED);
5824   Standard_Integer aWidth, aHeight;
5825   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5826   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
5827   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5828   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5829   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5830   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5831   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5832   aGroup->AddPrimitiveArray (aPrim);
5833 }
5834
5835 //=============================================================================
5836 //function : VLayerLine
5837 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5838 //         : linewidth, transparency coefficient
5839 //============================================================================
5840 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5841 {
5842   // get the active view
5843   Handle(V3d_View) aView = ViewerTest::CurrentView();
5844   if (aView.IsNull())
5845   {
5846     di << "Call vinit before!\n";
5847     return 1;
5848   }
5849   else if (argc < 5)
5850   {
5851     di << "Use: " << argv[0];
5852     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5853     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5854     di << "              0 - solid  \n";
5855     di << "              1 - dashed \n";
5856     di << "              2 - dot    \n";
5857     di << "              3 - dashdot\n";
5858     di << " transparency : { 0.0 - 1.0 } \n";
5859     di << "                  0.0 - transparent\n";
5860     di << "                  1.0 - visible    \n";
5861     return 1;
5862   }
5863
5864   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5865   // get the input params
5866   Standard_Real X1 = Draw::Atof(argv[1]);
5867   Standard_Real Y1 = Draw::Atof(argv[2]);
5868   Standard_Real X2 = Draw::Atof(argv[3]);
5869   Standard_Real Y2 = Draw::Atof(argv[4]);
5870
5871   Standard_Real aWidth = 0.5;
5872   Standard_Real aTransparency = 1.0;
5873
5874   // has width
5875   if (argc > 5)
5876     aWidth = Draw::Atof(argv[5]);
5877
5878   // select appropriate line type
5879   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5880   if (argc > 6
5881   && !ViewerTest::ParseLineType (argv[6], aLineType))
5882   {
5883     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5884     return 1;
5885   }
5886
5887   // has transparency
5888   if (argc > 7)
5889   {
5890     aTransparency = Draw::Atof(argv[7]);
5891     if (aTransparency < 0 || aTransparency > 1.0)
5892       aTransparency = 1.0;
5893   }
5894
5895   static Handle (V3d_LineItem) aLine;
5896   if (!aLine.IsNull())
5897   {
5898     aContext->Erase (aLine, Standard_False);
5899   }
5900   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5901                             aLineType, aWidth,
5902                             aTransparency);
5903
5904   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5905   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5906   aLine->SetToUpdate();
5907   aContext->Display (aLine, Standard_True);
5908
5909   return 0;
5910 }
5911
5912
5913 //==============================================================================
5914 //function : VGrid
5915 //purpose  :
5916 //==============================================================================
5917
5918 static int VGrid (Draw_Interpretor& /*theDI*/,
5919                   Standard_Integer  theArgNb,
5920                   const char**      theArgVec)
5921 {
5922   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5923   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5924   if (aView.IsNull() || aViewer.IsNull())
5925   {
5926     Message::SendFail ("Error: no active viewer");
5927     return 1;
5928   }
5929
5930   Aspect_GridType     aType = aViewer->GridType();
5931   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5932   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5933   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5934   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5935   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5936   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5937   {
5938     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5939     anArg.LowerCase();
5940     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5941     {
5942       continue;
5943     }
5944     else if (anArgIter + 1 < theArgNb
5945           && anArg == "-type")
5946     {
5947       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5948       anArgNext.LowerCase();
5949       if (anArgNext == "r"
5950        || anArgNext == "rect"
5951        || anArgNext == "rectangular")
5952       {
5953         aType = Aspect_GT_Rectangular;
5954       }
5955       else if (anArgNext == "c"
5956             || anArgNext == "circ"
5957             || anArgNext == "circular")
5958       {
5959         aType = Aspect_GT_Circular;
5960       }
5961       else
5962       {
5963         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5964         return 1;
5965       }
5966     }
5967     else if (anArgIter + 1 < theArgNb
5968           && anArg == "-mode")
5969     {
5970       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5971       anArgNext.LowerCase();
5972       if (anArgNext == "l"
5973        || anArgNext == "line"
5974        || anArgNext == "lines")
5975       {
5976         aMode = Aspect_GDM_Lines;
5977       }
5978       else if (anArgNext == "p"
5979             || anArgNext == "point"
5980             || anArgNext == "points")
5981       {
5982         aMode = Aspect_GDM_Points;
5983       }
5984       else
5985       {
5986         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5987         return 1;
5988       }
5989     }
5990     else if (anArgIter + 2 < theArgNb
5991           && (anArg == "-origin"
5992            || anArg == "-orig"))
5993     {
5994       hasOrigin = true;
5995       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5996                               Draw::Atof (theArgVec[anArgIter + 2]));
5997       anArgIter += 2;
5998     }
5999     else if (anArgIter + 2 < theArgNb
6000           && anArg == "-step")
6001     {
6002       hasStep = true;
6003       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
6004                             Draw::Atof (theArgVec[anArgIter + 2]));
6005       if (aNewStepXY.x() <= 0.0
6006        || aNewStepXY.y() <= 0.0)
6007       {
6008         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
6009         return 1;
6010       }
6011       anArgIter += 2;
6012     }
6013     else if (anArgIter + 1 < theArgNb
6014           && (anArg == "-angle"
6015            || anArg == "-rotangle"
6016            || anArg == "-rotationangle"))
6017     {
6018       hasRotAngle = true;
6019       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
6020     }
6021     else if (anArgIter + 1 < theArgNb
6022           && (anArg == "-zoffset"
6023            || anArg == "-dz"))
6024     {
6025       hasZOffset = true;
6026       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
6027     }
6028     else if (anArgIter + 1 < theArgNb
6029           && anArg == "-radius")
6030     {
6031       hasSize = true;
6032       ++anArgIter;
6033       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
6034       if (aNewStepXY.x() <= 0.0)
6035       {
6036         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
6037         return 1;
6038       }
6039     }
6040     else if (anArgIter + 2 < theArgNb
6041           && anArg == "-size")
6042     {
6043       hasSize = true;
6044       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
6045                             Draw::Atof (theArgVec[anArgIter + 2]));
6046       if (aNewStepXY.x() <= 0.0
6047        || aNewStepXY.y() <= 0.0)
6048       {
6049         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
6050         return 1;
6051       }
6052       anArgIter += 2;
6053     }
6054     else if (anArg == "r"
6055           || anArg == "rect"
6056           || anArg == "rectangular")
6057     {
6058       aType = Aspect_GT_Rectangular;
6059     }
6060     else if (anArg == "c"
6061           || anArg == "circ"
6062           || anArg == "circular")
6063     {
6064       aType = Aspect_GT_Circular;
6065     }
6066     else if (anArg == "l"
6067           || anArg == "line"
6068           || anArg == "lines")
6069     {
6070       aMode = Aspect_GDM_Lines;
6071     }
6072     else if (anArg == "p"
6073           || anArg == "point"
6074           || anArg == "points")
6075     {
6076       aMode = Aspect_GDM_Points;
6077     }
6078     else if (anArgIter + 1 >= theArgNb
6079           && anArg == "off")
6080     {
6081       aViewer->DeactivateGrid();
6082       return 0;
6083     }
6084     else
6085     {
6086       Message::SendFail() << "Syntax error at '" << anArg << "'";
6087       return 1;
6088     }
6089   }
6090
6091   if (aType == Aspect_GT_Rectangular)
6092   {
6093     Graphic3d_Vec2d anOrigXY, aStepXY;
6094     Standard_Real aRotAngle = 0.0;
6095     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6096     if (hasOrigin)
6097     {
6098       anOrigXY = aNewOriginXY;
6099     }
6100     if (hasStep)
6101     {
6102       aStepXY = aNewStepXY;
6103     }
6104     if (hasRotAngle)
6105     {
6106       aRotAngle = aNewRotAngle;
6107     }
6108     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6109     if (hasSize || hasZOffset)
6110     {
6111       Graphic3d_Vec3d aSize;
6112       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6113       if (hasSize)
6114       {
6115         aSize.x() = aNewSizeXY.x();
6116         aSize.y() = aNewSizeXY.y();
6117       }
6118       if (hasZOffset)
6119       {
6120         aSize.z() = aNewZOffset;
6121       }
6122       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6123     }
6124   }
6125   else if (aType == Aspect_GT_Circular)
6126   {
6127     Graphic3d_Vec2d anOrigXY;
6128     Standard_Real aRadiusStep;
6129     Standard_Integer aDivisionNumber;
6130     Standard_Real aRotAngle = 0.0;
6131     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6132     if (hasOrigin)
6133     {
6134       anOrigXY = aNewOriginXY;
6135     }
6136     if (hasStep)
6137     {
6138       aRadiusStep     = aNewStepXY[0];
6139       aDivisionNumber = (int )aNewStepXY[1];
6140       if (aDivisionNumber < 1)
6141       {
6142         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
6143         return 1;
6144       }
6145     }
6146     if (hasRotAngle)
6147     {
6148       aRotAngle = aNewRotAngle;
6149     }
6150
6151     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6152     if (hasSize || hasZOffset)
6153     {
6154       Standard_Real aRadius = 0.0, aZOffset = 0.0;
6155       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
6156       if (hasSize)
6157       {
6158         aRadius = aNewSizeXY.x();
6159         if (aNewSizeXY.y() != 0.0)
6160         {
6161           Message::SendFail ("Syntax error: circular size should be specified as radius");
6162           return 1;
6163         }
6164       }
6165       if (hasZOffset)
6166       {
6167         aZOffset = aNewZOffset;
6168       }
6169       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
6170     }
6171   }
6172   aViewer->ActivateGrid (aType, aMode);
6173   return 0;
6174 }
6175
6176 //==============================================================================
6177 //function : VPriviledgedPlane
6178 //purpose  :
6179 //==============================================================================
6180
6181 static int VPriviledgedPlane (Draw_Interpretor& theDI,
6182                               Standard_Integer  theArgNb,
6183                               const char**      theArgVec)
6184 {
6185   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
6186   {
6187     Message::SendFail ("Error: wrong number of arguments! See usage:");
6188     theDI.PrintHelp (theArgVec[0]);
6189     return 1;
6190   }
6191
6192   // get the active viewer
6193   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
6194   if (aViewer.IsNull())
6195   {
6196     Message::SendFail ("Error: no active viewer");
6197     return 1;
6198   }
6199
6200   if (theArgNb == 1)
6201   {
6202     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
6203     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
6204     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
6205     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
6206     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
6207           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
6208           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
6209     return 0;
6210   }
6211
6212   Standard_Integer anArgIdx = 1;
6213   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
6214   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
6215   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
6216   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
6217   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
6218   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
6219
6220   gp_Ax3 aPriviledgedPlane;
6221   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
6222   gp_Dir aNorm (aNormX, aNormY, aNormZ);
6223   if (theArgNb > 7)
6224   {
6225     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
6226     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
6227     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
6228     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
6229     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
6230   }
6231   else
6232   {
6233     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
6234   }
6235
6236   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
6237
6238   return 0;
6239 }
6240
6241 //==============================================================================
6242 //function : VConvert
6243 //purpose  :
6244 //==============================================================================
6245
6246 static int VConvert (Draw_Interpretor& theDI,
6247                      Standard_Integer  theArgNb,
6248                      const char**      theArgVec)
6249 {
6250   // get the active view
6251   Handle(V3d_View) aView = ViewerTest::CurrentView();
6252   if (aView.IsNull())
6253   {
6254     Message::SendFail ("Error: no active viewer");
6255     return 1;
6256   }
6257
6258   enum { Model, Ray, View, Window, Grid } aMode = Model;
6259
6260   // access coordinate arguments
6261   TColStd_SequenceOfReal aCoord;
6262   Standard_Integer anArgIdx = 1;
6263   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
6264   {
6265     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6266     if (!anArg.IsRealValue (Standard_True))
6267     {
6268       break;
6269     }
6270     aCoord.Append (anArg.RealValue());
6271   }
6272
6273   // non-numeric argument too early
6274   if (aCoord.IsEmpty())
6275   {
6276     Message::SendFail ("Error: wrong number of arguments! See usage:");
6277     theDI.PrintHelp (theArgVec[0]);
6278     return 1;
6279   }
6280
6281   // collect all other arguments and options
6282   for (; anArgIdx < theArgNb; ++anArgIdx)
6283   {
6284     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6285     anArg.LowerCase();
6286     if      (anArg == "window") aMode = Window;
6287     else if (anArg == "view")   aMode = View;
6288     else if (anArg == "grid")   aMode = Grid;
6289     else if (anArg == "ray")    aMode = Ray;
6290     else
6291     {
6292       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
6293       theDI.PrintHelp (theArgVec[0]);
6294       return 1;
6295     }
6296   }
6297
6298   // complete input checks
6299   if ((aCoord.Length() == 1 && theArgNb > 3) ||
6300       (aCoord.Length() == 2 && theArgNb > 4) ||
6301       (aCoord.Length() == 3 && theArgNb > 5))
6302   {
6303     Message::SendFail ("Error: wrong number of arguments! See usage:");
6304     theDI.PrintHelp (theArgVec[0]);
6305     return 1;
6306   }
6307
6308   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
6309   Standard_Integer aXYp[2] = {0, 0};
6310
6311   // convert one-dimensional coordinate
6312   if (aCoord.Length() == 1)
6313   {
6314     switch (aMode)
6315     {
6316       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
6317       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
6318       default:
6319         Message::SendFail ("Error: wrong arguments! See usage:");
6320         theDI.PrintHelp (theArgVec[0]);
6321         return 1;
6322     }
6323   }
6324
6325   // convert 2D coordinates from projection or view reference space
6326   if (aCoord.Length() == 2)
6327   {
6328     switch (aMode)
6329     {
6330       case Model :
6331         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6332         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6333         return 0;
6334
6335       case View :
6336         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
6337         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
6338         return 0;
6339
6340       case Window :
6341         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
6342         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6343         return 0;
6344
6345       case Grid :
6346         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6347         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
6348         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6349         return 0;
6350
6351       case Ray :
6352         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
6353                                 (Standard_Integer) aCoord (2),
6354                                 aXYZ[0], aXYZ[1], aXYZ[2],
6355                                 aXYZ[3], aXYZ[4], aXYZ[5]);
6356         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6357         return 0;
6358
6359       default:
6360         Message::SendFail ("Error: wrong arguments! See usage:");
6361         theDI.PrintHelp (theArgVec[0]);
6362         return 1;
6363     }
6364   }
6365
6366   // convert 3D coordinates from view reference space
6367   else if (aCoord.Length() == 3)
6368   {
6369     switch (aMode)
6370     {
6371       case Window :
6372         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
6373         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6374         return 0;
6375
6376       case Grid :
6377         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
6378         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6379         return 0;
6380
6381       default:
6382         Message::SendFail ("Error: wrong arguments! See usage:");
6383         theDI.PrintHelp (theArgVec[0]);
6384         return 1;
6385     }
6386   }
6387
6388   return 0;
6389 }
6390
6391 //==============================================================================
6392 //function : VFps
6393 //purpose  :
6394 //==============================================================================
6395
6396 static int VFps (Draw_Interpretor& theDI,
6397                  Standard_Integer  theArgNb,
6398                  const char**      theArgVec)
6399 {
6400   // get the active view
6401   Handle(V3d_View) aView = ViewerTest::CurrentView();
6402   if (aView.IsNull())
6403   {
6404     Message::SendFail ("Error: no active viewer");
6405     return 1;
6406   }
6407
6408   Standard_Integer aFramesNb = -1;
6409   Standard_Real aDuration = -1.0;
6410   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6411   {
6412     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6413     anArg.LowerCase();
6414     if (aDuration < 0.0
6415      && anArgIter + 1 < theArgNb
6416      && (anArg == "-duration"
6417       || anArg == "-dur"
6418       || anArg == "-time"))
6419     {
6420       aDuration = Draw::Atof (theArgVec[++anArgIter]);
6421     }
6422     else if (aFramesNb < 0
6423           && anArg.IsIntegerValue())
6424     {
6425       aFramesNb = anArg.IntegerValue();
6426       if (aFramesNb <= 0)
6427       {
6428         Message::SendFail() << "Syntax error at '" << anArg << "'";
6429         return 1;
6430       }
6431     }
6432     else
6433     {
6434       Message::SendFail() << "Syntax error at '" << anArg << "'";
6435       return 1;
6436     }
6437   }
6438   if (aFramesNb < 0 && aDuration < 0.0)
6439   {
6440     aFramesNb = 100;
6441   }
6442
6443   // the time is meaningless for first call
6444   // due to async OpenGl rendering
6445   aView->Redraw();
6446
6447   // redraw view in loop to estimate average values
6448   OSD_Timer aTimer;
6449   aTimer.Start();
6450   Standard_Integer aFrameIter = 1;
6451   for (;; ++aFrameIter)
6452   {
6453     aView->Redraw();
6454     if ((aFramesNb > 0
6455       && aFrameIter >= aFramesNb)
6456      || (aDuration > 0.0
6457       && aTimer.ElapsedTime() >= aDuration))
6458     {
6459       break;
6460     }
6461   }
6462   aTimer.Stop();
6463   Standard_Real aCpu;
6464   const Standard_Real aTime = aTimer.ElapsedTime();
6465   aTimer.OSD_Chronometer::Show (aCpu);
6466
6467   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
6468   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
6469
6470   // return statistics
6471   theDI << "FPS: " << aFpsAver << "\n"
6472         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
6473
6474   // compute additional statistics in ray-tracing mode
6475   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
6476   if (aParams.Method == Graphic3d_RM_RAYTRACING)
6477   {
6478     Graphic3d_Vec2i aWinSize (0, 0);
6479     aView->Window()->Size (aWinSize.x(), aWinSize.y());
6480
6481     // 1 shadow ray and 1 secondary ray pew each bounce
6482     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
6483     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
6484   }
6485
6486   return 0;
6487 }
6488
6489 //! Auxiliary function for parsing glsl dump level argument.
6490 static Standard_Boolean parseGlslSourceFlag (Standard_CString               theArg,
6491                                              OpenGl_ShaderProgramDumpLevel& theGlslDumpLevel)
6492 {
6493   TCollection_AsciiString aTypeStr (theArg);
6494   aTypeStr.LowerCase();
6495   if (aTypeStr == "off"
6496    || aTypeStr == "0")
6497   {
6498     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6499   }
6500   else if (aTypeStr == "short")
6501   {
6502     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Short;
6503   }
6504   else if (aTypeStr == "full"
6505         || aTypeStr == "1")
6506   {
6507     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6508   }
6509   else
6510   {
6511     return Standard_False;
6512   }
6513   return Standard_True;
6514 }
6515
6516 //==============================================================================
6517 //function : VGlDebug
6518 //purpose  :
6519 //==============================================================================
6520
6521 static int VGlDebug (Draw_Interpretor& theDI,
6522                      Standard_Integer  theArgNb,
6523                      const char**      theArgVec)
6524 {
6525   Handle(OpenGl_GraphicDriver) aDriver;
6526   Handle(V3d_View) aView = ViewerTest::CurrentView();
6527   if (!aView.IsNull())
6528   {
6529     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aView->Viewer()->Driver());
6530   }
6531   OpenGl_Caps* aDefCaps = &ViewerTest_myDefaultCaps;
6532   OpenGl_Caps* aCaps    = !aDriver.IsNull() ? &aDriver->ChangeOptions() : NULL;
6533
6534   if (theArgNb < 2)
6535   {
6536     TCollection_AsciiString aDebActive, aSyncActive;
6537     if (aCaps == NULL)
6538     {
6539       aCaps = aDefCaps;
6540     }
6541     else
6542     {
6543       Standard_Boolean isActive = OpenGl_Context::CheckExtension ((const char* )::glGetString (GL_EXTENSIONS),
6544                                                                   "GL_ARB_debug_output");
6545       aDebActive = isActive ? " (active)" : " (inactive)";
6546       if (isActive)
6547       {
6548         // GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
6549         aSyncActive = ::glIsEnabled (0x8242) == GL_TRUE ? " (active)" : " (inactive)";
6550       }
6551     }
6552
6553     TCollection_AsciiString aGlslCodeDebugStatus = TCollection_AsciiString()
6554       + "glslSourceCode: "
6555       + (aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Off
6556          ? "Off"
6557          : aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short
6558           ? "Short"
6559           : "Full")
6560       + "\n";
6561     theDI << "debug:          " << (aCaps->contextDebug      ? "1" : "0") << aDebActive  << "\n"
6562           << "sync:           " << (aCaps->contextSyncDebug  ? "1" : "0") << aSyncActive << "\n"
6563           << "glslWarn:       " << (aCaps->glslWarnings      ? "1" : "0") << "\n"
6564           << aGlslCodeDebugStatus
6565           << "extraMsg:       " << (aCaps->suppressExtraMsg  ? "0" : "1") << "\n";
6566     return 0;
6567   }
6568
6569   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6570   {
6571     Standard_CString        anArg     = theArgVec[anArgIter];
6572     TCollection_AsciiString anArgCase (anArg);
6573     anArgCase.LowerCase();
6574     Standard_Boolean toEnableDebug = Standard_True;
6575     if (anArgCase == "-glsl"
6576      || anArgCase == "-glslwarn"
6577      || anArgCase == "-glslwarns"
6578      || anArgCase == "-glslwarnings")
6579     {
6580       Standard_Boolean toShowWarns = Standard_True;
6581       if (++anArgIter < theArgNb
6582       && !Draw::ParseOnOff (theArgVec[anArgIter], toShowWarns))
6583       {
6584         --anArgIter;
6585       }
6586       aDefCaps->glslWarnings = toShowWarns;
6587       if (aCaps != NULL)
6588       {
6589         aCaps->glslWarnings = toShowWarns;
6590       }
6591     }
6592     else if (anArgCase == "-extra"
6593           || anArgCase == "-extramsg"
6594           || anArgCase == "-extramessages")
6595     {
6596       Standard_Boolean toShow = Standard_True;
6597       if (++anArgIter < theArgNb
6598       && !Draw::ParseOnOff (theArgVec[anArgIter], toShow))
6599       {
6600         --anArgIter;
6601       }
6602       aDefCaps->suppressExtraMsg = !toShow;
6603       if (aCaps != NULL)
6604       {
6605         aCaps->suppressExtraMsg = !toShow;
6606       }
6607     }
6608     else if (anArgCase == "-noextra"
6609           || anArgCase == "-noextramsg"
6610           || anArgCase == "-noextramessages")
6611     {
6612       Standard_Boolean toSuppress = Standard_True;
6613       if (++anArgIter < theArgNb
6614       && !Draw::ParseOnOff (theArgVec[anArgIter], toSuppress))
6615       {
6616         --anArgIter;
6617       }
6618       aDefCaps->suppressExtraMsg = toSuppress;
6619       if (aCaps != NULL)
6620       {
6621         aCaps->suppressExtraMsg = toSuppress;
6622       }
6623     }
6624     else if (anArgCase == "-sync")
6625     {
6626       Standard_Boolean toSync = Standard_True;
6627       if (++anArgIter < theArgNb
6628       && !Draw::ParseOnOff (theArgVec[anArgIter], toSync))
6629       {
6630         --anArgIter;
6631       }
6632       aDefCaps->contextSyncDebug = toSync;
6633       if (toSync)
6634       {
6635         aDefCaps->contextDebug = Standard_True;
6636       }
6637     }
6638     else if (anArgCase == "-glslsourcecode"
6639           || anArgCase == "-glslcode")
6640     {
6641       OpenGl_ShaderProgramDumpLevel aGslsDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6642       if (++anArgIter < theArgNb
6643       && !parseGlslSourceFlag (theArgVec[anArgIter], aGslsDumpLevel))
6644       {
6645         --anArgIter;
6646       }
6647       aDefCaps->glslDumpLevel = aGslsDumpLevel;
6648       if (aCaps != NULL)
6649       {
6650         aCaps->glslDumpLevel = aGslsDumpLevel;
6651       }
6652     }
6653     else if (anArgCase == "-debug")
6654     {
6655       if (++anArgIter < theArgNb
6656       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnableDebug))
6657       {
6658         --anArgIter;
6659       }
6660       aDefCaps->contextDebug = toEnableDebug;
6661     }
6662     else if (Draw::ParseOnOff (anArg, toEnableDebug)
6663           && (anArgIter + 1 == theArgNb))
6664     {
6665       // simple alias to turn on almost everything
6666       aDefCaps->contextDebug     = toEnableDebug;
6667       aDefCaps->contextSyncDebug = toEnableDebug;
6668       aDefCaps->glslWarnings     = toEnableDebug;
6669       if (!toEnableDebug)
6670       {
6671         aDefCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6672       }
6673       aDefCaps->suppressExtraMsg = !toEnableDebug;
6674       if (aCaps != NULL)
6675       {
6676         aCaps->contextDebug     = toEnableDebug;
6677         aCaps->contextSyncDebug = toEnableDebug;
6678         aCaps->glslWarnings     = toEnableDebug;
6679         if (!toEnableDebug)
6680         {
6681           aCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6682         }
6683         aCaps->suppressExtraMsg = !toEnableDebug;
6684       }
6685     }
6686     else
6687     {
6688       Message::SendFail() << "Syntax error at '" << anArg << "'";
6689       return 1;
6690     }
6691   }
6692
6693   return 0;
6694 }
6695
6696 //==============================================================================
6697 //function : VVbo
6698 //purpose  :
6699 //==============================================================================
6700
6701 static int VVbo (Draw_Interpretor& theDI,
6702                  Standard_Integer  theArgNb,
6703                  const char**      theArgVec)
6704 {
6705   const Standard_Boolean toSet    = (theArgNb > 1);
6706   const Standard_Boolean toUseVbo = toSet ? (Draw::Atoi (theArgVec[1]) == 0) : 1;
6707   if (toSet)
6708   {
6709     ViewerTest_myDefaultCaps.vboDisable = toUseVbo;
6710   }
6711
6712   // get the context
6713   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6714   if (aContextAIS.IsNull())
6715   {
6716     if (!toSet)
6717     {
6718       Message::SendFail ("Error: no active viewer");
6719     }
6720     return 1;
6721   }
6722   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContextAIS->CurrentViewer()->Driver());
6723   if (!aDriver.IsNull())
6724   {
6725     if (!toSet)
6726     {
6727       theDI << (aDriver->Options().vboDisable ? "0" : "1") << "\n";
6728     }
6729     else
6730     {
6731       aDriver->ChangeOptions().vboDisable = toUseVbo;
6732     }
6733   }
6734
6735   return 0;
6736 }
6737
6738 //==============================================================================
6739 //function : VCaps
6740 //purpose  :
6741 //==============================================================================
6742
6743 static int VCaps (Draw_Interpretor& theDI,
6744                   Standard_Integer  theArgNb,
6745                   const char**      theArgVec)
6746 {
6747   OpenGl_Caps* aCaps = &ViewerTest_myDefaultCaps;
6748   Handle(OpenGl_GraphicDriver)   aDriver;
6749   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
6750   if (!aContext.IsNull())
6751   {
6752     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
6753     aCaps   = &aDriver->ChangeOptions();
6754   }
6755
6756   if (theArgNb < 2)
6757   {
6758     theDI << "sRGB:    " << (aCaps->sRGBDisable       ? "0" : "1") << "\n";
6759     theDI << "VBO:     " << (aCaps->vboDisable        ? "0" : "1") << "\n";
6760     theDI << "Sprites: " << (aCaps->pntSpritesDisable ? "0" : "1") << "\n";
6761     theDI << "SoftMode:" << (aCaps->contextNoAccel    ? "1" : "0") << "\n";
6762     theDI << "FFP:     " << (aCaps->ffpEnable         ? "1" : "0") << "\n";
6763     theDI << "PolygonMode: " << (aCaps->usePolygonMode ? "1" : "0") << "\n";
6764     theDI << "VSync:   " <<  aCaps->swapInterval                   << "\n";
6765     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
6766     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
6767     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
6768     theDI << "OpaqueAlpha: " << (aCaps->buffersOpaqueAlpha ? "1" : "0") << "\n";
6769     theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
6770     theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
6771     theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n";
6772     return 0;
6773   }
6774
6775   ViewerTest_AutoUpdater anUpdateTool (aContext, ViewerTest::CurrentView());
6776   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6777   {
6778     Standard_CString        anArg     = theArgVec[anArgIter];
6779     TCollection_AsciiString anArgCase (anArg);
6780     anArgCase.LowerCase();
6781     if (anUpdateTool.parseRedrawMode (anArg))
6782     {
6783       continue;
6784     }
6785     else if (anArgCase == "-vsync"
6786           || anArgCase == "-swapinterval")
6787     {
6788       Standard_Boolean toEnable = Standard_True;
6789       if (++anArgIter < theArgNb
6790       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6791       {
6792         --anArgIter;
6793       }
6794       aCaps->swapInterval = toEnable;
6795     }
6796     else if (anArgCase == "-ffp")
6797     {
6798       Standard_Boolean toEnable = Standard_True;
6799       if (++anArgIter < theArgNb
6800       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6801       {
6802         --anArgIter;
6803       }
6804       aCaps->ffpEnable = toEnable;
6805     }
6806     else if (anArgCase == "-polygonmode")
6807     {
6808       Standard_Boolean toEnable = Standard_True;
6809       if (++anArgIter < theArgNb
6810       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6811       {
6812         --anArgIter;
6813       }
6814       aCaps->usePolygonMode = toEnable;
6815     }
6816     else if (anArgCase == "-srgb")
6817     {
6818       Standard_Boolean toEnable = Standard_True;
6819       if (++anArgIter < theArgNb
6820       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6821       {
6822         --anArgIter;
6823       }
6824       aCaps->sRGBDisable = !toEnable;
6825     }
6826     else if (anArgCase == "-compressedtextures")
6827     {
6828       Standard_Boolean toEnable = Standard_True;
6829       if (++anArgIter < theArgNb
6830       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6831       {
6832         --anArgIter;
6833       }
6834       aCaps->compressedTexturesDisable = !toEnable;
6835     }
6836     else if (anArgCase == "-vbo")
6837     {
6838       Standard_Boolean toEnable = Standard_True;
6839       if (++anArgIter < theArgNb
6840       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6841       {
6842         --anArgIter;
6843       }
6844       aCaps->vboDisable = !toEnable;
6845     }
6846     else if (anArgCase == "-sprite"
6847           || anArgCase == "-sprites")
6848     {
6849       Standard_Boolean toEnable = Standard_True;
6850       if (++anArgIter < theArgNb
6851       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6852       {
6853         --anArgIter;
6854       }
6855       aCaps->pntSpritesDisable = !toEnable;
6856     }
6857     else if (anArgCase == "-softmode")
6858     {
6859       Standard_Boolean toEnable = Standard_True;
6860       if (++anArgIter < theArgNb
6861       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6862       {
6863         --anArgIter;
6864       }
6865       aCaps->contextNoAccel = toEnable;
6866     }
6867     else if (anArgCase == "-opaquealpha"
6868           || anArgCase == "-buffersOpaqueAlpha")
6869     {
6870       Standard_Boolean toEnable = Standard_True;
6871       if (++anArgIter < theArgNb
6872       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6873       {
6874         --anArgIter;
6875       }
6876       aCaps->buffersOpaqueAlpha = toEnable;
6877     }
6878     else if (anArgCase == "-winbuffer"
6879           || anArgCase == "-windowbuffer"
6880           || anArgCase == "-usewinbuffer"
6881           || anArgCase == "-usewindowbuffer"
6882           || anArgCase == "-usesystembuffer")
6883     {
6884       Standard_Boolean toEnable = Standard_True;
6885       if (++anArgIter < theArgNb
6886       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6887       {
6888         --anArgIter;
6889       }
6890       aCaps->useSystemBuffer = toEnable;
6891     }
6892     else if (anArgCase == "-accel"
6893           || anArgCase == "-acceleration")
6894     {
6895       Standard_Boolean toEnable = Standard_True;
6896       if (++anArgIter < theArgNb
6897       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6898       {
6899         --anArgIter;
6900       }
6901       aCaps->contextNoAccel = !toEnable;
6902     }
6903     else if (anArgCase == "-compat"
6904           || anArgCase == "-compatprofile"
6905           || anArgCase == "-compatible"
6906           || anArgCase == "-compatibleprofile")
6907     {
6908       Standard_Boolean toEnable = Standard_True;
6909       if (++anArgIter < theArgNb
6910       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6911       {
6912         --anArgIter;
6913       }
6914       aCaps->contextCompatible = toEnable;
6915       if (!aCaps->contextCompatible)
6916       {
6917         aCaps->ffpEnable = Standard_False;
6918       }
6919     }
6920     else if (anArgCase == "-core"
6921           || anArgCase == "-coreprofile")
6922     {
6923       Standard_Boolean toEnable = Standard_True;
6924       if (++anArgIter < theArgNb
6925       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6926       {
6927         --anArgIter;
6928       }
6929       aCaps->contextCompatible = !toEnable;
6930       if (!aCaps->contextCompatible)
6931       {
6932         aCaps->ffpEnable = Standard_False;
6933       }
6934     }
6935     else if (anArgCase == "-stereo"
6936           || anArgCase == "-quadbuffer")
6937     {
6938       Standard_Boolean toEnable = Standard_True;
6939       if (++anArgIter < theArgNb
6940       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6941       {
6942         --anArgIter;
6943       }
6944       aCaps->contextStereo = toEnable;
6945     }
6946     else if (anArgCase == "-noext"
6947           || anArgCase == "-noextensions"
6948           || anArgCase == "-noextension")
6949     {
6950       Standard_Boolean toDisable = Standard_True;
6951       if (++anArgIter < theArgNb
6952       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
6953       {
6954         --anArgIter;
6955       }
6956       aCaps->contextNoExtensions = toDisable;
6957     }
6958     else if (anArgCase == "-maxversion"
6959           || anArgCase == "-upperversion"
6960           || anArgCase == "-limitversion")
6961     {
6962       Standard_Integer aVer[2] = { -2, -1 };
6963       for (Standard_Integer aValIter = 0; aValIter < 2; ++aValIter)
6964       {
6965         if (anArgIter + 1 < theArgNb)
6966         {
6967           const TCollection_AsciiString aStr (theArgVec[anArgIter + 1]);
6968           if (aStr.IsIntegerValue())
6969           {
6970             aVer[aValIter] = aStr.IntegerValue();
6971             ++anArgIter;
6972           }
6973         }
6974       }
6975       if (aVer[0] < -1
6976        || aVer[1] < -1)
6977       {
6978         Message::SendFail() << "Syntax error at '" << anArgCase << "'";
6979         return 1;
6980       }
6981       aCaps->contextMajorVersionUpper = aVer[0];
6982       aCaps->contextMinorVersionUpper = aVer[1];
6983     }
6984     else
6985     {
6986       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
6987       return 1;
6988     }
6989   }
6990   if (aCaps != &ViewerTest_myDefaultCaps)
6991   {
6992     ViewerTest_myDefaultCaps = *aCaps;
6993   }
6994   return 0;
6995 }
6996
6997 //==============================================================================
6998 //function : VMemGpu
6999 //purpose  :
7000 //==============================================================================
7001
7002 static int VMemGpu (Draw_Interpretor& theDI,
7003                     Standard_Integer  theArgNb,
7004                     const char**      theArgVec)
7005 {
7006   // get the context
7007   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
7008   if (aContextAIS.IsNull())
7009   {
7010     Message::SendFail ("Error: no active viewer");
7011     return 1;
7012   }
7013
7014   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
7015   if (aDriver.IsNull())
7016   {
7017     Message::SendFail ("Error: graphic driver not available");
7018     return 1;
7019   }
7020
7021   Standard_Size aFreeBytes = 0;
7022   TCollection_AsciiString anInfo;
7023   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
7024   {
7025     Message::SendFail ("Error: information not available");
7026     return 1;
7027   }
7028
7029   if (theArgNb > 1 && *theArgVec[1] == 'f')
7030   {
7031     theDI << Standard_Real (aFreeBytes);
7032   }
7033   else
7034   {
7035     theDI << anInfo;
7036   }
7037
7038   return 0;
7039 }
7040
7041 // ==============================================================================
7042 // function : VReadPixel
7043 // purpose  :
7044 // ==============================================================================
7045 static int VReadPixel (Draw_Interpretor& theDI,
7046                        Standard_Integer  theArgNb,
7047                        const char**      theArgVec)
7048 {
7049   // get the active view
7050   Handle(V3d_View) aView = ViewerTest::CurrentView();
7051   if (aView.IsNull())
7052   {
7053     Message::SendFail ("Error: no active viewer");
7054     return 1;
7055   }
7056   else if (theArgNb < 3)
7057   {
7058     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
7059                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
7060     return 1;
7061   }
7062
7063   Image_Format         aFormat     = Image_Format_RGBA;
7064   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
7065
7066   Standard_Integer aWidth, aHeight;
7067   aView->Window()->Size (aWidth, aHeight);
7068   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
7069   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
7070   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
7071   {
7072     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
7073     return 1;
7074   }
7075
7076   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
7077   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
7078   {
7079     TCollection_AsciiString aParam (theArgVec[anIter]);
7080     aParam.LowerCase();
7081     if (aParam == "-rgb"
7082      || aParam == "rgb"
7083      || aParam == "-srgb"
7084      || aParam == "srgb")
7085     {
7086       aFormat     = Image_Format_RGB;
7087       aBufferType = Graphic3d_BT_RGB;
7088       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
7089     }
7090     else if (aParam == "-hls"
7091           || aParam == "hls")
7092     {
7093       aFormat     = Image_Format_RGB;
7094       aBufferType = Graphic3d_BT_RGB;
7095       toShowHls   = Standard_True;
7096     }
7097     else if (aParam == "-rgbf"
7098           || aParam == "rgbf")
7099     {
7100       aFormat     = Image_Format_RGBF;
7101       aBufferType = Graphic3d_BT_RGB;
7102     }
7103     else if (aParam == "-rgba"
7104           || aParam == "rgba"
7105           || aParam == "-srgba"
7106           || aParam == "srgba")
7107     {
7108       aFormat     = Image_Format_RGBA;
7109       aBufferType = Graphic3d_BT_RGBA;
7110       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
7111     }
7112     else if (aParam == "-rgbaf"
7113           || aParam == "rgbaf")
7114     {
7115       aFormat     = Image_Format_RGBAF;
7116       aBufferType = Graphic3d_BT_RGBA;
7117     }
7118     else if (aParam == "-depth"
7119           || aParam == "depth")
7120     {
7121       aFormat     = Image_Format_GrayF;
7122       aBufferType = Graphic3d_BT_Depth;
7123     }
7124     else if (aParam == "-name"
7125           || aParam == "name")
7126     {
7127       toShowName = Standard_True;
7128     }
7129     else if (aParam == "-hex"
7130           || aParam == "hex")
7131     {
7132       toShowHex = Standard_True;
7133     }
7134     else
7135     {
7136       Message::SendFail() << "Syntax error at '" << aParam << "'";
7137       return 1;
7138     }
7139   }
7140
7141   Image_PixMap anImage;
7142   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
7143   {
7144     Message::SendFail ("Error: image allocation failed");
7145     return 1;
7146   }
7147   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
7148   {
7149     Message::SendFail ("Error: image dump failed");
7150     return 1;
7151   }
7152
7153   // redirect possible warning messages that could have been added by ToPixMap
7154   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
7155   // contaminate result of the command
7156   Standard_CString aWarnLog = theDI.Result();
7157   if (aWarnLog != NULL && aWarnLog[0] != '\0')
7158   {
7159     std::cout << aWarnLog << std::endl;
7160   }
7161   theDI.Reset();
7162
7163   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
7164   if (toShowName)
7165   {
7166     if (aBufferType == Graphic3d_BT_RGBA)
7167     {
7168       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
7169     }
7170     else
7171     {
7172       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
7173     }
7174   }
7175   else if (toShowHex)
7176   {
7177     if (aBufferType == Graphic3d_BT_RGBA)
7178     {
7179       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
7180     }
7181     else
7182     {
7183       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
7184     }
7185   }
7186   else
7187   {
7188     switch (aBufferType)
7189     {
7190       default:
7191       case Graphic3d_BT_RGB:
7192       {
7193         if (toShowHls)
7194         {
7195           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
7196         }
7197         else if (toShow_sRGB)
7198         {
7199           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
7200           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
7201         }
7202         else
7203         {
7204           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
7205         }
7206         break;
7207       }
7208       case Graphic3d_BT_RGBA:
7209       {
7210         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
7211         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
7212         break;
7213       }
7214       case Graphic3d_BT_Depth:
7215       {
7216         theDI << aColor.GetRGB().Red();
7217         break;
7218       }
7219     }
7220   }
7221
7222   return 0;
7223 }
7224
7225 //! Auxiliary presentation for an image plane.
7226 class ViewerTest_ImagePrs : public AIS_InteractiveObject
7227 {
7228 public:
7229   //! Main constructor.
7230   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
7231                        const Standard_Real theWidth,
7232                        const Standard_Real theHeight,
7233                        const TCollection_AsciiString& theLabel)
7234   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
7235   {
7236     SetDisplayMode (0);
7237     SetHilightMode (1);
7238     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
7239     {
7240       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
7241       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
7242       Graphic3d_MaterialAspect aMat;
7243       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
7244       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
7245       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
7246       aMat.SetSpecularColor (Quantity_NOC_BLACK);
7247       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
7248       aFillAspect->SetFrontMaterial (aMat);
7249       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
7250       aFillAspect->SetTextureMapOn();
7251     }
7252     {
7253       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
7254       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
7255       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
7256       myDrawer->SetTextAspect (aTextAspect);
7257     }
7258     {
7259       const gp_Dir aNorm (0.0, 0.0, 1.0);
7260       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
7261       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
7262       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
7263       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
7264       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
7265       myTris->AddEdge (1);
7266       myTris->AddEdge (2);
7267       myTris->AddEdge (3);
7268       myTris->AddEdge (3);
7269       myTris->AddEdge (2);
7270       myTris->AddEdge (4);
7271
7272       myRect = new Graphic3d_ArrayOfPolylines (4);
7273       myRect->AddVertex (myTris->Vertice (1));
7274       myRect->AddVertex (myTris->Vertice (3));
7275       myRect->AddVertex (myTris->Vertice (4));
7276       myRect->AddVertex (myTris->Vertice (2));
7277     }
7278   }
7279
7280   //! Returns TRUE for accepted display modes.
7281   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
7282
7283   //! Compute presentation.
7284   virtual void Compute (const Handle(PrsMgr_PresentationManager)& ,
7285                         const Handle(Prs3d_Presentation)& thePrs,
7286                         const Standard_Integer theMode) Standard_OVERRIDE
7287   {
7288     switch (theMode)
7289     {
7290       case 0:
7291       {
7292         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7293         aGroup->AddPrimitiveArray (myTris);
7294         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
7295         aGroup->AddPrimitiveArray (myRect);
7296         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7297         return;
7298       }
7299       case 1:
7300       {
7301         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
7302         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7303         aGroup->AddPrimitiveArray (myRect);
7304         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7305         return;
7306       }
7307     }
7308   }
7309
7310   //! Compute selection.
7311   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
7312   {
7313     if (theMode == 0)
7314     {
7315       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
7316       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
7317       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
7318       theSel->Add (aSensitive);
7319     }
7320   }
7321
7322 private:
7323   Handle(Graphic3d_ArrayOfTriangles) myTris;
7324   Handle(Graphic3d_ArrayOfPolylines) myRect;
7325   TCollection_AsciiString myLabel;
7326   Standard_Real myWidth;
7327   Standard_Real myHeight;
7328 };
7329
7330 //==============================================================================
7331 //function : VDiffImage
7332 //purpose  : The draw-command compares two images.
7333 //==============================================================================
7334
7335 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
7336 {
7337   if (theArgNb < 3)
7338   {
7339     Message::SendFail ("Syntax error: not enough arguments");
7340     return 1;
7341   }
7342
7343   Standard_Integer anArgIter = 1;
7344   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
7345   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
7346   TCollection_AsciiString aDiffImagePath;
7347   Standard_Real    aTolColor        = -1.0;
7348   Standard_Integer toBlackWhite     = -1;
7349   Standard_Integer isBorderFilterOn = -1;
7350   Standard_Boolean isOldSyntax = Standard_False;
7351   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
7352   for (; anArgIter < theArgNb; ++anArgIter)
7353   {
7354     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7355     anArg.LowerCase();
7356     if (anArgIter + 1 < theArgNb
7357      && (anArg == "-toleranceofcolor"
7358       || anArg == "-tolerancecolor"
7359       || anArg == "-tolerance"
7360       || anArg == "-toler"))
7361     {
7362       aTolColor = Atof (theArgVec[++anArgIter]);
7363       if (aTolColor < 0.0 || aTolColor > 1.0)
7364       {
7365         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7366         return 1;
7367       }
7368     }
7369     else if (anArg == "-blackwhite")
7370     {
7371       Standard_Boolean toEnable = Standard_True;
7372       if (anArgIter + 1 < theArgNb
7373        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7374       {
7375         ++anArgIter;
7376       }
7377       toBlackWhite = toEnable ? 1 : 0;
7378     }
7379     else if (anArg == "-borderfilter")
7380     {
7381       Standard_Boolean toEnable = Standard_True;
7382       if (anArgIter + 1 < theArgNb
7383        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7384       {
7385         ++anArgIter;
7386       }
7387       isBorderFilterOn = toEnable ? 1 : 0;
7388     }
7389     else if (anArg == "-exitonclose")
7390     {
7391       ViewerTest_EventManager::ToExitOnCloseView() = true;
7392       if (anArgIter + 1 < theArgNb
7393        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
7394       {
7395         ++anArgIter;
7396       }
7397     }
7398     else if (anArg == "-closeonescape"
7399           || anArg == "-closeonesc")
7400     {
7401       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
7402       if (anArgIter + 1 < theArgNb
7403        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
7404       {
7405         ++anArgIter;
7406       }
7407     }
7408     else if (anArgIter + 3 < theArgNb
7409           && anArg == "-display")
7410     {
7411       aViewName   = theArgVec[++anArgIter];
7412       aPrsNameRef = theArgVec[++anArgIter];
7413       aPrsNameNew = theArgVec[++anArgIter];
7414       if (anArgIter + 1 < theArgNb
7415       && *theArgVec[anArgIter + 1] != '-')
7416       {
7417         aPrsNameDiff = theArgVec[++anArgIter];
7418       }
7419     }
7420     else if (aTolColor < 0.0
7421           && anArg.IsRealValue (Standard_True))
7422     {
7423       isOldSyntax = Standard_True;
7424       aTolColor = anArg.RealValue();
7425       if (aTolColor < 0.0 || aTolColor > 1.0)
7426       {
7427         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7428         return 1;
7429       }
7430     }
7431     else if (isOldSyntax
7432           && toBlackWhite == -1
7433           && (anArg == "0" || anArg == "1"))
7434     {
7435       toBlackWhite = anArg == "1" ? 1 : 0;
7436     }
7437     else if (isOldSyntax
7438           && isBorderFilterOn == -1
7439           && (anArg == "0" || anArg == "1"))
7440     {
7441       isBorderFilterOn = anArg == "1" ? 1 : 0;
7442     }
7443     else if (aDiffImagePath.IsEmpty())
7444     {
7445       aDiffImagePath = theArgVec[anArgIter];
7446     }
7447     else
7448     {
7449       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7450       return 1;
7451     }
7452   }
7453
7454   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
7455   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
7456   if (!anImgRef->Load (anImgPathRef))
7457   {
7458     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
7459     return 1;
7460   }
7461   if (!anImgNew->Load (anImgPathNew))
7462   {
7463     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
7464     return 1;
7465   }
7466
7467   // compare the images
7468   Image_Diff aComparer;
7469   Standard_Integer aDiffColorsNb = -1;
7470   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
7471   {
7472     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
7473     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
7474     aDiffColorsNb = aComparer.Compare();
7475     theDI << aDiffColorsNb << "\n";
7476   }
7477
7478   // save image of difference
7479   Handle(Image_AlienPixMap) aDiff;
7480   if (aDiffColorsNb > 0
7481   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
7482   {
7483     aDiff = new Image_AlienPixMap();
7484     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
7485     {
7486       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
7487       return 1;
7488     }
7489     aComparer.SaveDiffImage (*aDiff);
7490     if (!aDiffImagePath.IsEmpty()
7491      && !aDiff->Save (aDiffImagePath))
7492     {
7493       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
7494       return 1;
7495     }
7496   }
7497
7498   if (aViewName.IsEmpty())
7499   {
7500     return 0;
7501   }
7502
7503   ViewerTest_Names aViewNames (aViewName);
7504   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
7505   {
7506     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
7507     theDI.Eval (aCommand.ToCString());
7508   }
7509
7510   Standard_Integer aPxLeft = 0;
7511   Standard_Integer aPxTop  = 0;
7512   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
7513   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
7514                               ? int(anImgRef->SizeY() * 2)
7515                               : int(anImgRef->SizeY());
7516   TCollection_AsciiString aDisplayName;
7517   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
7518                                                             aViewName, aDisplayName);
7519
7520   Standard_Real aRatio = anImgRef->Ratio();
7521   Standard_Real aSizeX = 1.0;
7522   Standard_Real aSizeY = aSizeX / aRatio;
7523   {
7524     OSD_Path aPath (anImgPathRef);
7525     TCollection_AsciiString aLabelRef;
7526     if (!aPath.Name().IsEmpty())
7527     {
7528       aLabelRef = aPath.Name() + aPath.Extension();
7529     }
7530     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
7531
7532     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
7533     gp_Trsf aTrsfRef;
7534     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
7535     anImgRefPrs->SetLocalTransformation (aTrsfRef);
7536     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
7537   }
7538   {
7539     OSD_Path aPath (anImgPathNew);
7540     TCollection_AsciiString aLabelNew;
7541     if (!aPath.Name().IsEmpty())
7542     {
7543       aLabelNew = aPath.Name() + aPath.Extension();
7544     }
7545     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
7546
7547     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
7548     gp_Trsf aTrsfRef;
7549     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
7550     anImgNewPrs->SetLocalTransformation (aTrsfRef);
7551     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
7552   }
7553   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
7554   if (!aDiff.IsNull())
7555   {
7556     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
7557     gp_Trsf aTrsfDiff;
7558     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
7559     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
7560   }
7561   if (!aPrsNameDiff.IsEmpty())
7562   {
7563     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
7564   }
7565   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
7566   ViewerTest::CurrentView()->FitAll();
7567   return 0;
7568 }
7569
7570 //=======================================================================
7571 //function : VSelect
7572 //purpose  : Emulates different types of selection by mouse:
7573 //           1) single click selection
7574 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
7575 //           3) selection with polygon having corners at
7576 //           pixel positions (x1,y1),...,(xn,yn)
7577 //           4) any of these selections with shift button pressed
7578 //=======================================================================
7579 static Standard_Integer VSelect (Draw_Interpretor& ,
7580                                  Standard_Integer theNbArgs,
7581                                  const char** theArgVec)
7582 {
7583   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
7584   if (aCtx.IsNull())
7585   {
7586     Message::SendFail ("Error: no active viewer");
7587     return 1;
7588   }
7589
7590   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
7591   bool toAllowOverlap = false;
7592   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
7593   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7594   {
7595     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7596     anArg.LowerCase();
7597     if (anArg == "-allowoverlap")
7598     {
7599       toAllowOverlap = true;
7600       if (anArgIter + 1 < theNbArgs
7601        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
7602       {
7603         ++anArgIter;
7604       }
7605     }
7606     else if (anArgIter + 1 < theNbArgs
7607           && anArg.IsIntegerValue()
7608           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
7609     {
7610       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
7611       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
7612     }
7613     else if (anArgIter + 1 == theNbArgs
7614           && anArg.IsIntegerValue())
7615     {
7616       if (anArg.IntegerValue() == 1)
7617       {
7618         aSelScheme = AIS_SelectionScheme_XOR;
7619       }
7620     }
7621     else
7622     {
7623       Message::SendFail() << "Syntax error at '" << anArg << "'";
7624       return 1;
7625     }
7626   }
7627
7628   if (toAllowOverlap)
7629   {
7630     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
7631   }
7632
7633   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
7634   if (aPnts.IsEmpty())
7635   {
7636     aCtx->SelectDetected (aSelScheme);
7637     aCtx->CurrentViewer()->Invalidate();
7638   }
7639   else if (aPnts.Length() == 2)
7640   {
7641     if (toAllowOverlap
7642      && aPnts.First().y() < aPnts.Last().y())
7643     {
7644       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7645     }
7646     else if (!toAllowOverlap
7647            && aPnts.First().y() > aPnts.Last().y())
7648     {
7649       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7650     }
7651     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme == AIS_SelectionScheme_XOR);
7652   }
7653   else
7654   {
7655     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme == AIS_SelectionScheme_XOR);
7656   }
7657   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
7658   return 0;
7659 }
7660
7661 //=======================================================================
7662 //function : VMoveTo
7663 //purpose  : Emulates cursor movement to defined pixel position
7664 //=======================================================================
7665 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
7666                                 Standard_Integer theNbArgs,
7667                                 const char**     theArgVec)
7668 {
7669   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
7670   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
7671   if (aContext.IsNull())
7672   {
7673     Message::SendFail ("Error: no active viewer");
7674     return 1;
7675   }
7676
7677   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
7678   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7679   {
7680     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
7681     anArgStr.LowerCase();
7682     if (anArgStr == "-reset"
7683      || anArgStr == "-clear")
7684     {
7685       if (anArgIter + 1 < theNbArgs)
7686       {
7687         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
7688         return 1;
7689       }
7690
7691       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
7692                                        && aContext->CurrentViewer()->GridEcho();
7693       if (toEchoGrid)
7694       {
7695         aContext->CurrentViewer()->HideGridEcho (aView);
7696       }
7697       if (aContext->ClearDetected() || toEchoGrid)
7698       {
7699         aContext->CurrentViewer()->RedrawImmediate();
7700       }
7701       return 0;
7702     }
7703     else if (aMousePos.x() == IntegerLast()
7704           && anArgStr.IsIntegerValue())
7705     {
7706       aMousePos.x() = anArgStr.IntegerValue();
7707     }
7708     else if (aMousePos.y() == IntegerLast()
7709           && anArgStr.IsIntegerValue())
7710     {
7711       aMousePos.y() = anArgStr.IntegerValue();
7712     }
7713     else
7714     {
7715       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7716       return 1;
7717     }
7718   }
7719
7720   if (aMousePos.x() == IntegerLast()
7721    || aMousePos.y() == IntegerLast())
7722   {
7723     Message::SendFail ("Syntax error: wrong number of arguments");
7724     return 1;
7725   }
7726
7727   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
7728   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
7729   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
7730
7731   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
7732   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
7733   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
7734   {
7735     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
7736     {
7737       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
7738       break;
7739     }
7740   }
7741   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
7742   return 0;
7743 }
7744
7745 namespace
7746 {
7747   //! Global map storing all animations registered in ViewerTest.
7748   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
7749
7750   //! The animation calling the Draw Harness command.
7751   class ViewerTest_AnimationProc : public AIS_Animation
7752   {
7753   public:
7754
7755     //! Main constructor.
7756     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
7757                               Draw_Interpretor* theDI,
7758                               const TCollection_AsciiString& theCommand)
7759     : AIS_Animation (theAnimationName),
7760       myDrawInter(theDI),
7761       myCommand  (theCommand)
7762     {
7763       //
7764     }
7765
7766   protected:
7767
7768     //! Evaluate the command.
7769     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
7770     {
7771       TCollection_AsciiString aCmd = myCommand;
7772       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
7773       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
7774       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
7775       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
7776       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
7777       myDrawInter->Eval (aCmd.ToCString());
7778     }
7779
7780     //! Find the keyword in the command and replace it with value.
7781     //! @return the position of the keyword to pass value
7782     void replace (TCollection_AsciiString&       theCmd,
7783                   const TCollection_AsciiString& theKey,
7784                   const TCollection_AsciiString& theVal)
7785     {
7786       TCollection_AsciiString aCmd (theCmd);
7787       aCmd.LowerCase();
7788       const Standard_Integer aPos = aCmd.Search (theKey);
7789       if (aPos == -1)
7790       {
7791         return;
7792       }
7793
7794       TCollection_AsciiString aPart1, aPart2;
7795       Standard_Integer aPart1To = aPos - 1;
7796       if (aPart1To >= 1
7797        && aPart1To <= theCmd.Length())
7798       {
7799         aPart1 = theCmd.SubString (1, aPart1To);
7800       }
7801
7802       Standard_Integer aPart2From = aPos + theKey.Length();
7803       if (aPart2From >= 1
7804        && aPart2From <= theCmd.Length())
7805       {
7806         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
7807       }
7808
7809       theCmd = aPart1 + theVal + aPart2;
7810     }
7811
7812   protected:
7813
7814     Draw_Interpretor*       myDrawInter;
7815     TCollection_AsciiString myCommand;
7816
7817   };
7818
7819   //! Replace the animation with the new one.
7820   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
7821                                 Handle(AIS_Animation)&       theAnimation,
7822                                 const Handle(AIS_Animation)& theAnimationNew)
7823   {
7824     theAnimationNew->CopyFrom (theAnimation);
7825     if (!theParentAnimation.IsNull())
7826     {
7827       theParentAnimation->Replace (theAnimation, theAnimationNew);
7828     }
7829     else
7830     {
7831       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
7832       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
7833     }
7834     theAnimation = theAnimationNew;
7835   }
7836
7837   //! Parse the point.
7838   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
7839   {
7840     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
7841     if (!anXYZ[0].IsRealValue (Standard_True)
7842      || !anXYZ[1].IsRealValue (Standard_True)
7843      || !anXYZ[2].IsRealValue (Standard_True))
7844     {
7845       return Standard_False;
7846     }
7847
7848     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
7849     return Standard_True;
7850   }
7851
7852   //! Parse the quaternion.
7853   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
7854   {
7855     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
7856     if (!anXYZW[0].IsRealValue (Standard_True)
7857      || !anXYZW[1].IsRealValue (Standard_True)
7858      || !anXYZW[2].IsRealValue (Standard_True)
7859      || !anXYZW[3].IsRealValue (Standard_True))
7860     {
7861       return Standard_False;
7862     }
7863
7864     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
7865     return Standard_True;
7866   }
7867
7868   //! Auxiliary class for flipping image upside-down.
7869   class ImageFlipper
7870   {
7871   public:
7872
7873     //! Empty constructor.
7874     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
7875
7876     //! Perform flipping.
7877     Standard_Boolean FlipY (Image_PixMap& theImage)
7878     {
7879       if (theImage.IsEmpty()
7880        || theImage.SizeX() == 0
7881        || theImage.SizeY() == 0)
7882       {
7883         return Standard_False;
7884       }
7885
7886       const Standard_Size aRowSize = theImage.SizeRowBytes();
7887       if (myTmp.Size() < aRowSize
7888       && !myTmp.Allocate (aRowSize))
7889       {
7890         return Standard_False;
7891       }
7892
7893       // for odd height middle row should be left as is
7894       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
7895       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
7896       {
7897         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
7898         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
7899         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
7900         memcpy (aTop,               aBot,         aRowSize);
7901         memcpy (aBot,               myTmp.Data(), aRowSize);
7902       }
7903       return Standard_True;
7904     }
7905
7906   private:
7907     NCollection_Buffer myTmp;
7908   };
7909
7910 }
7911
7912 //=================================================================================================
7913 //function : VViewParams
7914 //purpose  : Gets or sets AIS View characteristics
7915 //=================================================================================================
7916 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
7917 {
7918   Handle(V3d_View) aView = ViewerTest::CurrentView();
7919   if (aView.IsNull())
7920   {
7921     Message::SendFail ("Error: no active viewer");
7922     return 1;
7923   }
7924
7925   Standard_Boolean toSetProj     = Standard_False;
7926   Standard_Boolean toSetUp       = Standard_False;
7927   Standard_Boolean toSetAt       = Standard_False;
7928   Standard_Boolean toSetEye      = Standard_False;
7929   Standard_Boolean toSetScale    = Standard_False;
7930   Standard_Boolean toSetSize     = Standard_False;
7931   Standard_Boolean toSetCenter2d = Standard_False;
7932   Standard_Real    aViewScale = aView->Scale();
7933   Standard_Real    aViewSize  = 1.0;
7934   Graphic3d_Vec2i  aCenter2d;
7935   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
7936   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
7937   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
7938   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
7939   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
7940   if (theArgsNb == 1)
7941   {
7942     // print all of the available view parameters
7943     char aText[4096];
7944     Sprintf (aText,
7945              "Scale: %g\n"
7946              "Proj:  %12g %12g %12g\n"
7947              "Up:    %12g %12g %12g\n"
7948              "At:    %12g %12g %12g\n"
7949              "Eye:   %12g %12g %12g\n",
7950               aViewScale,
7951               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7952               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7953               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
7954               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z());
7955     theDi << aText;
7956     return 0;
7957   }
7958
7959   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
7960   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
7961   {
7962     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7963     anArg.LowerCase();
7964     if (anUpdateTool.parseRedrawMode (anArg))
7965     {
7966       continue;
7967     }
7968     else if (anArg == "-cmd"
7969           || anArg == "-command"
7970           || anArg == "-args")
7971     {
7972       char aText[4096];
7973       Sprintf (aText,
7974                "-scale %g "
7975                "-proj %g %g %g "
7976                "-up %g %g %g "
7977                "-at %g %g %g\n",
7978                 aViewScale,
7979                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7980                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7981                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
7982       theDi << aText;
7983     }
7984     else if (anArg == "-scale"
7985           || anArg == "-size")
7986     {
7987       if (anArgIter + 1 < theArgsNb
7988        && *theArgVec[anArgIter + 1] != '-')
7989       {
7990         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7991         if (aValueArg.IsRealValue (Standard_True))
7992         {
7993           ++anArgIter;
7994           if (anArg == "-scale")
7995           {
7996             toSetScale = Standard_True;
7997             aViewScale = aValueArg.RealValue();
7998           }
7999           else if (anArg == "-size")
8000           {
8001             toSetSize = Standard_True;
8002             aViewSize = aValueArg.RealValue();
8003           }
8004           continue;
8005         }
8006       }
8007       if (anArg == "-scale")
8008       {
8009         theDi << "Scale: " << aView->Scale() << "\n";
8010       }
8011       else if (anArg == "-size")
8012       {
8013         Graphic3d_Vec2d aSizeXY;
8014         aView->Size (aSizeXY.x(), aSizeXY.y());
8015         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
8016       }
8017     }
8018     else if (anArg == "-eye"
8019           || anArg == "-at"
8020           || anArg == "-up"
8021           || anArg == "-proj")
8022     {
8023       if (anArgIter + 3 < theArgsNb)
8024       {
8025         gp_XYZ anXYZ;
8026         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
8027         {
8028           anArgIter += 3;
8029           if (anArg == "-eye")
8030           {
8031             toSetEye = Standard_True;
8032             aViewEye = anXYZ;
8033           }
8034           else if (anArg == "-at")
8035           {
8036             toSetAt = Standard_True;
8037             aViewAt = anXYZ;
8038           }
8039           else if (anArg == "-up")
8040           {
8041             toSetUp = Standard_True;
8042             aViewUp = anXYZ;
8043           }
8044           else if (anArg == "-proj")
8045           {
8046             toSetProj = Standard_True;
8047             aViewProj = anXYZ;
8048           }
8049           continue;
8050         }
8051       }
8052
8053       if (anArg == "-eye")
8054       {
8055         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
8056       }
8057       else if (anArg == "-at")
8058       {
8059         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
8060       }
8061       else if (anArg == "-up")
8062       {
8063         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
8064       }
8065       else if (anArg == "-proj")
8066       {
8067         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
8068       }
8069     }
8070     else if (anArg == "-center")
8071     {
8072       if (anArgIter + 2 < theArgsNb)
8073       {
8074         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
8075         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
8076         if (anX.IsIntegerValue()
8077          && anY.IsIntegerValue())
8078         {
8079           toSetCenter2d = Standard_True;
8080           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
8081         }
8082       }
8083     }
8084     else
8085     {
8086       Message::SendFail() << "Syntax error at '" << anArg << "'";
8087       return 1;
8088     }
8089   }
8090
8091   // change view parameters in proper order
8092   if (toSetScale)
8093   {
8094     aView->SetScale (aViewScale);
8095   }
8096   if (toSetSize)
8097   {
8098     aView->SetSize (aViewSize);
8099   }
8100   if (toSetEye)
8101   {
8102     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
8103   }
8104   if (toSetAt)
8105   {
8106     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
8107   }
8108   if (toSetProj)
8109   {
8110     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
8111   }
8112   if (toSetUp)
8113   {
8114     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
8115   }
8116   if (toSetCenter2d)
8117   {
8118     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
8119   }
8120
8121   return 0;
8122 }
8123
8124 //==============================================================================
8125 //function : V2DMode
8126 //purpose  :
8127 //==============================================================================
8128 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
8129 {
8130   bool is2dMode = true;
8131   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
8132   if (aV3dView.IsNull())
8133   {
8134     Message::SendFail ("Error: no active viewer");
8135     return 1;
8136   }
8137   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
8138   {
8139     const TCollection_AsciiString anArg = theArgVec[anArgIt];
8140     TCollection_AsciiString anArgCase = anArg;
8141     anArgCase.LowerCase();
8142     if (anArgIt + 1 < theArgsNb
8143      && anArgCase == "-name")
8144     {
8145       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
8146       TCollection_AsciiString aViewName = aViewNames.GetViewName();
8147       if (!ViewerTest_myViews.IsBound1 (aViewName))
8148       {
8149         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
8150         return 1;
8151       }
8152       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
8153     }
8154     else if (anArgCase == "-mode")
8155     {
8156       if (anArgIt + 1 < theArgsNb
8157        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
8158       {
8159         ++anArgIt;
8160       }
8161     }
8162     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
8163     {
8164       //
8165     }
8166     else
8167     {
8168       Message::SendFail() << "Syntax error: unknown argument " << anArg;
8169       return 1;
8170     }
8171   }
8172
8173   aV3dView->SetView2DMode (is2dMode);
8174   return 0;
8175 }
8176
8177 //==============================================================================
8178 //function : VAnimation
8179 //purpose  :
8180 //==============================================================================
8181 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
8182                                     Standard_Integer  theArgNb,
8183                                     const char**      theArgVec)
8184 {
8185   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
8186   if (theArgNb < 2)
8187   {
8188     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
8189          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
8190     {
8191       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
8192     }
8193     return 0;
8194   }
8195   if (aCtx.IsNull())
8196   {
8197     Message::SendFail ("Error: no active viewer");
8198     return 1;
8199   }
8200
8201   Standard_Integer anArgIter = 1;
8202   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
8203   if (aNameArg.IsEmpty())
8204   {
8205     Message::SendFail ("Syntax error: animation name is not defined");
8206     return 1;
8207   }
8208
8209   TCollection_AsciiString aNameArgLower = aNameArg;
8210   aNameArgLower.LowerCase();
8211   if (aNameArgLower == "-reset"
8212    || aNameArgLower == "-clear")
8213   {
8214     ViewerTest_AnimationTimelineMap.Clear();
8215     return 0;
8216   }
8217   else if (aNameArg.Value (1) == '-')
8218   {
8219     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
8220     return 1;
8221   }
8222
8223   const char* aNameSplitter = "/";
8224   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
8225   if (aSplitPos == -1)
8226   {
8227     aNameSplitter = ".";
8228     aSplitPos = aNameArg.Search (aNameSplitter);
8229   }
8230
8231   // find existing or create a new animation by specified name within syntax "parent.child".
8232   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
8233   for (; !aNameArg.IsEmpty();)
8234   {
8235     TCollection_AsciiString aNameParent;
8236     if (aSplitPos != -1)
8237     {
8238       if (aSplitPos == aNameArg.Length())
8239       {
8240         Message::SendFail ("Syntax error: animation name is not defined");
8241         return 1;
8242       }
8243
8244       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
8245       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
8246
8247       aSplitPos = aNameArg.Search (aNameSplitter);
8248     }
8249     else
8250     {
8251       aNameParent = aNameArg;
8252       aNameArg.Clear();
8253     }
8254
8255     if (anAnimation.IsNull())
8256     {
8257       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
8258       {
8259         anAnimation = new AIS_Animation (aNameParent);
8260         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
8261       }
8262       aRootAnimation = anAnimation;
8263     }
8264     else
8265     {
8266       aParentAnimation = anAnimation;
8267       anAnimation = aParentAnimation->Find (aNameParent);
8268       if (anAnimation.IsNull())
8269       {
8270         anAnimation = new AIS_Animation (aNameParent);
8271         aParentAnimation->Add (anAnimation);
8272       }
8273     }
8274   }
8275
8276   if (anArgIter >= theArgNb)
8277   {
8278     // just print the list of children
8279     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
8280     {
8281       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
8282     }
8283     return 0;
8284   }
8285
8286   // animation parameters
8287   Standard_Boolean toPlay = Standard_False;
8288   Standard_Real aPlaySpeed     = 1.0;
8289   Standard_Real aPlayStartTime = anAnimation->StartPts();
8290   Standard_Real aPlayDuration  = anAnimation->Duration();
8291   Standard_Boolean isFreeCamera = Standard_False;
8292   Standard_Boolean isLockLoop   = Standard_False;
8293
8294   // video recording parameters
8295   TCollection_AsciiString aRecFile;
8296   Image_VideoParams aRecParams;
8297
8298   Handle(V3d_View) aView = ViewerTest::CurrentView();
8299   for (; anArgIter < theArgNb; ++anArgIter)
8300   {
8301     TCollection_AsciiString anArg (theArgVec[anArgIter]);
8302     anArg.LowerCase();
8303     // general options
8304     if (anArg == "-reset"
8305      || anArg == "-clear")
8306     {
8307       anAnimation->Clear();
8308     }
8309     else if (anArg == "-remove"
8310           || anArg == "-del"
8311           || anArg == "-delete")
8312     {
8313       if (!aParentAnimation.IsNull())
8314       {
8315         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
8316       }
8317       else
8318       {
8319         aParentAnimation->Remove (anAnimation);
8320       }
8321     }
8322     // playback options
8323     else if (anArg == "-play")
8324     {
8325       toPlay = Standard_True;
8326       if (++anArgIter < theArgNb)
8327       {
8328         if (*theArgVec[anArgIter] == '-')
8329         {
8330           --anArgIter;
8331           continue;
8332         }
8333         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
8334
8335         if (++anArgIter < theArgNb)
8336         {
8337           if (*theArgVec[anArgIter] == '-')
8338           {
8339             --anArgIter;
8340             continue;
8341           }
8342           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8343         }
8344       }
8345     }
8346     else if (anArg == "-resume")
8347     {
8348       toPlay = Standard_True;
8349       aPlayStartTime = anAnimation->ElapsedTime();
8350       if (++anArgIter < theArgNb)
8351       {
8352         if (*theArgVec[anArgIter] == '-')
8353         {
8354           --anArgIter;
8355           continue;
8356         }
8357
8358         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8359       }
8360     }
8361     else if (anArg == "-playspeed"
8362           || anArg == "-speed")
8363     {
8364       if (++anArgIter >= theArgNb)
8365       {
8366         Message::SendFail() << "Syntax error at " << anArg << "";
8367         return 1;
8368       }
8369       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
8370     }
8371     else if (anArg == "-lock"
8372           || anArg == "-lockloop"
8373           || anArg == "-playlockloop")
8374     {
8375       isLockLoop = Standard_True;
8376     }
8377     else if (anArg == "-freecamera"
8378           || anArg == "-playfreecamera"
8379           || anArg == "-freelook")
8380     {
8381       isFreeCamera = Standard_True;
8382     }
8383     // video recodring options
8384     else if (anArg == "-rec"
8385           || anArg == "-record")
8386     {
8387       if (++anArgIter >= theArgNb)
8388       {
8389         Message::SendFail() << "Syntax error at " << anArg;
8390         return 1;
8391       }
8392
8393       aRecFile = theArgVec[anArgIter];
8394       if (aRecParams.FpsNum <= 0)
8395       {
8396         aRecParams.FpsNum = 24;
8397       }
8398
8399       if (anArgIter + 2 < theArgNb
8400       && *theArgVec[anArgIter + 1] != '-'
8401       && *theArgVec[anArgIter + 2] != '-')
8402       {
8403         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
8404         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
8405         if (aWidthArg .IsIntegerValue()
8406          && aHeightArg.IsIntegerValue())
8407         {
8408           aRecParams.Width  = aWidthArg .IntegerValue();
8409           aRecParams.Height = aHeightArg.IntegerValue();
8410           anArgIter += 2;
8411         }
8412       }
8413     }
8414     else if (anArg == "-fps")
8415     {
8416       if (++anArgIter >= theArgNb)
8417       {
8418         Message::SendFail() << "Syntax error at " << anArg;
8419         return 1;
8420       }
8421
8422       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
8423       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
8424       if (aSplitIndex == 0)
8425       {
8426         aRecParams.FpsNum = aFpsArg.IntegerValue();
8427       }
8428       else
8429       {
8430         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
8431         aFpsArg.Split (aFpsArg.Length() - 1);
8432         const TCollection_AsciiString aNumStr = aFpsArg;
8433         aRecParams.FpsNum = aNumStr.IntegerValue();
8434         aRecParams.FpsDen = aDenStr.IntegerValue();
8435         if (aRecParams.FpsDen < 1)
8436         {
8437           Message::SendFail() << "Syntax error at " << anArg;
8438           return 1;
8439         }
8440       }
8441     }
8442     else if (anArg == "-format")
8443     {
8444       if (++anArgIter >= theArgNb)
8445       {
8446         Message::SendFail() << "Syntax error at " << anArg;
8447         return 1;
8448       }
8449       aRecParams.Format = theArgVec[anArgIter];
8450     }
8451     else if (anArg == "-pix_fmt"
8452           || anArg == "-pixfmt"
8453           || anArg == "-pixelformat")
8454     {
8455       if (++anArgIter >= theArgNb)
8456       {
8457         Message::SendFail() << "Syntax error at " << anArg;
8458         return 1;
8459       }
8460       aRecParams.PixelFormat = theArgVec[anArgIter];
8461     }
8462     else if (anArg == "-codec"
8463           || anArg == "-vcodec"
8464           || anArg == "-videocodec")
8465     {
8466       if (++anArgIter >= theArgNb)
8467       {
8468         Message::SendFail() << "Syntax error at " << anArg;
8469         return 1;
8470       }
8471       aRecParams.VideoCodec = theArgVec[anArgIter];
8472     }
8473     else if (anArg == "-crf"
8474           || anArg == "-preset"
8475           || anArg == "-qp")
8476     {
8477       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
8478       if (++anArgIter >= theArgNb)
8479       {
8480         Message::SendFail() << "Syntax error at " << anArg;
8481         return 1;
8482       }
8483
8484       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
8485     }
8486     // animation definition options
8487     else if (anArg == "-start"
8488           || anArg == "-starttime"
8489           || anArg == "-startpts")
8490     {
8491       if (++anArgIter >= theArgNb)
8492       {
8493         Message::SendFail() << "Syntax error at " << anArg;
8494         return 1;
8495       }
8496
8497       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
8498       aRootAnimation->UpdateTotalDuration();
8499     }
8500     else if (anArg == "-end"
8501           || anArg == "-endtime"
8502           || anArg == "-endpts")
8503     {
8504       if (++anArgIter >= theArgNb)
8505       {
8506         Message::SendFail() << "Syntax error at " << anArg;
8507         return 1;
8508       }
8509
8510       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
8511       aRootAnimation->UpdateTotalDuration();
8512     }
8513     else if (anArg == "-dur"
8514           || anArg == "-duration")
8515     {
8516       if (++anArgIter >= theArgNb)
8517       {
8518         Message::SendFail() << "Syntax error at " << anArg;
8519         return 1;
8520       }
8521
8522       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
8523       aRootAnimation->UpdateTotalDuration();
8524     }
8525     else if (anArg == "-command"
8526           || anArg == "-cmd"
8527           || anArg == "-invoke"
8528           || anArg == "-eval"
8529           || anArg == "-proc")
8530     {
8531       if (++anArgIter >= theArgNb)
8532       {
8533         Message::SendFail() << "Syntax error at " << anArg;
8534         return 1;
8535       }
8536
8537       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
8538       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
8539     }
8540     else if (anArg == "-objecttrsf"
8541           || anArg == "-objectransformation"
8542           || anArg == "-objtransformation"
8543           || anArg == "-objtrsf"
8544           || anArg == "-object"
8545           || anArg == "-obj")
8546     {
8547       if (++anArgIter >= theArgNb)
8548       {
8549         Message::SendFail() << "Syntax error at " << anArg;
8550         return 1;
8551       }
8552
8553       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
8554       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
8555       Handle(AIS_InteractiveObject) anObject;
8556       if (!aMapOfAIS.Find2 (anObjName, anObject))
8557       {
8558         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
8559         return 1;
8560       }
8561
8562       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
8563       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
8564       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
8565       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
8566       Standard_Boolean isTrsfSet = Standard_False;
8567       Standard_Integer aTrsfArgIter = anArgIter + 1;
8568       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
8569       {
8570         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
8571         aTrsfArg.LowerCase();
8572         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
8573         if (aTrsfArg.StartsWith ("-rotation")
8574          || aTrsfArg.StartsWith ("-rot"))
8575         {
8576           isTrsfSet = Standard_True;
8577           if (aTrsfArgIter + 4 >= theArgNb
8578           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
8579           {
8580             Message::SendFail() << "Syntax error at " << aTrsfArg;
8581             return 1;
8582           }
8583           aTrsfArgIter += 4;
8584         }
8585         else if (aTrsfArg.StartsWith ("-location")
8586               || aTrsfArg.StartsWith ("-loc"))
8587         {
8588           isTrsfSet = Standard_True;
8589           if (aTrsfArgIter + 3 >= theArgNb
8590           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
8591           {
8592             Message::SendFail() << "Syntax error at " << aTrsfArg;
8593             return 1;
8594           }
8595           aTrsfArgIter += 3;
8596         }
8597         else if (aTrsfArg.StartsWith ("-scale"))
8598         {
8599           isTrsfSet = Standard_True;
8600           if (++aTrsfArgIter >= theArgNb)
8601           {
8602             Message::SendFail() << "Syntax error at " << aTrsfArg;
8603             return 1;
8604           }
8605
8606           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
8607           if (!aScaleStr.IsRealValue (Standard_True))
8608           {
8609             Message::SendFail() << "Syntax error at " << aTrsfArg;
8610             return 1;
8611           }
8612           aScales[anIndex] = aScaleStr.RealValue();
8613         }
8614         else
8615         {
8616           anArgIter = aTrsfArgIter - 1;
8617           break;
8618         }
8619       }
8620       if (!isTrsfSet)
8621       {
8622         Message::SendFail() << "Syntax error at " << anArg;
8623         return 1;
8624       }
8625       else if (aTrsfArgIter >= theArgNb)
8626       {
8627         anArgIter = theArgNb;
8628       }
8629
8630       aTrsfs[0].SetRotation        (aRotQuats[0]);
8631       aTrsfs[1].SetRotation        (aRotQuats[1]);
8632       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
8633       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
8634       aTrsfs[0].SetScaleFactor     (aScales[0]);
8635       aTrsfs[1].SetScaleFactor     (aScales[1]);
8636
8637       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
8638       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
8639     }
8640     else if (anArg == "-viewtrsf"
8641           || anArg == "-view")
8642     {
8643       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
8644       if (aCamAnimation.IsNull())
8645       {
8646         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
8647         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
8648       }
8649
8650       Handle(Graphic3d_Camera) aCams[2] =
8651       {
8652         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
8653         new Graphic3d_Camera (aCamAnimation->View()->Camera())
8654       };
8655
8656       Standard_Boolean isTrsfSet = Standard_False;
8657       Standard_Integer aViewArgIter = anArgIter + 1;
8658       for (; aViewArgIter < theArgNb; ++aViewArgIter)
8659       {
8660         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
8661         aViewArg.LowerCase();
8662         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
8663         if (aViewArg.StartsWith ("-scale"))
8664         {
8665           isTrsfSet = Standard_True;
8666           if (++aViewArgIter >= theArgNb)
8667           {
8668             Message::SendFail() << "Syntax error at " << anArg;
8669             return 1;
8670           }
8671
8672           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
8673           if (!aScaleStr.IsRealValue (Standard_True))
8674           {
8675             Message::SendFail() << "Syntax error at " << aViewArg;
8676             return 1;
8677           }
8678           Standard_Real aScale = aScaleStr.RealValue();
8679           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
8680           aCams[anIndex]->SetScale (aScale);
8681         }
8682         else if (aViewArg.StartsWith ("-eye")
8683               || aViewArg.StartsWith ("-center")
8684               || aViewArg.StartsWith ("-at")
8685               || aViewArg.StartsWith ("-up"))
8686         {
8687           isTrsfSet = Standard_True;
8688           gp_XYZ anXYZ;
8689           if (aViewArgIter + 3 >= theArgNb
8690           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
8691           {
8692             Message::SendFail() << "Syntax error at " << aViewArg;
8693             return 1;
8694           }
8695           aViewArgIter += 3;
8696
8697           if (aViewArg.StartsWith ("-eye"))
8698           {
8699             aCams[anIndex]->SetEye (anXYZ);
8700           }
8701           else if (aViewArg.StartsWith ("-center")
8702                 || aViewArg.StartsWith ("-at"))
8703           {
8704             aCams[anIndex]->SetCenter (anXYZ);
8705           }
8706           else if (aViewArg.StartsWith ("-up"))
8707           {
8708             aCams[anIndex]->SetUp (anXYZ);
8709           }
8710         }
8711         else
8712         {
8713           anArgIter = aViewArgIter - 1;
8714           break;
8715         }
8716       }
8717       if (!isTrsfSet)
8718       {
8719         Message::SendFail() << "Syntax error at " << anArg;
8720         return 1;
8721       }
8722       else if (aViewArgIter >= theArgNb)
8723       {
8724         anArgIter = theArgNb;
8725       }
8726
8727       aCamAnimation->SetCameraStart(aCams[0]);
8728       aCamAnimation->SetCameraEnd  (aCams[1]);
8729     }
8730     else
8731     {
8732       Message::SendFail() << "Syntax error at " << anArg;
8733       return 1;
8734     }
8735   }
8736
8737   if (!toPlay && aRecFile.IsEmpty())
8738   {
8739     return 0;
8740   }
8741
8742   // Start animation timeline and process frame updating.
8743   TheIsAnimating = Standard_True;
8744   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
8745   Handle(Graphic3d_Camera) aCameraBack = new Graphic3d_Camera (aView->Camera());
8746   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
8747   if (isFreeCamera)
8748   {
8749     aView->Camera()->Copy (aCameraBack);
8750   }
8751
8752   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
8753   if (aRecParams.FpsNum <= 0)
8754   {
8755     while (!anAnimation->IsStopped())
8756     {
8757       aCameraBack->Copy (aView->Camera());
8758       const Standard_Real aPts = anAnimation->UpdateTimer();
8759       if (isFreeCamera)
8760       {
8761         aView->Camera()->Copy (aCameraBack);
8762       }
8763
8764       if (aPts >= anUpperPts)
8765       {
8766         anAnimation->Pause();
8767         break;
8768       }
8769
8770       if (aView->IsInvalidated())
8771       {
8772         aView->Redraw();
8773       }
8774       else
8775       {
8776         aView->RedrawImmediate();
8777       }
8778
8779       if (!isLockLoop)
8780       {
8781         // handle user events
8782         theDI.Eval ("after 1 set waiter 1");
8783         theDI.Eval ("vwait waiter");
8784       }
8785       if (!TheIsAnimating)
8786       {
8787         anAnimation->Pause();
8788         theDI << aPts;
8789         break;
8790       }
8791     }
8792
8793     if (aView->IsInvalidated())
8794     {
8795       aView->Redraw();
8796     }
8797     else
8798     {
8799       aView->RedrawImmediate();
8800     }
8801   }
8802   else
8803   {
8804     OSD_Timer aPerfTimer;
8805     aPerfTimer.Start();
8806
8807     Handle(Image_VideoRecorder) aRecorder;
8808     ImageFlipper aFlipper;
8809     Handle(Draw_ProgressIndicator) aProgress;
8810     if (!aRecFile.IsEmpty())
8811     {
8812       if (aRecParams.Width  <= 0
8813        || aRecParams.Height <= 0)
8814       {
8815         aView->Window()->Size (aRecParams.Width, aRecParams.Height);
8816       }
8817
8818       aRecorder = new Image_VideoRecorder();
8819       if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
8820       {
8821         Message::SendFail ("Error: failed to open video file for recording");
8822         return 0;
8823       }
8824
8825       aProgress = new Draw_ProgressIndicator (theDI, 1);
8826     }
8827
8828     // Manage frame-rated animation here
8829     Standard_Real aPts = aPlayStartTime;
8830     int64_t aNbFrames = 0;
8831     Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
8832                               "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
8833     Standard_Integer aSecondsProgress = 0;
8834     for (; aPts <= anUpperPts && aPS.More();)
8835     {
8836       const Standard_Real aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
8837       aPts = aPlayStartTime + aRecPts;
8838       ++aNbFrames;
8839       if (!anAnimation->Update (aPts))
8840       {
8841         break;
8842       }
8843
8844       if (!aRecorder.IsNull())
8845       {
8846         V3d_ImageDumpOptions aDumpParams;
8847         aDumpParams.Width          = aRecParams.Width;
8848         aDumpParams.Height         = aRecParams.Height;
8849         aDumpParams.BufferType     = Graphic3d_BT_RGBA;
8850         aDumpParams.StereoOptions  = V3d_SDO_MONO;
8851         aDumpParams.ToAdjustAspect = Standard_True;
8852         if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
8853         {
8854           Message::SendFail ("Error: view dump is failed");
8855           return 0;
8856         }
8857         aFlipper.FlipY (aRecorder->ChangeFrame());
8858         if (!aRecorder->PushFrame())
8859         {
8860           return 0;
8861         }
8862       }
8863       else
8864       {
8865         aView->Redraw();
8866       }
8867
8868       while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
8869       {
8870         aPS.Next();
8871         ++aSecondsProgress;
8872       }
8873     }
8874
8875     aPerfTimer.Stop();
8876     anAnimation->Stop();
8877     const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
8878     theDI << "Average FPS: " << aRecFps << "\n"
8879           << "Nb. Frames: "  << Standard_Real(aNbFrames);
8880
8881     aView->Redraw();
8882   }
8883
8884   aView->SetImmediateUpdate (wasImmediateUpdate);
8885   TheIsAnimating = Standard_False;
8886   return 0;
8887 }
8888
8889
8890 //=======================================================================
8891 //function : VChangeSelected
8892 //purpose  : Adds the shape to selection or remove one from it
8893 //=======================================================================
8894 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
8895                                 Standard_Integer argc,
8896                                 const char ** argv)
8897 {
8898   if(argc != 2)
8899   {
8900     di<<"Usage : " << argv[0] << " shape \n";
8901     return 1;
8902   }
8903   //get AIS_Shape:
8904   TCollection_AsciiString aName(argv[1]);
8905   Handle(AIS_InteractiveObject) anAISObject;
8906   if (!GetMapOfAIS().Find2 (aName, anAISObject)
8907     || anAISObject.IsNull())
8908   {
8909     di<<"Use 'vdisplay' before";
8910     return 1;
8911   }
8912
8913   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
8914   return 0;
8915 }
8916
8917 //=======================================================================
8918 //function : VNbSelected
8919 //purpose  : Returns number of selected objects
8920 //=======================================================================
8921 static Standard_Integer VNbSelected (Draw_Interpretor& di,
8922                                 Standard_Integer argc,
8923                                 const char ** argv)
8924 {
8925   if(argc != 1)
8926   {
8927     di << "Usage : " << argv[0] << "\n";
8928     return 1;
8929   }
8930   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8931   if(aContext.IsNull())
8932   {
8933     di << "use 'vinit' command before " << argv[0] << "\n";
8934     return 1;
8935   }
8936   di << aContext->NbSelected() << "\n";
8937   return 0;
8938 }
8939
8940 //=======================================================================
8941 //function : VSetViewSize
8942 //purpose  :
8943 //=======================================================================
8944 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
8945                                 Standard_Integer argc,
8946                                 const char ** argv)
8947 {
8948   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8949   if(aContext.IsNull())
8950   {
8951     di << "use 'vinit' command before " << argv[0] << "\n";
8952     return 1;
8953   }
8954   if(argc != 2)
8955   {
8956     di<<"Usage : " << argv[0] << " Size\n";
8957     return 1;
8958   }
8959   Standard_Real aSize = Draw::Atof (argv[1]);
8960   if (aSize <= 0.)
8961   {
8962     di<<"Bad Size value  : " << aSize << "\n";
8963     return 1;
8964   }
8965
8966   Handle(V3d_View) aView = ViewerTest::CurrentView();
8967   aView->SetSize(aSize);
8968   return 0;
8969 }
8970
8971 //=======================================================================
8972 //function : VMoveView
8973 //purpose  :
8974 //=======================================================================
8975 static Standard_Integer VMoveView (Draw_Interpretor& di,
8976                                 Standard_Integer argc,
8977                                 const char ** argv)
8978 {
8979   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8980   if(aContext.IsNull())
8981   {
8982     di << "use 'vinit' command before " << argv[0] << "\n";
8983     return 1;
8984   }
8985   if(argc < 4 || argc > 5)
8986   {
8987     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8988     return 1;
8989   }
8990   Standard_Real Dx = Draw::Atof (argv[1]);
8991   Standard_Real Dy = Draw::Atof (argv[2]);
8992   Standard_Real Dz = Draw::Atof (argv[3]);
8993   Standard_Boolean aStart = Standard_True;
8994   if (argc == 5)
8995   {
8996       aStart = (Draw::Atoi (argv[4]) > 0);
8997   }
8998
8999   Handle(V3d_View) aView = ViewerTest::CurrentView();
9000   aView->Move(Dx,Dy,Dz,aStart);
9001   return 0;
9002 }
9003
9004 //=======================================================================
9005 //function : VTranslateView
9006 //purpose  :
9007 //=======================================================================
9008 static Standard_Integer VTranslateView (Draw_Interpretor& di,
9009                                 Standard_Integer argc,
9010                                 const char ** argv)
9011 {
9012   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
9013   if(aContext.IsNull())
9014   {
9015     di << "use 'vinit' command before " << argv[0] << "\n";
9016     return 1;
9017   }
9018   if(argc < 4 || argc > 5)
9019   {
9020     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
9021     return 1;
9022   }
9023   Standard_Real Dx = Draw::Atof (argv[1]);
9024   Standard_Real Dy = Draw::Atof (argv[2]);
9025   Standard_Real Dz = Draw::Atof (argv[3]);
9026   Standard_Boolean aStart = Standard_True;
9027   if (argc == 5)
9028   {
9029       aStart = (Draw::Atoi (argv[4]) > 0);
9030   }
9031
9032   Handle(V3d_View) aView = ViewerTest::CurrentView();
9033   aView->Translate(Dx,Dy,Dz,aStart);
9034   return 0;
9035 }
9036
9037 //=======================================================================
9038 //function : VTurnView
9039 //purpose  :
9040 //=======================================================================
9041 static Standard_Integer VTurnView (Draw_Interpretor& di,
9042                                 Standard_Integer argc,
9043                                 const char ** argv)
9044 {
9045   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
9046   if(aContext.IsNull()) {
9047     di << "use 'vinit' command before " << argv[0] << "\n";
9048     return 1;
9049   }
9050   if(argc < 4 || argc > 5){
9051     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
9052     return 1;
9053   }
9054   Standard_Real Ax = Draw::Atof (argv[1]);
9055   Standard_Real Ay = Draw::Atof (argv[2]);
9056   Standard_Real Az = Draw::Atof (argv[3]);
9057   Standard_Boolean aStart = Standard_True;
9058   if (argc == 5)
9059   {
9060       aStart = (Draw::Atoi (argv[4]) > 0);
9061   }
9062
9063   Handle(V3d_View) aView = ViewerTest::CurrentView();
9064   aView->Turn(Ax,Ay,Az,aStart);
9065   return 0;
9066 }
9067
9068 //==============================================================================
9069 //function : VTextureEnv
9070 //purpose  : ENables or disables environment mapping
9071 //==============================================================================
9072 class OCC_TextureEnv : public Graphic3d_TextureEnv
9073 {
9074 public:
9075   OCC_TextureEnv(const Standard_CString FileName);
9076   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
9077   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
9078                             const Standard_Boolean theModulateFlag,
9079                             const Graphic3d_TypeOfTextureFilter theFilter,
9080                             const Standard_ShortReal theXScale,
9081                             const Standard_ShortReal theYScale,
9082                             const Standard_ShortReal theXShift,
9083                             const Standard_ShortReal theYShift,
9084                             const Standard_ShortReal theAngle);
9085   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
9086 };
9087 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
9088
9089 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
9090   : Graphic3d_TextureEnv(theFileName)
9091 {
9092 }
9093
9094 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
9095   : Graphic3d_TextureEnv(theTexId)
9096 {
9097 }
9098
9099 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
9100                                           const Standard_Boolean theModulateFlag,
9101                                           const Graphic3d_TypeOfTextureFilter theFilter,
9102                                           const Standard_ShortReal theXScale,
9103                                           const Standard_ShortReal theYScale,
9104                                           const Standard_ShortReal theXShift,
9105                                           const Standard_ShortReal theYShift,
9106                                           const Standard_ShortReal theAngle)
9107 {
9108   myParams->SetRepeat     (theRepeatFlag);
9109   myParams->SetModulate   (theModulateFlag);
9110   myParams->SetFilter     (theFilter);
9111   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
9112   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
9113   myParams->SetRotation   (theAngle);
9114 }
9115
9116 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
9117 {
9118   // get the active view
9119   Handle(V3d_View) aView = ViewerTest::CurrentView();
9120   if (aView.IsNull())
9121   {
9122     Message::SendFail ("Error: no active viewer");
9123     return 1;
9124   }
9125
9126   // Checking the input arguments
9127   Standard_Boolean anEnableFlag = Standard_False;
9128   Standard_Boolean isOk         = theArgNb >= 2;
9129   if (isOk)
9130   {
9131     TCollection_AsciiString anEnableOpt(theArgVec[1]);
9132     anEnableFlag = anEnableOpt.IsEqual("on");
9133     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
9134   }
9135   if (anEnableFlag)
9136   {
9137     isOk = (theArgNb == 3 || theArgNb == 11);
9138     if (isOk)
9139     {
9140       TCollection_AsciiString aTextureOpt(theArgVec[2]);
9141       isOk = (!aTextureOpt.IsIntegerValue() ||
9142              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
9143
9144       if (isOk && theArgNb == 11)
9145       {
9146         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
9147                                 aModulateOpt(theArgVec[4]),
9148                                 aFilterOpt  (theArgVec[5]),
9149                                 aSScaleOpt  (theArgVec[6]),
9150                                 aTScaleOpt  (theArgVec[7]),
9151                                 aSTransOpt  (theArgVec[8]),
9152                                 aTTransOpt  (theArgVec[9]),
9153                                 anAngleOpt  (theArgVec[10]);
9154         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
9155                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
9156                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
9157                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
9158                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
9159                 anAngleOpt.IsRealValue (Standard_True));
9160       }
9161     }
9162   }
9163
9164   if (!isOk)
9165   {
9166     Message::SendFail() << "Usage:\n"
9167                         << theArgVec[0] << " off\n"
9168                         << 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]";
9169     return 1;
9170   }
9171
9172   if (anEnableFlag)
9173   {
9174     TCollection_AsciiString aTextureOpt(theArgVec[2]);
9175     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
9176                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
9177                                      new OCC_TextureEnv(theArgVec[2]);
9178
9179     if (theArgNb == 11)
9180     {
9181       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
9182       aTexEnv->SetTextureParameters(
9183         aRepeatOpt.  IsEqual("repeat"),
9184         aModulateOpt.IsEqual("modulate"),
9185         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
9186                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
9187                                                                            Graphic3d_TOTF_TRILINEAR,
9188         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
9189         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
9190         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
9191         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
9192         (Standard_ShortReal)Draw::Atof(theArgVec[10])
9193         );
9194     }
9195     aView->SetTextureEnv(aTexEnv);
9196   }
9197   else // Disabling environment mapping
9198   {
9199     Handle(Graphic3d_TextureEnv) aTexture;
9200     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
9201   }
9202
9203   aView->Redraw();
9204   return 0;
9205 }
9206
9207 namespace
9208 {
9209   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
9210
9211   //! Remove registered clipping plane from all views and objects.
9212   static void removePlane (MapOfPlanes& theRegPlanes,
9213                            const TCollection_AsciiString& theName)
9214   {
9215     Handle(Graphic3d_ClipPlane) aClipPlane;
9216     if (!theRegPlanes.Find (theName, aClipPlane))
9217     {
9218       Message::SendWarning ("Warning: no such plane");
9219       return;
9220     }
9221
9222     theRegPlanes.UnBind (theName);
9223     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
9224          anIObjIt.More(); anIObjIt.Next())
9225     {
9226       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
9227       aPrs->RemoveClipPlane (aClipPlane);
9228     }
9229
9230     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
9231          aViewIt.More(); aViewIt.Next())
9232     {
9233       const Handle(V3d_View)& aView = aViewIt.Key2();
9234       aView->RemoveClipPlane(aClipPlane);
9235     }
9236
9237     ViewerTest::RedrawAllViews();
9238   }
9239 }
9240
9241 //===============================================================================================
9242 //function : VClipPlane
9243 //purpose  :
9244 //===============================================================================================
9245 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9246 {
9247   // use short-cut for created clip planes map of created (or "registered by name") clip planes
9248   static MapOfPlanes aRegPlanes;
9249
9250   if (theArgsNb < 2)
9251   {
9252     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
9253     {
9254       theDi << aPlaneIter.Key() << " ";
9255     }
9256     return 0;
9257   }
9258
9259   TCollection_AsciiString aCommand (theArgVec[1]);
9260   aCommand.LowerCase();
9261   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
9262   if (anActiveView.IsNull())
9263   {
9264     Message::SendFail ("Error: no active viewer");
9265     return 1;
9266   }
9267
9268   // print maximum number of planes for current viewer
9269   if (aCommand == "-maxplanes"
9270    || aCommand == "maxplanes")
9271   {
9272     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
9273           << " plane slots provided by driver.\n";
9274     return 0;
9275   }
9276
9277   // create / delete plane instance
9278   if (aCommand == "-create"
9279    || aCommand == "create"
9280    || aCommand == "-delete"
9281    || aCommand == "delete"
9282    || aCommand == "-clone"
9283    || aCommand == "clone")
9284   {
9285     if (theArgsNb < 3)
9286     {
9287       Message::SendFail ("Syntax error: plane name is required");
9288       return 1;
9289     }
9290
9291     Standard_Boolean toCreate = aCommand == "-create"
9292                              || aCommand == "create";
9293     Standard_Boolean toClone  = aCommand == "-clone"
9294                              || aCommand == "clone";
9295     Standard_Boolean toDelete = aCommand == "-delete"
9296                              || aCommand == "delete";
9297     TCollection_AsciiString aPlane (theArgVec[2]);
9298
9299     if (toCreate)
9300     {
9301       if (aRegPlanes.IsBound (aPlane))
9302       {
9303         std::cout << "Warning: existing plane has been overridden.\n";
9304         toDelete = true;
9305       }
9306       else
9307       {
9308         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9309         return 0;
9310       }
9311     }
9312     else if (toClone) // toClone
9313     {
9314       if (!aRegPlanes.IsBound (aPlane))
9315       {
9316         Message::SendFail ("Error: no such plane");
9317         return 1;
9318       }
9319       else if (theArgsNb < 4)
9320       {
9321         Message::SendFail ("Syntax error: enter name for new plane");
9322         return 1;
9323       }
9324
9325       TCollection_AsciiString aClone (theArgVec[3]);
9326       if (aRegPlanes.IsBound (aClone))
9327       {
9328         Message::SendFail ("Error: plane name is in use");
9329         return 1;
9330       }
9331
9332       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
9333
9334       aRegPlanes.Bind (aClone, aClipPlane->Clone());
9335       return 0;
9336     }
9337
9338     if (toDelete)
9339     {
9340       if (aPlane == "ALL"
9341        || aPlane == "all"
9342        || aPlane == "*")
9343       {
9344         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
9345         {
9346           aPlane = aPlaneIter.Key();
9347           removePlane (aRegPlanes, aPlane);
9348           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
9349         }
9350       }
9351       else
9352       {
9353         removePlane (aRegPlanes, aPlane);
9354       }
9355     }
9356
9357     if (toCreate)
9358     {
9359       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9360     }
9361     return 0;
9362   }
9363
9364   // set / unset plane command
9365   if (aCommand == "set"
9366    || aCommand == "unset")
9367   {
9368     if (theArgsNb < 5)
9369     {
9370       Message::SendFail ("Syntax error: need more arguments");
9371       return 1;
9372     }
9373
9374     // redirect to new syntax
9375     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
9376     anArgVec.SetValue (1, theArgVec[0]);
9377     anArgVec.SetValue (2, theArgVec[2]);
9378     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
9379     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
9380     {
9381       anArgVec.SetValue (anIt, theArgVec[anIt]);
9382     }
9383
9384     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
9385   }
9386
9387   // change plane command
9388   TCollection_AsciiString aPlaneName;
9389   Handle(Graphic3d_ClipPlane) aClipPlane;
9390   Standard_Integer anArgIter = 0;
9391   if (aCommand == "-change"
9392    || aCommand == "change")
9393   {
9394     // old syntax support
9395     if (theArgsNb < 3)
9396     {
9397       Message::SendFail ("Syntax error: need more arguments");
9398       return 1;
9399     }
9400
9401     anArgIter  = 3;
9402     aPlaneName = theArgVec[2];
9403     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
9404     {
9405       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
9406       return 1;
9407     }
9408   }
9409   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
9410   {
9411     anArgIter  = 2;
9412     aPlaneName = theArgVec[1];
9413   }
9414   else
9415   {
9416     anArgIter  = 2;
9417     aPlaneName = theArgVec[1];
9418     aClipPlane = new Graphic3d_ClipPlane();
9419     aRegPlanes.Bind (aPlaneName, aClipPlane);
9420     theDi << "Created new plane " << aPlaneName << ".\n";
9421   }
9422
9423   if (theArgsNb - anArgIter < 1)
9424   {
9425     Message::SendFail ("Syntax error: need more arguments");
9426     return 1;
9427   }
9428
9429   for (; anArgIter < theArgsNb; ++anArgIter)
9430   {
9431     const char**     aChangeArgs   = theArgVec + anArgIter;
9432     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
9433     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
9434     aChangeArg.LowerCase();
9435
9436     Standard_Boolean toEnable = Standard_True;
9437     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
9438     {
9439       aClipPlane->SetOn (toEnable);
9440     }
9441     else if (aChangeArg.StartsWith ("-equation")
9442           || aChangeArg.StartsWith ("equation"))
9443     {
9444       if (aNbChangeArgs < 5)
9445       {
9446         Message::SendFail ("Syntax error: need more arguments");
9447         return 1;
9448       }
9449
9450       Standard_Integer aSubIndex = 1;
9451       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
9452       if (aPrefixLen < aChangeArg.Length())
9453       {
9454         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
9455         if (!aSubStr.IsIntegerValue()
9456           || aSubStr.IntegerValue() <= 0)
9457         {
9458           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9459           return 1;
9460         }
9461         aSubIndex = aSubStr.IntegerValue();
9462       }
9463
9464       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
9465       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
9466       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
9467       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
9468       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9469       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
9470       {
9471         if (aSubPln->ChainNextPlane().IsNull())
9472         {
9473           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9474         }
9475         aSubPln = aSubPln->ChainNextPlane();
9476       }
9477       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9478       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
9479       anArgIter += 4;
9480     }
9481     else if ((aChangeArg == "-boxinterior"
9482            || aChangeArg == "-boxint"
9483            || aChangeArg == "-box")
9484             && aNbChangeArgs >= 7)
9485     {
9486       Graphic3d_BndBox3d aBndBox;
9487       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
9488       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
9489       anArgIter += 6;
9490
9491       Standard_Integer aNbSubPlanes = 6;
9492       const Graphic3d_Vec3d aDirArray[6] =
9493       {
9494         Graphic3d_Vec3d (-1, 0, 0),
9495         Graphic3d_Vec3d ( 1, 0, 0),
9496         Graphic3d_Vec3d ( 0,-1, 0),
9497         Graphic3d_Vec3d ( 0, 1, 0),
9498         Graphic3d_Vec3d ( 0, 0,-1),
9499         Graphic3d_Vec3d ( 0, 0, 1),
9500       };
9501       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9502       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
9503       {
9504         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
9505         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
9506         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
9507         if (aSubPlaneIter + 1 == aNbSubPlanes)
9508         {
9509           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9510         }
9511         else
9512         {
9513           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9514         }
9515         aSubPln = aSubPln->ChainNextPlane();
9516       }
9517     }
9518     else if (aChangeArg == "-capping"
9519           || aChangeArg == "capping")
9520     {
9521       if (aNbChangeArgs < 2)
9522       {
9523         Message::SendFail ("Syntax error: need more arguments");
9524         return 1;
9525       }
9526
9527       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9528       {
9529         aClipPlane->SetCapping (toEnable);
9530         anArgIter += 1;
9531       }
9532       else
9533       {
9534         // just skip otherwise (old syntax)
9535       }
9536     }
9537     else if (aChangeArg == "-useobjectmaterial"
9538           || aChangeArg == "-useobjectmat"
9539           || aChangeArg == "-useobjmat"
9540           || aChangeArg == "-useobjmaterial")
9541     {
9542       if (aNbChangeArgs < 2)
9543       {
9544         Message::SendFail ("Syntax error: need more arguments");
9545         return 1;
9546       }
9547
9548       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9549       {
9550         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
9551         anArgIter += 1;
9552       }
9553     }
9554     else if (aChangeArg == "-useobjecttexture"
9555           || aChangeArg == "-useobjecttex"
9556           || aChangeArg == "-useobjtexture"
9557           || aChangeArg == "-useobjtex")
9558     {
9559       if (aNbChangeArgs < 2)
9560       {
9561         Message::SendFail ("Syntax error: need more arguments");
9562         return 1;
9563       }
9564
9565       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9566       {
9567         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
9568         anArgIter += 1;
9569       }
9570     }
9571     else if (aChangeArg == "-useobjectshader"
9572           || aChangeArg == "-useobjshader")
9573     {
9574       if (aNbChangeArgs < 2)
9575       {
9576         Message::SendFail ("Syntax error: need more arguments");
9577         return 1;
9578       }
9579
9580       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9581       {
9582         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
9583         anArgIter += 1;
9584       }
9585     }
9586     else if (aChangeArg == "-color"
9587           || aChangeArg == "color")
9588     {
9589       Quantity_Color aColor;
9590       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
9591                                                      aChangeArgs + 1,
9592                                                      aColor);
9593       if (aNbParsed == 0)
9594       {
9595         Message::SendFail ("Syntax error: need more arguments");
9596         return 1;
9597       }
9598       aClipPlane->SetCappingColor (aColor);
9599       anArgIter += aNbParsed;
9600     }
9601     else if (aNbChangeArgs >= 1
9602           && (aChangeArg == "-material"
9603            || aChangeArg == "material"))
9604     {
9605       ++anArgIter;
9606       Graphic3d_NameOfMaterial aMatName;
9607       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
9608       {
9609         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
9610         return 1;
9611       }
9612       aClipPlane->SetCappingMaterial (aMatName);
9613     }
9614     else if ((aChangeArg == "-transparency"
9615            || aChangeArg == "-transp")
9616           && aNbChangeArgs >= 2)
9617     {
9618       TCollection_AsciiString aValStr (aChangeArgs[1]);
9619       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
9620       if (aValStr.IsRealValue (Standard_True))
9621       {
9622         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
9623         aMat.SetTransparency ((float )aValStr.RealValue());
9624         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
9625         aClipPlane->SetCappingMaterial (aMat);
9626       }
9627       else
9628       {
9629         aValStr.LowerCase();
9630         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
9631         if (aValStr == "opaque")
9632         {
9633           aMode = Graphic3d_AlphaMode_Opaque;
9634         }
9635         else if (aValStr == "mask")
9636         {
9637           aMode = Graphic3d_AlphaMode_Mask;
9638         }
9639         else if (aValStr == "blend")
9640         {
9641           aMode = Graphic3d_AlphaMode_Blend;
9642         }
9643         else if (aValStr == "blendauto")
9644         {
9645           aMode = Graphic3d_AlphaMode_BlendAuto;
9646         }
9647         else
9648         {
9649           Message::SendFail() << "Syntax error at '" << aValStr << "'";
9650           return 1;
9651         }
9652         anAspect->SetAlphaMode (aMode);
9653         aClipPlane->SetCappingAspect (anAspect);
9654       }
9655       anArgIter += 1;
9656     }
9657     else if (aChangeArg == "-texname"
9658           || aChangeArg == "texname")
9659     {
9660       if (aNbChangeArgs < 2)
9661       {
9662         Message::SendFail ("Syntax error: need more arguments");
9663         return 1;
9664       }
9665
9666       TCollection_AsciiString aTextureName (aChangeArgs[1]);
9667       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
9668       if (!aTexture->IsDone())
9669       {
9670         aClipPlane->SetCappingTexture (NULL);
9671       }
9672       else
9673       {
9674         aTexture->EnableModulate();
9675         aTexture->EnableRepeat();
9676         aClipPlane->SetCappingTexture (aTexture);
9677       }
9678       anArgIter += 1;
9679     }
9680     else if (aChangeArg == "-texscale"
9681           || aChangeArg == "texscale")
9682     {
9683       if (aClipPlane->CappingTexture().IsNull())
9684       {
9685         Message::SendFail ("Error: no texture is set");
9686         return 1;
9687       }
9688
9689       if (aNbChangeArgs < 3)
9690       {
9691         Message::SendFail ("Syntax error: need more arguments");
9692         return 1;
9693       }
9694
9695       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9696       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9697       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
9698       anArgIter += 2;
9699     }
9700     else if (aChangeArg == "-texorigin"
9701           || aChangeArg == "texorigin") // texture origin
9702     {
9703       if (aClipPlane->CappingTexture().IsNull())
9704       {
9705         Message::SendFail ("Error: no texture is set");
9706         return 1;
9707       }
9708
9709       if (aNbChangeArgs < 3)
9710       {
9711         Message::SendFail ("Syntax error: need more arguments");
9712         return 1;
9713       }
9714
9715       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9716       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9717
9718       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
9719       anArgIter += 2;
9720     }
9721     else if (aChangeArg == "-texrotate"
9722           || aChangeArg == "texrotate") // texture rotation
9723     {
9724       if (aClipPlane->CappingTexture().IsNull())
9725       {
9726         Message::SendFail ("Error: no texture is set");
9727         return 1;
9728       }
9729
9730       if (aNbChangeArgs < 2)
9731       {
9732         Message::SendFail ("Syntax error: need more arguments");
9733         return 1;
9734       }
9735
9736       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9737       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
9738       anArgIter += 1;
9739     }
9740     else if (aChangeArg == "-hatch"
9741           || aChangeArg == "hatch")
9742     {
9743       if (aNbChangeArgs < 2)
9744       {
9745         Message::SendFail ("Syntax error: need more arguments");
9746         return 1;
9747       }
9748
9749       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
9750       aHatchStr.LowerCase();
9751       if (aHatchStr == "on")
9752       {
9753         aClipPlane->SetCappingHatchOn();
9754       }
9755       else if (aHatchStr == "off")
9756       {
9757         aClipPlane->SetCappingHatchOff();
9758       }
9759       else
9760       {
9761         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
9762       }
9763       anArgIter += 1;
9764     }
9765     else if (aChangeArg == "-delete"
9766           || aChangeArg == "delete")
9767     {
9768       removePlane (aRegPlanes, aPlaneName);
9769       return 0;
9770     }
9771     else if (aChangeArg == "-set"
9772           || aChangeArg == "-unset"
9773           || aChangeArg == "-setoverrideglobal")
9774     {
9775       // set / unset plane command
9776       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
9777       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
9778       Standard_Integer anIt = 1;
9779       for (; anIt < aNbChangeArgs; ++anIt)
9780       {
9781         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
9782         if (anEntityName.IsEmpty()
9783          || anEntityName.Value (1) == '-')
9784         {
9785           break;
9786         }
9787         else if (!toOverrideGlobal
9788                && ViewerTest_myViews.IsBound1 (anEntityName))
9789         {
9790           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
9791           if (toSet)
9792           {
9793             aView->AddClipPlane (aClipPlane);
9794           }
9795           else
9796           {
9797             aView->RemoveClipPlane (aClipPlane);
9798           }
9799           continue;
9800         }
9801         else if (GetMapOfAIS().IsBound2 (anEntityName))
9802         {
9803           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
9804           if (toSet)
9805           {
9806             aIObj->AddClipPlane (aClipPlane);
9807           }
9808           else
9809           {
9810             aIObj->RemoveClipPlane (aClipPlane);
9811           }
9812           if (!aIObj->ClipPlanes().IsNull())
9813           {
9814             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
9815           }
9816         }
9817         else
9818         {
9819           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
9820           return 1;
9821         }
9822       }
9823
9824       if (anIt == 1)
9825       {
9826         // apply to active view
9827         if (toSet)
9828         {
9829           anActiveView->AddClipPlane (aClipPlane);
9830         }
9831         else
9832         {
9833           anActiveView->RemoveClipPlane (aClipPlane);
9834         }
9835       }
9836       else
9837       {
9838         anArgIter = anArgIter + anIt - 1;
9839       }
9840     }
9841     else
9842     {
9843       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9844       return 1;
9845     }
9846   }
9847
9848   ViewerTest::RedrawAllViews();
9849   return 0;
9850 }
9851
9852 //===============================================================================================
9853 //function : VZRange
9854 //purpose  :
9855 //===============================================================================================
9856 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9857 {
9858   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9859
9860   if (aCurrentView.IsNull())
9861   {
9862     Message::SendFail ("Error: no active viewer");
9863     return 1;
9864   }
9865
9866   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
9867
9868   if (theArgsNb < 2)
9869   {
9870     theDi << "ZNear: " << aCamera->ZNear() << "\n";
9871     theDi << "ZFar: " << aCamera->ZFar() << "\n";
9872     return 0;
9873   }
9874
9875   if (theArgsNb == 3)
9876   {
9877     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
9878     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
9879
9880     if (aNewZNear >= aNewZFar)
9881     {
9882       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
9883       return 1;
9884     }
9885
9886     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
9887     {
9888       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
9889       return 1;
9890     }
9891
9892     aCamera->SetZRange (aNewZNear, aNewZFar);
9893   }
9894   else
9895   {
9896     Message::SendFail ("Syntax error: wrong command arguments");
9897     return 1;
9898   }
9899
9900   aCurrentView->Redraw();
9901
9902   return 0;
9903 }
9904
9905 //===============================================================================================
9906 //function : VAutoZFit
9907 //purpose  :
9908 //===============================================================================================
9909 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9910 {
9911   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9912
9913   if (aCurrentView.IsNull())
9914   {
9915     Message::SendFail ("Error: no active viewer");
9916     return 1;
9917   }
9918
9919   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
9920
9921   if (theArgsNb > 3)
9922   {
9923     Message::SendFail ("Syntax error: wrong command arguments");
9924     return 1;
9925   }
9926
9927   if (theArgsNb < 2)
9928   {
9929     theDi << "Auto z-fit mode: \n"
9930           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
9931           << "Scale: " << aScale << "\n";
9932     return 0;
9933   }
9934
9935   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
9936
9937   if (theArgsNb >= 3)
9938   {
9939     aScale = Draw::Atoi (theArgVec[2]);
9940   }
9941
9942   aCurrentView->SetAutoZFitMode (isOn, aScale);
9943   aCurrentView->Redraw();
9944   return 0;
9945 }
9946
9947 //! Auxiliary function to print projection type
9948 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
9949 {
9950   switch (theProjType)
9951   {
9952     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
9953     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
9954     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
9955     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
9956     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
9957   }
9958   return "UNKNOWN";
9959 }
9960
9961 //===============================================================================================
9962 //function : VCamera
9963 //purpose  :
9964 //===============================================================================================
9965 static int VCamera (Draw_Interpretor& theDI,
9966                     Standard_Integer  theArgsNb,
9967                     const char**      theArgVec)
9968 {
9969   Handle(V3d_View) aView = ViewerTest::CurrentView();
9970   if (aView.IsNull())
9971   {
9972     Message::SendFail ("Error: no active viewer");
9973     return 1;
9974   }
9975
9976   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9977   if (theArgsNb < 2)
9978   {
9979     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
9980     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
9981     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
9982     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
9983     theDI << "Distance:   " << aCamera->Distance() << "\n";
9984     theDI << "IOD:        " << aCamera->IOD() << "\n";
9985     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
9986     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
9987     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
9988     return 0;
9989   }
9990
9991   TCollection_AsciiString aPrsName;
9992   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
9993   {
9994     Standard_CString        anArg = theArgVec[anArgIter];
9995     TCollection_AsciiString anArgCase (anArg);
9996     anArgCase.LowerCase();
9997     if (anArgCase == "-proj"
9998      || anArgCase == "-projection"
9999      || anArgCase == "-projtype"
10000      || anArgCase == "-projectiontype")
10001     {
10002       theDI << projTypeName (aCamera->ProjectionType()) << " ";
10003     }
10004     else if (anArgCase == "-ortho"
10005           || anArgCase == "-orthographic")
10006     {
10007       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
10008     }
10009     else if (anArgCase == "-persp"
10010           || anArgCase == "-perspective"
10011           || anArgCase == "-perspmono"
10012           || anArgCase == "-perspectivemono"
10013           || anArgCase == "-mono")
10014     {
10015       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10016     }
10017     else if (anArgCase == "-stereo"
10018           || anArgCase == "-stereoscopic"
10019           || anArgCase == "-perspstereo"
10020           || anArgCase == "-perspectivestereo")
10021     {
10022       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10023     }
10024     else if (anArgCase == "-left"
10025           || anArgCase == "-lefteye"
10026           || anArgCase == "-monoleft"
10027           || anArgCase == "-monolefteye"
10028           || anArgCase == "-perpsleft"
10029           || anArgCase == "-perpslefteye")
10030     {
10031       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
10032     }
10033     else if (anArgCase == "-right"
10034           || anArgCase == "-righteye"
10035           || anArgCase == "-monoright"
10036           || anArgCase == "-monorighteye"
10037           || anArgCase == "-perpsright")
10038     {
10039       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
10040     }
10041     else if (anArgCase == "-dist"
10042           || anArgCase == "-distance")
10043     {
10044       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10045       if (anArgValue != NULL
10046       && *anArgValue != '-')
10047       {
10048         ++anArgIter;
10049         aCamera->SetDistance (Draw::Atof (anArgValue));
10050         continue;
10051       }
10052       theDI << aCamera->Distance() << " ";
10053     }
10054     else if (anArgCase == "-iod")
10055     {
10056       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10057       if (anArgValue != NULL
10058       && *anArgValue != '-')
10059       {
10060         ++anArgIter;
10061         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
10062         continue;
10063       }
10064       theDI << aCamera->IOD() << " ";
10065     }
10066     else if (anArgCase == "-iodtype")
10067     {
10068       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10069       TCollection_AsciiString anValueCase (anArgValue);
10070       anValueCase.LowerCase();
10071       if (anValueCase == "abs"
10072        || anValueCase == "absolute")
10073       {
10074         ++anArgIter;
10075         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
10076         continue;
10077       }
10078       else if (anValueCase == "rel"
10079             || anValueCase == "relative")
10080       {
10081         ++anArgIter;
10082         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
10083         continue;
10084       }
10085       else if (*anArgValue != '-')
10086       {
10087         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
10088         return 1;
10089       }
10090       switch (aCamera->GetIODType())
10091       {
10092         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
10093         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
10094       }
10095     }
10096     else if (anArgCase == "-zfocus")
10097     {
10098       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10099       if (anArgValue != NULL
10100       && *anArgValue != '-')
10101       {
10102         ++anArgIter;
10103         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
10104         continue;
10105       }
10106       theDI << aCamera->ZFocus() << " ";
10107     }
10108     else if (anArgCase == "-zfocustype")
10109     {
10110       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10111       TCollection_AsciiString anValueCase (anArgValue);
10112       anValueCase.LowerCase();
10113       if (anValueCase == "abs"
10114        || anValueCase == "absolute")
10115       {
10116         ++anArgIter;
10117         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
10118         continue;
10119       }
10120       else if (anValueCase == "rel"
10121             || anValueCase == "relative")
10122       {
10123         ++anArgIter;
10124         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
10125         continue;
10126       }
10127       else if (*anArgValue != '-')
10128       {
10129         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
10130         return 1;
10131       }
10132       switch (aCamera->ZFocusType())
10133       {
10134         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
10135         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
10136       }
10137     }
10138     else if (anArgCase == "-lockzup"
10139           || anArgCase == "-turntable")
10140     {
10141       bool toLockUp = true;
10142       if (++anArgIter < theArgsNb
10143       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
10144       {
10145         --anArgIter;
10146       }
10147       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
10148     }
10149     else if (anArgCase == "-fov"
10150           || anArgCase == "-fovy"
10151           || anArgCase == "-fovx"
10152           || anArgCase == "-fov2d")
10153     {
10154       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10155       if (anArgValue != NULL
10156       && *anArgValue != '-')
10157       {
10158         ++anArgIter;
10159         if (anArgCase == "-fov2d")
10160         {
10161           aCamera->SetFOV2d (Draw::Atof (anArgValue));
10162         }
10163         else if (anArgCase == "-fovx")
10164         {
10165           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
10166         }
10167         else
10168         {
10169           aCamera->SetFOVy (Draw::Atof (anArgValue));
10170         }
10171         continue;
10172       }
10173       if (anArgCase == "-fov2d")
10174       {
10175         theDI << aCamera->FOV2d() << " ";
10176       }
10177       else if (anArgCase == "-fovx")
10178       {
10179         theDI << aCamera->FOVx() << " ";
10180       }
10181       else
10182       {
10183         theDI << aCamera->FOVy() << " ";
10184       }
10185     }
10186     else if (anArgIter + 1 < theArgsNb
10187           && anArgCase == "-xrpose")
10188     {
10189       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
10190       anXRArg.LowerCase();
10191       if (anXRArg == "base")
10192       {
10193         aCamera = aView->View()->BaseXRCamera();
10194       }
10195       else if (anXRArg == "head")
10196       {
10197         aCamera = aView->View()->PosedXRCamera();
10198       }
10199       else
10200       {
10201         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
10202         return 1;
10203       }
10204       if (aCamera.IsNull())
10205       {
10206         Message::SendFail() << "Error: undefined XR pose";
10207         return 0;
10208       }
10209       if (aView->AutoZFitMode())
10210       {
10211         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
10212         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
10213         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
10214       }
10215     }
10216     else if (aPrsName.IsEmpty()
10217          && !anArgCase.StartsWith ("-"))
10218     {
10219       aPrsName = anArg;
10220     }
10221     else
10222     {
10223       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
10224       return 1;
10225     }
10226   }
10227
10228   if (aPrsName.IsEmpty()
10229    || theArgsNb > 2)
10230   {
10231     aView->Redraw();
10232   }
10233
10234   if (!aPrsName.IsEmpty())
10235   {
10236     Handle(AIS_CameraFrustum) aCameraFrustum;
10237     if (GetMapOfAIS().IsBound2 (aPrsName))
10238     {
10239       // find existing object
10240       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
10241       if (aCameraFrustum.IsNull())
10242       {
10243         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
10244         return 1;
10245       }
10246     }
10247
10248     if (aCameraFrustum.IsNull())
10249     {
10250       aCameraFrustum = new AIS_CameraFrustum();
10251     }
10252     else
10253     {
10254       // not include displayed object of old camera frustum in the new one.
10255       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
10256       aView->ZFitAll();
10257     }
10258     aCameraFrustum->SetCameraFrustum (aCamera);
10259
10260     ViewerTest::Display (aPrsName, aCameraFrustum);
10261   }
10262
10263   return 0;
10264 }
10265
10266 //! Parse stereo output mode
10267 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
10268                                          Graphic3d_StereoMode& theMode)
10269 {
10270   TCollection_AsciiString aFlag (theArg);
10271   aFlag.LowerCase();
10272   if (aFlag == "quadbuffer")
10273   {
10274     theMode = Graphic3d_StereoMode_QuadBuffer;
10275   }
10276   else if (aFlag == "anaglyph")
10277   {
10278     theMode = Graphic3d_StereoMode_Anaglyph;
10279   }
10280   else if (aFlag == "row"
10281         || aFlag == "rowinterlaced")
10282   {
10283     theMode = Graphic3d_StereoMode_RowInterlaced;
10284   }
10285   else if (aFlag == "col"
10286         || aFlag == "colinterlaced"
10287         || aFlag == "columninterlaced")
10288   {
10289     theMode = Graphic3d_StereoMode_ColumnInterlaced;
10290   }
10291   else if (aFlag == "chess"
10292         || aFlag == "chessboard")
10293   {
10294     theMode = Graphic3d_StereoMode_ChessBoard;
10295   }
10296   else if (aFlag == "sbs"
10297         || aFlag == "sidebyside")
10298   {
10299     theMode = Graphic3d_StereoMode_SideBySide;
10300   }
10301   else if (aFlag == "ou"
10302         || aFlag == "overunder")
10303   {
10304     theMode = Graphic3d_StereoMode_OverUnder;
10305   }
10306   else if (aFlag == "pageflip"
10307         || aFlag == "softpageflip")
10308   {
10309     theMode = Graphic3d_StereoMode_SoftPageFlip;
10310   }
10311   else if (aFlag == "openvr"
10312         || aFlag == "vr")
10313   {
10314     theMode = Graphic3d_StereoMode_OpenVR;
10315   }
10316   else
10317   {
10318     return Standard_False;
10319   }
10320   return Standard_True;
10321 }
10322
10323 //! Parse anaglyph filter
10324 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
10325                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
10326 {
10327   TCollection_AsciiString aFlag (theArg);
10328   aFlag.LowerCase();
10329   if (aFlag == "redcyansimple")
10330   {
10331     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10332   }
10333   else if (aFlag == "redcyan"
10334         || aFlag == "redcyanoptimized")
10335   {
10336     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
10337   }
10338   else if (aFlag == "yellowbluesimple")
10339   {
10340     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
10341   }
10342   else if (aFlag == "yellowblue"
10343         || aFlag == "yellowblueoptimized")
10344   {
10345     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
10346   }
10347   else if (aFlag == "greenmagenta"
10348         || aFlag == "greenmagentasimple")
10349   {
10350     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
10351   }
10352   else
10353   {
10354     return Standard_False;
10355   }
10356   return Standard_True;
10357 }
10358
10359 //==============================================================================
10360 //function : VStereo
10361 //purpose  :
10362 //==============================================================================
10363
10364 static int VStereo (Draw_Interpretor& theDI,
10365                     Standard_Integer  theArgNb,
10366                     const char**      theArgVec)
10367 {
10368   Handle(V3d_View) aView = ViewerTest::CurrentView();
10369   if (theArgNb < 2)
10370   {
10371     if (aView.IsNull())
10372     {
10373       Message::SendFail ("Error: no active viewer");
10374       return 0;
10375     }
10376
10377     Standard_Boolean isActive = ViewerTest_myDefaultCaps.contextStereo;
10378     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
10379     if (isActive)
10380     {
10381       TCollection_AsciiString aMode;
10382       switch (aView->RenderingParams().StereoMode)
10383       {
10384         case Graphic3d_StereoMode_QuadBuffer       : aMode = "quadBuffer";       break;
10385         case Graphic3d_StereoMode_RowInterlaced    : aMode = "rowInterlaced";    break;
10386         case Graphic3d_StereoMode_ColumnInterlaced : aMode = "columnInterlaced"; break;
10387         case Graphic3d_StereoMode_ChessBoard       : aMode = "chessBoard";       break;
10388         case Graphic3d_StereoMode_SideBySide       : aMode = "sideBySide";       break;
10389         case Graphic3d_StereoMode_OverUnder        : aMode = "overUnder";        break;
10390         case Graphic3d_StereoMode_SoftPageFlip     : aMode = "softpageflip";     break;
10391         case Graphic3d_StereoMode_OpenVR           : aMode = "openVR";           break;
10392         case Graphic3d_StereoMode_Anaglyph  :
10393           aMode = "anaglyph";
10394           switch (aView->RenderingParams().AnaglyphFilter)
10395           {
10396             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
10397             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
10398             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
10399             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
10400             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
10401             default: break;
10402           }
10403         default: break;
10404       }
10405       theDI << "Mode " << aMode << "\n";
10406     }
10407     return 0;
10408   }
10409
10410   Handle(Graphic3d_Camera) aCamera;
10411   Graphic3d_RenderingParams*   aParams   = NULL;
10412   Graphic3d_StereoMode         aMode     = Graphic3d_StereoMode_QuadBuffer;
10413   if (!aView.IsNull())
10414   {
10415     aParams   = &aView->ChangeRenderingParams();
10416     aMode     = aParams->StereoMode;
10417     aCamera   = aView->Camera();
10418   }
10419
10420   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10421   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10422   {
10423     Standard_CString        anArg = theArgVec[anArgIter];
10424     TCollection_AsciiString aFlag (anArg);
10425     aFlag.LowerCase();
10426     if (anUpdateTool.parseRedrawMode (aFlag))
10427     {
10428       continue;
10429     }
10430     else if (aFlag == "0"
10431           || aFlag == "off")
10432     {
10433       if (++anArgIter < theArgNb)
10434       {
10435         Message::SendFail ("Error: wrong number of arguments");
10436         return 1;
10437       }
10438
10439       if (!aCamera.IsNull()
10440        &&  aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
10441       {
10442         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10443       }
10444       ViewerTest_myDefaultCaps.contextStereo = Standard_False;
10445       return 0;
10446     }
10447     else if (aFlag == "1"
10448           || aFlag == "on")
10449     {
10450       if (++anArgIter < theArgNb)
10451       {
10452         Message::SendFail ("Error: wrong number of arguments");
10453         return 1;
10454       }
10455
10456       if (!aCamera.IsNull())
10457       {
10458         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10459       }
10460       ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10461       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
10462       {
10463         return 0;
10464       }
10465     }
10466     else if (aFlag == "-reverse"
10467           || aFlag == "-reversed"
10468           || aFlag == "-swap")
10469     {
10470       Standard_Boolean toEnable = Standard_True;
10471       if (++anArgIter < theArgNb
10472       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10473       {
10474         --anArgIter;
10475       }
10476       aParams->ToReverseStereo = toEnable;
10477     }
10478     else if (aFlag == "-noreverse"
10479           || aFlag == "-noswap")
10480     {
10481       Standard_Boolean toDisable = Standard_True;
10482       if (++anArgIter < theArgNb
10483       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
10484       {
10485         --anArgIter;
10486       }
10487       aParams->ToReverseStereo = !toDisable;
10488     }
10489     else if (aFlag == "-mode"
10490           || aFlag == "-stereomode")
10491     {
10492       if (++anArgIter >= theArgNb
10493       || !parseStereoMode (theArgVec[anArgIter], aMode))
10494       {
10495         Message::SendFail() << "Syntax error at '" << anArg << "'";
10496         return 1;
10497       }
10498
10499       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10500       {
10501         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10502       }
10503     }
10504     else if (aFlag == "-anaglyph"
10505           || aFlag == "-anaglyphfilter")
10506     {
10507       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10508       if (++anArgIter >= theArgNb
10509       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
10510       {
10511         Message::SendFail() << "Syntax error at '" << anArg << "'";
10512         return 1;
10513       }
10514
10515       aMode = Graphic3d_StereoMode_Anaglyph;
10516       aParams->AnaglyphFilter = aFilter;
10517     }
10518     else if (parseStereoMode (anArg, aMode)) // short syntax
10519     {
10520       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10521       {
10522         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10523       }
10524     }
10525     else if (anArgIter + 1 < theArgNb
10526           && aFlag == "-hmdfov2d")
10527     {
10528       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
10529       if (aParams->HmdFov2d < 10.0f
10530        || aParams->HmdFov2d > 180.0f)
10531       {
10532         Message::SendFail() << "Error: FOV is out of range";
10533         return 1;
10534       }
10535     }
10536     else if (aFlag == "-mirror"
10537           || aFlag == "-mirrorcomposer")
10538     {
10539       Standard_Boolean toEnable = Standard_True;
10540       if (++anArgIter < theArgNb
10541       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10542       {
10543         --anArgIter;
10544       }
10545       aParams->ToMirrorComposer = toEnable;
10546     }
10547     else if (anArgIter + 1 < theArgNb
10548           && (aFlag == "-unitfactor"
10549            || aFlag == "-unitscale"))
10550     {
10551       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
10552     }
10553     else
10554     {
10555       Message::SendFail() << "Syntax error at '" << anArg << "'";
10556       return 1;
10557     }
10558   }
10559
10560   if (!aView.IsNull())
10561   {
10562     aParams->StereoMode = aMode;
10563     aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10564     if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
10565     {
10566       // initiate implicit continuous rendering
10567       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
10568     }
10569   }
10570   return 0;
10571 }
10572
10573 //===============================================================================================
10574 //function : VDefaults
10575 //purpose  :
10576 //===============================================================================================
10577 static int VDefaults (Draw_Interpretor& theDi,
10578                       Standard_Integer  theArgsNb,
10579                       const char**      theArgVec)
10580 {
10581   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
10582   if (aCtx.IsNull())
10583   {
10584     Message::SendFail ("Error: no active viewer");
10585     return 1;
10586   }
10587
10588   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
10589   if (theArgsNb < 2)
10590   {
10591     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
10592     {
10593       theDi << "DeflType:           relative\n"
10594             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
10595     }
10596     else
10597     {
10598       theDi << "DeflType:           absolute\n"
10599             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
10600     }
10601     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
10602     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
10603     return 0;
10604   }
10605
10606   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
10607   {
10608     TCollection_AsciiString anArg (theArgVec[anArgIter]);
10609     anArg.UpperCase();
10610     if (anArg == "-ABSDEFL"
10611      || anArg == "-ABSOLUTEDEFLECTION"
10612      || anArg == "-DEFL"
10613      || anArg == "-DEFLECTION")
10614     {
10615       if (++anArgIter >= theArgsNb)
10616       {
10617         Message::SendFail() << "Syntax error at " << anArg;
10618         return 1;
10619       }
10620       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
10621       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
10622     }
10623     else if (anArg == "-RELDEFL"
10624           || anArg == "-RELATIVEDEFLECTION"
10625           || anArg == "-DEVCOEFF"
10626           || anArg == "-DEVIATIONCOEFF"
10627           || anArg == "-DEVIATIONCOEFFICIENT")
10628     {
10629       if (++anArgIter >= theArgsNb)
10630       {
10631         Message::SendFail() << "Syntax error at " << anArg;
10632         return 1;
10633       }
10634       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
10635       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
10636     }
10637     else if (anArg == "-ANGDEFL"
10638           || anArg == "-ANGULARDEFL"
10639           || anArg == "-ANGULARDEFLECTION")
10640     {
10641       if (++anArgIter >= theArgsNb)
10642       {
10643         Message::SendFail() << "Syntax error at " << anArg;
10644         return 1;
10645       }
10646       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
10647     }
10648     else if (anArg == "-AUTOTR"
10649           || anArg == "-AUTOTRIANG"
10650           || anArg == "-AUTOTRIANGULATION")
10651     {
10652       ++anArgIter;
10653       bool toTurnOn = true;
10654       if (anArgIter >= theArgsNb
10655       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
10656       {
10657         Message::SendFail() << "Syntax error at '" << anArg << "'";
10658         return 1;
10659       }
10660       aDefParams->SetAutoTriangulation (toTurnOn);
10661     }
10662     else
10663     {
10664       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
10665       return 1;
10666     }
10667   }
10668
10669   return 0;
10670 }
10671
10672 //! Auxiliary method
10673 inline void addLight (const Handle(V3d_Light)& theLightNew,
10674                       const Graphic3d_ZLayerId theLayer,
10675                       const Standard_Boolean   theIsGlobal)
10676 {
10677   if (theLightNew.IsNull())
10678   {
10679     return;
10680   }
10681
10682   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10683   if (theLayer == Graphic3d_ZLayerId_UNKNOWN)
10684   {
10685     aViewer->AddLight (theLightNew);
10686     if (theIsGlobal)
10687     {
10688       aViewer->SetLightOn (theLightNew);
10689     }
10690     else
10691     {
10692       ViewerTest::CurrentView()->SetLightOn (theLightNew);
10693     }
10694   }
10695   else
10696   {
10697     Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (theLayer);
10698     if (aSettings.Lights().IsNull())
10699     {
10700       aSettings.SetLights (new Graphic3d_LightSet());
10701     }
10702     aSettings.Lights()->Add (theLightNew);
10703     aViewer->SetZLayerSettings (theLayer, aSettings);
10704   }
10705 }
10706
10707 //! Auxiliary method
10708 inline Standard_Integer getLightId (const TCollection_AsciiString& theArgNext)
10709 {
10710   TCollection_AsciiString anArgNextCase (theArgNext);
10711   anArgNextCase.UpperCase();
10712   if (anArgNextCase.Length() > 5
10713    && anArgNextCase.SubString (1, 5).IsEqual ("LIGHT"))
10714   {
10715     return theArgNext.SubString (6, theArgNext.Length()).IntegerValue();
10716   }
10717   else
10718   {
10719     return theArgNext.IntegerValue();
10720   }
10721 }
10722
10723 static Handle(AIS_LightSource) findLightPrs (const Handle(V3d_Light)& theLight,
10724                                              const bool theToShowErrors = true)
10725 {
10726   if (theLight.IsNull())
10727   {
10728     if (theToShowErrors)
10729     {
10730       Message::SendFail() << "Syntax error: no active light source to find presentation";
10731     }
10732     return Handle(AIS_LightSource)();
10733   }
10734
10735   Handle(AIS_InteractiveObject) anObject;
10736   GetMapOfAIS().Find2 (theLight->Name(), anObject);
10737   Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (anObject);
10738   if (aLightSource.IsNull())
10739   {
10740     if (theToShowErrors)
10741     {
10742       Message::SendFail() << "Syntax error: could not find '" << theLight->Name() << "' AIS object";
10743     }
10744   }
10745   return aLightSource;
10746 }
10747
10748 //===============================================================================================
10749 //function : VLight
10750 //purpose  :
10751 //===============================================================================================
10752 static int VLight (Draw_Interpretor& theDi,
10753                    Standard_Integer  theArgsNb,
10754                    const char**      theArgVec)
10755 {
10756   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
10757   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10758   if (aView.IsNull()
10759    || aViewer.IsNull())
10760   {
10761     Message::SendFail ("Error: no active viewer");
10762     return 1;
10763   }
10764
10765   Standard_Real anXYZ[3]   = {};
10766   Standard_Real anAtten[2] = {};
10767   if (theArgsNb < 2)
10768   {
10769     // print lights info
10770     Standard_Integer aLightId = 0;
10771     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
10772     {
10773       Handle(V3d_Light) aLight = aLightIter.Value();
10774       const Quantity_Color aColor = aLight->Color();
10775       theDi << "Light #" << aLightId
10776             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
10777             << " [" << aLight->GetId() << "]" << "\n";
10778       switch (aLight->Type())
10779       {
10780         case V3d_AMBIENT:
10781         {
10782           theDi << "  Type:       Ambient\n";
10783           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10784           break;
10785         }
10786         case V3d_DIRECTIONAL:
10787         {
10788           theDi << "  Type:       Directional\n";
10789           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10790           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10791           theDi << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
10792           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10793           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10794           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10795           break;
10796         }
10797         case V3d_POSITIONAL:
10798         {
10799           theDi << "  Type:       Positional\n";
10800           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10801           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10802           theDi << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
10803           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10804           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10805           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10806           aLight->Attenuation (anAtten[0], anAtten[1]);
10807           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10808           theDi << "  Range:      " << aLight->Range() << "\n";
10809           break;
10810         }
10811         case V3d_SPOT:
10812         {
10813           theDi << "  Type:       Spot\n";
10814           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10815           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10816           theDi << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
10817           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10818           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10819           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10820           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10821           aLight->Attenuation (anAtten[0], anAtten[1]);
10822           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10823           theDi << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n";
10824           theDi << "  Exponent:   " << aLight->Concentration() << "\n";
10825           theDi << "  Range:      " << aLight->Range() << "\n";
10826           break;
10827         }
10828         default:
10829         {
10830           theDi << "  Type:       UNKNOWN\n";
10831           break;
10832         }
10833       }
10834       theDi << "  Color:      " << aColor.Red() << ", " << aColor.Green() << ", " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
10835     }
10836   }
10837
10838   Handle(V3d_Light) aLightNew, aLightOld;
10839   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
10840   Standard_Boolean  isGlobal = Standard_True;
10841   Standard_Boolean  toCreate = Standard_False;
10842   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10843   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
10844   {
10845     Handle(V3d_Light) aLightCurr = aLightNew.IsNull() ? aLightOld : aLightNew;
10846
10847     TCollection_AsciiString aName, aValue;
10848     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
10849     TCollection_AsciiString anArgCase (anArg);
10850     anArgCase.UpperCase();
10851     if (anUpdateTool.parseRedrawMode (anArg))
10852     {
10853       continue;
10854     }
10855
10856     if (anArgCase.IsEqual ("NEW")
10857      || anArgCase.IsEqual ("ADD")
10858      || anArgCase.IsEqual ("CREATE")
10859      || anArgCase.IsEqual ("-NEW")
10860      || anArgCase.IsEqual ("-ADD")
10861      || anArgCase.IsEqual ("-CREATE"))
10862     {
10863       toCreate = Standard_True;
10864     }
10865     else if (anArgCase.IsEqual ("-LAYER")
10866           || anArgCase.IsEqual ("-ZLAYER"))
10867     {
10868       if (++anArgIt >= theArgsNb)
10869       {
10870         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10871         return 1;
10872       }
10873
10874       TCollection_AsciiString aValStr (theArgVec[anArgIt]);
10875       aValStr.LowerCase();
10876       if (aValStr == "default"
10877        || aValStr == "def")
10878       {
10879         aLayer = Graphic3d_ZLayerId_Default;
10880       }
10881       else if (aValStr == "top")
10882       {
10883         aLayer = Graphic3d_ZLayerId_Top;
10884       }
10885       else if (aValStr == "topmost")
10886       {
10887         aLayer = Graphic3d_ZLayerId_Topmost;
10888       }
10889       else if (aValStr == "toposd"
10890             || aValStr == "osd")
10891       {
10892         aLayer = Graphic3d_ZLayerId_TopOSD;
10893       }
10894       else if (aValStr == "botosd"
10895             || aValStr == "bottom")
10896       {
10897         aLayer = Graphic3d_ZLayerId_BotOSD;
10898       }
10899       else if (aValStr.IsIntegerValue())
10900       {
10901         aLayer = Draw::Atoi (theArgVec[anArgIt]);
10902       }
10903       else
10904       {
10905         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10906         return 1;
10907       }
10908     }
10909     else if (anArgCase.IsEqual ("GLOB")
10910           || anArgCase.IsEqual ("GLOBAL")
10911           || anArgCase.IsEqual ("-GLOB")
10912           || anArgCase.IsEqual ("-GLOBAL"))
10913     {
10914       isGlobal = Standard_True;
10915     }
10916     else if (anArgCase.IsEqual ("LOC")
10917           || anArgCase.IsEqual ("LOCAL")
10918           || anArgCase.IsEqual ("-LOC")
10919           || anArgCase.IsEqual ("-LOCAL"))
10920     {
10921       isGlobal = Standard_False;
10922     }
10923     else if (anArgCase.IsEqual ("DEF")
10924           || anArgCase.IsEqual ("DEFAULTS")
10925           || anArgCase.IsEqual ("-DEF")
10926           || anArgCase.IsEqual ("-DEFAULTS"))
10927     {
10928       toCreate = Standard_False;
10929       aViewer->SetDefaultLights();
10930     }
10931     else if (anArgCase.IsEqual ("CLR")
10932           || anArgCase.IsEqual ("CLEAR")
10933           || anArgCase.IsEqual ("-CLR")
10934           || anArgCase.IsEqual ("-CLEAR"))
10935     {
10936       toCreate = Standard_False;
10937
10938       TColStd_SequenceOfInteger aLayers;
10939       aViewer->GetAllZLayers (aLayers);
10940       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10941       {
10942         if (aLayeriter.Value() == aLayer
10943          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10944         {
10945           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10946           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10947           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10948           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10949           {
10950             break;
10951           }
10952         }
10953       }
10954
10955       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10956       {
10957         ViewerTest_DoubleMapOfInteractiveAndName aMap = GetMapOfAIS();
10958         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10959         {
10960           Handle(V3d_Light) aLight = aLightIter.Value();
10961           if (Handle(AIS_LightSource) aLightSourceDel = findLightPrs (aLight, false))
10962           {
10963             ViewerTest::GetAISContext()->Remove (aLightSourceDel, false);
10964             GetMapOfAIS().UnBind2 (aLight->Name());
10965           }
10966           aViewer->DelLight (aLight);
10967           aLightIter = aView->ActiveLightIterator();
10968         }
10969       }
10970     }
10971     else if (anArgCase.IsEqual ("AMB")
10972           || anArgCase.IsEqual ("AMBIENT")
10973           || anArgCase.IsEqual ("AMBLIGHT"))
10974     {
10975       if (!toCreate)
10976       {
10977         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10978         return 1;
10979       }
10980
10981       addLight (aLightNew, aLayer, isGlobal);
10982       toCreate  = Standard_False;
10983       aLightNew = new V3d_AmbientLight();
10984     }
10985     else if (anArgCase.IsEqual ("DIRECTIONAL")
10986           || anArgCase.IsEqual ("DIRLIGHT"))
10987     {
10988       if (!toCreate)
10989       {
10990         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10991         return 1;
10992       }
10993
10994       addLight (aLightNew, aLayer, isGlobal);
10995       toCreate  = Standard_False;
10996       aLightNew = new V3d_DirectionalLight();
10997     }
10998     else if (anArgCase.IsEqual ("SPOT")
10999           || anArgCase.IsEqual ("SPOTLIGHT"))
11000     {
11001       if (!toCreate)
11002       {
11003         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11004         return 1;
11005       }
11006
11007       addLight (aLightNew, aLayer, isGlobal);
11008       toCreate  = Standard_False;
11009       aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
11010     }
11011     else if (anArgCase.IsEqual ("POSLIGHT")
11012           || anArgCase.IsEqual ("POSITIONAL"))
11013     {
11014       if (!toCreate)
11015       {
11016         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11017         return 1;
11018       }
11019
11020       addLight (aLightNew, aLayer, isGlobal);
11021       toCreate  = Standard_False;
11022       aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
11023     }
11024     else if (anArgCase.IsEqual ("CHANGE")
11025           || anArgCase.IsEqual ("-CHANGE"))
11026     {
11027       if (++anArgIt >= theArgsNb)
11028       {
11029         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11030         return 1;
11031       }
11032
11033       addLight (aLightNew, aLayer, isGlobal);
11034       aLightNew.Nullify();
11035       const Standard_Integer aLightId = getLightId (theArgVec[anArgIt]);
11036       Standard_Integer aLightIt = 0;
11037       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
11038       {
11039         if (aLightIt == aLightId)
11040         {
11041           aLightOld = aLightIter.Value();
11042           break;
11043         }
11044       }
11045
11046       if (aLightOld.IsNull())
11047       {
11048         Message::SendFail() << "Error: Light " << theArgVec[anArgIt] << " is undefined";
11049         return 1;
11050       }
11051     }
11052     else if (anArgCase == "-DISPLAY"
11053           || anArgCase == "-DISP"
11054           || anArgCase == "-PRESENTATION"
11055           || anArgCase == "-PRS")
11056     {
11057       if (aLightCurr.IsNull())
11058       {
11059         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11060         return 1;
11061       }
11062
11063       TCollection_AsciiString aLightName = aLightCurr->Name();
11064       if (++anArgIt > theArgsNb
11065        && aLightName.IsEmpty())
11066       {
11067         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11068         return 1;
11069       }
11070       if (anArgIt < theArgsNb)
11071       {
11072         if (theArgVec[anArgIt][0] != '-')
11073         {
11074           aLightName = theArgVec[anArgIt];
11075           aLightCurr->SetName (aLightName);
11076         }
11077         else
11078         {
11079           --anArgIt;
11080         }
11081       }
11082       if (aLightName.IsEmpty())
11083       {
11084         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11085         return 1;
11086       }
11087       ViewerTest::Display (aLightName, new AIS_LightSource (aLightCurr), false);
11088     }
11089     else if (anArgCase == "DEL"
11090           || anArgCase == "DELETE"
11091           || anArgCase == "-DEL"
11092           || anArgCase == "-DELETE"
11093           || anArgCase == "-REMOVE")
11094     {
11095       Handle(V3d_Light) aLightDel;
11096       if (++anArgIt >= theArgsNb)
11097       {
11098         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11099         return 1;
11100       }
11101
11102       const TCollection_AsciiString anArgNext (theArgVec[anArgIt]);
11103       const Standard_Integer aLightDelId = getLightId (theArgVec[anArgIt]);
11104       Standard_Integer aLightIt = 0;
11105       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
11106       {
11107         aLightDel = aLightIter.Value();
11108         if (aLightIt == aLightDelId)
11109         {
11110           break;
11111         }
11112       }
11113       if (aLightDel.IsNull())
11114       {
11115         continue;
11116       }
11117
11118       TColStd_SequenceOfInteger aLayers;
11119       aViewer->GetAllZLayers (aLayers);
11120       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
11121       {
11122         if (aLayeriter.Value() == aLayer
11123          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
11124         {
11125           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
11126           if (!aSettings.Lights().IsNull())
11127           {
11128             aSettings.Lights()->Remove (aLightDel);
11129             if (aSettings.Lights()->IsEmpty())
11130             {
11131               aSettings.SetLights (Handle(Graphic3d_LightSet)());
11132             }
11133           }
11134           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
11135           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
11136           {
11137             break;
11138           }
11139         }
11140       }
11141
11142       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
11143       {
11144         if (Handle(AIS_LightSource) aLightSourceDel = findLightPrs (aLightDel, false))
11145         {
11146           ViewerTest::GetAISContext()->Remove (aLightSourceDel, false);
11147           GetMapOfAIS().UnBind2 (aLightDel->Name());
11148         }
11149         aViewer->DelLight (aLightDel);
11150       }
11151     }
11152     else if (anArgCase.IsEqual ("COLOR")
11153           || anArgCase.IsEqual ("COLOUR")
11154           || anArgCase.IsEqual ("-COLOR")
11155           || anArgCase.IsEqual ("-COLOUR"))
11156     {
11157       Quantity_Color aColor;
11158       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
11159                                                      theArgVec + anArgIt + 1,
11160                                                      aColor);
11161       anArgIt += aNbParsed;
11162       if (aNbParsed == 0
11163        || aLightCurr.IsNull())
11164       {
11165         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11166         return 1;
11167       }
11168       aLightCurr->SetColor (aColor);
11169     }
11170     else if (anArgCase == "POS"
11171           || anArgCase == "POSITION"
11172           || anArgCase == "-POS"
11173           || anArgCase == "-POSITION"
11174           || anArgCase == "-PRSPOSITION"
11175           || anArgCase == "-PRSPOS")
11176     {
11177       gp_XYZ aPosXYZ;
11178       if ((anArgIt + 3) >= theArgsNb
11179        || !parseXYZ (theArgVec + anArgIt + 1, aPosXYZ)
11180        || aLightCurr.IsNull())
11181       {
11182         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11183         return 1;
11184       }
11185
11186       anArgIt += 3;
11187       if (anArgCase == "-PRSPOSITION"
11188        || anArgCase == "-PRSPOS")
11189       {
11190         aLightCurr->SetDisplayPosition (aPosXYZ);
11191       }
11192       else
11193       {
11194         if (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11195          && aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11196         {
11197           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11198           return 1;
11199         }
11200
11201         aLightCurr->SetPosition (aPosXYZ);
11202       }
11203     }
11204     else if (anArgCase.IsEqual ("DIR")
11205           || anArgCase.IsEqual ("DIRECTION")
11206           || anArgCase.IsEqual ("-DIR")
11207           || anArgCase.IsEqual ("-DIRECTION"))
11208     {
11209       gp_XYZ aDirXYZ;
11210       if ((anArgIt + 3) >= theArgsNb
11211        || !parseXYZ (theArgVec + anArgIt + 1, aDirXYZ)
11212        || aLightCurr.IsNull()
11213        || (aLightCurr->Type() != Graphic3d_TOLS_DIRECTIONAL
11214         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11215       {
11216         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11217         return 1;
11218       }
11219
11220       anArgIt += 3;
11221       aLightCurr->SetDirection (gp_Dir (aDirXYZ));
11222     }
11223     else if (anArgCase.IsEqual ("SM")
11224           || anArgCase.IsEqual ("SMOOTHNESS")
11225           || anArgCase.IsEqual ("-SM")
11226           || anArgCase.IsEqual ("-SMOOTHNESS"))
11227     {
11228       if (++anArgIt >= theArgsNb
11229        || aLightCurr.IsNull())
11230       {
11231         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11232         return 1;
11233       }
11234
11235       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11236       if (Abs (aSmoothness) <= ShortRealEpsilon())
11237       {
11238         aLightCurr->SetIntensity (1.f);
11239       }
11240       else if (Abs (aLightCurr->Smoothness()) <= ShortRealEpsilon())
11241       {
11242         aLightCurr->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
11243       }
11244       else
11245       {
11246         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightCurr->Smoothness());
11247         aLightCurr->SetIntensity (aLightCurr->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
11248       }
11249
11250       if (aLightCurr->Type() == Graphic3d_TOLS_POSITIONAL)
11251       {
11252         aLightCurr->SetSmoothRadius (aSmoothness);
11253       }
11254       else if (aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11255       {
11256         aLightCurr->SetSmoothAngle (aSmoothness);
11257       }
11258     }
11259     else if (anArgCase.IsEqual ("INT")
11260           || anArgCase.IsEqual ("INTENSITY")
11261           || anArgCase.IsEqual ("-INT")
11262           || anArgCase.IsEqual ("-INTENSITY"))
11263     {
11264       if (++anArgIt >= theArgsNb
11265        || aLightCurr.IsNull())
11266       {
11267         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11268         return 1;
11269       }
11270
11271       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11272       aLightCurr->SetIntensity (aIntensity);
11273     }
11274     else if (anArgCase.IsEqual ("ANG")
11275           || anArgCase.IsEqual ("ANGLE")
11276           || anArgCase.IsEqual ("-ANG")
11277           || anArgCase.IsEqual ("-ANGLE"))
11278     {
11279       if (++anArgIt >= theArgsNb
11280        || aLightCurr.IsNull()
11281        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11282       {
11283         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11284         return 1;
11285       }
11286       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11287       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
11288       aLightCurr->SetAngle (anAngle);
11289     }
11290     else if (anArgCase.IsEqual ("CONSTATTEN")
11291           || anArgCase.IsEqual ("CONSTATTENUATION")
11292           || anArgCase.IsEqual ("-CONSTATTEN")
11293           || anArgCase.IsEqual ("-CONSTATTENUATION"))
11294     {
11295       if (++anArgIt >= theArgsNb
11296        || aLightCurr.IsNull()
11297        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11298         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11299       {
11300         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11301         return 1;
11302       }
11303
11304       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11305       anAtten[0] = Atof (theArgVec[anArgIt]);
11306       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11307     }
11308     else if (anArgCase.IsEqual ("LINATTEN")
11309           || anArgCase.IsEqual ("LINEARATTEN")
11310           || anArgCase.IsEqual ("LINEARATTENUATION")
11311           || anArgCase.IsEqual ("-LINATTEN")
11312           || anArgCase.IsEqual ("-LINEARATTEN")
11313           || anArgCase.IsEqual ("-LINEARATTENUATION"))
11314     {
11315       if (++anArgIt >= theArgsNb
11316        || aLightCurr.IsNull()
11317        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11318         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11319       {
11320         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11321         return 1;
11322       }
11323
11324       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11325       anAtten[1] = Atof (theArgVec[anArgIt]);
11326       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11327     }
11328     else if (anArgCase.IsEqual ("EXP")
11329           || anArgCase.IsEqual ("EXPONENT")
11330           || anArgCase.IsEqual ("SPOTEXP")
11331           || anArgCase.IsEqual ("SPOTEXPONENT")
11332           || anArgCase.IsEqual ("-EXP")
11333           || anArgCase.IsEqual ("-EXPONENT")
11334           || anArgCase.IsEqual ("-SPOTEXP")
11335           || anArgCase.IsEqual ("-SPOTEXPONENT"))
11336     {
11337       if (++anArgIt >= theArgsNb
11338        || aLightCurr.IsNull()
11339        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11340       {
11341         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11342         return 1;
11343       }
11344
11345       aLightCurr->SetConcentration ((Standard_ShortReal )Atof (theArgVec[anArgIt]));
11346     }
11347     else if (anArgCase.IsEqual("RANGE")
11348           || anArgCase.IsEqual("-RANGE"))
11349     {
11350       if (++anArgIt >= theArgsNb
11351        || aLightCurr.IsNull()
11352        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT
11353        || aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11354       {
11355         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11356         return 1;
11357       }
11358       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[anArgIt]));
11359       aLightCurr->SetRange (aRange);
11360     }
11361     else if (anArgCase.IsEqual ("HEAD")
11362           || anArgCase.IsEqual ("HEADLIGHT")
11363           || anArgCase.IsEqual ("-HEAD")
11364           || anArgCase.IsEqual ("-HEADLIGHT"))
11365     {
11366       if (aLightCurr.IsNull()
11367        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
11368       {
11369         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11370         return 1;
11371       }
11372
11373       Standard_Boolean isHeadLight = Standard_True;
11374       if (anArgIt + 1 < theArgsNb
11375        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
11376       {
11377         ++anArgIt;
11378       }
11379       aLightCurr->SetHeadlight (isHeadLight);
11380     }
11381     else if (anArgCase.IsEqual ("NAME")
11382           || anArgCase.IsEqual ("-NAME"))
11383     {
11384       if ((anArgIt + 1) >= theArgsNb
11385         || aLightCurr.IsNull())
11386       {
11387         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11388         return 1;
11389       }
11390       aName = theArgVec[++anArgIt];
11391       aLightCurr->SetName (aName);
11392     }
11393     else if (anArgCase == "-SHOWZOOMABLE"
11394           || anArgCase == "-PRSZOOMABLE"
11395           || anArgCase == "-ZOOMABLE")
11396     {
11397       if (aLightCurr.IsNull())
11398       {
11399         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11400         return 1;
11401       }
11402
11403       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11404       {
11405         const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
11406         aLightSource->SetZoomable (isZoomable);
11407       }
11408       else
11409       {
11410         return 1;
11411       }
11412     }
11413     else if (anArgCase == "-SHOWNAME"
11414           || anArgCase == "-PRSNAME")
11415     {
11416       if (aLightCurr.IsNull())
11417       {
11418         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11419         return 1;
11420       }
11421
11422       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11423       {
11424         const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
11425         aLightSource->SetDisplayName (toDisplay);
11426       }
11427       else
11428       {
11429         return 1;
11430       }
11431     }
11432     else if (anArgCase == "-SHOWRANGE"
11433           || anArgCase == "-PRSRANGE")
11434     {
11435       if (aLightCurr.IsNull()
11436       || (aLightCurr->Type() != Graphic3d_TOLS_SPOT
11437        && aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL))
11438       {
11439         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11440         return 1;
11441       }
11442
11443       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11444       {
11445         const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
11446         aLightSource->SetDisplayRange (toDisplay);
11447       }
11448       else
11449       {
11450         return 1;
11451       }
11452     }
11453     else if (anArgCase == "-SHOWSIZE"
11454           || anArgCase == "-PRSSIZE")
11455     {
11456       Standard_Real aSize = 0.0;
11457       if ((anArgIt + 1) >= theArgsNb
11458       || !Draw::ParseReal (theArgVec[anArgIt + 1], aSize)
11459       ||  aSize <= 0.0)
11460       {
11461         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11462         return 1;
11463       }
11464
11465       ++anArgIt;
11466       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11467       {
11468         aLightSource->SetSize (aSize);
11469       }
11470       else
11471       {
11472         return 1;
11473       }
11474     }
11475     else if (anArgCase.IsEqual ("-CASTSHADOW")
11476           || anArgCase.IsEqual ("-CASTSHADOWS")
11477           || anArgCase.IsEqual ("-SHADOWS"))
11478     {
11479       if (aLightCurr.IsNull()
11480        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
11481       {
11482         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11483         return 1;
11484       }
11485
11486       bool toCastShadows = true;
11487       if (anArgIt + 1 < theArgsNb
11488        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
11489       {
11490         ++anArgIt;
11491       }
11492       aLightCurr->SetCastShadows (toCastShadows);
11493     }
11494     else
11495     {
11496       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
11497     }
11498   }
11499
11500   addLight (aLightNew, aLayer, isGlobal);
11501
11502   struct LightPrsSort
11503   {
11504     bool operator() (const Handle(AIS_LightSource)& theLeft,
11505                      const Handle(AIS_LightSource)& theRight)
11506     {
11507       return theLeft->Light()->GetId() < theRight->Light()->GetId();
11508     }
11509   };
11510
11511   AIS_ListOfInteractive aPrsList;
11512   ViewerTest::GetAISContext()->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
11513   if (!aPrsList.IsEmpty())
11514   {
11515     // update light source presentations
11516     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
11517     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
11518     {
11519       if (Handle(AIS_LightSource) aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
11520       {
11521         aLightPrsVec.push_back (aLightPrs);
11522       }
11523     }
11524
11525     // sort objects by id as AIS_InteractiveContext stores them in unordered map
11526     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
11527
11528     Standard_Integer aTopStack = 0;
11529     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
11530     {
11531       Handle(AIS_LightSource) aLightPrs = *aPrsIter;
11532       if (!aLightPrs->TransformPersistence().IsNull()
11533         && aLightPrs->TransformPersistence()->IsTrihedronOr2d())
11534       {
11535         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs->Size();
11536         aLightPrs->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
11537         aTopStack += aPrsSize + aPrsSize / 2;
11538       }
11539       ViewerTest::GetAISContext()->Redisplay (aLightPrs, false);
11540       ViewerTest::GetAISContext()->SetTransformPersistence (aLightPrs, aLightPrs->TransformPersistence());
11541     }
11542   }
11543   return 0;
11544 }
11545
11546 //===============================================================================================
11547 //function : VPBREnvironment
11548 //purpose  :
11549 //===============================================================================================
11550 static int VPBREnvironment (Draw_Interpretor&,
11551                             Standard_Integer theArgsNb,
11552                             const char**     theArgVec)
11553 {
11554   if (theArgsNb > 2)
11555   {
11556     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
11557     return 1;
11558   }
11559
11560   Handle(V3d_View) aView = ViewerTest::CurrentView();
11561   if (aView.IsNull())
11562   {
11563     Message::SendFail ("Error: no active viewer");
11564     return 1;
11565   }
11566
11567   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
11568   anArg.LowerCase();
11569
11570   if (anArg == "-generate"
11571    || anArg == "-gen")
11572   {
11573     aView->GeneratePBREnvironment (Standard_True);
11574   }
11575   else if (anArg == "-clear")
11576   {
11577     aView->ClearPBREnvironment (Standard_True);
11578   }
11579   else
11580   {
11581     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
11582     return 1;
11583   }
11584
11585   return 0;
11586 }
11587
11588 //! Read Graphic3d_RenderingParams::PerfCounters flag.
11589 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
11590                                             Standard_Boolean& theToReset,
11591                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
11592                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
11593 {
11594   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
11595   TCollection_AsciiString aVal = theValue;
11596   Standard_Boolean toReverse = Standard_False;
11597   if (aVal == "none")
11598   {
11599     theToReset = Standard_True;
11600     return Standard_True;
11601   }
11602   else if (aVal.StartsWith ("-"))
11603   {
11604     toReverse = Standard_True;
11605     aVal = aVal.SubString (2, aVal.Length());
11606   }
11607   else if (aVal.StartsWith ("no"))
11608   {
11609     toReverse = Standard_True;
11610     aVal = aVal.SubString (3, aVal.Length());
11611   }
11612   else if (aVal.StartsWith ("+"))
11613   {
11614     aVal = aVal.SubString (2, aVal.Length());
11615   }
11616   else
11617   {
11618     theToReset = Standard_True;
11619   }
11620
11621   if (     aVal == "fps"
11622         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11623   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
11624   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
11625   else if (aVal == "structs"
11626         || aVal == "structures"
11627         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
11628   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
11629   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
11630   else if (aVal == "tris"
11631         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
11632   else if (aVal == "pnts"
11633         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
11634   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
11635   else if (aVal == "mem"
11636         || aVal == "gpumem"
11637         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
11638   else if (aVal == "skipimmediate"
11639         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
11640   else if (aVal == "frametime"
11641         || aVal == "frametimers"
11642         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
11643   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
11644   else if (aVal == "extended"
11645         || aVal == "verbose"
11646         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
11647   else if (aVal == "full"
11648         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
11649   else
11650   {
11651     return Standard_False;
11652   }
11653
11654   if (toReverse)
11655   {
11656     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
11657   }
11658   else
11659   {
11660     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
11661   }
11662   return Standard_True;
11663 }
11664
11665 //! Read Graphic3d_RenderingParams::PerfCounters flags.
11666 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
11667                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
11668 {
11669   TCollection_AsciiString aValue = theValue;
11670   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
11671   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
11672   Standard_Boolean toReset = Standard_False;
11673   for (;;)
11674   {
11675     Standard_Integer aSplitPos = aValue.Search ("|");
11676     if (aSplitPos <= 0)
11677     {
11678       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
11679       {
11680         return Standard_False;
11681       }
11682       if (toReset)
11683       {
11684         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
11685       }
11686       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
11687       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
11688       return Standard_True;
11689     }
11690
11691     if (aSplitPos > 1)
11692     {
11693       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
11694       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
11695       {
11696         return Standard_False;
11697       }
11698     }
11699     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
11700   }
11701 }
11702
11703 //=======================================================================
11704 //function : VRenderParams
11705 //purpose  : Enables/disables rendering features
11706 //=======================================================================
11707
11708 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
11709                                        Standard_Integer  theArgNb,
11710                                        const char**      theArgVec)
11711 {
11712   Handle(V3d_View) aView = ViewerTest::CurrentView();
11713   if (aView.IsNull())
11714   {
11715     Message::SendFail ("Error: no active viewer");
11716     return 1;
11717   }
11718
11719   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
11720   TCollection_AsciiString aCmdName (theArgVec[0]);
11721   aCmdName.LowerCase();
11722   if (aCmdName == "vraytrace")
11723   {
11724     if (theArgNb == 1)
11725     {
11726       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
11727       return 0;
11728     }
11729     else if (theArgNb == 2)
11730     {
11731       TCollection_AsciiString aValue (theArgVec[1]);
11732       aValue.LowerCase();
11733       if (aValue == "on"
11734        || aValue == "1")
11735       {
11736         aParams.Method = Graphic3d_RM_RAYTRACING;
11737         aView->Redraw();
11738         return 0;
11739       }
11740       else if (aValue == "off"
11741             || aValue == "0")
11742       {
11743         aParams.Method = Graphic3d_RM_RASTERIZATION;
11744         aView->Redraw();
11745         return 0;
11746       }
11747       else
11748       {
11749         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
11750         return 1;
11751       }
11752     }
11753     else
11754     {
11755       Message::SendFail ("Syntax error: wrong number of arguments");
11756       return 1;
11757     }
11758   }
11759
11760   if (theArgNb < 2)
11761   {
11762     theDI << "renderMode:  ";
11763     switch (aParams.Method)
11764     {
11765       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11766       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
11767     }
11768     theDI << "\n";
11769     theDI << "transparency:  ";
11770     switch (aParams.TransparencyMethod)
11771     {
11772       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
11773       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
11774                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
11775       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
11776                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
11777     }
11778     theDI << "\n";
11779     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
11780     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
11781     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
11782     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
11783     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
11784     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
11785     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
11786     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
11787     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
11788     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
11789     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
11790     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
11791     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
11792     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
11793     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
11794     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
11795     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
11796     theDI << "shadingModel: ";
11797     switch (aView->ShadingModel())
11798     {
11799       case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
11800       case Graphic3d_TOSM_UNLIT:     theDI << "unlit";     break;
11801       case Graphic3d_TOSM_FACET:     theDI << "flat";      break;
11802       case Graphic3d_TOSM_VERTEX:    theDI << "gouraud";   break;
11803       case Graphic3d_TOSM_FRAGMENT:  theDI << "phong";     break;
11804       case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
11805       case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
11806     }
11807     theDI << "\n";
11808     {
11809       theDI << "perfCounters:";
11810       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
11811       {
11812         theDI << " fps";
11813       }
11814       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
11815       {
11816         theDI << " cpu";
11817       }
11818       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
11819       {
11820         theDI << " structs";
11821       }
11822       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
11823       {
11824         theDI << " groups";
11825       }
11826       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
11827       {
11828         theDI << " arrays";
11829       }
11830       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
11831       {
11832         theDI << " tris";
11833       }
11834       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
11835       {
11836         theDI << " lines";
11837       }
11838       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
11839       {
11840         theDI << " pnts";
11841       }
11842       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
11843       {
11844         theDI << " gpumem";
11845       }
11846       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
11847       {
11848         theDI << " frameTime";
11849       }
11850       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
11851       {
11852         theDI << " skipimmediate";
11853       }
11854       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
11855       {
11856         theDI << " none";
11857       }
11858       theDI << "\n";
11859     }
11860     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
11861     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
11862     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
11863                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
11864                                                                                                                     "noUpdate") << "\n";
11865     theDI << "\n";
11866     return 0;
11867   }
11868
11869   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
11870   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
11871   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11872   {
11873     Standard_CString        anArg (theArgVec[anArgIter]);
11874     TCollection_AsciiString aFlag (anArg);
11875     aFlag.LowerCase();
11876     if (anUpdateTool.parseRedrawMode (aFlag))
11877     {
11878       continue;
11879     }
11880     else if (aFlag == "-echo"
11881           || aFlag == "-print")
11882     {
11883       toPrint = Standard_True;
11884       anUpdateTool.Invalidate();
11885     }
11886     else if (aFlag == "-reset")
11887     {
11888       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
11889     }
11890     else if (aFlag == "-sync"
11891           && (anArgIter + 1 < theArgNb))
11892     {
11893       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
11894       aSyncFlag.LowerCase();
11895       if (aSyncFlag == "default"
11896        || aSyncFlag == "defaults"
11897        || aSyncFlag == "viewer")
11898       {
11899         toSyncDefaults = true;
11900       }
11901       else if (aSyncFlag == "allviews"
11902             || aSyncFlag == "views")
11903       {
11904         toSyncAllViews = true;
11905       }
11906       else
11907       {
11908         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
11909         return 1;
11910       }
11911     }
11912     else if (aFlag == "-mode"
11913           || aFlag == "-rendermode"
11914           || aFlag == "-render_mode")
11915     {
11916       if (toPrint)
11917       {
11918         switch (aParams.Method)
11919         {
11920           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11921           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
11922         }
11923         continue;
11924       }
11925       else
11926       {
11927         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11928         return 1;
11929       }
11930     }
11931     else if (aFlag == "-ray"
11932           || aFlag == "-raytrace")
11933     {
11934       if (toPrint)
11935       {
11936         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
11937         continue;
11938       }
11939
11940       bool isRayTrace = true;
11941       if (anArgIter + 1 < theArgNb
11942        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
11943       {
11944         ++anArgIter;
11945       }
11946       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
11947     }
11948     else if (aFlag == "-rast"
11949           || aFlag == "-raster"
11950           || aFlag == "-rasterization")
11951     {
11952       if (toPrint)
11953       {
11954         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
11955         continue;
11956       }
11957
11958       bool isRaster = true;
11959       if (anArgIter + 1 < theArgNb
11960        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
11961       {
11962         ++anArgIter;
11963       }
11964       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
11965     }
11966     else if (aFlag == "-msaa")
11967     {
11968       if (toPrint)
11969       {
11970         theDI << aParams.NbMsaaSamples << " ";
11971         continue;
11972       }
11973       else if (++anArgIter >= theArgNb)
11974       {
11975         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11976         return 1;
11977       }
11978
11979       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11980       if (aNbSamples < 0)
11981       {
11982         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11983         return 1;
11984       }
11985       else
11986       {
11987         aParams.NbMsaaSamples = aNbSamples;
11988       }
11989     }
11990     else if (aFlag == "-linefeather"
11991           || aFlag == "-edgefeather"
11992           || aFlag == "-feather")
11993     {
11994       if (toPrint)
11995       {
11996         theDI << " " << aParams.LineFeather << " ";
11997         continue;
11998       }
11999       else if (++anArgIter >= theArgNb)
12000       {
12001         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12002         return 1;
12003       }
12004
12005       TCollection_AsciiString aParam = theArgVec[anArgIter];
12006       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
12007       if (aFeather <= 0.0f)
12008       {
12009         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
12010         return 1;
12011       }
12012       aParams.LineFeather = aFeather;
12013     }
12014     else if (aFlag == "-oit")
12015     {
12016       if (toPrint)
12017       {
12018         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
12019         {
12020           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
12021         }
12022         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
12023         {
12024           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
12025         }
12026         else
12027         {
12028           theDI << "off" << " ";
12029         }
12030         continue;
12031       }
12032       else if (++anArgIter >= theArgNb)
12033       {
12034         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12035         return 1;
12036       }
12037
12038       TCollection_AsciiString aParam = theArgVec[anArgIter];
12039       aParam.LowerCase();
12040       if (aParam == "peeling"
12041        || aParam == "peel")
12042       {
12043         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
12044         if (anArgIter + 1 < theArgNb
12045          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
12046         {
12047           ++anArgIter;
12048           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
12049           if (aNbLayers < 2)
12050           {
12051             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
12052             return 1;
12053           }
12054           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
12055         }
12056       }
12057       else if (aParam == "weighted"
12058             || aParam == "weight")
12059       {
12060         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
12061         if (anArgIter + 1 < theArgNb
12062          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
12063         {
12064           ++anArgIter;
12065           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
12066           if (aWeight < 0.f || aWeight > 1.f)
12067           {
12068             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
12069             return 1;
12070           }
12071           aParams.OitDepthFactor = aWeight;
12072         }
12073       }
12074       else if (aParam.IsRealValue())
12075       {
12076         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
12077         if (aWeight < 0.f || aWeight > 1.f)
12078         {
12079           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
12080           return 1;
12081         }
12082
12083         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
12084         aParams.OitDepthFactor     = aWeight;
12085       }
12086       else if (aParam == "off")
12087       {
12088         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
12089       }
12090       else
12091       {
12092         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12093         return 1;
12094       }
12095     }
12096     else if (aFlag == "-depthprepass")
12097     {
12098       if (toPrint)
12099       {
12100         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
12101         continue;
12102       }
12103       aParams.ToEnableDepthPrepass = Standard_True;
12104       if (anArgIter + 1 < theArgNb
12105        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
12106       {
12107         ++anArgIter;
12108       }
12109     }
12110     else if (aFlag == "-samplealphatocoverage"
12111           || aFlag == "-alphatocoverage")
12112     {
12113       if (toPrint)
12114       {
12115         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
12116         continue;
12117       }
12118       aParams.ToEnableAlphaToCoverage = Standard_True;
12119       if (anArgIter + 1 < theArgNb
12120        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
12121       {
12122         ++anArgIter;
12123       }
12124     }
12125     else if (aFlag == "-rendscale"
12126           || aFlag == "-renderscale"
12127           || aFlag == "-renderresolutionscale")
12128     {
12129       if (toPrint)
12130       {
12131         theDI << aParams.RenderResolutionScale << " ";
12132         continue;
12133       }
12134       else if (++anArgIter >= theArgNb)
12135       {
12136         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12137         return 1;
12138       }
12139
12140       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
12141       if (aScale < 0.01)
12142       {
12143         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
12144         return 1;
12145       }
12146       else
12147       {
12148         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
12149       }
12150     }
12151     else if (aFlag == "-raydepth"
12152           || aFlag == "-ray_depth")
12153     {
12154       if (toPrint)
12155       {
12156         theDI << aParams.RaytracingDepth << " ";
12157         continue;
12158       }
12159       else if (++anArgIter >= theArgNb)
12160       {
12161         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12162         return 1;
12163       }
12164
12165       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
12166
12167       // We allow RaytracingDepth be more than 10 in case of GI enabled
12168       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
12169       {
12170         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
12171         return 1;
12172       }
12173       else
12174       {
12175         aParams.RaytracingDepth = aDepth;
12176       }
12177     }
12178     else if (aFlag == "-shad"
12179           || aFlag == "-shadows")
12180     {
12181       if (toPrint)
12182       {
12183         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
12184         continue;
12185       }
12186
12187       Standard_Boolean toEnable = Standard_True;
12188       if (++anArgIter < theArgNb
12189       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12190       {
12191         --anArgIter;
12192       }
12193       aParams.IsShadowEnabled = toEnable;
12194     }
12195     else if (aFlag == "-shadowmapresolution"
12196           || aFlag == "-shadowmap")
12197     {
12198       if (toPrint)
12199       {
12200         theDI << aParams.ShadowMapResolution << " ";
12201         continue;
12202       }
12203       else if (++anArgIter >= theArgNb)
12204       {
12205         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12206         return 1;
12207       }
12208
12209       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
12210     }
12211     else if (aFlag == "-shadowmapbias")
12212     {
12213       if (toPrint)
12214       {
12215         theDI << aParams.ShadowMapBias << " ";
12216         continue;
12217       }
12218       else if (++anArgIter >= theArgNb)
12219       {
12220         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12221         return 1;
12222       }
12223
12224       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
12225     }
12226     else if (aFlag == "-refl"
12227           || aFlag == "-reflections")
12228     {
12229       if (toPrint)
12230       {
12231         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
12232         continue;
12233       }
12234
12235       Standard_Boolean toEnable = Standard_True;
12236       if (++anArgIter < theArgNb
12237       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12238       {
12239         --anArgIter;
12240       }
12241       aParams.IsReflectionEnabled = toEnable;
12242     }
12243     else if (aFlag == "-fsaa")
12244     {
12245       if (toPrint)
12246       {
12247         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
12248         continue;
12249       }
12250
12251       Standard_Boolean toEnable = Standard_True;
12252       if (++anArgIter < theArgNb
12253       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12254       {
12255         --anArgIter;
12256       }
12257       aParams.IsAntialiasingEnabled = toEnable;
12258     }
12259     else if (aFlag == "-gleam")
12260     {
12261       if (toPrint)
12262       {
12263         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
12264         continue;
12265       }
12266
12267       Standard_Boolean toEnable = Standard_True;
12268       if (++anArgIter < theArgNb
12269       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12270       {
12271         --anArgIter;
12272       }
12273       aParams.IsTransparentShadowEnabled = toEnable;
12274     }
12275     else if (aFlag == "-gi")
12276     {
12277       if (toPrint)
12278       {
12279         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
12280         continue;
12281       }
12282
12283       Standard_Boolean toEnable = Standard_True;
12284       if (++anArgIter < theArgNb
12285       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12286       {
12287         --anArgIter;
12288       }
12289       aParams.IsGlobalIlluminationEnabled = toEnable;
12290       if (!toEnable)
12291       {
12292         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
12293       }
12294     }
12295     else if (aFlag == "-blockedrng"
12296           || aFlag == "-brng")
12297     {
12298       if (toPrint)
12299       {
12300         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
12301         continue;
12302       }
12303
12304       Standard_Boolean toEnable = Standard_True;
12305       if (++anArgIter < theArgNb
12306         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12307       {
12308         --anArgIter;
12309       }
12310       aParams.CoherentPathTracingMode = toEnable;
12311     }
12312     else if (aFlag == "-maxrad")
12313     {
12314       if (toPrint)
12315       {
12316         theDI << aParams.RadianceClampingValue << " ";
12317         continue;
12318       }
12319       else if (++anArgIter >= theArgNb)
12320       {
12321         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12322         return 1;
12323       }
12324
12325       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
12326       if (!aMaxRadStr.IsRealValue (Standard_True))
12327       {
12328         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12329         return 1;
12330       }
12331
12332       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
12333       if (aMaxRadiance <= 0.0)
12334       {
12335         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
12336         return 1;
12337       }
12338       else
12339       {
12340         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
12341       }
12342     }
12343     else if (aFlag == "-iss")
12344     {
12345       if (toPrint)
12346       {
12347         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
12348         continue;
12349       }
12350
12351       Standard_Boolean toEnable = Standard_True;
12352       if (++anArgIter < theArgNb
12353         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12354       {
12355         --anArgIter;
12356       }
12357       aParams.AdaptiveScreenSampling = toEnable;
12358     }
12359     else if (aFlag == "-issatomic")
12360     {
12361       if (toPrint)
12362       {
12363         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
12364         continue;
12365       }
12366
12367       Standard_Boolean toEnable = Standard_True;
12368       if (++anArgIter < theArgNb
12369       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12370       {
12371         --anArgIter;
12372       }
12373       aParams.AdaptiveScreenSamplingAtomic = toEnable;
12374     }
12375     else if (aFlag == "-issd")
12376     {
12377       if (toPrint)
12378       {
12379         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
12380         continue;
12381       }
12382
12383       Standard_Boolean toEnable = Standard_True;
12384       if (++anArgIter < theArgNb
12385         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12386       {
12387         --anArgIter;
12388       }
12389       aParams.ShowSamplingTiles = toEnable;
12390     }
12391     else if (aFlag == "-tilesize")
12392     {
12393       if (toPrint)
12394       {
12395         theDI << aParams.RayTracingTileSize << " ";
12396         continue;
12397       }
12398       else if (++anArgIter >= theArgNb)
12399       {
12400         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12401         return 1;
12402       }
12403
12404       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
12405       if (aTileSize < 1)
12406       {
12407         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
12408         return 1;
12409       }
12410       aParams.RayTracingTileSize = aTileSize;
12411     }
12412     else if (aFlag == "-nbtiles")
12413     {
12414       if (toPrint)
12415       {
12416         theDI << aParams.NbRayTracingTiles << " ";
12417         continue;
12418       }
12419       else if (++anArgIter >= theArgNb)
12420       {
12421         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12422         return 1;
12423       }
12424
12425       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
12426       if (aNbTiles < -1)
12427       {
12428         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
12429         return 1;
12430       }
12431       else if (aNbTiles > 0
12432             && (aNbTiles < 64
12433              || aNbTiles > 1024))
12434       {
12435         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
12436       }
12437       aParams.NbRayTracingTiles = aNbTiles;
12438     }
12439     else if (aFlag == "-env")
12440     {
12441       if (toPrint)
12442       {
12443         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
12444         continue;
12445       }
12446
12447       Standard_Boolean toEnable = Standard_True;
12448       if (++anArgIter < theArgNb
12449         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12450       {
12451         --anArgIter;
12452       }
12453       aParams.UseEnvironmentMapBackground = toEnable;
12454     }
12455     else if (aFlag == "-ignorenormalmap")
12456     {
12457       if (toPrint)
12458       {
12459         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
12460         continue;
12461       }
12462
12463       Standard_Boolean toEnable = Standard_True;
12464       if (++anArgIter < theArgNb
12465         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12466       {
12467         --anArgIter;
12468       }
12469       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
12470     }
12471     else if (aFlag == "-twoside")
12472     {
12473       if (toPrint)
12474       {
12475         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
12476         continue;
12477       }
12478
12479       Standard_Boolean toEnable = Standard_True;
12480       if (++anArgIter < theArgNb
12481         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12482       {
12483         --anArgIter;
12484       }
12485       aParams.TwoSidedBsdfModels = toEnable;
12486     }
12487     else if (aFlag == "-shademodel"
12488           || aFlag == "-shadingmodel"
12489           || aFlag == "-shading")
12490     {
12491       if (toPrint)
12492       {
12493         switch (aView->ShadingModel())
12494         {
12495           case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
12496           case Graphic3d_TOSM_UNLIT:     theDI << "unlit ";    break;
12497           case Graphic3d_TOSM_FACET:     theDI << "flat ";     break;
12498           case Graphic3d_TOSM_VERTEX:    theDI << "gouraud ";  break;
12499           case Graphic3d_TOSM_FRAGMENT:  theDI << "phong ";    break;
12500           case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
12501           case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
12502         }
12503         continue;
12504       }
12505
12506       if (++anArgIter >= theArgNb)
12507       {
12508         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12509       }
12510
12511       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TOSM_DEFAULT;
12512       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
12513        && aModel != Graphic3d_TOSM_DEFAULT)
12514       {
12515         aView->SetShadingModel (aModel);
12516       }
12517       else
12518       {
12519         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
12520         return 1;
12521       }
12522     }
12523     else if (aFlag == "-pbrenvpow2size"
12524           || aFlag == "-pbrenvp2s"
12525           || aFlag == "-pep2s")
12526     {
12527       if (++anArgIter >= theArgNb)
12528       {
12529         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12530         return 1;
12531       }
12532
12533       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
12534       if (aPbrEnvPow2Size < 1)
12535       {
12536         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
12537         return 1;
12538       }
12539       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
12540     }
12541     else if (aFlag == "-pbrenvspecmaplevelsnumber"
12542           || aFlag == "-pbrenvspecmapnblevels"
12543           || aFlag == "-pbrenvspecmaplevels"
12544           || aFlag == "-pbrenvsmln"
12545           || aFlag == "-pesmln")
12546     {
12547       if (++anArgIter >= theArgNb)
12548       {
12549         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12550         return 1;
12551       }
12552
12553       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
12554       if (aPbrEnvSpecMapNbLevels < 2)
12555       {
12556         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
12557         return 1;
12558       }
12559       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
12560     }
12561     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
12562           || aFlag == "-pbrenvbakingdiffsamples"
12563           || aFlag == "-pbrenvbdsn")
12564     {
12565       if (++anArgIter >= theArgNb)
12566       {
12567         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12568         return 1;
12569       }
12570
12571       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
12572       if (aPbrEnvBakingDiffNbSamples < 1)
12573       {
12574         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
12575         return 1;
12576       }
12577       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
12578     }
12579     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
12580           || aFlag == "-pbrenvbakingspecsamples"
12581           || aFlag == "-pbrenvbssn")
12582     {
12583     if (++anArgIter >= theArgNb)
12584     {
12585       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12586       return 1;
12587     }
12588
12589     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
12590     if (aPbrEnvBakingSpecNbSamples < 1)
12591     {
12592       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
12593       return 1;
12594     }
12595     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
12596     }
12597     else if (aFlag == "-pbrenvbakingprobability"
12598           || aFlag == "-pbrenvbp")
12599     {
12600       if (++anArgIter >= theArgNb)
12601       {
12602         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12603         return 1;
12604       }
12605       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
12606       if (aPbrEnvBakingProbability < 0.f
12607        || aPbrEnvBakingProbability > 1.f)
12608       {
12609         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
12610         return 1;
12611       }
12612       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
12613     }
12614     else if (aFlag == "-resolution")
12615     {
12616       if (++anArgIter >= theArgNb)
12617       {
12618         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12619         return 1;
12620       }
12621
12622       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
12623       if (aResolution.IsIntegerValue())
12624       {
12625         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
12626       }
12627       else
12628       {
12629         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
12630         return 1;
12631       }
12632     }
12633     else if (aFlag == "-rebuildglsl"
12634           || aFlag == "-rebuild")
12635     {
12636       if (toPrint)
12637       {
12638         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
12639         continue;
12640       }
12641
12642       Standard_Boolean toEnable = Standard_True;
12643       if (++anArgIter < theArgNb
12644           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12645       {
12646         --anArgIter;
12647       }
12648       aParams.RebuildRayTracingShaders = toEnable;
12649     }
12650     else if (aFlag == "-focal")
12651     {
12652       if (++anArgIter >= theArgNb)
12653       {
12654         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12655         return 1;
12656       }
12657
12658       TCollection_AsciiString aParam (theArgVec[anArgIter]);
12659       if (aParam.IsRealValue (Standard_True))
12660       {
12661         float aFocalDist = static_cast<float> (aParam.RealValue());
12662         if (aFocalDist < 0)
12663         {
12664           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12665           return 1;
12666         }
12667         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
12668       }
12669       else
12670       {
12671         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12672         return 1;
12673       }
12674     }
12675     else if (aFlag == "-aperture")
12676     {
12677       if (++anArgIter >= theArgNb)
12678       {
12679         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12680         return 1;
12681       }
12682
12683       TCollection_AsciiString aParam(theArgVec[anArgIter]);
12684       if (aParam.IsRealValue (Standard_True))
12685       {
12686         float aApertureSize = static_cast<float> (aParam.RealValue());
12687         if (aApertureSize < 0)
12688         {
12689           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12690           return 1;
12691         }
12692         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
12693       }
12694       else
12695       {
12696         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12697         return 1;
12698       }
12699     }
12700     else if (aFlag == "-exposure")
12701     {
12702       if (++anArgIter >= theArgNb)
12703       {
12704         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12705         return 1;
12706       }
12707
12708       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
12709       if (anExposure.IsRealValue (Standard_True))
12710       {
12711         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
12712       }
12713       else
12714       {
12715         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12716         return 1;
12717       }
12718     }
12719     else if (aFlag == "-whitepoint")
12720     {
12721       if (++anArgIter >= theArgNb)
12722       {
12723         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12724         return 1;
12725       }
12726
12727       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
12728       if (aWhitePoint.IsRealValue (Standard_True))
12729       {
12730         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
12731       }
12732       else
12733       {
12734         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12735         return 1;
12736       }
12737     }
12738     else if (aFlag == "-tonemapping")
12739     {
12740       if (++anArgIter >= theArgNb)
12741       {
12742         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12743         return 1;
12744       }
12745
12746       TCollection_AsciiString aMode (theArgVec[anArgIter]);
12747       aMode.LowerCase();
12748
12749       if (aMode == "disabled")
12750       {
12751         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
12752       }
12753       else if (aMode == "filmic")
12754       {
12755         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
12756       }
12757       else
12758       {
12759         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12760         return 1;
12761       }
12762     }
12763     else if (aFlag == "-performancestats"
12764           || aFlag == "-performancecounters"
12765           || aFlag == "-perfstats"
12766           || aFlag == "-perfcounters"
12767           || aFlag == "-stats")
12768     {
12769       if (++anArgIter >= theArgNb)
12770       {
12771         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12772         return 1;
12773       }
12774
12775       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
12776       aFlagsStr.LowerCase();
12777       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
12778       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
12779       {
12780         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12781         return 1;
12782       }
12783       aView->ChangeRenderingParams().CollectedStats = aFlags;
12784       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
12785     }
12786     else if (aFlag == "-perfupdateinterval"
12787           || aFlag == "-statsupdateinterval")
12788     {
12789       if (++anArgIter >= theArgNb)
12790       {
12791         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12792         return 1;
12793       }
12794       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12795     }
12796     else if (aFlag == "-perfchart"
12797           || aFlag == "-statschart")
12798     {
12799       if (++anArgIter >= theArgNb)
12800       {
12801         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12802         return 1;
12803       }
12804       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
12805     }
12806     else if (aFlag == "-perfchartmax"
12807           || aFlag == "-statschartmax")
12808     {
12809       if (++anArgIter >= theArgNb)
12810       {
12811         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12812         return 1;
12813       }
12814       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12815     }
12816     else if (aFlag == "-frustumculling"
12817           || aFlag == "-culling")
12818     {
12819       if (toPrint)
12820       {
12821         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
12822                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
12823                                                                                                    "noUpdate") << " ";
12824         continue;
12825       }
12826
12827       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
12828       if (++anArgIter < theArgNb)
12829       {
12830         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
12831         aStateStr.LowerCase();
12832         bool toEnable = true;
12833         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
12834         {
12835           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
12836         }
12837         else if (aStateStr == "noupdate"
12838               || aStateStr == "freeze")
12839         {
12840           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
12841         }
12842         else
12843         {
12844           --anArgIter;
12845         }
12846       }
12847       aParams.FrustumCullingState = aState;
12848     }
12849     else
12850     {
12851       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
12852       return 1;
12853     }
12854   }
12855
12856   // set current view parameters as defaults
12857   if (toSyncDefaults)
12858   {
12859     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
12860   }
12861   if (toSyncAllViews)
12862   {
12863     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
12864     {
12865       aViewIter.Value()->ChangeRenderingParams() = aParams;
12866     }
12867   }
12868   return 0;
12869 }
12870
12871 //=======================================================================
12872 //function : searchInfo
12873 //purpose  :
12874 //=======================================================================
12875 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12876                                            const TCollection_AsciiString&              theKey)
12877 {
12878   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12879   {
12880     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12881     {
12882       return anIter.Value();
12883     }
12884   }
12885   return TCollection_AsciiString();
12886 }
12887
12888 //=======================================================================
12889 //function : VStatProfiler
12890 //purpose  :
12891 //=======================================================================
12892 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12893                                        Standard_Integer  theArgNb,
12894                                        const char**      theArgVec)
12895 {
12896   Handle(V3d_View) aView = ViewerTest::CurrentView();
12897   if (aView.IsNull())
12898   {
12899     Message::SendFail ("Error: no active viewer");
12900     return 1;
12901   }
12902
12903   Standard_Boolean toRedraw = Standard_True;
12904   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12905   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12906   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12907   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12908   {
12909     Standard_CString        anArg (theArgVec[anArgIter]);
12910     TCollection_AsciiString aFlag (anArg);
12911     aFlag.LowerCase();
12912     if (aFlag == "-noredraw")
12913     {
12914       toRedraw = Standard_False;
12915     }
12916     else
12917     {
12918       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12919       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12920       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12921       else if (aFlag == "alllayers"
12922             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12923       else if (aFlag == "allstructs"
12924             || aFlag == "allstructures"
12925             || aFlag == "structs"
12926             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12927       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12928       else if (aFlag == "allarrays"
12929             || aFlag == "fillarrays"
12930             || aFlag == "linearrays"
12931             || aFlag == "pointarrays"
12932             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12933       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12934       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12935       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12936       else if (aFlag == "geommem"
12937             || aFlag == "texturemem"
12938             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12939       else if (aFlag == "elapsedframe"
12940             || aFlag == "cpuframeaverage"
12941             || aFlag == "cpupickingaverage"
12942             || aFlag == "cpucullingaverage"
12943             || aFlag == "cpudynaverage"
12944             || aFlag == "cpuframemax"
12945             || aFlag == "cpupickingmax"
12946             || aFlag == "cpucullingmax"
12947             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12948       else
12949       {
12950         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12951         continue;
12952       }
12953
12954       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12955     }
12956   }
12957
12958   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12959   {
12960     aView->ChangeRenderingParams().CollectedStats =
12961       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12962
12963     if (toRedraw)
12964     {
12965       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12966       aView->Redraw();
12967       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12968     }
12969
12970     TColStd_IndexedDataMapOfStringString aDict;
12971     aView->StatisticInformation (aDict);
12972
12973     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12974
12975     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12976     {
12977       Standard_CString        anArg(theArgVec[anArgIter]);
12978       TCollection_AsciiString aFlag(anArg);
12979       aFlag.LowerCase();
12980       if (aFlag == "fps")
12981       {
12982         theDI << searchInfo (aDict, "FPS") << " ";
12983       }
12984       else if (aFlag == "cpu")
12985       {
12986         theDI << searchInfo (aDict, "CPU FPS") << " ";
12987       }
12988       else if (aFlag == "alllayers")
12989       {
12990         theDI << searchInfo (aDict, "Layers") << " ";
12991       }
12992       else if (aFlag == "layers")
12993       {
12994         theDI << searchInfo (aDict, "Rendered layers") << " ";
12995       }
12996       else if (aFlag == "allstructs"
12997             || aFlag == "allstructures")
12998       {
12999         theDI << searchInfo (aDict, "Structs") << " ";
13000       }
13001       else if (aFlag == "structs"
13002             || aFlag == "structures")
13003       {
13004         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
13005         if (aRend.IsEmpty()) // all structures rendered
13006         {
13007           aRend = searchInfo (aDict, "Structs");
13008         }
13009         theDI << aRend << " ";
13010       }
13011       else if (aFlag == "groups")
13012       {
13013         theDI << searchInfo (aDict, "Rendered groups") << " ";
13014       }
13015       else if (aFlag == "allarrays")
13016       {
13017         theDI << searchInfo (aDict, "Rendered arrays") << " ";
13018       }
13019       else if (aFlag == "fillarrays")
13020       {
13021         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
13022       }
13023       else if (aFlag == "linearrays")
13024       {
13025         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
13026       }
13027       else if (aFlag == "pointarrays")
13028       {
13029         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
13030       }
13031       else if (aFlag == "textarrays")
13032       {
13033         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
13034       }
13035       else if (aFlag == "triangles")
13036       {
13037         theDI << searchInfo (aDict, "Rendered triangles") << " ";
13038       }
13039       else if (aFlag == "points")
13040       {
13041         theDI << searchInfo (aDict, "Rendered points") << " ";
13042       }
13043       else if (aFlag == "geommem")
13044       {
13045         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
13046       }
13047       else if (aFlag == "texturemem")
13048       {
13049         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
13050       }
13051       else if (aFlag == "framemem")
13052       {
13053         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
13054       }
13055       else if (aFlag == "elapsedframe")
13056       {
13057         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
13058       }
13059       else if (aFlag == "cpuframe_average")
13060       {
13061         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
13062       }
13063       else if (aFlag == "cpupicking_average")
13064       {
13065         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
13066       }
13067       else if (aFlag == "cpuculling_average")
13068       {
13069         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
13070       }
13071       else if (aFlag == "cpudyn_average")
13072       {
13073         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
13074       }
13075       else if (aFlag == "cpuframe_max")
13076       {
13077         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
13078       }
13079       else if (aFlag == "cpupicking_max")
13080       {
13081         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
13082       }
13083       else if (aFlag == "cpuculling_max")
13084       {
13085         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
13086       }
13087       else if (aFlag == "cpudyn_max")
13088       {
13089         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
13090       }
13091     }
13092   }
13093   else
13094   {
13095     if (toRedraw)
13096     {
13097       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
13098       aView->Redraw();
13099       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
13100     }
13101     theDI << "Statistic info:\n" << aView->StatisticInformation();
13102   }
13103   return 0;
13104 }
13105
13106 //=======================================================================
13107 //function : VXRotate
13108 //purpose  :
13109 //=======================================================================
13110 static Standard_Integer VXRotate (Draw_Interpretor& di,
13111                                    Standard_Integer argc,
13112                                    const char ** argv)
13113 {
13114   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
13115   if (aContext.IsNull())
13116   {
13117     di << argv[0] << "ERROR : use 'vinit' command before \n";
13118     return 1;
13119   }
13120
13121   if (argc != 3)
13122   {
13123     di << "ERROR : Usage : " << argv[0] << " name angle\n";
13124     return 1;
13125   }
13126
13127   TCollection_AsciiString aName (argv[1]);
13128   Standard_Real anAngle = Draw::Atof (argv[2]);
13129
13130   // find object
13131   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
13132   Handle(AIS_InteractiveObject) anIObj;
13133   if (!aMap.Find2 (aName, anIObj))
13134   {
13135     di << "Use 'vdisplay' before\n";
13136     return 1;
13137   }
13138
13139   gp_Trsf aTransform;
13140   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
13141   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
13142
13143   aContext->SetLocation (anIObj, aTransform);
13144   aContext->UpdateCurrentViewer();
13145   return 0;
13146 }
13147
13148 namespace
13149 {
13150   //! Structure for setting AIS_Manipulator::SetPart() property.
13151   struct ManipAxisModeOnOff
13152   {
13153     Standard_Integer    Axis;
13154     AIS_ManipulatorMode Mode;
13155     Standard_Boolean    ToEnable;
13156
13157     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
13158   };
13159
13160   enum ManipAjustPosition
13161   {
13162     ManipAjustPosition_Off,
13163     ManipAjustPosition_Center,
13164     ManipAjustPosition_Location,
13165     ManipAjustPosition_ShapeLocation,
13166   };
13167 }
13168
13169 //===============================================================================================
13170 //function : VManipulator
13171 //purpose  :
13172 //===============================================================================================
13173 static int VManipulator (Draw_Interpretor& theDi,
13174                          Standard_Integer  theArgsNb,
13175                          const char**      theArgVec)
13176 {
13177   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
13178   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
13179   if (aCurrentView.IsNull()
13180    || aViewer.IsNull())
13181   {
13182     Message::SendFail ("Error: no active viewer");
13183     return 1;
13184   }
13185
13186   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
13187   Standard_Integer anArgIter = 1;
13188   Handle(AIS_Manipulator) aManipulator;
13189   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
13190   TCollection_AsciiString aName;
13191   // parameters
13192   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
13193   Standard_Real aGap = -1.0, aSize = -1.0;
13194   NCollection_Sequence<ManipAxisModeOnOff> aParts;
13195   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
13196   //
13197   bool toDetach = false;
13198   AIS_Manipulator::OptionsForAttach anAttachOptions;
13199   Handle(AIS_InteractiveObject) anAttachObject;
13200   Handle(V3d_View) aViewAffinity;
13201   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
13202   //
13203   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
13204   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
13205   Standard_Integer toStopMouseTransform = -1;
13206   // explicit transformation
13207   gp_Trsf aTrsf;
13208   gp_XYZ aTmpXYZ;
13209   Standard_Real aTmpReal = 0.0;
13210   gp_XYZ aRotPnt, aRotAxis;
13211   for (; anArgIter < theArgsNb; ++anArgIter)
13212   {
13213     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13214     anArg.LowerCase();
13215     if (anUpdateTool.parseRedrawMode (anArg))
13216     {
13217       continue;
13218     }
13219     else if (anArg == "-help")
13220     {
13221       theDi.PrintHelp (theArgVec[0]);
13222       return 0;
13223     }
13224     //
13225     else if (anArg == "-autoactivate"
13226           || anArg == "-noautoactivate")
13227     {
13228       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13229     }
13230     else if (anArg == "-followtranslation"
13231           || anArg == "-nofollowtranslation")
13232     {
13233       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13234     }
13235     else if (anArg == "-followrotation"
13236           || anArg == "-nofollowrotation")
13237     {
13238       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13239     }
13240     else if (anArg == "-followdragging"
13241           || anArg == "-nofollowdragging")
13242     {
13243       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13244     }
13245     else if (anArg == "-gap"
13246           && anArgIter + 1 < theArgsNb
13247           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
13248           && aGap >= 0.0)
13249     {
13250       ++anArgIter;
13251     }
13252     else if (anArg == "-size"
13253           && anArgIter + 1 < theArgsNb
13254           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
13255           && aSize > 0.0)
13256     {
13257       ++anArgIter;
13258     }
13259     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
13260           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
13261     {
13262       ManipAxisModeOnOff aPart;
13263       Standard_Integer aMode = 0;
13264       if (anArg == "-part")
13265       {
13266         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
13267           || aPart.Axis < 0 || aPart.Axis > 3)
13268         {
13269           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
13270           return 1;
13271         }
13272       }
13273       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
13274         || aMode < 1 || aMode > 4)
13275       {
13276         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
13277         return 1;
13278       }
13279       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
13280       {
13281         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
13282         return 1;
13283       }
13284       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
13285       aParts.Append (aPart);
13286     }
13287     else if (anArg == "-pos"
13288           && anArgIter + 3 < theArgsNb
13289           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
13290     {
13291       anArgIter += 3;
13292       if (anArgIter + 3 < theArgsNb
13293        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
13294        && aVDir.Modulus() > Precision::Confusion())
13295       {
13296         anArgIter += 3;
13297       }
13298       if (anArgIter + 3 < theArgsNb
13299        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
13300        && anXDir.Modulus() > Precision::Confusion())
13301       {
13302         anArgIter += 3;
13303       }
13304     }
13305     else if (anArg == "-zoomable"
13306           || anArg == "-notzoomable")
13307     {
13308       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13309     }
13310     //
13311     else if (anArg == "-adjustposition"
13312           || anArg == "-noadjustposition")
13313     {
13314       anAttachPos = ManipAjustPosition_Center;
13315       if (anArgIter + 1 < theArgsNb)
13316       {
13317         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
13318         aPosName.LowerCase();
13319         if (aPosName == "0")
13320         {
13321           anAttachPos = ManipAjustPosition_Off;
13322         }
13323         else if (aPosName == "1"
13324               || aPosName == "center")
13325         {
13326           anAttachPos = ManipAjustPosition_Center;
13327         }
13328         else if (aPosName == "transformation"
13329               || aPosName == "trsf"
13330               || aPosName == "location"
13331               || aPosName == "loc")
13332         {
13333           anAttachPos = ManipAjustPosition_Location;
13334         }
13335         else if (aPosName == "shapelocation"
13336               || aPosName == "shapeloc")
13337         {
13338           anAttachPos = ManipAjustPosition_ShapeLocation;
13339         }
13340         else
13341         {
13342           --anArgIter;
13343         }
13344       }
13345       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
13346     }
13347     else if (anArg == "-adjustsize"
13348           || anArg == "-noadjustsize")
13349     {
13350       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
13351     }
13352     else if (anArg == "-enablemodes"
13353           || anArg == "-enablemodes")
13354     {
13355       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
13356     }
13357     //
13358     else if (anArg == "-starttransform"
13359           && anArgIter + 2 < theArgsNb
13360           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
13361           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
13362     {
13363       anArgIter += 2;
13364     }
13365     else if (anArg == "-transform"
13366           && anArgIter + 2 < theArgsNb
13367           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
13368           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
13369     {
13370       anArgIter += 2;
13371     }
13372     else if (anArg == "-stoptransform")
13373     {
13374       toStopMouseTransform = 1;
13375       if (anArgIter + 1 < theArgsNb
13376        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
13377       {
13378         ++anArgIter;
13379         toStopMouseTransform = 0;
13380       }
13381     }
13382     //
13383     else if (anArg == "-move"
13384           && anArgIter + 3 < theArgsNb
13385           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
13386     {
13387       anArgIter += 3;
13388       aTrsf.SetTranslationPart (aTmpXYZ);
13389     }
13390     else if (anArg == "-scale"
13391           && anArgIter + 1 < theArgsNb
13392           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
13393     {
13394       ++anArgIter;
13395       aTrsf.SetScale (gp_Pnt(), aTmpReal);
13396     }
13397     else if (anArg == "-rotate"
13398           && anArgIter + 7 < theArgsNb
13399           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
13400           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
13401           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
13402     {
13403       anArgIter += 7;
13404       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
13405     }
13406     //
13407     else if (anArg == "-detach")
13408     {
13409       toDetach = true;
13410     }
13411     else if (anArg == "-attach"
13412           && anArgIter + 1 < theArgsNb)
13413     {
13414       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
13415       if (!aMapAIS.Find2 (anObjName, anAttachObject))
13416       {
13417         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
13418         return 1;
13419       }
13420
13421       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
13422       {
13423         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
13424         if (!aManip.IsNull()
13425           && aManip->IsAttached()
13426           && aManip->Object() == anAttachObject)
13427         {
13428           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
13429           return 1;
13430         }
13431       }
13432     }
13433     else if (anArg == "-view"
13434           && anArgIter + 1 < theArgsNb
13435           && aViewAffinity.IsNull())
13436     {
13437       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
13438       if (aViewString == "active")
13439       {
13440         aViewAffinity = ViewerTest::CurrentView();
13441       }
13442       else // Check view name
13443       {
13444         ViewerTest_Names aViewNames (aViewString);
13445         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
13446         {
13447           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
13448           return 1;
13449         }
13450         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
13451         if (aViewAffinity.IsNull())
13452         {
13453           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
13454           return 1;
13455         }
13456       }
13457     }
13458     else if (aName.IsEmpty())
13459     {
13460       aName = theArgVec[anArgIter];
13461       if (!aMapAIS.IsBound2 (aName))
13462       {
13463         aManipulator = new AIS_Manipulator();
13464         aManipulator->SetModeActivationOnDetection (true);
13465         aMapAIS.Bind (aManipulator, aName);
13466       }
13467       else
13468       {
13469         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
13470         if (aManipulator.IsNull())
13471         {
13472           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
13473           return 1;
13474         }
13475       }
13476     }
13477     else
13478     {
13479       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13480     }
13481   }
13482
13483   if (aName.IsEmpty())
13484   {
13485     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
13486     return 1;
13487   }
13488   if (!toDetach
13489     && aManipulator.IsNull())
13490   {
13491     aManipulator = new AIS_Manipulator();
13492     aManipulator->SetModeActivationOnDetection (true);
13493     aMapAIS.Bind (aManipulator, aName);
13494   }
13495
13496   // -----------------------------------------
13497   // change properties of manipulator instance
13498   // -----------------------------------------
13499
13500   if (toAutoActivate != -1)
13501   {
13502     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
13503   }
13504   if (toFollowTranslation != -1)
13505   {
13506     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
13507   }
13508   if (toFollowRotation != -1)
13509   {
13510     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
13511   }
13512   if (toFollowDragging != -1)
13513   {
13514     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
13515   }
13516   if (aGap >= 0.0f)
13517   {
13518     aManipulator->SetGap ((float )aGap);
13519   }
13520
13521   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
13522   {
13523     const ManipAxisModeOnOff& aPart = aPartIter.Value();
13524     if (aPart.Axis == -1)
13525     {
13526       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
13527     }
13528     else
13529     {
13530       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
13531     }
13532   }
13533
13534   if (aSize > 0.0)
13535   {
13536     aManipulator->SetSize ((float )aSize);
13537   }
13538   if (isZoomable != -1)
13539   {
13540     aManipulator->SetZoomPersistence (isZoomable == 0);
13541
13542     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
13543     {
13544       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
13545       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
13546     }
13547   }
13548
13549   // ----------------------------------
13550   // detach existing manipulator object
13551   // ----------------------------------
13552
13553   if (toDetach)
13554   {
13555     aManipulator->Detach();
13556     aMapAIS.UnBind2 (aName);
13557     ViewerTest::GetAISContext()->Remove (aManipulator, false);
13558   }
13559
13560   // ---------------------------------------------------
13561   // attach, detach or access manipulator from an object
13562   // ---------------------------------------------------
13563
13564   if (!anAttachObject.IsNull())
13565   {
13566     aManipulator->Attach (anAttachObject, anAttachOptions);
13567   }
13568   if (!aViewAffinity.IsNull())
13569   {
13570     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
13571          anIter.More(); anIter.Next())
13572     {
13573       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
13574     }
13575     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
13576   }
13577
13578   if (anAttachPos != ManipAjustPosition_Off
13579    && aManipulator->IsAttached()
13580    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
13581   {
13582     gp_Ax2 aPosition = gp::XOY();
13583     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
13584     switch (anAttachPos)
13585     {
13586       case ManipAjustPosition_Off:
13587       {
13588         break;
13589       }
13590       case ManipAjustPosition_Location:
13591       {
13592         aPosition = gp::XOY().Transformed (aBaseTrsf);
13593         break;
13594       }
13595       case ManipAjustPosition_ShapeLocation:
13596       {
13597         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
13598         {
13599           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
13600         }
13601         else
13602         {
13603           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
13604           return 1;
13605         }
13606         break;
13607       }
13608       case ManipAjustPosition_Center:
13609       {
13610         Bnd_Box aBox;
13611         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
13612         {
13613           Bnd_Box anObjBox;
13614           anObjIter.Value()->BoundingBox (anObjBox);
13615           aBox.Add (anObjBox);
13616         }
13617         aBox = aBox.FinitePart();
13618         if (!aBox.IsVoid())
13619         {
13620           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
13621           aPosition.SetLocation (aCenter);
13622         }
13623         break;
13624       }
13625     }
13626     aManipulator->SetPosition (aPosition);
13627   }
13628   if (!Precision::IsInfinite (aLocation.X()))
13629   {
13630     if (aVDir.Modulus() <= Precision::Confusion())
13631     {
13632       aVDir = aManipulator->Position().Direction().XYZ();
13633     }
13634     if (anXDir.Modulus() <= Precision::Confusion())
13635     {
13636       anXDir = aManipulator->Position().XDirection().XYZ();
13637     }
13638     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
13639   }
13640
13641   // --------------------------------------
13642   // apply transformation using manipulator
13643   // --------------------------------------
13644
13645   if (aMousePosFrom.x() != IntegerLast())
13646   {
13647     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
13648   }
13649   if (aMousePosTo.x() != IntegerLast())
13650   {
13651     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
13652   }
13653   if (toStopMouseTransform != -1)
13654   {
13655     aManipulator->StopTransform (toStopMouseTransform == 1);
13656   }
13657
13658   if (aTrsf.Form() != gp_Identity)
13659   {
13660     aManipulator->Transform (aTrsf);
13661   }
13662
13663   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
13664   {
13665     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
13666   }
13667   return 0;
13668 }
13669
13670 //===============================================================================================
13671 //function : VSelectionProperties
13672 //purpose  :
13673 //===============================================================================================
13674 static int VSelectionProperties (Draw_Interpretor& theDi,
13675                                  Standard_Integer  theArgsNb,
13676                                  const char**      theArgVec)
13677 {
13678   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
13679   if (aCtx.IsNull())
13680   {
13681     Message::SendFail ("Error: no active viewer");
13682     return 1;
13683   }
13684
13685   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
13686   {
13687     // handle obsolete alias
13688     bool toEnable = true;
13689     if (theArgsNb < 2)
13690     {
13691       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
13692       return 0;
13693     }
13694     else if (theArgsNb != 2
13695          || !Draw::ParseOnOff (theArgVec[1], toEnable))
13696     {
13697       Message::SendFail ("Syntax error: wrong number of parameters");
13698       return 1;
13699     }
13700     if (toEnable != aCtx->ToHilightSelected())
13701     {
13702       aCtx->ClearDetected();
13703       aCtx->SetToHilightSelected (toEnable);
13704     }
13705     return 0;
13706   }
13707
13708   Standard_Boolean toPrint  = theArgsNb == 1;
13709   Standard_Boolean toRedraw = Standard_False;
13710   Standard_Integer anArgIter = 1;
13711   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
13712   if (anArgIter < theArgsNb)
13713   {
13714     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
13715     anArgFirst.LowerCase();
13716     ++anArgIter;
13717     if (anArgFirst == "dynhighlight"
13718      || anArgFirst == "dynhilight"
13719      || anArgFirst == "dynamichighlight"
13720      || anArgFirst == "dynamichilight")
13721     {
13722       aType = Prs3d_TypeOfHighlight_Dynamic;
13723     }
13724     else if (anArgFirst == "localdynhighlight"
13725           || anArgFirst == "localdynhilight"
13726           || anArgFirst == "localdynamichighlight"
13727           || anArgFirst == "localdynamichilight")
13728     {
13729       aType = Prs3d_TypeOfHighlight_LocalDynamic;
13730     }
13731     else if (anArgFirst == "selhighlight"
13732           || anArgFirst == "selhilight"
13733           || anArgFirst == "selectedhighlight"
13734           || anArgFirst == "selectedhilight")
13735     {
13736       aType = Prs3d_TypeOfHighlight_Selected;
13737     }
13738     else if (anArgFirst == "localselhighlight"
13739           || anArgFirst == "localselhilight"
13740           || anArgFirst == "localselectedhighlight"
13741           || anArgFirst == "localselectedhilight")
13742     {
13743       aType = Prs3d_TypeOfHighlight_LocalSelected;
13744     }
13745     else
13746     {
13747       --anArgIter;
13748     }
13749   }
13750   for (; anArgIter < theArgsNb; ++anArgIter)
13751   {
13752     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13753     anArg.LowerCase();
13754     if (anArg == "-help")
13755     {
13756       theDi.PrintHelp (theArgVec[0]);
13757       return 0;
13758     }
13759     else if (anArg == "-print")
13760     {
13761       toPrint = Standard_True;
13762     }
13763     else if (anArg == "-autoactivate")
13764     {
13765       Standard_Boolean toEnable = Standard_True;
13766       if (anArgIter + 1 < theArgsNb
13767        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13768       {
13769         ++anArgIter;
13770       }
13771       aCtx->SetAutoActivateSelection (toEnable);
13772     }
13773     else if (anArg == "-automatichighlight"
13774           || anArg == "-automatichilight"
13775           || anArg == "-autohighlight"
13776           || anArg == "-autohilight")
13777     {
13778       Standard_Boolean toEnable = Standard_True;
13779       if (anArgIter + 1 < theArgsNb
13780        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13781       {
13782         ++anArgIter;
13783       }
13784       aCtx->ClearSelected (false);
13785       aCtx->ClearDetected();
13786       aCtx->SetAutomaticHilight (toEnable);
13787       toRedraw = true;
13788     }
13789     else if (anArg == "-highlightselected"
13790           || anArg == "-hilightselected")
13791     {
13792       Standard_Boolean toEnable = Standard_True;
13793       if (anArgIter + 1 < theArgsNb
13794        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13795       {
13796         ++anArgIter;
13797       }
13798       aCtx->ClearDetected();
13799       aCtx->SetToHilightSelected (toEnable);
13800       toRedraw = true;
13801     }
13802     else if (anArg == "-pickstrategy"
13803           || anArg == "-pickingstrategy")
13804     {
13805       if (++anArgIter >= theArgsNb)
13806       {
13807         Message::SendFail ("Syntax error: type of highlighting is undefined");
13808         return 1;
13809       }
13810
13811       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13812       TCollection_AsciiString aVal (theArgVec[anArgIter]);
13813       aVal.LowerCase();
13814       if (aVal == "first"
13815        || aVal == "firstaccepted"
13816        || aVal == "firstacceptable")
13817       {
13818         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13819       }
13820       else if (aVal == "topmost"
13821             || aVal == "onlyTopmost")
13822       {
13823         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
13824       }
13825       else
13826       {
13827         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
13828         return 1;
13829       }
13830
13831       aCtx->SetPickingStrategy (aStrategy);
13832     }
13833     else if (anArg == "-pixtol"
13834           && anArgIter + 1 < theArgsNb)
13835     {
13836       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
13837     }
13838     else if (anArg == "-preferclosest")
13839     {
13840       bool toPreferClosest = true;
13841       if (anArgIter + 1 < theArgsNb
13842        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
13843       {
13844         ++anArgIter;
13845       }
13846       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
13847     }
13848     else if ((anArg == "-depthtol"
13849            || anArg == "-depthtolerance")
13850           && anArgIter + 1 < theArgsNb)
13851     {
13852       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
13853       aTolType.LowerCase();
13854       if (aTolType == "uniform")
13855       {
13856         if (anArgIter + 1 >= theArgsNb)
13857         {
13858           Message::SendFail() << "Syntax error: wrong number of arguments";
13859           return 1;
13860         }
13861         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
13862                                                  Draw::Atof (theArgVec[++anArgIter]));
13863       }
13864       else if (aTolType == "uniformpx")
13865       {
13866         if (anArgIter + 1 >= theArgsNb)
13867         {
13868           Message::SendFail() << "Syntax error: wrong number of arguments";
13869           return 1;
13870         }
13871         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
13872                                                  Draw::Atof (theArgVec[++anArgIter]));
13873       }
13874       else if (aTolType == "sensfactor")
13875       {
13876         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
13877       }
13878       else
13879       {
13880         Message::SendFail() << "Syntax error at '" << aTolType << "'";
13881         return 1;
13882       }
13883     }
13884     else if ((anArg == "-mode"
13885            || anArg == "-dispmode")
13886           && anArgIter + 1 < theArgsNb)
13887     {
13888       if (aType == Prs3d_TypeOfHighlight_None)
13889       {
13890         Message::SendFail ("Syntax error: type of highlighting is undefined");
13891         return 1;
13892       }
13893
13894       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13895       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13896       aStyle->SetDisplayMode (aDispMode);
13897       toRedraw = Standard_True;
13898     }
13899     else if (anArg == "-layer"
13900           && anArgIter + 1 < theArgsNb)
13901     {
13902       if (aType == Prs3d_TypeOfHighlight_None)
13903       {
13904         Message::SendFail ("Syntax error: type of highlighting is undefined");
13905         return 1;
13906       }
13907
13908       ++anArgIter;
13909       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13910       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13911       {
13912         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13913         return 1;
13914       }
13915
13916       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13917       aStyle->SetZLayer (aNewLayer);
13918       toRedraw = Standard_True;
13919     }
13920     else if (anArg == "-hicolor"
13921           || anArg == "-selcolor"
13922           || anArg == "-color")
13923     {
13924       if (anArg.StartsWith ("-hi"))
13925       {
13926         aType = Prs3d_TypeOfHighlight_Dynamic;
13927       }
13928       else if (anArg.StartsWith ("-sel"))
13929       {
13930         aType = Prs3d_TypeOfHighlight_Selected;
13931       }
13932       else if (aType == Prs3d_TypeOfHighlight_None)
13933       {
13934         Message::SendFail ("Syntax error: type of highlighting is undefined");
13935         return 1;
13936       }
13937
13938       Quantity_Color aColor;
13939       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13940                                                      theArgVec + anArgIter + 1,
13941                                                      aColor);
13942       if (aNbParsed == 0)
13943       {
13944         Message::SendFail ("Syntax error: need more arguments");
13945         return 1;
13946       }
13947       anArgIter += aNbParsed;
13948
13949       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13950       aStyle->SetColor (aColor);
13951       toRedraw = Standard_True;
13952     }
13953     else if ((anArg == "-transp"
13954            || anArg == "-transparency"
13955            || anArg == "-hitransp"
13956            || anArg == "-seltransp"
13957            || anArg == "-hitransplocal"
13958            || anArg == "-seltransplocal")
13959           && anArgIter + 1 < theArgsNb)
13960     {
13961       if (anArg.StartsWith ("-hi"))
13962       {
13963         aType = Prs3d_TypeOfHighlight_Dynamic;
13964       }
13965       else if (anArg.StartsWith ("-sel"))
13966       {
13967         aType = Prs3d_TypeOfHighlight_Selected;
13968       }
13969       else if (aType == Prs3d_TypeOfHighlight_None)
13970       {
13971         Message::SendFail ("Syntax error: type of highlighting is undefined");
13972         return 1;
13973       }
13974
13975       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13976       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13977       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13978       toRedraw = Standard_True;
13979     }
13980     else if ((anArg == "-mat"
13981            || anArg == "-material")
13982           && anArgIter + 1 < theArgsNb)
13983     {
13984       if (aType == Prs3d_TypeOfHighlight_None)
13985       {
13986         Message::SendFail ("Syntax error: type of highlighting is undefined");
13987         return 1;
13988       }
13989
13990       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13991       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
13992       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
13993       {
13994         ++anArgIter;
13995         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
13996         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
13997         Graphic3d_MaterialAspect aMat (aMatName);
13998         aMat.SetColor (aStyle->Color());
13999         aMat.SetTransparency (aStyle->Transparency());
14000         anAspect->SetFrontMaterial (aMat);
14001         anAspect->SetInteriorColor (aStyle->Color());
14002         aStyle->SetBasicFillAreaAspect (anAspect);
14003       }
14004       else
14005       {
14006         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
14007       }
14008       toRedraw = Standard_True;
14009     }
14010     else
14011     {
14012       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
14013       return 1;
14014     }
14015   }
14016
14017   if (toPrint)
14018   {
14019     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
14020     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
14021     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
14022     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
14023     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
14024     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
14025     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
14026     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
14027     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
14028     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
14029     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
14030     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
14031     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
14032     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
14033   }
14034
14035   if (aCtx->NbSelected() != 0 && toRedraw)
14036   {
14037     aCtx->HilightSelected (Standard_True);
14038   }
14039
14040   return 0;
14041 }
14042
14043 //===============================================================================================
14044 //function : VDumpSelectionImage
14045 //purpose  :
14046 //===============================================================================================
14047 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
14048                                 Standard_Integer  theArgsNb,
14049                                 const char**      theArgVec)
14050 {
14051   if (theArgsNb < 2)
14052   {
14053     Message::SendFail() << "Syntax error: wrong number arguments for '" << theArgVec[0] << "'";
14054     return 1;
14055   }
14056
14057   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
14058   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
14059   if (aContext.IsNull())
14060   {
14061     Message::SendFail ("Error: no active viewer");
14062     return 1;
14063   }
14064
14065   TCollection_AsciiString aFile;
14066   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
14067   Handle(Graphic3d_Camera) aCustomCam;
14068   Image_Format anImgFormat = Image_Format_BGR;
14069   Standard_Integer aPickedIndex = 1;
14070   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
14071   {
14072     TCollection_AsciiString aParam (theArgVec[anArgIter]);
14073     aParam.LowerCase();
14074     if (aParam == "-type")
14075     {
14076       if (++anArgIter >= theArgsNb)
14077       {
14078         Message::SendFail ("Syntax error: wrong number parameters of flag '-depth'");
14079         return 1;
14080       }
14081
14082       TCollection_AsciiString aValue (theArgVec[anArgIter]);
14083       aValue.LowerCase();
14084       if (aValue == "depth"
14085        || aValue == "normdepth"
14086        || aValue == "normalizeddepth")
14087       {
14088         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
14089         anImgFormat = Image_Format_GrayF;
14090       }
14091       if (aValue == "depthinverted"
14092        || aValue == "normdepthinverted"
14093        || aValue == "normalizeddepthinverted"
14094        || aValue == "inverted")
14095       {
14096         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
14097         anImgFormat = Image_Format_GrayF;
14098       }
14099       else if (aValue == "unnormdepth"
14100             || aValue == "unnormalizeddepth")
14101       {
14102         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
14103         anImgFormat = Image_Format_GrayF;
14104       }
14105       else if (aValue == "objectcolor"
14106             || aValue == "object"
14107             || aValue == "color")
14108       {
14109         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
14110       }
14111       else if (aValue == "entitycolor"
14112             || aValue == "entity")
14113       {
14114         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
14115       }
14116       else if (aValue == "ownercolor"
14117             || aValue == "owner")
14118       {
14119         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
14120       }
14121       else if (aValue == "selectionmodecolor"
14122             || aValue == "selectionmode"
14123             || aValue == "selmodecolor"
14124             || aValue == "selmode")
14125       {
14126         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
14127       }
14128     }
14129     else if (aParam == "-picked"
14130           || aParam == "-pickeddepth"
14131           || aParam == "-pickedindex")
14132     {
14133       if (++anArgIter >= theArgsNb)
14134       {
14135         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
14136         return 1;
14137       }
14138
14139       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
14140     }
14141     else if (anArgIter + 1 < theArgsNb
14142           && aParam == "-xrpose")
14143     {
14144       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
14145       anXRArg.LowerCase();
14146       if (anXRArg == "base")
14147       {
14148         aCustomCam = aView->View()->BaseXRCamera();
14149       }
14150       else if (anXRArg == "head")
14151       {
14152         aCustomCam = aView->View()->PosedXRCamera();
14153       }
14154       else
14155       {
14156         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
14157         return 1;
14158       }
14159       if (aCustomCam.IsNull())
14160       {
14161         Message::SendFail() << "Error: undefined XR pose";
14162         return 0;
14163       }
14164     }
14165     else if (aFile.IsEmpty())
14166     {
14167       aFile = theArgVec[anArgIter];
14168     }
14169     else
14170     {
14171       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
14172       return 1;
14173     }
14174   }
14175   if (aFile.IsEmpty())
14176   {
14177     Message::SendFail ("Syntax error: image file name is missing");
14178     return 1;
14179   }
14180
14181   Standard_Integer aWidth = 0, aHeight = 0;
14182   aView->Window()->Size (aWidth, aHeight);
14183
14184   Image_AlienPixMap aPixMap;
14185   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
14186   {
14187     Message::SendFail ("Error: can't allocate image");
14188     return 1;
14189   }
14190
14191   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
14192   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
14193   if (!aCustomCam.IsNull())
14194   {
14195     aView->SetCamera (aCustomCam);
14196   }
14197   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
14198   {
14199     Message::SendFail ("Error: can't generate selection image");
14200     return 1;
14201   }
14202   if (!aCustomCam.IsNull())
14203   {
14204     aView->SetCamera (aCamBack);
14205   }
14206   aView->SetImmediateUpdate (wasImmUpdate);
14207
14208   if (!aPixMap.Save (aFile))
14209   {
14210     Message::SendFail ("Error: can't save selection image");
14211     return 0;
14212   }
14213   return 0;
14214 }
14215
14216 //===============================================================================================
14217 //function : VViewCube
14218 //purpose  :
14219 //===============================================================================================
14220 static int VViewCube (Draw_Interpretor& ,
14221                       Standard_Integer  theNbArgs,
14222                       const char**      theArgVec)
14223 {
14224   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
14225   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
14226   if (aContext.IsNull() || aView.IsNull())
14227   {
14228     Message::SendFail ("Error: no active viewer");
14229     return 1;
14230   }
14231   else if (theNbArgs < 2)
14232   {
14233     Message::SendFail ("Syntax error: wrong number arguments");
14234     return 1;
14235   }
14236
14237   Handle(AIS_ViewCube) aViewCube;
14238   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
14239   Quantity_Color aColorRgb;
14240   TCollection_AsciiString aName;
14241   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
14242   {
14243     TCollection_AsciiString anArg (theArgVec[anArgIter]);
14244     anArg.LowerCase();
14245     if (anUpdateTool.parseRedrawMode (anArg))
14246     {
14247       //
14248     }
14249     else if (aViewCube.IsNull())
14250     {
14251       aName = theArgVec[anArgIter];
14252       if (aName.StartsWith ("-"))
14253       {
14254         Message::SendFail ("Syntax error: object name should be specified");
14255         return 1;
14256       }
14257       Handle(AIS_InteractiveObject) aPrs;
14258       GetMapOfAIS().Find2 (aName, aPrs);
14259       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
14260       if (aViewCube.IsNull())
14261       {
14262         aViewCube = new AIS_ViewCube();
14263         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
14264         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
14265         aViewCube->SetFixedAnimationLoop (false);
14266       }
14267     }
14268     else if (anArg == "-reset")
14269     {
14270       aViewCube->ResetStyles();
14271     }
14272     else if (anArg == "-color"
14273           || anArg == "-boxcolor"
14274           || anArg == "-boxsidecolor"
14275           || anArg == "-sidecolor"
14276           || anArg == "-boxedgecolor"
14277           || anArg == "-edgecolor"
14278           || anArg == "-boxcornercolor"
14279           || anArg == "-cornercolor"
14280           || anArg == "-innercolor"
14281           || anArg == "-textcolor"
14282           || anArg == "-xaxistextcolor"
14283           || anArg == "-yaxistextcolor"
14284           || anArg == "-zaxistextcolor")
14285     {
14286       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
14287                                                      theArgVec + anArgIter + 1,
14288                                                      aColorRgb);
14289       if (aNbParsed == 0)
14290       {
14291         Message::SendFail() << "Syntax error at '" << anArg << "'";
14292         return 1;
14293       }
14294       anArgIter += aNbParsed;
14295       if (anArg == "-boxcolor")
14296       {
14297         aViewCube->SetBoxColor (aColorRgb);
14298       }
14299       else if (anArg == "-boxsidecolor"
14300             || anArg == "-sidecolor")
14301       {
14302         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
14303         aViewCube->SynchronizeAspects();
14304       }
14305       else if (anArg == "-boxedgecolor"
14306             || anArg == "-edgecolor")
14307       {
14308         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
14309         aViewCube->SynchronizeAspects();
14310       }
14311       else if (anArg == "-boxcornercolor"
14312             || anArg == "-cornercolor")
14313       {
14314         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
14315         aViewCube->SynchronizeAspects();
14316       }
14317       else if (anArg == "-innercolor")
14318       {
14319         aViewCube->SetInnerColor (aColorRgb);
14320       }
14321       else if (anArg == "-textcolor")
14322       {
14323         aViewCube->SetTextColor (aColorRgb);
14324       }
14325       else if (anArg == "-xaxistextcolor"
14326             || anArg == "-yaxistextcolor"
14327             || anArg == "-zaxistextcolor")
14328       {
14329         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
14330                                 ? Prs3d_DatumParts_XAxis
14331                                 : (anArg.Value (2) == 'y'
14332                                  ? Prs3d_DatumParts_YAxis
14333                                  : Prs3d_DatumParts_ZAxis);
14334         aViewCube->Attributes()->SetOwnDatumAspects();
14335         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
14336       }
14337       else
14338       {
14339         aViewCube->SetColor (aColorRgb);
14340       }
14341     }
14342     else if (anArgIter + 1 < theNbArgs
14343           && (anArg == "-transparency"
14344            || anArg == "-boxtransparency"))
14345     {
14346       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
14347       if (aValue < 0.0 || aValue > 1.0)
14348       {
14349         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
14350         return 1;
14351       }
14352
14353       if (anArg == "-boxtransparency")
14354       {
14355         aViewCube->SetBoxTransparency (aValue);
14356       }
14357       else
14358       {
14359         aViewCube->SetTransparency (aValue);
14360       }
14361     }
14362     else if (anArg == "-axes"
14363           || anArg == "-edges"
14364           || anArg == "-vertices"
14365           || anArg == "-vertexes"
14366           || anArg == "-fixedanimation")
14367     {
14368       bool toShow = true;
14369       if (anArgIter + 1 < theNbArgs
14370        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
14371       {
14372         ++anArgIter;
14373       }
14374       if (anArg == "-fixedanimation")
14375       {
14376         aViewCube->SetFixedAnimationLoop (toShow);
14377       }
14378       else if (anArg == "-axes")
14379       {
14380         aViewCube->SetDrawAxes (toShow);
14381       }
14382       else if (anArg == "-edges")
14383       {
14384         aViewCube->SetDrawEdges (toShow);
14385       }
14386       else
14387       {
14388         aViewCube->SetDrawVertices (toShow);
14389       }
14390     }
14391     else if (anArg == "-yup"
14392           || anArg == "-zup")
14393     {
14394       bool isOn = true;
14395       if (anArgIter + 1 < theNbArgs
14396        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
14397       {
14398         ++anArgIter;
14399       }
14400       if (anArg == "-yup")
14401       {
14402         aViewCube->SetYup (isOn);
14403       }
14404       else
14405       {
14406         aViewCube->SetYup (!isOn);
14407       }
14408     }
14409     else if (anArgIter + 1 < theNbArgs
14410           && anArg == "-font")
14411     {
14412       aViewCube->SetFont (theArgVec[++anArgIter]);
14413     }
14414     else if (anArgIter + 1 < theNbArgs
14415           && anArg == "-fontheight")
14416     {
14417       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
14418     }
14419     else if (anArgIter + 1 < theNbArgs
14420           && (anArg == "-size"
14421            || anArg == "-boxsize"))
14422     {
14423       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
14424                           anArg != "-boxsize");
14425     }
14426     else if (anArgIter + 1 < theNbArgs
14427           && (anArg == "-boxfacet"
14428            || anArg == "-boxfacetextension"
14429            || anArg == "-facetextension"
14430            || anArg == "-extension"))
14431     {
14432       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
14433     }
14434     else if (anArgIter + 1 < theNbArgs
14435           && (anArg == "-boxedgegap"
14436            || anArg == "-edgegap"))
14437     {
14438       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
14439     }
14440     else if (anArgIter + 1 < theNbArgs
14441           && (anArg == "-boxedgeminsize"
14442            || anArg == "-edgeminsize"))
14443     {
14444       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
14445     }
14446     else if (anArgIter + 1 < theNbArgs
14447           && (anArg == "-boxcornerminsize"
14448            || anArg == "-cornerminsize"))
14449     {
14450       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
14451     }
14452     else if (anArgIter + 1 < theNbArgs
14453           && anArg == "-axespadding")
14454     {
14455       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
14456     }
14457     else if (anArgIter + 1 < theNbArgs
14458           && anArg == "-roundradius")
14459     {
14460       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
14461     }
14462     else if (anArgIter + 1 < theNbArgs
14463           && anArg == "-duration")
14464     {
14465       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
14466     }
14467     else if (anArgIter + 1 < theNbArgs
14468           && anArg == "-axesradius")
14469     {
14470       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
14471     }
14472     else if (anArgIter + 1 < theNbArgs
14473           && anArg == "-axesconeradius")
14474     {
14475       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
14476     }
14477     else if (anArgIter + 1 < theNbArgs
14478           && anArg == "-axessphereradius")
14479     {
14480       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
14481     }
14482     else
14483     {
14484       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14485       return 1;
14486     }
14487   }
14488   if (aViewCube.IsNull())
14489   {
14490     Message::SendFail ("Syntax error: wrong number of arguments");
14491     return 1;
14492   }
14493
14494   ViewerTest::Display (aName, aViewCube, false);
14495   return 0;
14496 }
14497
14498 //===============================================================================================
14499 //function : VColorConvert
14500 //purpose  :
14501 //===============================================================================================
14502 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
14503 {
14504   if (theNbArgs != 6)
14505   {
14506     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
14507     return 1;
14508   }
14509
14510   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
14511   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
14512   {
14513     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
14514     return 1;
14515   }
14516
14517   const char* aTypeStr = theArgVec[2];
14518   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
14519   if (! strcasecmp (aTypeStr, "srgb"))
14520   {
14521     aType = Quantity_TOC_sRGB;
14522   }
14523   else if (! strcasecmp (aTypeStr, "hls"))
14524   {
14525     aType = Quantity_TOC_HLS;
14526   }
14527   else if (! strcasecmp (aTypeStr, "lab"))
14528   {
14529     aType = Quantity_TOC_CIELab;
14530   }
14531   else if (! strcasecmp (aTypeStr, "lch"))
14532   {
14533     aType = Quantity_TOC_CIELch;
14534   }
14535   else
14536   {
14537     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
14538     return 1;
14539   }
14540
14541   double aC1 = Draw::Atof (theArgVec[3]);
14542   double aC2 = Draw::Atof (theArgVec[4]);
14543   double aC3 = Draw::Atof (theArgVec[5]);
14544
14545   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
14546   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
14547
14548   // print values with 6 decimal digits
14549   char buffer[1024];
14550   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
14551   theDI << buffer;
14552
14553   return 0;
14554 }
14555  
14556 //===============================================================================================
14557 //function : VColorDiff
14558 //purpose  :
14559 //===============================================================================================
14560 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
14561 {
14562   if (theNbArgs != 7)
14563   {
14564     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
14565     return 1;
14566   }
14567
14568   double aR1 = Draw::Atof (theArgVec[1]);
14569   double aG1 = Draw::Atof (theArgVec[2]);
14570   double aB1 = Draw::Atof (theArgVec[3]);
14571   double aR2 = Draw::Atof (theArgVec[4]);
14572   double aG2 = Draw::Atof (theArgVec[5]);
14573   double aB2 = Draw::Atof (theArgVec[6]);
14574
14575   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
14576   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
14577
14578   theDI << aColor1.DeltaE2000 (aColor2);
14579
14580   return 0;
14581 }
14582  
14583 //===============================================================================================
14584 //function : VSelBvhBuild
14585 //purpose  :
14586 //===============================================================================================
14587 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
14588 {
14589   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
14590   if (aCtx.IsNull())
14591   {
14592     Message::SendFail ("Error: no active viewer");
14593     return 1;
14594   }
14595
14596   if (theNbArgs < 2)
14597   {
14598     Message::SendFail ("Error: command syntax is incorrect, see help");
14599     return 1;
14600   }
14601
14602   Standard_Integer toEnable = -1;
14603   Standard_Integer aThreadsNb = -1;
14604   Standard_Boolean toWait = Standard_False;
14605
14606   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
14607   {
14608     TCollection_AsciiString anArg (theArgVec[anArgIter]);
14609     anArg.LowerCase();
14610
14611     if (anArg == "-nbthreads"
14612         && anArgIter + 1 < theNbArgs)
14613     {
14614       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
14615       if (aThreadsNb < 1)
14616       {
14617         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
14618       }
14619     }
14620     else if (anArg == "-wait")
14621     {
14622       toWait = Standard_True;
14623     }
14624     else if (toEnable == -1)
14625     {
14626       Standard_Boolean toEnableValue = Standard_True;
14627       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
14628       {
14629         toEnable = toEnableValue ? 1 : 0;
14630       }
14631       else
14632       {
14633         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14634         return 1;
14635       }
14636     }
14637     else
14638     {
14639       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14640       return 1;
14641     }
14642   }
14643
14644   if (aThreadsNb == -1)
14645   {
14646     aThreadsNb = 1;
14647   }
14648   if (toEnable != -1)
14649   {
14650     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
14651   }
14652   if (toWait)
14653   {
14654     aCtx->MainSelector()->WaitForBVHBuild();
14655   }
14656
14657   return 0;
14658 }
14659
14660 //=======================================================================
14661 //function : ViewerCommands
14662 //purpose  :
14663 //=======================================================================
14664
14665 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
14666 {
14667
14668   const char *group = "ZeViewer";
14669   theCommands.Add("vinit",
14670           "vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]"
14671     "\n\t\t:     [-exitOnClose] [-closeOnEscape] [-cloneActive] [-virtual {on|off}=off] [-2d_mode {on|off}=off]"
14672   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
14673     "\n\t\t:     [-display displayName]"
14674   #endif
14675     "\n\t\t: Creates new View window with specified name viewName."
14676     "\n\t\t: By default the new view is created in the viewer and in"
14677     "\n\t\t: graphic driver shared with active view."
14678     "\n\t\t:  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}"
14679     "\n\t\t: If driverName isn't specified the driver will be shared with active view."
14680     "\n\t\t: If viewerName isn't specified the viewer will be shared with active view."
14681 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
14682     "\n\t\t:  -display HostName.DisplayNumber[:ScreenNumber]"
14683     "\n\t\t: Display name will be used within creation of graphic driver, when specified."
14684 #endif
14685     "\n\t\t:  -left,  -top    pixel position of left top corner of the window."
14686     "\n\t\t:  -width, -height width and height of window respectively."
14687     "\n\t\t:  -cloneActive flag to copy camera and dimensions of active view."
14688     "\n\t\t:  -exitOnClose when specified, closing the view will exit application."
14689     "\n\t\t:  -closeOnEscape when specified, view will be closed on pressing Escape."
14690     "\n\t\t:  -virtual create an offscreen window within interactive session"
14691     "\n\t\t:  -2d_mode when on, view will not react on rotate scene events"
14692     "\n\t\t: Additional commands for operations with views: vclose, vactivate, vviewlist.",
14693     __FILE__,VInit,group);
14694   theCommands.Add("vclose" ,
14695     "[view_id [keep_context=0|1]]\n"
14696     "or vclose ALL - to remove all created views\n"
14697     " - removes view(viewer window) defined by its view_id.\n"
14698     " - keep_context: by default 0; if 1 and the last view is deleted"
14699     " the current context is not removed.",
14700     __FILE__,VClose,group);
14701   theCommands.Add("vactivate" ,
14702     "vactivate view_id [-noUpdate]"
14703     " - activates view(viewer window) defined by its view_id",
14704     __FILE__,VActivate,group);
14705   theCommands.Add("vviewlist",
14706     "vviewlist [format={tree, long}]"
14707     " - prints current list of views per viewer and graphic_driver ID shared between viewers"
14708     " - format: format of result output, if tree the output is a tree view;"
14709     "otherwise it's a list of full view names. By default format = tree",
14710     __FILE__,VViewList,group);
14711   theCommands.Add("vhelp" ,
14712     "vhelp            : display help on the viewer commands",
14713     __FILE__,VHelp,group);
14714   theCommands.Add("vviewproj",
14715           "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]"
14716     "\n\t\t:         [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]"
14717     "\n\t\t: Setup view direction"
14718     "\n\t\t:   -Yup      use Y-up convention instead of Zup (which is default)."
14719     "\n\t\t:   +-X+-Y+-Z define direction as combination of DX, DY and DZ;"
14720     "\n\t\t:             for example '+Z' will show front of the model,"
14721     "\n\t\t:             '-X-Y+Z' will define left axonometrical view."
14722     "\n\t\t:   -frame    define camera Up and Right directions (regardless Up convention);"
14723     "\n\t\t:             for example '+X+Z' will show front of the model with Z-up."
14724     __FILE__,VViewProj,group);
14725   theCommands.Add("vtop" ,
14726     "vtop or <T>      : Top view. Orientation +X+Y" ,
14727     __FILE__,VViewProj,group);
14728   theCommands.Add("vbottom" ,
14729     "vbottom          : Bottom view. Orientation +X-Y" ,
14730     __FILE__,VViewProj,group);
14731   theCommands.Add("vleft" ,
14732     "vleft            : Left view. Orientation -Y+Z" ,
14733     __FILE__,VViewProj,group);
14734   theCommands.Add("vright" ,
14735     "vright           : Right view. Orientation +Y+Z" ,
14736     __FILE__,VViewProj,group);
14737   theCommands.Add("vaxo" ,
14738     " vaxo or <A>     : Axonometric view. Orientation +X-Y+Z",
14739     __FILE__,VViewProj,group);
14740   theCommands.Add("vfront" ,
14741     "vfront           : Front view. Orientation +X+Z" ,
14742     __FILE__,VViewProj,group);
14743   theCommands.Add("vback" ,
14744     "vback            : Back view. Orientation -X+Z" ,
14745     __FILE__,VViewProj,group);
14746   theCommands.Add("vpick" ,
14747     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
14748     VPick,group);
14749   theCommands.Add("vfit",
14750     "vfit or <F> [-selected] [-noupdate]"
14751     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
14752     __FILE__,VFit,group);
14753   theCommands.Add ("vfitarea",
14754     "vfitarea x1 y1 x2 y2"
14755     "\n\t\t: vfitarea x1 y1 z1 x2 y2 z2"
14756     "\n\t\t: Fit view to show area located between two points"
14757     "\n\t\t: given in world 2D or 3D corrdinates.",
14758     __FILE__, VFitArea, group);
14759   theCommands.Add ("vzfit", "vzfit [scale]\n"
14760     "   Matches Z near, Z far view volume planes to the displayed objects.\n"
14761     "   \"scale\" - specifies factor to scale computed z range.\n",
14762     __FILE__, VZFit, group);
14763   theCommands.Add("vrepaint",
14764             "vrepaint [-immediate] [-continuous FPS]"
14765     "\n\t\t: force redraw of active View"
14766     "\n\t\t:   -immediate  flag performs redraw of immediate layers only;"
14767     "\n\t\t:   -continuous activates/deactivates continuous redraw of active View,"
14768     "\n\t\t:                0 means no continuous rendering,"
14769     "\n\t\t:               -1 means non-stop redraws,"
14770     "\n\t\t:               >0 specifies target framerate,",
14771     __FILE__,VRepaint,group);
14772   theCommands.Add("vclear",
14773     "vclear          : vclear"
14774     "\n\t\t: remove all the object from the viewer",
14775     __FILE__,VClear,group);
14776   theCommands.Add (
14777     "vbackground",
14778     "Changes background or some background settings.\n"
14779     "\n"
14780     "Usage:\n"
14781     "  vbackground -imageFile ImageFile [-imageMode FillType]\n"
14782     "  vbackground -imageMode FillType\n"
14783     "  vbackground -gradient Color1 Color2 [-gradientMode FillMethod]\n"
14784     "  vbackground -gradientMode FillMethod\n"
14785     "  vbackground -cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]\n"
14786     "  vbackground -color Color\n"
14787     "  vbackground -default -gradient Color1 Color2 [-gradientMode FillType]\n"
14788     "  vbackground -default -color Color\n"
14789     "  vbackground -help\n"
14790     "\n"
14791     "Options:\n"
14792     "  -imageFile    (-imgFile, -image, -img):             sets filename of image used as background\n"
14793     "  -imageMode    (-imgMode, -imageMd, -imgMd):         sets image fill type\n"
14794     "  -gradient     (-grad, -gr):                         sets background gradient starting and ending colors\n"
14795     "  -gradientMode (-gradMode, -gradMd, -grMode, -grMd): sets gradient fill method\n"
14796     "  -cubemap      (-cmap, -cm):                         sets environment cubemap as background\n"
14797     "  -invertedz    (-invz, -iz):                         sets inversion of Z axis for background cubemap rendering\n"
14798     "  -order        (-o):                                 defines order of tiles in one image cubemap\n"
14799     "                                                      (has no effect in case of multi image cubemaps)\n"
14800     "  -color        (-col):                               sets background color\n"
14801     "  -default      (-def):                               sets background default gradient or color\n"
14802     "  -help         (-h):                                 outputs short help message\n"
14803     "\n"
14804     "Arguments:\n"
14805     "  Color:        Red Green Blue  - where Red, Green, Blue must be integers within the range [0, 255]\n"
14806     "                                  or reals within the range [0.0, 1.0]\n"
14807     "                ColorName       - one of WHITE, BLACK, RED, GREEN, BLUE, etc.\n"
14808     "                #HHH, [#]HHHHHH - where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F)\n"
14809     "  FillMethod:   one of NONE, HOR[IZONTAL], VER[TICAL], DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, "
14810     "CORNER4\n"
14811     "  FillType:     one of CENTERED, TILED, STRETCH, NONE\n"
14812     "  ImageFile:    a name of the file with the image used as a background\n"
14813     "  CubemapFilei: a name of the file with one image packed cubemap or names of separate files with every cubemap side\n"
14814     "  TileIndexi:   a cubemap side index in range [0, 5] for i tile of one image packed cubemap\n",
14815     __FILE__,
14816     vbackground,
14817     group);
14818   theCommands.Add ("vsetbg",
14819                    "Loads image as background."
14820                    "\n\t\t: vsetbg ImageFile [FillType]"
14821                    "\n\t\t: vsetbg -imageFile ImageFile [-imageMode FillType]"
14822                    "\n\t\t: Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.",
14823                    __FILE__,
14824                    vbackground,
14825                    group);
14826   theCommands.Add ("vsetbgmode",
14827                    "Changes background image fill type."
14828                    "\n\t\t: vsetbgmode [-imageMode] FillType"
14829                    "\n\t\t: Alias for 'vbackground -imageMode FillType'.",
14830                    __FILE__,
14831                    vbackground,
14832                    group);
14833   theCommands.Add ("vsetgradientbg",
14834                    "Mounts gradient background."
14835                    "\n\t\t: vsetgradientbg Color1 Color2 [FillMethod]"
14836                    "\n\t\t: vsetgradientbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14837                    "\n\t\t: Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.",
14838                    __FILE__,
14839                    vbackground,
14840                    group);
14841   theCommands.Add ("vsetgrbgmode",
14842                    "Changes gradient background fill method."
14843                    "\n\t\t: vsetgrbgmode [-gradientMode] FillMethod"
14844                    "\n\t\t: Alias for 'vbackground -gradientMode FillMethod'.",
14845                    __FILE__,
14846                    vbackground,
14847                    group);
14848   theCommands.Add ("vsetcolorbg",
14849                    "Sets background color."
14850                    "\n\t\t: vsetcolorbg [-color] Color."
14851                    "\n\t\t: Alias for 'vbackground -color Color'.",
14852                    __FILE__,
14853                    vbackground,
14854                    group);
14855   theCommands.Add ("vsetdefaultbg",
14856                    "Sets default viewer background fill color (flat/gradient)."
14857                    "\n\t\t: vsetdefaultbg Color1 Color2 [FillMethod]"
14858                    "\n\t\t: vsetdefaultbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14859                    "\n\t\t: Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'."
14860                    "\n\t\t: vsetdefaultbg [-color] Color"
14861                    "\n\t\t: Alias for 'vbackground -default -color Color'.",
14862                    __FILE__,
14863                    vbackground,
14864                    group);
14865   theCommands.Add("vscale",
14866     "vscale          : vscale X Y Z",
14867     __FILE__,VScale,group);
14868   theCommands.Add("vzbufftrihedron",
14869             "vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]"
14870     "\n\t\t:       [-position center|left_lower|left_upper|right_lower|right_upper]"
14871     "\n\t\t:       [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]"
14872     "\n\t\t:       [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]"
14873     "\n\t\t:       [-nbfacets value=12] [-colorLabels color=WHITE]"
14874     "\n\t\t:       [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]"
14875     "\n\t\t: Displays a trihedron",
14876     __FILE__,VZBuffTrihedron,group);
14877   theCommands.Add("vrotate",
14878     "vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]"
14879     "\n                : Option -mouseStart starts rotation according to the mouse position"
14880     "\n                : Option -mouseMove continues rotation with angle computed"
14881     "\n                : from last and new mouse position."
14882     "\n                : vrotate AX AY AZ [X Y Z]",
14883     __FILE__,VRotate,group);
14884   theCommands.Add("vzoom",
14885     "vzoom           : vzoom coef",
14886     __FILE__,VZoom,group);
14887   theCommands.Add("vpan",
14888     "vpan            : vpan dx dy",
14889     __FILE__,VPan,group);
14890   theCommands.Add("vcolorscale",
14891     "vcolorscale name [-noupdate|-update] [-demo]"
14892     "\n\t\t:       [-range RangeMin=0 RangeMax=1 NbIntervals=10]"
14893     "\n\t\t:       [-font HeightFont=20]"
14894     "\n\t\t:       [-logarithmic {on|off}=off] [-reversed {on|off}=off]"
14895     "\n\t\t:       [-smoothTransition {on|off}=off]"
14896     "\n\t\t:       [-hueRange MinAngle=230 MaxAngle=0]"
14897     "\n\t\t:       [-colorRange MinColor=BLUE1 MaxColor=RED]"
14898     "\n\t\t:       [-textpos {left|right|center|none}=right]"
14899     "\n\t\t:       [-labelAtBorder {on|off}=on]"
14900     "\n\t\t:       [-colors Color1 Color2 ...] [-color Index Color]"
14901     "\n\t\t:       [-labels Label1 Label2 ...] [-label Index Label]"
14902     "\n\t\t:       [-freeLabels NbOfLabels Label1 Label2 ...]"
14903     "\n\t\t:       [-xy Left=0 Bottom=0]"
14904     "\n\t\t:       [-uniform lightness hue_from hue_to]"
14905     "\n\t\t:  -demo     - displays a color scale with demonstratio values"
14906     "\n\t\t:  -colors   - set colors for all intervals"
14907     "\n\t\t:  -color    - set color for specific interval"
14908     "\n\t\t:  -uniform  - generate colors with the same lightness"
14909     "\n\t\t:  -textpos  - horizontal label position relative to color scale bar"
14910     "\n\t\t:  -labelAtBorder - vertical label position relative to color interval;"
14911     "\n\t\t:              at border means the value inbetween neighbor intervals,"
14912     "\n\t\t:              at center means the center value within current interval"
14913     "\n\t\t:  -labels   - set labels for all intervals"
14914     "\n\t\t:  -freeLabels - same as -labels but does not require"
14915     "\n\t\t:              matching the number of intervals"
14916     "\n\t\t:  -label    - set label for specific interval"
14917     "\n\t\t:  -title    - set title"
14918     "\n\t\t:  -reversed - setup smooth color transition between intervals"
14919     "\n\t\t:  -smoothTransition - swap colorscale direction"
14920     "\n\t\t:  -hueRange - set hue angles corresponding to minimum and maximum values",
14921     __FILE__, VColorScale, group);
14922   theCommands.Add("vgraduatedtrihedron",
14923     "vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
14924     "\t[-namefont Name] [-valuesfont Name]\n"
14925     "\t[-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]\n"
14926     "\t[-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]"
14927     "\t[-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]\n"
14928     "\t[-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]\n"
14929     "\t[-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]"
14930     "\t[-xcolor Color] [-ycolor Color] [-zcolor Color]\n"
14931     "\t[-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]\n"
14932     "\t[-xticks Number] [-yticks Number] [-zticks Number]\n"
14933     "\t[-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]\n"
14934     "\t[-drawgrid on/off] [-drawaxes on/off]\n"
14935     " - Displays or erases graduated trihedron"
14936     " - xname, yname, zname - names of axes, default: X, Y, Z\n"
14937     " - namefont - font of axes names. Default: Arial\n"
14938     " - xnameoffset, ynameoffset, znameoffset - offset of name from values or tickmarks or axis. Default: 30\n"
14939     " - xnamecolor, ynamecolor, znamecolor - colors of axes names\n"
14940     " - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values from tickmarks or axis. Default: 10\n"
14941     " - valuesfont - font of axes values. Default: Arial\n"
14942     " - xcolor, ycolor, zcolor - color of axis and values\n"
14943     " - xticks, yticks, xzicks - number of tickmark on axes. Default: 5\n"
14944     " - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10\n",
14945     __FILE__,VGraduatedTrihedron,group);
14946   theCommands.Add("vtile" ,
14947             "vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]"
14948     "\n\t\t: Setup view to draw a tile (a part of virtual bigger viewport)."
14949     "\n\t\t:  -totalSize the size of virtual bigger viewport"
14950     "\n\t\t:  -tileSize  tile size (the view size will be used if omitted)"
14951     "\n\t\t:  -lowerLeft tile offset as lower left corner"
14952     "\n\t\t:  -upperLeft tile offset as upper left corner",
14953     __FILE__, VTile, group);
14954   theCommands.Add("vzlayer",
14955               "vzlayer [layerId]"
14956       "\n\t\t:         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]"
14957       "\n\t\t:         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]"
14958       "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
14959       "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]"
14960       "\n\t\t: ZLayer list management:"
14961       "\n\t\t:   -add      add new z layer to viewer and print its id"
14962       "\n\t\t:   -insertBefore add new z layer and insert it before existing one"
14963       "\n\t\t:   -insertAfter  add new z layer and insert it after  existing one"
14964       "\n\t\t:   -delete   delete z layer"
14965       "\n\t\t:   -get      print sequence of z layers"
14966       "\n\t\t:   -settings print status of z layer settings"
14967       "\n\t\t:   -disable  disables given setting"
14968       "\n\t\t:   -enable   enables  given setting",
14969     __FILE__,VZLayer,group);
14970   theCommands.Add("vlayerline",
14971     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
14972     __FILE__,VLayerLine,group);
14973   theCommands.Add("vgrid",
14974               "vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]"
14975       "\n\t\t:       [-step X Y] [-size DX DY]"
14976       "\n\t\t:       [-step StepRadius NbDivisions] [-radius Radius]",
14977     __FILE__, VGrid, group);
14978   theCommands.Add ("vpriviledgedplane",
14979     "vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]"
14980     "\n\t\t:   Ox, Oy, Oz - plane origin"
14981     "\n\t\t:   Nx, Ny, Nz - plane normal direction"
14982     "\n\t\t:   Xx, Xy, Xz - plane x-reference axis direction"
14983     "\n\t\t: Sets or prints viewer's priviledged plane geometry.",
14984     __FILE__, VPriviledgedPlane, group);
14985   theCommands.Add ("vconvert",
14986     "vconvert v [Mode={window|view}]"
14987     "\n\t\t: vconvert x y [Mode={window|view|grid|ray}]"
14988     "\n\t\t: vconvert x y z [Mode={window|grid}]"
14989     "\n\t\t:   window - convert to window coordinates, pixels"
14990     "\n\t\t:   view   - convert to view projection plane"
14991     "\n\t\t:   grid   - convert to model coordinates, given on grid"
14992     "\n\t\t:   ray    - convert projection ray to model coordinates"
14993     "\n\t\t: - vconvert v window : convert view to window;"
14994     "\n\t\t: - vconvert v view   : convert window to view;"
14995     "\n\t\t: - vconvert x y window : convert view to window;"
14996     "\n\t\t: - vconvert x y view : convert window to view;"
14997     "\n\t\t: - vconvert x y : convert window to model;"
14998     "\n\t\t: - vconvert x y grid : convert window to model using grid;"
14999     "\n\t\t: - vconvert x y ray : convert window projection line to model;"
15000     "\n\t\t: - vconvert x y z window : convert model to window;"
15001     "\n\t\t: - vconvert x y z grid : convert view to model using grid;"
15002     "\n\t\t: Converts the given coordinates to window/view/model space.",
15003     __FILE__, VConvert, group);
15004   theCommands.Add ("vfps",
15005     "vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view",
15006     __FILE__, VFps, group);
15007   theCommands.Add ("vgldebug",
15008             "vgldebug [-sync {0|1}] [-debug {0|1}] [-glslWarn {0|1}]"
15009     "\n\t\t:          [-glslCode {off|short|full}] [-extraMsg {0|1}] [{0|1}]"
15010     "\n\t\t: Request debug GL context. Should be called BEFORE vinit."
15011     "\n\t\t: Debug context can be requested only on Windows"
15012     "\n\t\t: with GL_ARB_debug_output extension implemented by GL driver!"
15013     "\n\t\t:  -sync     - request synchronized debug GL context"
15014     "\n\t\t:  -glslWarn - log GLSL compiler/linker warnings,"
15015     "\n\t\t:              which are suppressed by default,"
15016     "\n\t\t:  -glslCode - log GLSL program source code,"
15017     "\n\t\t:              which are suppressed by default,"
15018     "\n\t\t:  -extraMsg - log extra diagnostic messages from GL context,"
15019     "\n\t\t:              which are suppressed by default",
15020     __FILE__, VGlDebug, group);
15021   theCommands.Add ("vvbo",
15022     "vvbo [{0|1}] : turn VBO usage On/Off; affects only newly displayed objects",
15023     __FILE__, VVbo, group);
15024   theCommands.Add ("vstereo",
15025             "vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
15026     "\n\t\t:         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]"
15027     "\n\t\t:         [-anaglyph Filter]"
15028     "\n\t\t: Control stereo output mode."
15029     "\n\t\t: When -mirrorComposer is specified, VR rendered frame will be mirrored in window (debug)."
15030     "\n\t\t: Parameter -unitFactor specifies meters scale factor for mapping VR input."
15031     "\n\t\t: Available modes for -mode:"
15032     "\n\t\t:  quadBuffer        - OpenGL QuadBuffer stereo,"
15033     "\n\t\t:                     requires driver support."
15034     "\n\t\t:                     Should be called BEFORE vinit!"
15035     "\n\t\t:  anaglyph         - Anaglyph glasses"
15036     "\n\t\t:  rowInterlaced    - row-interlaced display"
15037     "\n\t\t:  columnInterlaced - column-interlaced display"
15038     "\n\t\t:  chessBoard       - chess-board output"
15039     "\n\t\t:  sideBySide       - horizontal pair"
15040     "\n\t\t:  overUnder        - vertical   pair"
15041     "\n\t\t:  openVR           - OpenVR (HMD)"
15042     "\n\t\t: Available Anaglyph filters for -anaglyph:"
15043     "\n\t\t:  redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
15044     "\n\t\t:  greenMagentaSimple",
15045     __FILE__, VStereo, group);
15046   theCommands.Add ("vcaps",
15047             "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
15048     "\n\t\t:       [-compatibleProfile {0|1}] [-compressedTextures {0|1}]"
15049     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}] [-opaqueAlpha {0|1}]"
15050     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
15051     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
15052     "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
15053     "\n\t\t: Modify particular graphic driver options:"
15054     "\n\t\t:  sRGB     - enable/disable sRGB rendering"
15055     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
15056     "\n\t\t:             built-in GLSL programs"
15057     "\n\t\t:            (requires compatible profile)"
15058     "\n\t\t:  polygonMode - use Polygon Mode instead of built-in GLSL programs"
15059     "\n\t\t:  compressedTexture - allow uploading of GPU-supported compressed texture formats"
15060     "\n\t\t:  VBO      - use Vertex Buffer Object (copy vertex"
15061     "\n\t\t:             arrays to GPU memory)"
15062     "\n\t\t:  sprite   - use textured sprites instead of bitmaps"
15063     "\n\t\t:  vsync    - switch VSync on or off"
15064     "\n\t\t:  opaqueAlpha - disable writes in alpha component of color buffer"
15065     "\n\t\t:  winBuffer - allow using window buffer for rendering"
15066     "\n\t\t: Context creation options:"
15067     "\n\t\t:  softMode          - software OpenGL implementation"
15068     "\n\t\t:  compatibleProfile - backward-compatible profile"
15069     "\n\t\t:  quadbuffer        - QuadBuffer"
15070     "\n\t\t:  noExtensions      - disallow usage of extensions"
15071     "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
15072     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
15073     "\n\t\t: rendering paths producing the same visual result when"
15074     "\n\t\t: possible."
15075     "\n\t\t: Command is intended for testing old hardware compatibility.",
15076     __FILE__, VCaps, group);
15077   theCommands.Add ("vmemgpu",
15078     "vmemgpu [f]: print system-dependent GPU memory information if available;"
15079     " with f option returns free memory in bytes",
15080     __FILE__, VMemGpu, group);
15081   theCommands.Add ("vreadpixel",
15082     "vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]"
15083     " : Read pixel value for active view",
15084     __FILE__, VReadPixel, group);
15085   theCommands.Add("diffimage",
15086             "diffimage imageFile1 imageFile2 [diffImageFile]"
15087     "\n\t\t:           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]"
15088     "\n\t\t:           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]"
15089     "\n\t\t: Compare two images by content and generate difference image."
15090     "\n\t\t: When -exitOnClose is specified, closing the view will exit application."
15091     "\n\t\t: When -closeOnEscape is specified, view will be closed on pressing Escape.",
15092     __FILE__, VDiffImage, group);
15093   theCommands.Add ("vselect",
15094     "vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1] [shift_selection = 0|1]\n"
15095     "- emulates different types of selection:\n"
15096     "- 1) single click selection\n"
15097     "- 2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)\n"
15098     "- 3) selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn)\n"
15099     "- 4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.\n"
15100     "     If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined \n"
15101     "     rectangle or polygon will be detected, otherwise algorithm will chose only fully included sensitives.\n"
15102     "     Default behavior is to detect only full inclusion. (partial inclusion - overlap - is not allowed by default)\n"
15103     "- 5) any of these selections with shift button pressed",
15104     __FILE__, VSelect, group);
15105   theCommands.Add ("vmoveto",
15106     "vmoveto [x y] [-reset]"
15107     "\n\t\t: Emulates cursor movement to pixel position (x,y)."
15108     "\n\t\t:   -reset resets current highlighting",
15109     __FILE__, VMoveTo, group);
15110   theCommands.Add ("vviewparams",
15111               "vviewparams [-args] [-scale [s]]"
15112       "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
15113       "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
15114       "\n\t\t: Manage current view parameters or prints all"
15115       "\n\t\t: current values when called without argument."
15116       "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
15117       "\n\t\t:   -eye  [x y z] prints or sets eye location"
15118       "\n\t\t:   -at   [x y z] prints or sets center of look"
15119       "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
15120       "\n\t\t:   -proj [x y z] prints or sets direction of look"
15121       "\n\t\t:   -center x y   sets location of center of the screen in pixels"
15122       "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
15123       "\n\t\t:                 or changes the size of its maximum dimension"
15124       "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
15125     __FILE__, VViewParams, group);
15126
15127   theCommands.Add("v2dmode",
15128     "v2dmode [-name viewName] [-mode {-on|-off}=-on]"
15129     "\n\t\t:   name   - name of existing view, if not defined, the active view is changed"
15130     "\n\t\t:   mode   - switches On/Off rotation mode"
15131     "\n\t\t: Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:"
15132     "\n\t\t:   - rotation of the view by 3rd mouse button with Ctrl active"
15133     "\n\t\t:   - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right"
15134     "\n\t\t: View camera position might be changed only by commands.",
15135     __FILE__, V2DMode, group);
15136
15137   theCommands.Add("vanimation", "Alias for vanim",
15138     __FILE__, VAnimation, group);
15139
15140   theCommands.Add("vanim",
15141             "List existing animations:"
15142     "\n\t\t:  vanim"
15143     "\n\t\t: Animation playback:"
15144     "\n\t\t:  vanim name -play|-resume [playFrom [playDuration]]"
15145     "\n\t\t:            [-speed Coeff] [-freeLook] [-lockLoop]"
15146     "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
15147     "\n\t\t:   -freeLook skip camera animations"
15148     "\n\t\t:   -lockLoop disable any interactions"
15149     "\n\t\t:"
15150     "\n\t\t: Animation definition:"
15151     "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
15152     "\n\t\t:        [start TimeSec] [duration TimeSec]"
15153     "\n\t\t:"
15154     "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
15155     "\n\t\t: specifies nested animations."
15156     "\n\t\t: There is no syntax to explicitly add new animation,"
15157     "\n\t\t: and all non-existing animations within the name will be"
15158     "\n\t\t: implicitly created on first use (including parents)."
15159     "\n\t\t:"
15160     "\n\t\t: Each animation might define the SINGLE action (see below),"
15161     "\n\t\t: like camera transition, object transformation or custom callback."
15162     "\n\t\t: Child animations can be used for defining concurrent actions."
15163     "\n\t\t:"
15164     "\n\t\t: Camera animation:"
15165     "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
15166     "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
15167     "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
15168     "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
15169     "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
15170     "\n\t\t:   -atX    camera Center positions pair"
15171     "\n\t\t:   -upX    camera Up directions pair"
15172     "\n\t\t:   -scaleX camera Scale factors pair"
15173     "\n\t\t: Object animation:"
15174     "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
15175     "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
15176     "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
15177     "\n\t\t:   -locX   object Location points pair (translation)"
15178     "\n\t\t:   -rotX   object Orientations pair (quaternions)"
15179     "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
15180     "\n\t\t: Custom callback:"
15181     "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
15182     "\n\t\t:   %Pts        overall animation presentation timestamp"
15183     "\n\t\t:   %LocalPts   local animation timestamp"
15184     "\n\t\t:   %Normalized local animation normalized value in range 0..1"
15185     "\n\t\t:"
15186     "\n\t\t: Video recording:"
15187     "\n\t\t:  vanim name -record FileName [Width Height] [-fps FrameRate=24]"
15188     "\n\t\t:             [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]"
15189     "\n\t\t:             [-crf Value] [-preset Preset]"
15190     "\n\t\t:   -fps     video framerate"
15191     "\n\t\t:   -format  file format, container (matroska, etc.)"
15192     "\n\t\t:   -vcodec  video codec identifier (ffv1, mjpeg, etc.)"
15193     "\n\t\t:   -pix_fmt image pixel format (yuv420p, rgb24, etc.)"
15194     "\n\t\t:   -crf     constant rate factor (specific to codec)"
15195     "\n\t\t:   -preset  codec parameters preset (specific to codec)"
15196     __FILE__, VAnimation, group);
15197
15198   theCommands.Add("vchangeselected",
15199     "vchangeselected shape"
15200     "- adds to shape to selection or remove one from it",
15201                 __FILE__, VChangeSelected, group);
15202   theCommands.Add ("vnbselected",
15203     "vnbselected"
15204     "\n\t\t: Returns number of selected objects", __FILE__, VNbSelected, group);
15205   theCommands.Add ("vcamera",
15206               "vcamera [PrsName] [-ortho] [-projtype]"
15207       "\n\t\t:         [-persp]"
15208       "\n\t\t:         [-fovy   [Angle]] [-distance [Distance]]"
15209       "\n\t\t:         [-stereo] [-leftEye] [-rightEye]"
15210       "\n\t\t:         [-iod [Distance]] [-iodType    [absolute|relative]]"
15211       "\n\t\t:         [-zfocus [Value]] [-zfocusType [absolute|relative]]"
15212       "\n\t\t:         [-fov2d  [Angle]] [-lockZup {0|1}]"
15213       "\n\t\t:         [-xrPose base|head=base]"
15214       "\n\t\t: Manages camera parameters."
15215       "\n\t\t: Displays frustum when presentation name PrsName is specified."
15216       "\n\t\t: Prints current value when option called without argument."
15217       "\n\t\t: Orthographic camera:"
15218       "\n\t\t:   -ortho      activate orthographic projection"
15219       "\n\t\t: Perspective camera:"
15220       "\n\t\t:   -persp      activate perspective  projection (mono)"
15221       "\n\t\t:   -fovy       field of view in y axis, in degrees"
15222       "\n\t\t:   -fov2d      field of view limit for 2d on-screen elements"
15223       "\n\t\t:   -distance   distance of eye from camera center"
15224       "\n\t\t:   -lockZup    lock Z up (tunrtable mode)"
15225       "\n\t\t: Stereoscopic camera:"
15226       "\n\t\t:   -stereo     perspective  projection (stereo)"
15227       "\n\t\t:   -leftEye    perspective  projection (left  eye)"
15228       "\n\t\t:   -rightEye   perspective  projection (right eye)"
15229       "\n\t\t:   -iod        intraocular distance value"
15230       "\n\t\t:   -iodType    distance type, absolute or relative"
15231       "\n\t\t:   -zfocus     stereographic focus value"
15232       "\n\t\t:   -zfocusType focus type, absolute or relative",
15233     __FILE__, VCamera, group);
15234   theCommands.Add ("vautozfit", "command to enable or disable automatic z-range adjusting\n"
15235     "- vautozfit [on={1|0}] [scale]\n"
15236     "    Prints or changes parameters of automatic z-fit mode:\n"
15237     "   \"on\" - turns automatic z-fit on or off\n"
15238     "   \"scale\" - specifies factor to scale computed z range.\n",
15239     __FILE__, VAutoZFit, group);
15240   theCommands.Add ("vzrange", "command to manually access znear and zfar values\n"
15241     "   vzrange                - without parameters shows current values\n"
15242     "   vzrange [znear] [zfar] - applies provided values to view",
15243     __FILE__,VZRange, group);
15244   theCommands.Add("vsetviewsize",
15245     "vsetviewsize size",
15246     __FILE__,VSetViewSize,group);
15247   theCommands.Add("vmoveview",
15248     "vmoveview Dx Dy Dz [Start = 1|0]",
15249     __FILE__,VMoveView,group);
15250   theCommands.Add("vtranslateview",
15251     "vtranslateview Dx Dy Dz [Start = 1|0)]",
15252     __FILE__,VTranslateView,group);
15253   theCommands.Add("vturnview",
15254     "vturnview Ax Ay Az [Start = 1|0]",
15255     __FILE__,VTurnView,group);
15256   theCommands.Add("vtextureenv",
15257     "Enables or disables environment mapping in the 3D view, loading the texture from the given standard "
15258     "or user-defined file and optionally applying texture mapping parameters\n"
15259     "                  Usage:\n"
15260     "                  vtextureenv off - disables environment mapping\n"
15261     "                  vtextureenv on {std_texture|texture_file_name} [rep mod flt ss st ts tt rot] - enables environment mapping\n"
15262     "                              std_texture = (0..7)\n"
15263     "                              rep         = {clamp|repeat}\n"
15264     "                              mod         = {decal|modulate}\n"
15265     "                              flt         = {nearest|bilinear|trilinear}\n"
15266     "                              ss, st      - scale factors for s and t texture coordinates\n"
15267     "                              ts, tt      - translation for s and t texture coordinates\n"
15268     "                              rot         - texture rotation angle in degrees",
15269     __FILE__, VTextureEnv, group);
15270   theCommands.Add("vhlr",
15271             "vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]"
15272       "\n\t\t: Hidden Line Removal algorithm."
15273       "\n\t\t:   -showHidden if set ON, hidden lines are drawn as dotted ones"
15274       "\n\t\t:   -algoType   type of HLR algorithm.\n",
15275     __FILE__,VHLR,group);
15276   theCommands.Add("vhlrtype",
15277               "vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]"
15278       "\n\t\t: Changes the type of HLR algorithm using for shapes:"
15279       "\n\t\t:   'algo' - exact HLR algorithm is applied"
15280       "\n\t\t:   'polyAlgo' - polygonal HLR algorithm is applied"
15281       "\n\t\t: If shapes are not given - option is applied to all shapes in the view",
15282     __FILE__,VHLRType,group);
15283   theCommands.Add("vclipplane",
15284               "vclipplane planeName [{0|1}]"
15285       "\n\t\t:   [-equation1 A B C D]"
15286       "\n\t\t:   [-equation2 A B C D]"
15287       "\n\t\t:   [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]"
15288       "\n\t\t:   [-set|-unset|-setOverrideGlobal [objects|views]]"
15289       "\n\t\t:   [-maxPlanes]"
15290       "\n\t\t:   [-capping {0|1}]"
15291       "\n\t\t:     [-color R G B] [-transparency Value] [-hatch {on|off|ID}]"
15292       "\n\t\t:     [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]"
15293       "\n\t\t:       [-texRotate Angle]"
15294       "\n\t\t:     [-useObjMaterial {0|1}] [-useObjTexture {0|1}]"
15295       "\n\t\t:       [-useObjShader {0|1}]"
15296       "\n\t\t: Clipping planes management:"
15297       "\n\t\t:   -maxPlanes   print plane limit for view"
15298       "\n\t\t:   -delete      delete plane with given name"
15299       "\n\t\t:   {off|on|0|1} turn clipping on/off"
15300       "\n\t\t:   -set|-unset  set/unset plane for Object or View list;"
15301       "\n\t\t:                applied to active View when list is omitted"
15302       "\n\t\t:   -equation A B C D change plane equation"
15303       "\n\t\t:   -clone SourcePlane NewPlane clone the plane definition."
15304       "\n\t\t: Capping options:"
15305       "\n\t\t:   -capping {off|on|0|1} turn capping on/off"
15306       "\n\t\t:   -color R G B          set capping color"
15307       "\n\t\t:   -transparency Value   set capping transparency 0..1"
15308       "\n\t\t:   -texName Texture      set capping texture"
15309       "\n\t\t:   -texScale SX SY       set capping tex scale"
15310       "\n\t\t:   -texOrigin TX TY      set capping tex origin"
15311       "\n\t\t:   -texRotate Angle      set capping tex rotation"
15312       "\n\t\t:   -hatch {on|off|ID}    set capping hatching mask"
15313       "\n\t\t:   -useObjMaterial {off|on|0|1} use material of clipped object"
15314       "\n\t\t:   -useObjTexture  {off|on|0|1} use texture of clipped object"
15315       "\n\t\t:   -useObjShader   {off|on|0|1} use shader program of object",
15316       __FILE__, VClipPlane, group);
15317   theCommands.Add("vdefaults",
15318                "vdefaults [-absDefl value]"
15319        "\n\t\t:           [-devCoeff value]"
15320        "\n\t\t:           [-angDefl value]"
15321        "\n\t\t:           [-autoTriang {off/on | 0/1}]"
15322     , __FILE__, VDefaults, group);
15323   theCommands.Add("vlight",
15324     "tool to manage light sources, without arguments shows list of lights."
15325     "\n    Main commands: "
15326     "\n      '-clear' to clear lights"
15327     "\n      '-{def}aults' to load default lights"
15328     "\n      '-add' <type> to add any light source"
15329     "\n          where <type> is one of {amb}ient|directional|{spot}light|positional"
15330     "\n      'change' <lightId> to edit light source with specified lightId"
15331     "\n\n      In addition to 'add' and 'change' commands you can use light parameters:"
15332     "\n        -layer Id"
15333     "\n        -{pos}ition X Y Z"
15334     "\n        -{dir}ection X Y Z (for directional light or for spotlight)"
15335     "\n        -color colorName"
15336     "\n        -{head}light 0|1"
15337     "\n        -castShadows 0|1"
15338     "\n        -{sm}oothness value"
15339     "\n        -{int}ensity value"
15340     "\n        -{constAtten}uation value"
15341     "\n        -{linearAtten}uation value"
15342     "\n        -angle angleDeg"
15343     "\n        -{spotexp}onent value"
15344     "\n        -range value"
15345     "\n        -local|-global"
15346     "\n        -name value"
15347     "\n        -display nameOfLight (display light source with specified nameOfLight or its name)"
15348     "\n        -showName  {1|0} show/hide the name of light source; 1 by default"
15349     "\n        -showRange {1|0} show/hide the range of spot/positional light source; 1 by default"
15350     "\n        -prsZoomable {1|0} make light presentation zoomable/non-zoomable"
15351     "\n        -prsSize {Value} set light presentation size"
15352     "\n\n      example: vlight -add positional -head 1 -pos 0 1 1 -color red"
15353     "\n        example: vlight -change 0 -direction 0 -1 0 -linearAttenuation 0.2",
15354     __FILE__, VLight, group);
15355   theCommands.Add("vpbrenv",
15356     "vpbrenv -clear|-generate"
15357     "\n\t\t: Clears or generates PBR environment map of active view."
15358     "\n\t\t:  -clear clears PBR environment (fills by white color)"
15359     "\n\t\t:  -generate generates PBR environment from current background cubemap",
15360     __FILE__, VPBREnvironment, group);
15361   theCommands.Add("vraytrace",
15362             "vraytrace [0|1]"
15363     "\n\t\t: Turns on/off ray-tracing renderer."
15364     "\n\t\t:   'vraytrace 0' alias for 'vrenderparams -raster'."
15365     "\n\t\t:   'vraytrace 1' alias for 'vrenderparams -rayTrace'.",
15366     __FILE__, VRenderParams, group);
15367   theCommands.Add("vrenderparams",
15368     "\n\t\t: Manages rendering parameters, affecting visual appearance, quality and performance."
15369     "\n\t\t: Should be applied taking into account GPU hardware capabilities and performance."
15370     "\n\t\t: Common parameters:"
15371     "\n\t\t: vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]"
15372     "\n\t\t:               [-msaa 0..8=0] [-rendScale scale=1] [-resolution value=72]"
15373     "\n\t\t:               [-oit {off|0.0-1.0}=off]"
15374     "\n\t\t:               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]"
15375     "\n\t\t:               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]"
15376     "\n\t\t:               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]"
15377     "\n\t\t:               [-sync {default|views}] [-reset]"
15378     "\n\t\t:   -raster          Disables GPU ray-tracing."
15379     "\n\t\t:   -shadingModel    Controls shading model."
15380     "\n\t\t:   -msaa            Specifies number of samples for MSAA."
15381     "\n\t\t:   -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA)."
15382     "\n\t\t:   -resolution      Sets new pixels density (PPI) used as text scaling factor."
15383     "\n\t\t:   -lineFeather     Sets line feather factor while displaying mesh edges."
15384     "\n\t\t:   -alphaToCoverage Enables/disables alpha to coverage (needs MSAA)."
15385     "\n\t\t:   -oit             Enables/disables order-independent transparency (OIT) rendering;"
15386     "\n\t\t:                    weight OIT fixes transparency artifacts at the cost of blurry result,"
15387     "\n\t\t:                    it is managed by depth weight factor (0.0 value also enables weight OIT)."
15388     "\n\t\t:   -shadows         Enables/disables shadows rendering."
15389     "\n\t\t:   -shadowMapResolution Shadow texture map resolution."
15390     "\n\t\t:   -shadowMapBias   Shadow map bias."
15391     "\n\t\t:   -depthPrePass    Enables/disables depth pre-pass."
15392     "\n\t\t:   -frustumCulling  Enables/disables objects frustum clipping or"
15393     "\n\t\t:                    sets state to check structures culled previously."
15394     "\n\t\t:   -sync            Sets active View parameters as Viewer defaults / to other Views."
15395     "\n\t\t:   -reset           Resets active View parameters to Viewer defaults."
15396     "\n\t\t: Diagnostic output (on-screen overlay):"
15397     "\n\t\t: vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points"
15398     "\n\t\t:                             |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]"
15399     "\n\t\t:               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]"
15400     "\n\t\t:   -perfCounters       Show/hide performance counters (flags can be combined)."
15401     "\n\t\t:   -perfUpdateInterval Performance counters update interval."
15402     "\n\t\t:   -perfChart          Show frame timers chart limited by specified number of frames."
15403     "\n\t\t:   -perfChartMax       Maximum time in seconds with the chart."
15404     "\n\t\t: Ray-Tracing options:"
15405     "\n\t\t: vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]"
15406     "\n\t\t:               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]"
15407     "\n\t\t:               [-gi {on|off}=off] [-brng {on|off}=off]"
15408     "\n\t\t:               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]"
15409     "\n\t\t:               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]"
15410     "\n\t\t:               [-maxRad {value>0}=30.0]"
15411     "\n\t\t:               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]"
15412     "\n\t\t:               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]"
15413     "\n\t\t:   -rayTrace     Enables  GPU ray-tracing."
15414     "\n\t\t:   -rayDepth     Defines maximum ray-tracing depth."
15415     "\n\t\t:   -reflections  Enables/disables specular reflections."
15416     "\n\t\t:   -fsaa         Enables/disables adaptive anti-aliasing."
15417     "\n\t\t:   -gleam        Enables/disables transparency shadow effects."
15418     "\n\t\t:   -gi           Enables/disables global illumination effects (Path-Tracing)."
15419     "\n\t\t:   -env          Enables/disables environment map background."
15420     "\n\t\t:   -ignoreNormalMap Enables/disables normal map ignoring during path tracing."
15421     "\n\t\t:   -twoSide      Enables/disables two-sided BSDF models (PT mode)."
15422     "\n\t\t:   -iss          Enables/disables adaptive screen sampling (PT mode)."
15423     "\n\t\t:   -maxRad       Value used for clamping radiance estimation (PT mode)."
15424     "\n\t\t:   -tileSize     Specifies   size of screen tiles in ISS mode (32 by default)."
15425     "\n\t\t:   -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default)."
15426     "\n\t\t:   -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF)."
15427     "\n\t\t:   -focal        Focal distance of perspective camera for depth-of-field effect."
15428     "\n\t\t:   -exposure     Exposure value for tone mapping (0.0 value disables the effect)."
15429     "\n\t\t:   -whitePoint   White point value for filmic tone mapping."
15430     "\n\t\t:   -toneMapping  Tone mapping mode (disabled, filmic)."
15431     "\n\t\t: PBR environment baking parameters (advanced/debug):"
15432     "\n\t\t: vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]"
15433     "\n\t\t:               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]"
15434     "\n\t\t:   -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size)."
15435     "\n\t\t:   -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map."
15436     "\n\t\t:   -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during"
15437     "\n\t\t:                   diffuse IBL map's sherical harmonics calculation."
15438     "\n\t\t:   -pbrEnvBSSN     Controls maximum number of samples per mipmap level"
15439     "\n\t\t:                   in Monte-Carlo integration during specular IBL maps generation."
15440     "\n\t\t:   -pbrEnvBP       Controls strength of samples number reducing"
15441     "\n\t\t:                   during specular IBL maps generation (1 disables reducing)."
15442     "\n\t\t: Debug options:"
15443     "\n\t\t: vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]"
15444     "\n\t\t:   -issd         Shows screen sampling distribution in ISS mode."
15445     "\n\t\t:   -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging)."
15446     "\n\t\t:   -brng         Enables/disables blocked RNG (fast coherent PT).",
15447     __FILE__, VRenderParams, group);
15448   theCommands.Add("vstatprofiler",
15449     "\n vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups"
15450     "\n                |allArrays|fillArrays|lineArrays|pointArrays|textArrays"
15451     "\n                |triangles|points|geomMem|textureMem|frameMem"
15452     "\n                |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage"
15453     "\n                |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]"
15454     "\n                [-noredraw]"
15455     "\n\t\t: Prints rendering statistics."
15456     "\n\t\t:   If there are some parameters - print corresponding statistic counters values,"
15457     "\n\t\t:   else - print all performance counters set previously."
15458     "\n\t\t:   '-noredraw' Flag to avoid additional redraw call and use already collected values.\n",
15459     __FILE__, VStatProfiler, group);
15460   theCommands.Add ("vplace",
15461             "vplace dx dy"
15462     "\n\t\t: Places the point (in pixels) at the center of the window",
15463     __FILE__, VPlace, group);
15464   theCommands.Add("vxrotate",
15465     "vxrotate",
15466     __FILE__,VXRotate,group);
15467
15468     theCommands.Add("vmanipulator",
15469       "\n    vmanipulator Name [-attach AISObject | -detach | ...]"
15470       "\n    tool to create and manage AIS manipulators."
15471       "\n    Options: "
15472       "\n      '-attach AISObject'                 attach manipulator to AISObject"
15473       "\n      '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching"
15474       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
15475       "\n      '-enableModes    {0|1}'             enable modes when attaching"
15476       "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
15477       "\n                                          by default it is displayed in all views of the current viewer"
15478       "\n      '-detach'                           detach manipulator"
15479       "\n      '-startTransform mouse_x mouse_y' - invoke start of transformation"
15480       "\n      '-transform      mouse_x mouse_y' - invoke transformation"
15481       "\n      '-stopTransform  [abort]'         - invoke stop of transformation"
15482       "\n      '-move x y z'                     - move attached object"
15483       "\n      '-rotate x y z dx dy dz angle'    - rotate attached object"
15484       "\n      '-scale factor'                   - scale attached object"
15485       "\n      '-autoActivate      {0|1}'        - set activation on detection"
15486       "\n      '-followTranslation {0|1}'        - set following translation transform"
15487       "\n      '-followRotation    {0|1}'        - set following rotation transform"
15488       "\n      '-followDragging    {0|1}'        - set following dragging transform"
15489       "\n      '-gap value'                      - set gap between sub-parts"
15490       "\n      '-part axis mode    {0|1}'        - set visual part"
15491       "\n      '-parts axis mode   {0|1}'        - set visual part"
15492       "\n      '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator"
15493       "\n      '-size value'                     - set size of manipulator"
15494       "\n      '-zoomable {0|1}'                 - set zoom persistence",
15495     __FILE__, VManipulator, group);
15496
15497   theCommands.Add("vselprops",
15498     "\n    vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]"
15499     "\n    Customizes selection and dynamic highlight parameters for the whole interactive context:"
15500     "\n    -autoActivate {0|1}     : disables|enables default computation and activation of global selection mode"
15501     "\n    -autoHighlight {0|1}    : disables|enables automatic highlighting in 3D Viewer"
15502     "\n    -highlightSelected {0|1}: disables|enables highlighting of detected object in selected state"
15503     "\n    -pickStrategy {first|topmost} : defines picking strategy"
15504     "\n                            'first'   to pick first acceptable (default)"
15505     "\n                            'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)"
15506     "\n    -pixTol    value        : sets up pixel tolerance"
15507     "\n    -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth"
15508     "\n    -depthTol {sensfactor}  : use sensitive factor for sorting results by depth"
15509     "\n    -preferClosest {0|1}    : sets if depth should take precedence over priority while sorting results"
15510     "\n    -dispMode  dispMode     : sets display mode for highlighting"
15511     "\n    -layer     ZLayer       : sets ZLayer for highlighting"
15512     "\n    -color     {name|r g b} : sets highlight color"
15513     "\n    -transp    value        : sets transparency coefficient for highlight"
15514     "\n    -material  material     : sets highlight material"
15515     "\n    -print                  : prints current state of all mentioned parameters",
15516     __FILE__, VSelectionProperties, group);
15517   theCommands.Add ("vhighlightselected",
15518                    "vhighlightselected [0|1]: alias for vselprops -highlightSelected.\n",
15519                    __FILE__, VSelectionProperties, group);
15520
15521   theCommands.Add ("vseldump",
15522                    "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
15523                    "\n\t\t:       [-xrPose base|head=base]"
15524                    "\n\t\t: Generate an image based on detection results:"
15525                    "\n\t\t:   depth       normalized depth values"
15526                    "\n\t\t:   unnormDepth unnormalized depth values"
15527                    "\n\t\t:   object      color of detected object"
15528                    "\n\t\t:   owner       color of detected owner"
15529                    "\n\t\t:   selMode     color of selection mode"
15530                    "\n\t\t:   entity      color of etected entity",
15531                    __FILE__, VDumpSelectionImage, group);
15532
15533   theCommands.Add ("vviewcube",
15534                    "vviewcube name"
15535                    "\n\t\t: Displays interactive view manipualtion object."
15536                    "\n\t\t: Options: "
15537                    "\n\t\t:   -reset                   reset geomertical and visual attributes'"
15538                    "\n\t\t:   -size Size               adapted size of View Cube"
15539                    "\n\t\t:   -boxSize Size            box size"
15540                    "\n\t\t:   -axes  {0|1}             show/hide axes (trihedron)"
15541                    "\n\t\t:   -edges {0|1}             show/hide edges of View Cube"
15542                    "\n\t\t:   -vertices {0|1}          show/hide vertices of View Cube"
15543                    "\n\t\t:   -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation"
15544                    "\n\t\t:   -color Color             color of View Cube"
15545                    "\n\t\t:   -boxColor Color          box color"
15546                    "\n\t\t:   -boxSideColor Color      box sides color"
15547                    "\n\t\t:   -boxEdgeColor Color      box edges color"
15548                    "\n\t\t:   -boxCornerColor Color    box corner color"
15549                    "\n\t\t:   -textColor Color         color of side text of view cube"
15550                    "\n\t\t:   -innerColor Color        inner box color"
15551                    "\n\t\t:   -transparency Value      transparency of object within [0, 1] range"
15552                    "\n\t\t:   -boxTransparency Value   transparency of box    within [0, 1] range"
15553                    "\n\t\t:   -xAxisTextColor Color    color of X axis label"
15554                    "\n\t\t:   -yAxisTextColor Color    color of Y axis label"
15555                    "\n\t\t:   -zAxisTextColor Color    color of Z axis label"
15556                    "\n\t\t:   -font Name               font name"
15557                    "\n\t\t:   -fontHeight Value        font height"
15558                    "\n\t\t:   -boxFacetExtension Value box facet extension"
15559                    "\n\t\t:   -boxEdgeGap Value        gap between box edges and box sides"
15560                    "\n\t\t:   -boxEdgeMinSize Value    minimal box edge size"
15561                    "\n\t\t:   -boxCornerMinSize Value  minimal box corner size"
15562                    "\n\t\t:   -axesPadding Value       padding between box and arrows"
15563                    "\n\t\t:   -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range"
15564                    "\n\t\t:   -axesRadius Value        radius of axes of the trihedron"
15565                    "\n\t\t:   -axesConeRadius Value    radius of the cone (arrow) of the trihedron"
15566                    "\n\t\t:   -axesSphereRadius Value  radius of the sphere (central point) of trihedron"
15567                    "\n\t\t:   -fixedanimation {0|1}    uninterruptible animation loop"
15568                    "\n\t\t:   -duration Seconds        animation duration in seconds",
15569     __FILE__, VViewCube, group);
15570
15571   theCommands.Add("vcolorconvert" ,
15572                   "vcolorconvert {from|to} type C1 C2 C2"
15573                   "\n\t\t: vcolorconvert from type C1 C2 C2: Converts color from specified color space to linear RGB"
15574                   "\n\t\t: vcolorconvert to type R G B: Converts linear RGB color to specified color space"
15575                   "\n\t\t: type can be sRGB, HLS, Lab, or Lch",
15576                   __FILE__,VColorConvert,group);
15577   theCommands.Add("vcolordiff" ,
15578                   "vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
15579                   __FILE__,VColorDiff,group);
15580   theCommands.Add("vselbvhbuild",
15581                   "vselbvhbuild [{0|1}] [-nbThreads value] [-wait]"
15582                   "\n\t\t: Turns on/off prebuilding of BVH within background thread(s)"
15583                   "\n\t\t:   -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1)"
15584                   "\n\t\t:   -wait        waits for building all of BVH",
15585                   __FILE__,VSelBvhBuild,group);
15586 }